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