blob: 2b8e481dd979a8369b47eef09b7427ac6d008801 [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};
Charlie Boutierd572dd02023-04-10 18:14:23 +000017use std::os::fd::AsRawFd;
Henri Chataing7e798082023-10-05 16:14:12 +000018use std::os::unix::fs::OpenOptionsExt;
Charlie Boutierd572dd02023-04-10 18:14:23 +000019
Charlie Boutierd572dd02023-04-10 18:14:23 +000020enum State {
21 Closed,
22 Opened {
23 callbacks: Strong<dyn IUwbClientCallback>,
Henri Chataing7e798082023-10-05 16:14:12 +000024 handle: tokio::task::JoinHandle<()>,
Henri Chataing77971b32023-08-16 16:55:24 +000025 serial: File,
ziyiw4fec12a2023-09-27 21:00:25 +000026 death_recipient: DeathRecipient,
27 token: CancellationToken,
Charlie Boutierd572dd02023-04-10 18:14:23 +000028 },
29}
30
31pub struct UwbChip {
32 name: String,
33 path: String,
ziyiw4fec12a2023-09-27 21:00:25 +000034 state: Arc<Mutex<State>>,
Charlie Boutierd572dd02023-04-10 18:14:23 +000035}
36
37impl UwbChip {
38 pub fn new(name: String, path: String) -> Self {
39 Self {
40 name,
41 path,
ziyiw4fec12a2023-09-27 21:00:25 +000042 state: Arc::new(Mutex::new(State::Closed)),
Charlie Boutierd572dd02023-04-10 18:14:23 +000043 }
44 }
45}
46
ziyiw4fec12a2023-09-27 21:00:25 +000047impl State {
48 /// Terminate the reader task.
Henri Chataing7e798082023-10-05 16:14:12 +000049 async fn close(&mut self) -> Result<()> {
50 if let State::Opened { ref mut token, ref callbacks, ref mut death_recipient, ref mut handle, .. } = *self {
ziyiw4fec12a2023-09-27 21:00:25 +000051 log::info!("waiting for task cancellation");
52 callbacks.as_binder().unlink_to_death(death_recipient)?;
53 token.cancel();
Henri Chataing7e798082023-10-05 16:14:12 +000054 handle.await.unwrap();
ziyiw4fec12a2023-09-27 21:00:25 +000055 log::info!("task successfully cancelled");
56 callbacks.onHalEvent(UwbEvent::CLOSE_CPLT, UwbStatus::OK)?;
57 *self = State::Closed;
58 }
59 Ok(())
60 }
61}
62
Charlie Boutierd572dd02023-04-10 18:14:23 +000063pub fn makeraw(file: File) -> io::Result<File> {
64 let fd = file.as_raw_fd();
65
ziyiw4fec12a2023-09-27 21:00:25 +000066 // Configure the file descritpro as raw fd.
67 use nix::sys::termios::*;
68 let mut attrs = tcgetattr(fd)?;
69 cfmakeraw(&mut attrs);
70 tcsetattr(fd, SetArg::TCSANOW, &attrs)?;
Charlie Boutierd572dd02023-04-10 18:14:23 +000071
Charlie Boutierd572dd02023-04-10 18:14:23 +000072 Ok(file)
73}
74
ziyiw4fec12a2023-09-27 21:00:25 +000075/// Wrapper around Read::read to handle EWOULDBLOCK.
76/// /!\ will actively wait for more data, make sure to call
77/// this method only when data is immediately expected.
78fn read_exact(file: &mut File, mut buf: &mut [u8]) -> io::Result<()> {
79 while buf.len() > 0 {
80 match file.read(buf) {
81 Ok(0) => panic!("unexpectedly reached end of file"),
82 Ok(read_len) => buf = &mut buf[read_len..],
83 Err(err) if err.kind() == io::ErrorKind::WouldBlock => continue,
84 Err(err) => return Err(err),
85 }
86 }
87 Ok(())
88}
89
Charlie Boutierd572dd02023-04-10 18:14:23 +000090impl binder::Interface for UwbChip {}
91
92#[async_trait]
93impl IUwbChipAsyncServer for UwbChip {
94 async fn getName(&self) -> Result<String> {
95 Ok(self.name.clone())
96 }
97
98 async fn open(&self, callbacks: &Strong<dyn IUwbClientCallback>) -> Result<()> {
99 log::debug!("open: {:?}", &self.path);
100
ziyiw4fec12a2023-09-27 21:00:25 +0000101 let mut state = self.state.lock().await;
102
103 if matches!(*state, State::Opened { .. }) {
104 log::error!("the state is already opened");
105 return Err(binder::ExceptionCode::ILLEGAL_STATE.into());
106 }
107
Henri Chataing77971b32023-08-16 16:55:24 +0000108 let serial = OpenOptions::new()
109 .read(true)
110 .write(true)
111 .create(false)
Henri Chataing7e798082023-10-05 16:14:12 +0000112 .custom_flags(libc::O_NONBLOCK)
Henri Chataing77971b32023-08-16 16:55:24 +0000113 .open(&self.path)
Charlie Boutierd572dd02023-04-10 18:14:23 +0000114 .and_then(makeraw)
115 .map_err(|_| binder::StatusCode::UNKNOWN_ERROR)?;
116
ziyiw4fec12a2023-09-27 21:00:25 +0000117 let state_death_recipient = self.state.clone();
118 let mut death_recipient = DeathRecipient::new(move || {
119 let mut state = state_death_recipient.blocking_lock();
120 log::info!("Uwb service has died");
Henri Chataing7e798082023-10-05 16:14:12 +0000121 if let State::Opened { ref mut token, .. } = *state {
122 token.cancel();
123 *state = State::Closed;
124 }
ziyiw4fec12a2023-09-27 21:00:25 +0000125 });
Charlie Boutierd572dd02023-04-10 18:14:23 +0000126
ziyiw4fec12a2023-09-27 21:00:25 +0000127 callbacks.as_binder().link_to_death(&mut death_recipient)?;
Charlie Boutierd572dd02023-04-10 18:14:23 +0000128
ziyiw4fec12a2023-09-27 21:00:25 +0000129 let token = CancellationToken::new();
130 let cloned_token = token.clone();
Charlie Boutierd572dd02023-04-10 18:14:23 +0000131
ziyiw4fec12a2023-09-27 21:00:25 +0000132 let client_callbacks = callbacks.clone();
Charlie Boutierd572dd02023-04-10 18:14:23 +0000133
ziyiw4fec12a2023-09-27 21:00:25 +0000134 let reader = serial
135 .try_clone()
136 .map_err(|_| binder::StatusCode::UNKNOWN_ERROR)?;
Charlie Boutierd572dd02023-04-10 18:14:23 +0000137
ziyiw4fec12a2023-09-27 21:00:25 +0000138 let join_handle = tokio::task::spawn(async move {
Henri Chataing7e798082023-10-05 16:14:12 +0000139 log::info!("UCI reader task started");
ziyiw4fec12a2023-09-27 21:00:25 +0000140 let mut reader = AsyncFd::new(reader).unwrap();
Charlie Boutierd572dd02023-04-10 18:14:23 +0000141
ziyiw4fec12a2023-09-27 21:00:25 +0000142 loop {
143 const UWB_HEADER_SIZE: usize = 4;
144 let mut buffer = vec![0; UWB_HEADER_SIZE];
Charlie Boutierd572dd02023-04-10 18:14:23 +0000145
ziyiw4fec12a2023-09-27 21:00:25 +0000146 // The only time where the task can be safely
147 // cancelled is when no packet bytes have been read.
148 //
149 // - read_exact() cannot be used here since it is not
150 // cancellation safe.
151 // - read() cannot be used because it cannot be cancelled:
152 // the syscall is executed blocking on the threadpool
153 // and completes after termination of the task when
154 // the pipe receives more data.
155 let read_len = loop {
156 // On some platforms, the readiness detecting mechanism
157 // relies on edge-triggered notifications. This means that
158 // the OS will only notify Tokio when the file descriptor
159 // transitions from not-ready to ready. For this to work
160 // you should first try to read or write and only poll for
Henri Chataing7e798082023-10-05 16:14:12 +0000161 // readiness if that fails with an error of
ziyiw4fec12a2023-09-27 21:00:25 +0000162 // std::io::ErrorKind::WouldBlock.
163 match reader.get_mut().read(&mut buffer) {
164 Ok(0) => {
165 log::error!("file unexpectedly closed");
166 return;
167 }
168 Ok(read_len) => break read_len,
169 Err(err) if err.kind() == io::ErrorKind::WouldBlock => (),
170 Err(_) => panic!("unexpected read failure"),
171 }
Charlie Boutierd572dd02023-04-10 18:14:23 +0000172
ziyiw4fec12a2023-09-27 21:00:25 +0000173 let mut guard = select! {
174 _ = cloned_token.cancelled() => {
Henri Chataing7e798082023-10-05 16:14:12 +0000175 log::info!("task is cancelled!");
ziyiw4fec12a2023-09-27 21:00:25 +0000176 return;
177 },
178 result = reader.readable() => result.unwrap()
179 };
Charlie Boutierd572dd02023-04-10 18:14:23 +0000180
ziyiw4fec12a2023-09-27 21:00:25 +0000181 guard.clear_ready();
182 };
Charlie Boutierd572dd02023-04-10 18:14:23 +0000183
ziyiw4fec12a2023-09-27 21:00:25 +0000184 // Read the remaining header bytes, if truncated.
185 read_exact(reader.get_mut(), &mut buffer[read_len..]).unwrap();
186
187 let length = buffer[3] as usize + UWB_HEADER_SIZE;
188 buffer.resize(length, 0);
189
190 // Read the payload bytes.
191 read_exact(reader.get_mut(), &mut buffer[UWB_HEADER_SIZE..]).unwrap();
192
193 client_callbacks.onUciMessage(&buffer).unwrap();
194 }
195 });
196
197 callbacks.onHalEvent(UwbEvent::OPEN_CPLT, UwbStatus::OK)?;
198
199 *state = State::Opened {
200 callbacks: callbacks.clone(),
Henri Chataing7e798082023-10-05 16:14:12 +0000201 handle: join_handle,
ziyiw4fec12a2023-09-27 21:00:25 +0000202 serial,
203 death_recipient,
204 token,
205 };
206
207 Ok(())
Charlie Boutierd572dd02023-04-10 18:14:23 +0000208 }
209
210 async fn close(&self) -> Result<()> {
211 log::debug!("close");
212
213 let mut state = self.state.lock().await;
214
ziyiw4fec12a2023-09-27 21:00:25 +0000215 if matches!(*state, State::Opened { .. }) {
Henri Chataing7e798082023-10-05 16:14:12 +0000216 state.close().await
Charlie Boutierd572dd02023-04-10 18:14:23 +0000217 } else {
218 Err(binder::ExceptionCode::ILLEGAL_STATE.into())
219 }
220 }
221
222 async fn coreInit(&self) -> Result<()> {
223 log::debug!("coreInit");
224
225 if let State::Opened { ref callbacks, .. } = *self.state.lock().await {
226 callbacks.onHalEvent(UwbEvent::POST_INIT_CPLT, UwbStatus::OK)?;
227 Ok(())
228 } else {
229 Err(binder::ExceptionCode::ILLEGAL_STATE.into())
230 }
231 }
232
233 async fn sessionInit(&self, _id: i32) -> Result<()> {
234 log::debug!("sessionInit");
235
236 Ok(())
237 }
238
239 async fn getSupportedAndroidUciVersion(&self) -> Result<i32> {
240 Ok(1)
241 }
242
243 async fn sendUciMessage(&self, data: &[u8]) -> Result<i32> {
244 log::debug!("sendUciMessage");
245
Henri Chataing77971b32023-08-16 16:55:24 +0000246 if let State::Opened { ref mut serial, .. } = &mut *self.state.lock().await {
247 serial
248 .write(data)
Henri Chataing77971b32023-08-16 16:55:24 +0000249 .map(|written| written as i32)
Charlie Boutierd572dd02023-04-10 18:14:23 +0000250 .map_err(|_| binder::StatusCode::UNKNOWN_ERROR.into())
251 } else {
252 Err(binder::ExceptionCode::ILLEGAL_STATE.into())
253 }
254 }
255}