blob: b63aabe010995311bc2ee324e1236c2c24d4bde4 [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 log::info;
10use std::sync::Arc;
11use tokio::io::unix::AsyncFd;
12use tokio::select;
Charlie Boutierd572dd02023-04-10 18:14:23 +000013use tokio::sync::Mutex;
ziyiw4fec12a2023-09-27 21:00:25 +000014use tokio_util::sync::CancellationToken;
Charlie Boutierd572dd02023-04-10 18:14:23 +000015
ziyiw4fec12a2023-09-27 21:00:25 +000016use std::fs::{File, OpenOptions};
17use std::io::{self, Read, Write};
Charlie Boutierd572dd02023-04-10 18:14:23 +000018use std::os::fd::AsRawFd;
19
Charlie Boutierd572dd02023-04-10 18:14:23 +000020enum State {
21 Closed,
22 Opened {
23 callbacks: Strong<dyn IUwbClientCallback>,
ziyiw4fec12a2023-09-27 21:00:25 +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.
49 #[allow(dead_code)]
50 fn close(&mut self) -> Result<()> {
51 if let State::Opened { ref mut token, ref callbacks, ref mut death_recipient, .. } = *self {
52 log::info!("waiting for task cancellation");
53 callbacks.as_binder().unlink_to_death(death_recipient)?;
54 token.cancel();
55 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
ziyiw4fec12a2023-09-27 21:00:25 +000072 // Configure the file descriptor as non blocking.
73 use nix::fcntl::*;
74 let flags = OFlag::from_bits(fcntl(fd, FcntlArg::F_GETFL)?).unwrap();
75 fcntl(fd, FcntlArg::F_SETFL(flags | OFlag::O_NONBLOCK))?;
Charlie Boutierd572dd02023-04-10 18:14:23 +000076
77 Ok(file)
78}
79
ziyiw4fec12a2023-09-27 21:00:25 +000080/// Wrapper around Read::read to handle EWOULDBLOCK.
81/// /!\ will actively wait for more data, make sure to call
82/// this method only when data is immediately expected.
83fn read_exact(file: &mut File, mut buf: &mut [u8]) -> io::Result<()> {
84 while buf.len() > 0 {
85 match file.read(buf) {
86 Ok(0) => panic!("unexpectedly reached end of file"),
87 Ok(read_len) => buf = &mut buf[read_len..],
88 Err(err) if err.kind() == io::ErrorKind::WouldBlock => continue,
89 Err(err) => return Err(err),
90 }
91 }
92 Ok(())
93}
94
Charlie Boutierd572dd02023-04-10 18:14:23 +000095impl binder::Interface for UwbChip {}
96
97#[async_trait]
98impl IUwbChipAsyncServer for UwbChip {
99 async fn getName(&self) -> Result<String> {
100 Ok(self.name.clone())
101 }
102
103 async fn open(&self, callbacks: &Strong<dyn IUwbClientCallback>) -> Result<()> {
104 log::debug!("open: {:?}", &self.path);
105
ziyiw4fec12a2023-09-27 21:00:25 +0000106 let mut state = self.state.lock().await;
107
108 if matches!(*state, State::Opened { .. }) {
109 log::error!("the state is already opened");
110 return Err(binder::ExceptionCode::ILLEGAL_STATE.into());
111 }
112
Henri Chataing77971b32023-08-16 16:55:24 +0000113 let serial = OpenOptions::new()
114 .read(true)
115 .write(true)
116 .create(false)
117 .open(&self.path)
Charlie Boutierd572dd02023-04-10 18:14:23 +0000118 .and_then(makeraw)
119 .map_err(|_| binder::StatusCode::UNKNOWN_ERROR)?;
120
ziyiw4fec12a2023-09-27 21:00:25 +0000121 let state_death_recipient = self.state.clone();
122 let mut death_recipient = DeathRecipient::new(move || {
123 let mut state = state_death_recipient.blocking_lock();
124 log::info!("Uwb service has died");
125 state.close().unwrap();
126 });
Charlie Boutierd572dd02023-04-10 18:14:23 +0000127
ziyiw4fec12a2023-09-27 21:00:25 +0000128 callbacks.as_binder().link_to_death(&mut death_recipient)?;
Charlie Boutierd572dd02023-04-10 18:14:23 +0000129
ziyiw4fec12a2023-09-27 21:00:25 +0000130 let token = CancellationToken::new();
131 let cloned_token = token.clone();
Charlie Boutierd572dd02023-04-10 18:14:23 +0000132
ziyiw4fec12a2023-09-27 21:00:25 +0000133 let client_callbacks = callbacks.clone();
Charlie Boutierd572dd02023-04-10 18:14:23 +0000134
ziyiw4fec12a2023-09-27 21:00:25 +0000135 let reader = serial
136 .try_clone()
137 .map_err(|_| binder::StatusCode::UNKNOWN_ERROR)?;
Charlie Boutierd572dd02023-04-10 18:14:23 +0000138
ziyiw4fec12a2023-09-27 21:00:25 +0000139 let join_handle = tokio::task::spawn(async move {
140 info!("UCI reader task started");
141 let mut reader = AsyncFd::new(reader).unwrap();
Charlie Boutierd572dd02023-04-10 18:14:23 +0000142
ziyiw4fec12a2023-09-27 21:00:25 +0000143 loop {
144 const UWB_HEADER_SIZE: usize = 4;
145 let mut buffer = vec![0; UWB_HEADER_SIZE];
Charlie Boutierd572dd02023-04-10 18:14:23 +0000146
ziyiw4fec12a2023-09-27 21:00:25 +0000147 // The only time where the task can be safely
148 // cancelled is when no packet bytes have been read.
149 //
150 // - read_exact() cannot be used here since it is not
151 // cancellation safe.
152 // - read() cannot be used because it cannot be cancelled:
153 // the syscall is executed blocking on the threadpool
154 // and completes after termination of the task when
155 // the pipe receives more data.
156 let read_len = loop {
157 // On some platforms, the readiness detecting mechanism
158 // relies on edge-triggered notifications. This means that
159 // the OS will only notify Tokio when the file descriptor
160 // transitions from not-ready to ready. For this to work
161 // you should first try to read or write and only poll for
162 // readiness if that fails with an error of 
163 // std::io::ErrorKind::WouldBlock.
164 match reader.get_mut().read(&mut buffer) {
165 Ok(0) => {
166 log::error!("file unexpectedly closed");
167 return;
168 }
169 Ok(read_len) => break read_len,
170 Err(err) if err.kind() == io::ErrorKind::WouldBlock => (),
171 Err(_) => panic!("unexpected read failure"),
172 }
Charlie Boutierd572dd02023-04-10 18:14:23 +0000173
ziyiw4fec12a2023-09-27 21:00:25 +0000174 let mut guard = select! {
175 _ = cloned_token.cancelled() => {
176 info!("task is cancelled!");
177 return;
178 },
179 result = reader.readable() => result.unwrap()
180 };
Charlie Boutierd572dd02023-04-10 18:14:23 +0000181
ziyiw4fec12a2023-09-27 21:00:25 +0000182 guard.clear_ready();
183 };
Charlie Boutierd572dd02023-04-10 18:14:23 +0000184
ziyiw4fec12a2023-09-27 21:00:25 +0000185 // Read the remaining header bytes, if truncated.
186 read_exact(reader.get_mut(), &mut buffer[read_len..]).unwrap();
187
188 let length = buffer[3] as usize + UWB_HEADER_SIZE;
189 buffer.resize(length, 0);
190
191 // Read the payload bytes.
192 read_exact(reader.get_mut(), &mut buffer[UWB_HEADER_SIZE..]).unwrap();
193
194 client_callbacks.onUciMessage(&buffer).unwrap();
195 }
196 });
197
198 callbacks.onHalEvent(UwbEvent::OPEN_CPLT, UwbStatus::OK)?;
199
200 *state = State::Opened {
201 callbacks: callbacks.clone(),
202 _handle: join_handle,
203 serial,
204 death_recipient,
205 token,
206 };
207
208 Ok(())
Charlie Boutierd572dd02023-04-10 18:14:23 +0000209 }
210
211 async fn close(&self) -> Result<()> {
212 log::debug!("close");
213
214 let mut state = self.state.lock().await;
215
ziyiw4fec12a2023-09-27 21:00:25 +0000216 if matches!(*state, State::Opened { .. }) {
217 state.close()
Charlie Boutierd572dd02023-04-10 18:14:23 +0000218 } else {
219 Err(binder::ExceptionCode::ILLEGAL_STATE.into())
220 }
221 }
222
223 async fn coreInit(&self) -> Result<()> {
224 log::debug!("coreInit");
225
226 if let State::Opened { ref callbacks, .. } = *self.state.lock().await {
227 callbacks.onHalEvent(UwbEvent::POST_INIT_CPLT, UwbStatus::OK)?;
228 Ok(())
229 } else {
230 Err(binder::ExceptionCode::ILLEGAL_STATE.into())
231 }
232 }
233
234 async fn sessionInit(&self, _id: i32) -> Result<()> {
235 log::debug!("sessionInit");
236
237 Ok(())
238 }
239
240 async fn getSupportedAndroidUciVersion(&self) -> Result<i32> {
241 Ok(1)
242 }
243
244 async fn sendUciMessage(&self, data: &[u8]) -> Result<i32> {
245 log::debug!("sendUciMessage");
246
Henri Chataing77971b32023-08-16 16:55:24 +0000247 if let State::Opened { ref mut serial, .. } = &mut *self.state.lock().await {
248 serial
249 .write(data)
Henri Chataing77971b32023-08-16 16:55:24 +0000250 .map(|written| written as i32)
Charlie Boutierd572dd02023-04-10 18:14:23 +0000251 .map_err(|_| binder::StatusCode::UNKNOWN_ERROR.into())
252 } else {
253 Err(binder::ExceptionCode::ILLEGAL_STATE.into())
254 }
255 }
256}