blob: efb24543234942484efbcfb8d6aa53a3e48bcbe3 [file] [log] [blame]
Charlie Boutierd572dd02023-04-10 18:14:23 +00001use android_hardware_uwb::aidl::android::hardware::uwb::{
2 IUwbChip::IUwbChipAsyncServer, IUwbClientCallback::IUwbClientCallback, UwbEvent::UwbEvent,
3 UwbStatus::UwbStatus,
4};
5use android_hardware_uwb::binder;
6use async_trait::async_trait;
ziyiw4fec12a2023-09-27 21:00:25 +00007use binder::{DeathRecipient, IBinder, Result, Strong};
Charlie Boutierd572dd02023-04-10 18:14:23 +00008
ziyiw4fec12a2023-09-27 21:00:25 +00009use std::sync::Arc;
10use tokio::io::unix::AsyncFd;
11use tokio::select;
Charlie Boutierd572dd02023-04-10 18:14:23 +000012use tokio::sync::Mutex;
ziyiw4fec12a2023-09-27 21:00:25 +000013use tokio_util::sync::CancellationToken;
Charlie Boutierd572dd02023-04-10 18:14:23 +000014
ziyiw4fec12a2023-09-27 21:00:25 +000015use std::fs::{File, OpenOptions};
16use std::io::{self, Read, Write};
Henri Chataing7e798082023-10-05 16:14:12 +000017use std::os::unix::fs::OpenOptionsExt;
Charlie Boutierd572dd02023-04-10 18:14:23 +000018
Charlie Boutierd572dd02023-04-10 18:14:23 +000019enum State {
20 Closed,
21 Opened {
22 callbacks: Strong<dyn IUwbClientCallback>,
Henri Chataing7e798082023-10-05 16:14:12 +000023 handle: tokio::task::JoinHandle<()>,
Henri Chataing77971b32023-08-16 16:55:24 +000024 serial: File,
ziyiw4fec12a2023-09-27 21:00:25 +000025 death_recipient: DeathRecipient,
26 token: CancellationToken,
Charlie Boutierd572dd02023-04-10 18:14:23 +000027 },
28}
29
30pub struct UwbChip {
31 name: String,
32 path: String,
ziyiw4fec12a2023-09-27 21:00:25 +000033 state: Arc<Mutex<State>>,
Charlie Boutierd572dd02023-04-10 18:14:23 +000034}
35
36impl UwbChip {
37 pub fn new(name: String, path: String) -> Self {
38 Self {
39 name,
40 path,
ziyiw4fec12a2023-09-27 21:00:25 +000041 state: Arc::new(Mutex::new(State::Closed)),
Charlie Boutierd572dd02023-04-10 18:14:23 +000042 }
43 }
44}
45
ziyiw4fec12a2023-09-27 21:00:25 +000046impl State {
47 /// Terminate the reader task.
Henri Chataing7e798082023-10-05 16:14:12 +000048 async fn close(&mut self) -> Result<()> {
49 if let State::Opened { ref mut token, ref callbacks, ref mut death_recipient, ref mut handle, .. } = *self {
ziyiw4fec12a2023-09-27 21:00:25 +000050 log::info!("waiting for task cancellation");
51 callbacks.as_binder().unlink_to_death(death_recipient)?;
52 token.cancel();
Henri Chataing7e798082023-10-05 16:14:12 +000053 handle.await.unwrap();
ziyiw4fec12a2023-09-27 21:00:25 +000054 log::info!("task successfully cancelled");
55 callbacks.onHalEvent(UwbEvent::CLOSE_CPLT, UwbStatus::OK)?;
56 *self = State::Closed;
57 }
58 Ok(())
59 }
60}
61
Charlie Boutierd572dd02023-04-10 18:14:23 +000062pub fn makeraw(file: File) -> io::Result<File> {
Andrew Walbran116bf2a2023-12-05 16:17:24 +000063 // Configure the file descriptor as raw fd.
ziyiw4fec12a2023-09-27 21:00:25 +000064 use nix::sys::termios::*;
Andrew Walbran116bf2a2023-12-05 16:17:24 +000065 let mut attrs = tcgetattr(&file)?;
ziyiw4fec12a2023-09-27 21:00:25 +000066 cfmakeraw(&mut attrs);
Andrew Walbran116bf2a2023-12-05 16:17:24 +000067 tcsetattr(&file, SetArg::TCSANOW, &attrs)?;
Charlie Boutierd572dd02023-04-10 18:14:23 +000068
Charlie Boutierd572dd02023-04-10 18:14:23 +000069 Ok(file)
70}
71
ziyiw4fec12a2023-09-27 21:00:25 +000072/// Wrapper around Read::read to handle EWOULDBLOCK.
73/// /!\ will actively wait for more data, make sure to call
74/// this method only when data is immediately expected.
75fn read_exact(file: &mut File, mut buf: &mut [u8]) -> io::Result<()> {
76 while buf.len() > 0 {
77 match file.read(buf) {
78 Ok(0) => panic!("unexpectedly reached end of file"),
79 Ok(read_len) => buf = &mut buf[read_len..],
80 Err(err) if err.kind() == io::ErrorKind::WouldBlock => continue,
81 Err(err) => return Err(err),
82 }
83 }
84 Ok(())
85}
86
Charlie Boutierd572dd02023-04-10 18:14:23 +000087impl binder::Interface for UwbChip {}
88
89#[async_trait]
90impl IUwbChipAsyncServer for UwbChip {
91 async fn getName(&self) -> Result<String> {
92 Ok(self.name.clone())
93 }
94
95 async fn open(&self, callbacks: &Strong<dyn IUwbClientCallback>) -> Result<()> {
96 log::debug!("open: {:?}", &self.path);
97
ziyiw4fec12a2023-09-27 21:00:25 +000098 let mut state = self.state.lock().await;
99
100 if matches!(*state, State::Opened { .. }) {
101 log::error!("the state is already opened");
102 return Err(binder::ExceptionCode::ILLEGAL_STATE.into());
103 }
104
Henri Chataing77971b32023-08-16 16:55:24 +0000105 let serial = OpenOptions::new()
106 .read(true)
107 .write(true)
108 .create(false)
Henri Chataing7e798082023-10-05 16:14:12 +0000109 .custom_flags(libc::O_NONBLOCK)
Henri Chataing77971b32023-08-16 16:55:24 +0000110 .open(&self.path)
Charlie Boutierd572dd02023-04-10 18:14:23 +0000111 .and_then(makeraw)
112 .map_err(|_| binder::StatusCode::UNKNOWN_ERROR)?;
113
ziyiw4fec12a2023-09-27 21:00:25 +0000114 let state_death_recipient = self.state.clone();
115 let mut death_recipient = DeathRecipient::new(move || {
116 let mut state = state_death_recipient.blocking_lock();
117 log::info!("Uwb service has died");
Henri Chataing7e798082023-10-05 16:14:12 +0000118 if let State::Opened { ref mut token, .. } = *state {
119 token.cancel();
120 *state = State::Closed;
121 }
ziyiw4fec12a2023-09-27 21:00:25 +0000122 });
Charlie Boutierd572dd02023-04-10 18:14:23 +0000123
ziyiw4fec12a2023-09-27 21:00:25 +0000124 callbacks.as_binder().link_to_death(&mut death_recipient)?;
Charlie Boutierd572dd02023-04-10 18:14:23 +0000125
ziyiw4fec12a2023-09-27 21:00:25 +0000126 let token = CancellationToken::new();
127 let cloned_token = token.clone();
Charlie Boutierd572dd02023-04-10 18:14:23 +0000128
ziyiw4fec12a2023-09-27 21:00:25 +0000129 let client_callbacks = callbacks.clone();
Charlie Boutierd572dd02023-04-10 18:14:23 +0000130
ziyiw4fec12a2023-09-27 21:00:25 +0000131 let reader = serial
132 .try_clone()
133 .map_err(|_| binder::StatusCode::UNKNOWN_ERROR)?;
Charlie Boutierd572dd02023-04-10 18:14:23 +0000134
ziyiw4fec12a2023-09-27 21:00:25 +0000135 let join_handle = tokio::task::spawn(async move {
Henri Chataing7e798082023-10-05 16:14:12 +0000136 log::info!("UCI reader task started");
ziyiw4fec12a2023-09-27 21:00:25 +0000137 let mut reader = AsyncFd::new(reader).unwrap();
Charlie Boutierd572dd02023-04-10 18:14:23 +0000138
ziyiw4fec12a2023-09-27 21:00:25 +0000139 loop {
140 const UWB_HEADER_SIZE: usize = 4;
141 let mut buffer = vec![0; UWB_HEADER_SIZE];
Charlie Boutierd572dd02023-04-10 18:14:23 +0000142
ziyiw4fec12a2023-09-27 21:00:25 +0000143 // The only time where the task can be safely
144 // cancelled is when no packet bytes have been read.
145 //
146 // - read_exact() cannot be used here since it is not
147 // cancellation safe.
148 // - read() cannot be used because it cannot be cancelled:
149 // the syscall is executed blocking on the threadpool
150 // and completes after termination of the task when
151 // the pipe receives more data.
152 let read_len = loop {
153 // On some platforms, the readiness detecting mechanism
154 // relies on edge-triggered notifications. This means that
155 // the OS will only notify Tokio when the file descriptor
156 // transitions from not-ready to ready. For this to work
157 // you should first try to read or write and only poll for
Henri Chataing7e798082023-10-05 16:14:12 +0000158 // readiness if that fails with an error of
ziyiw4fec12a2023-09-27 21:00:25 +0000159 // std::io::ErrorKind::WouldBlock.
160 match reader.get_mut().read(&mut buffer) {
161 Ok(0) => {
162 log::error!("file unexpectedly closed");
163 return;
164 }
165 Ok(read_len) => break read_len,
166 Err(err) if err.kind() == io::ErrorKind::WouldBlock => (),
167 Err(_) => panic!("unexpected read failure"),
168 }
Charlie Boutierd572dd02023-04-10 18:14:23 +0000169
ziyiw4fec12a2023-09-27 21:00:25 +0000170 let mut guard = select! {
171 _ = cloned_token.cancelled() => {
Henri Chataing7e798082023-10-05 16:14:12 +0000172 log::info!("task is cancelled!");
ziyiw4fec12a2023-09-27 21:00:25 +0000173 return;
174 },
175 result = reader.readable() => result.unwrap()
176 };
Charlie Boutierd572dd02023-04-10 18:14:23 +0000177
ziyiw4fec12a2023-09-27 21:00:25 +0000178 guard.clear_ready();
179 };
Charlie Boutierd572dd02023-04-10 18:14:23 +0000180
ziyiw4fec12a2023-09-27 21:00:25 +0000181 // Read the remaining header bytes, if truncated.
182 read_exact(reader.get_mut(), &mut buffer[read_len..]).unwrap();
183
184 let length = buffer[3] as usize + UWB_HEADER_SIZE;
185 buffer.resize(length, 0);
186
187 // Read the payload bytes.
188 read_exact(reader.get_mut(), &mut buffer[UWB_HEADER_SIZE..]).unwrap();
189
190 client_callbacks.onUciMessage(&buffer).unwrap();
191 }
192 });
193
194 callbacks.onHalEvent(UwbEvent::OPEN_CPLT, UwbStatus::OK)?;
195
196 *state = State::Opened {
197 callbacks: callbacks.clone(),
Henri Chataing7e798082023-10-05 16:14:12 +0000198 handle: join_handle,
ziyiw4fec12a2023-09-27 21:00:25 +0000199 serial,
200 death_recipient,
201 token,
202 };
203
204 Ok(())
Charlie Boutierd572dd02023-04-10 18:14:23 +0000205 }
206
207 async fn close(&self) -> Result<()> {
208 log::debug!("close");
209
210 let mut state = self.state.lock().await;
211
ziyiw4fec12a2023-09-27 21:00:25 +0000212 if matches!(*state, State::Opened { .. }) {
Henri Chataing7e798082023-10-05 16:14:12 +0000213 state.close().await
Charlie Boutierd572dd02023-04-10 18:14:23 +0000214 } else {
215 Err(binder::ExceptionCode::ILLEGAL_STATE.into())
216 }
217 }
218
219 async fn coreInit(&self) -> Result<()> {
220 log::debug!("coreInit");
221
222 if let State::Opened { ref callbacks, .. } = *self.state.lock().await {
223 callbacks.onHalEvent(UwbEvent::POST_INIT_CPLT, UwbStatus::OK)?;
224 Ok(())
225 } else {
226 Err(binder::ExceptionCode::ILLEGAL_STATE.into())
227 }
228 }
229
230 async fn sessionInit(&self, _id: i32) -> Result<()> {
231 log::debug!("sessionInit");
232
233 Ok(())
234 }
235
236 async fn getSupportedAndroidUciVersion(&self) -> Result<i32> {
237 Ok(1)
238 }
239
240 async fn sendUciMessage(&self, data: &[u8]) -> Result<i32> {
241 log::debug!("sendUciMessage");
242
Henri Chataing77971b32023-08-16 16:55:24 +0000243 if let State::Opened { ref mut serial, .. } = &mut *self.state.lock().await {
244 serial
245 .write(data)
Henri Chataing77971b32023-08-16 16:55:24 +0000246 .map(|written| written as i32)
Charlie Boutierd572dd02023-04-10 18:14:23 +0000247 .map_err(|_| binder::StatusCode::UNKNOWN_ERROR.into())
248 } else {
249 Err(binder::ExceptionCode::ILLEGAL_STATE.into())
250 }
251 }
252}