xref: /aosp_15_r20/frameworks/native/libs/binder/rust/binder_tokio/lib.rs (revision 38e8c45f13ce32b0dcecb25141ffecaf386fa17f)
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