1 use android_hardware_uwb::aidl::android::hardware::uwb::{
2     IUwbChip::IUwbChipAsyncServer, IUwbClientCallback::IUwbClientCallback, UwbEvent::UwbEvent,
3     UwbStatus::UwbStatus,
4 };
5 use android_hardware_uwb::binder;
6 use async_trait::async_trait;
7 use binder::{DeathRecipient, IBinder, Result, Strong};
8 
9 use std::sync::Arc;
10 use tokio::io::unix::AsyncFd;
11 use tokio::select;
12 use tokio::sync::Mutex;
13 use tokio_util::sync::CancellationToken;
14 
15 use std::fs::{File, OpenOptions};
16 use std::io::{self, Read, Write};
17 use std::os::unix::fs::OpenOptionsExt;
18 
19 use pdl_runtime::Packet;
20 use uwb_uci_packets::{DeviceResetCmdBuilder, ResetConfig, UciControlPacket, UciControlPacketHal};
21 
22 enum State {
23     Closed,
24     Opened {
25         callbacks: Strong<dyn IUwbClientCallback>,
26         handle: tokio::task::JoinHandle<()>,
27         serial: File,
28         death_recipient: DeathRecipient,
29         token: CancellationToken,
30     },
31 }
32 
33 pub struct UwbChip {
34     name: String,
35     path: String,
36     state: Arc<Mutex<State>>,
37 }
38 
39 impl UwbChip {
new(name: String, path: String) -> Self40     pub fn new(name: String, path: String) -> Self {
41         Self {
42             name,
43             path,
44             state: Arc::new(Mutex::new(State::Closed)),
45         }
46     }
47 }
48 
49 impl State {
50     /// Terminate the reader task.
close(&mut self) -> Result<()>51     async fn close(&mut self) -> Result<()> {
52         if let State::Opened {
53             ref mut token,
54             ref callbacks,
55             ref mut death_recipient,
56             ref mut handle,
57             ref mut serial,
58         } = *self
59         {
60             log::info!("waiting for task cancellation");
61             callbacks.as_binder().unlink_to_death(death_recipient)?;
62             token.cancel();
63             handle.await.unwrap();
64             let packet: UciControlPacket = DeviceResetCmdBuilder {
65                 reset_config: ResetConfig::UwbsReset,
66             }
67             .build()
68             .into();
69             // DeviceResetCmd need to be send to reset the device to stop all running
70             // activities on UWBS.
71             let packet_vec: Vec<UciControlPacketHal> = packet.into();
72             for hal_packet in packet_vec.into_iter() {
73                 serial
74                     .write(&hal_packet.encode_to_vec().unwrap())
75                     .map(|written| written as i32)
76                     .map_err(|_| binder::StatusCode::UNKNOWN_ERROR)?;
77             }
78             consume_device_reset_rsp_and_ntf(
79                 &mut serial
80                     .try_clone()
81                     .map_err(|_| binder::StatusCode::UNKNOWN_ERROR)?,
82             );
83             log::info!("task successfully cancelled");
84             callbacks.onHalEvent(UwbEvent::CLOSE_CPLT, UwbStatus::OK)?;
85             *self = State::Closed;
86         }
87         Ok(())
88     }
89 }
90 
consume_device_reset_rsp_and_ntf(reader: &mut File)91 fn consume_device_reset_rsp_and_ntf(reader: &mut File) {
92     // Poll the DeviceResetRsp and DeviceStatusNtf before hal is closed to prevent
93     // the host from getting response and notifications from a 'powered down' UWBS.
94     // Do nothing when these packets are received.
95     const DEVICE_RESET_RSP: [u8; 5] = [64, 0, 0, 1, 0];
96     const DEVICE_STATUS_NTF: [u8; 5] = [96, 1, 0, 1, 1];
97     let mut buffer = vec![0; DEVICE_RESET_RSP.len() + DEVICE_STATUS_NTF.len()];
98     read_exact(reader, &mut buffer).unwrap();
99 
100     // Make sure received packets are the expected ones.
101     assert_eq!(&buffer[0..DEVICE_RESET_RSP.len()], &DEVICE_RESET_RSP);
102     assert_eq!(&buffer[DEVICE_RESET_RSP.len()..], &DEVICE_STATUS_NTF);
103 }
104 
makeraw(file: File) -> io::Result<File>105 pub fn makeraw(file: File) -> io::Result<File> {
106     // Configure the file descriptor as raw fd.
107     use nix::sys::termios::*;
108     let mut attrs = tcgetattr(&file)?;
109     cfmakeraw(&mut attrs);
110     tcsetattr(&file, SetArg::TCSANOW, &attrs)?;
111 
112     Ok(file)
113 }
114 
115 /// Wrapper around Read::read to handle EWOULDBLOCK.
116 /// /!\ will actively wait for more data, make sure to call
117 /// this method only when data is immediately expected.
read_exact(file: &mut File, mut buf: &mut [u8]) -> io::Result<()>118 fn read_exact(file: &mut File, mut buf: &mut [u8]) -> io::Result<()> {
119     while buf.len() > 0 {
120         match file.read(buf) {
121             Ok(0) => panic!("unexpectedly reached end of file"),
122             Ok(read_len) => buf = &mut buf[read_len..],
123             Err(err) if err.kind() == io::ErrorKind::WouldBlock => continue,
124             Err(err) => return Err(err),
125         }
126     }
127     Ok(())
128 }
129 
130 impl binder::Interface for UwbChip {}
131 
132 #[async_trait]
133 impl IUwbChipAsyncServer for UwbChip {
getName(&self) -> Result<String>134     async fn getName(&self) -> Result<String> {
135         Ok(self.name.clone())
136     }
137 
open(&self, callbacks: &Strong<dyn IUwbClientCallback>) -> Result<()>138     async fn open(&self, callbacks: &Strong<dyn IUwbClientCallback>) -> Result<()> {
139         log::debug!("open: {:?}", &self.path);
140 
141         let mut state = self.state.lock().await;
142 
143         if matches!(*state, State::Opened { .. }) {
144             log::error!("the state is already opened");
145             return Err(binder::ExceptionCode::ILLEGAL_STATE.into());
146         }
147 
148         let serial = OpenOptions::new()
149             .read(true)
150             .write(true)
151             .create(false)
152             .custom_flags(libc::O_NONBLOCK)
153             .open(&self.path)
154             .and_then(makeraw)
155             .map_err(|_| binder::StatusCode::UNKNOWN_ERROR)?;
156 
157         let state_death_recipient = self.state.clone();
158         let mut death_recipient = DeathRecipient::new(move || {
159             let mut state = state_death_recipient.blocking_lock();
160             log::info!("Uwb service has died");
161             if let State::Opened { ref mut token, .. } = *state {
162                 token.cancel();
163                 *state = State::Closed;
164             }
165         });
166 
167         callbacks.as_binder().link_to_death(&mut death_recipient)?;
168 
169         let token = CancellationToken::new();
170         let cloned_token = token.clone();
171 
172         let client_callbacks = callbacks.clone();
173 
174         let reader = serial
175             .try_clone()
176             .map_err(|_| binder::StatusCode::UNKNOWN_ERROR)?;
177 
178         let join_handle = tokio::task::spawn(async move {
179             log::info!("UCI reader task started");
180             let mut reader = AsyncFd::new(reader).unwrap();
181 
182             loop {
183                 const MESSAGE_TYPE_MASK: u8 = 0b11100000;
184                 const DATA_MESSAGE_TYPE: u8 = 0b000;
185                 const UWB_HEADER_SIZE: usize = 4;
186                 let mut buffer = vec![0; UWB_HEADER_SIZE];
187 
188                 // The only time where the task can be safely
189                 // cancelled is when no packet bytes have been read.
190                 //
191                 // - read_exact() cannot be used here since it is not
192                 //   cancellation safe.
193                 // - read() cannot be used because it cannot be cancelled:
194                 //   the syscall is executed blocking on the threadpool
195                 //   and completes after termination of the task when
196                 //   the pipe receives more data.
197                 let read_len = loop {
198                     // On some platforms, the readiness detecting mechanism
199                     // relies on edge-triggered notifications. This means that
200                     // the OS will only notify Tokio when the file descriptor
201                     // transitions from not-ready to ready. For this to work
202                     // you should first try to read or write and only poll for
203                     // readiness if that fails with an error of
204                     // std::io::ErrorKind::WouldBlock.
205                     match reader.get_mut().read(&mut buffer) {
206                         Ok(0) => {
207                             log::error!("file unexpectedly closed");
208                             return;
209                         }
210                         Ok(read_len) => break read_len,
211                         Err(err) if err.kind() == io::ErrorKind::WouldBlock => (),
212                         Err(_) => panic!("unexpected read failure"),
213                     }
214 
215                     let mut guard = select! {
216                         _ = cloned_token.cancelled() => {
217                             log::info!("task is cancelled!");
218                             return;
219                         },
220                         result = reader.readable() => result.unwrap()
221                     };
222 
223                     guard.clear_ready();
224                 };
225 
226                 // Read the remaining header bytes, if truncated.
227                 read_exact(reader.get_mut(), &mut buffer[read_len..]).unwrap();
228 
229                 let common_header = buffer[0];
230                 let mt = (common_header & MESSAGE_TYPE_MASK) >> 5;
231                 let payload_length = if mt == DATA_MESSAGE_TYPE {
232                     let payload_length_fields: [u8; 2] = buffer[2..=3].try_into().unwrap();
233                     u16::from_le_bytes(payload_length_fields) as usize
234                 } else {
235                     buffer[3] as usize
236                 };
237 
238                 let length = payload_length + UWB_HEADER_SIZE;
239                 buffer.resize(length, 0);
240 
241                 // Read the payload bytes.
242                 read_exact(reader.get_mut(), &mut buffer[UWB_HEADER_SIZE..]).unwrap();
243 
244                 log::debug!(" <-- {:?}", buffer);
245                 client_callbacks.onUciMessage(&buffer).unwrap();
246             }
247         });
248 
249         callbacks.onHalEvent(UwbEvent::OPEN_CPLT, UwbStatus::OK)?;
250 
251         *state = State::Opened {
252             callbacks: callbacks.clone(),
253             handle: join_handle,
254             serial,
255             death_recipient,
256             token,
257         };
258 
259         Ok(())
260     }
261 
close(&self) -> Result<()>262     async fn close(&self) -> Result<()> {
263         log::debug!("close");
264 
265         let mut state = self.state.lock().await;
266 
267         if let State::Opened { .. } = *state {
268             state.close().await
269         } else {
270             Err(binder::ExceptionCode::ILLEGAL_STATE.into())
271         }
272     }
273 
coreInit(&self) -> Result<()>274     async fn coreInit(&self) -> Result<()> {
275         log::debug!("coreInit");
276 
277         if let State::Opened { ref callbacks, .. } = *self.state.lock().await {
278             callbacks.onHalEvent(UwbEvent::POST_INIT_CPLT, UwbStatus::OK)?;
279             Ok(())
280         } else {
281             Err(binder::ExceptionCode::ILLEGAL_STATE.into())
282         }
283     }
284 
sessionInit(&self, _id: i32) -> Result<()>285     async fn sessionInit(&self, _id: i32) -> Result<()> {
286         log::debug!("sessionInit");
287 
288         Ok(())
289     }
290 
getSupportedAndroidUciVersion(&self) -> Result<i32>291     async fn getSupportedAndroidUciVersion(&self) -> Result<i32> {
292         Ok(1)
293     }
294 
sendUciMessage(&self, data: &[u8]) -> Result<i32>295     async fn sendUciMessage(&self, data: &[u8]) -> Result<i32> {
296         log::debug!("sendUciMessage");
297 
298         if let State::Opened { ref mut serial, .. } = &mut *self.state.lock().await {
299             log::debug!(" --> {:?}", data);
300             let result = serial
301                 .write_all(data)
302                 .map(|_| data.len() as i32)
303                 .map_err(|_| binder::StatusCode::UNKNOWN_ERROR.into());
304             log::debug!(" status: {:?}", result);
305             result
306         } else {
307             Err(binder::ExceptionCode::ILLEGAL_STATE.into())
308         }
309     }
310 }
311