1 // Copyright 2023, The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 //! Cuttlefish's NFC HAL.
16 
17 use android_hardware_nfc::aidl::android::hardware::nfc::INfc::{BnNfc, INfcAsyncServer};
18 use binder::{self, BinderFeatures, ProcessState};
19 use binder_tokio::TokioRuntime;
20 use clap::Parser;
21 use log::{error, info, LevelFilter};
22 use std::path::PathBuf;
23 use std::{panic, process};
24 use tokio::runtime::Runtime;
25 
26 mod nci;
27 mod nfc;
28 
29 use crate::nfc::NfcService;
30 
31 const LOG_TAG: &str = "CfNfc";
32 
33 #[derive(Parser)]
34 struct Cli {
35     /// Virtio-console dev driver path
36     #[arg(long)]
37     virtio_dev_path: PathBuf,
38 }
39 
main()40 fn main() {
41     android_logger::init_once(
42         android_logger::Config::default().with_tag(LOG_TAG).with_max_level(LevelFilter::Debug),
43     );
44 
45     // Redirect panic messages to logcat.
46     panic::set_hook(Box::new(|panic_info| {
47         error!("{}", panic_info);
48         process::exit(0); // Force panic in thread to quit.
49     }));
50 
51     // Start binder thread pool with the minimum threads pool (= 1),
52     // because NFC APEX is the only user of the NFC HAL.
53     ProcessState::set_thread_pool_max_thread_count(0);
54     ProcessState::start_thread_pool();
55 
56     // Prepare Tokio runtime with default (multi-threaded) configurations.
57     // We'll spawn I/O threads in AIDL calls, so Runtime can't create with current thread
58     // as other HALs do.
59     let runtime = Runtime::new().expect("Failed to initialize Tokio runtime");
60 
61     // Initializes.
62     let cli = Cli::parse();
63     let nfc_service = runtime.block_on(NfcService::new(&cli.virtio_dev_path));
64     let nfc_service_binder =
65         BnNfc::new_async_binder(nfc_service, TokioRuntime(runtime), BinderFeatures::default());
66 
67     let service_name = format!("{}/default", NfcService::get_descriptor());
68     info!("Starting {service_name} with {:?}", cli.virtio_dev_path);
69     binder::add_service(&service_name, nfc_service_binder.as_binder())
70         .expect("Failed to register service");
71 
72     // Wait for binder thread to be completed. Unexpected for HAL, though.
73     ProcessState::join_thread_pool();
74 
75     info!("NFC HAL is shutting down");
76 }
77