1 /*
2 * Copyright (C) 2021 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 //! This crate lets you use the Tokio `spawn_blocking` pool with AIDL in async
18 //! Rust code.
19 //!
20 //! This crate works by defining a type [`Tokio`], which you can use as the
21 //! generic parameter in the async version of the trait generated by the AIDL
22 //! compiler.
23 //! ```text
24 //! use binder_tokio::Tokio;
25 //!
26 //! binder::get_interface::<dyn SomeAsyncInterface<Tokio>>("...").
27 //! ```
28 //!
29 //! [`Tokio`]: crate::Tokio
30
31 use binder::binder_impl::BinderAsyncRuntime;
32 use binder::{BinderAsyncPool, BoxFuture, FromIBinder, StatusCode, Strong};
33 use std::future::Future;
34
35 /// Retrieve an existing service for a particular interface, sleeping for a few
36 /// seconds if it doesn't yet exist.
37 #[deprecated = "this polls 5s, use wait_for_interface or check_interface"]
get_interface<T: FromIBinder + ?Sized + 'static>( name: &str, ) -> Result<Strong<T>, StatusCode>38 pub async fn get_interface<T: FromIBinder + ?Sized + 'static>(
39 name: &str,
40 ) -> Result<Strong<T>, StatusCode> {
41 if binder::is_handling_transaction() {
42 // See comment in the BinderAsyncPool impl.
43 return binder::get_interface::<T>(name);
44 }
45
46 let name = name.to_string();
47 let res = tokio::task::spawn_blocking(move || binder::get_interface::<T>(&name)).await;
48
49 // The `is_panic` branch is not actually reachable in Android as we compile
50 // with `panic = abort`.
51 match res {
52 Ok(Ok(service)) => Ok(service),
53 Ok(Err(err)) => Err(err),
54 Err(e) if e.is_panic() => std::panic::resume_unwind(e.into_panic()),
55 Err(e) if e.is_cancelled() => Err(StatusCode::FAILED_TRANSACTION),
56 Err(_) => Err(StatusCode::UNKNOWN_ERROR),
57 }
58 }
59
60 /// Retrieve an existing service for a particular interface. Returns
61 /// `Err(StatusCode::NAME_NOT_FOUND)` immediately if the service is not available.
62 ///
63 /// NOTE: "immediately" above does not mean the future will complete the first time it is polled.
check_interface<T: FromIBinder + ?Sized + 'static>( name: &str, ) -> Result<Strong<T>, StatusCode>64 pub async fn check_interface<T: FromIBinder + ?Sized + 'static>(
65 name: &str,
66 ) -> Result<Strong<T>, StatusCode> {
67 if binder::is_handling_transaction() {
68 // See comment in the BinderAsyncPool impl.
69 return binder::check_interface::<T>(name);
70 }
71
72 let name = name.to_string();
73 let res = tokio::task::spawn_blocking(move || binder::check_interface::<T>(&name)).await;
74
75 // The `is_panic` branch is not actually reachable in Android as we compile
76 // with `panic = abort`.
77 match res {
78 Ok(Ok(service)) => Ok(service),
79 Ok(Err(err)) => Err(err),
80 Err(e) if e.is_panic() => std::panic::resume_unwind(e.into_panic()),
81 Err(e) if e.is_cancelled() => Err(StatusCode::FAILED_TRANSACTION),
82 Err(_) => Err(StatusCode::UNKNOWN_ERROR),
83 }
84 }
85
86 /// Retrieve an existing service for a particular interface, or start it if it
87 /// is configured as a dynamic service and isn't yet started.
wait_for_interface<T: FromIBinder + ?Sized + 'static>( name: &str, ) -> Result<Strong<T>, StatusCode>88 pub async fn wait_for_interface<T: FromIBinder + ?Sized + 'static>(
89 name: &str,
90 ) -> Result<Strong<T>, StatusCode> {
91 if binder::is_handling_transaction() {
92 // See comment in the BinderAsyncPool impl.
93 return binder::wait_for_interface::<T>(name);
94 }
95
96 let name = name.to_string();
97 let res = tokio::task::spawn_blocking(move || binder::wait_for_interface::<T>(&name)).await;
98
99 // The `is_panic` branch is not actually reachable in Android as we compile
100 // with `panic = abort`.
101 match res {
102 Ok(Ok(service)) => Ok(service),
103 Ok(Err(err)) => Err(err),
104 Err(e) if e.is_panic() => std::panic::resume_unwind(e.into_panic()),
105 Err(e) if e.is_cancelled() => Err(StatusCode::FAILED_TRANSACTION),
106 Err(_) => Err(StatusCode::UNKNOWN_ERROR),
107 }
108 }
109
110 /// Use the Tokio `spawn_blocking` pool with AIDL.
111 pub enum Tokio {}
112
113 impl BinderAsyncPool for Tokio {
spawn<'a, F1, F2, Fut, A, B, E>(spawn_me: F1, after_spawn: F2) -> BoxFuture<'a, Result<B, E>> where F1: FnOnce() -> A, F2: FnOnce(A) -> Fut, Fut: Future<Output = Result<B, E>>, F1: Send + 'static, F2: Send + 'a, Fut: Send + 'a, A: Send + 'static, B: Send + 'a, E: From<crate::StatusCode>,114 fn spawn<'a, F1, F2, Fut, A, B, E>(spawn_me: F1, after_spawn: F2) -> BoxFuture<'a, Result<B, E>>
115 where
116 F1: FnOnce() -> A,
117 F2: FnOnce(A) -> Fut,
118 Fut: Future<Output = Result<B, E>>,
119 F1: Send + 'static,
120 F2: Send + 'a,
121 Fut: Send + 'a,
122 A: Send + 'static,
123 B: Send + 'a,
124 E: From<crate::StatusCode>,
125 {
126 if binder::is_handling_transaction() {
127 // We are currently on the thread pool for a binder server, so we should execute the
128 // transaction on the current thread so that the binder kernel driver is able to apply
129 // its deadlock prevention strategy to the sub-call.
130 //
131 // This shouldn't cause issues with blocking the thread as only one task will run in a
132 // call to `block_on`, so there aren't other tasks to block.
133 //
134 // If the `block_in_place` call fails, then you are driving a current-thread runtime on
135 // the binder threadpool. Instead, it is recommended to use `TokioRuntime<Handle>` when
136 // the runtime is a current-thread runtime, as the current-thread runtime can be driven
137 // only by `Runtime::block_on` calls and not by `Handle::block_on`.
138 let result = tokio::task::block_in_place(spawn_me);
139 Box::pin(after_spawn(result))
140 } else {
141 let handle = tokio::task::spawn_blocking(spawn_me);
142 Box::pin(async move {
143 // The `is_panic` branch is not actually reachable in Android as we compile
144 // with `panic = abort`.
145 match handle.await {
146 Ok(res) => after_spawn(res).await,
147 Err(e) if e.is_panic() => std::panic::resume_unwind(e.into_panic()),
148 Err(e) if e.is_cancelled() => Err(StatusCode::FAILED_TRANSACTION.into()),
149 Err(_) => Err(StatusCode::UNKNOWN_ERROR.into()),
150 }
151 })
152 }
153 }
154 }
155
156 /// Wrapper around Tokio runtime types for providing a runtime to a binder server.
157 pub struct TokioRuntime<R>(pub R);
158
159 impl BinderAsyncRuntime for TokioRuntime<tokio::runtime::Runtime> {
block_on<F: Future>(&self, future: F) -> F::Output160 fn block_on<F: Future>(&self, future: F) -> F::Output {
161 self.0.block_on(future)
162 }
163 }
164
165 impl BinderAsyncRuntime for TokioRuntime<std::sync::Arc<tokio::runtime::Runtime>> {
block_on<F: Future>(&self, future: F) -> F::Output166 fn block_on<F: Future>(&self, future: F) -> F::Output {
167 self.0.block_on(future)
168 }
169 }
170
171 impl BinderAsyncRuntime for TokioRuntime<tokio::runtime::Handle> {
block_on<F: Future>(&self, future: F) -> F::Output172 fn block_on<F: Future>(&self, future: F) -> F::Output {
173 self.0.block_on(future)
174 }
175 }
176