• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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::{BinderAsyncPool, BoxFuture, FromIBinder, StatusCode, Strong};
32 use binder::binder_impl::BinderAsyncRuntime;
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.
get_interface<T: FromIBinder + ?Sized + 'static>(name: &str) -> Result<Strong<T>, StatusCode>37 pub async fn get_interface<T: FromIBinder + ?Sized + 'static>(name: &str) -> Result<Strong<T>, StatusCode> {
38     if binder::is_handling_transaction() {
39         // See comment in the BinderAsyncPool impl.
40         return binder::get_interface::<T>(name);
41     }
42 
43     let name = name.to_string();
44     let res = tokio::task::spawn_blocking(move || {
45         binder::get_interface::<T>(&name)
46     }).await;
47 
48     // The `is_panic` branch is not actually reachable in Android as we compile
49     // with `panic = abort`.
50     match res {
51         Ok(Ok(service)) => Ok(service),
52         Ok(Err(err)) => Err(err),
53         Err(e) if e.is_panic() => std::panic::resume_unwind(e.into_panic()),
54         Err(e) if e.is_cancelled() => Err(StatusCode::FAILED_TRANSACTION),
55         Err(_) => Err(StatusCode::UNKNOWN_ERROR),
56     }
57 }
58 
59 /// Retrieve an existing service for a particular interface, or start it if it
60 /// is configured as a dynamic service and isn't yet started.
wait_for_interface<T: FromIBinder + ?Sized + 'static>(name: &str) -> Result<Strong<T>, StatusCode>61 pub async fn wait_for_interface<T: FromIBinder + ?Sized + 'static>(name: &str) -> Result<Strong<T>, StatusCode> {
62     if binder::is_handling_transaction() {
63         // See comment in the BinderAsyncPool impl.
64         return binder::wait_for_interface::<T>(name);
65     }
66 
67     let name = name.to_string();
68     let res = tokio::task::spawn_blocking(move || {
69         binder::wait_for_interface::<T>(&name)
70     }).await;
71 
72     // The `is_panic` branch is not actually reachable in Android as we compile
73     // with `panic = abort`.
74     match res {
75         Ok(Ok(service)) => Ok(service),
76         Ok(Err(err)) => Err(err),
77         Err(e) if e.is_panic() => std::panic::resume_unwind(e.into_panic()),
78         Err(e) if e.is_cancelled() => Err(StatusCode::FAILED_TRANSACTION),
79         Err(_) => Err(StatusCode::UNKNOWN_ERROR),
80     }
81 }
82 
83 /// Use the Tokio `spawn_blocking` pool with AIDL.
84 pub enum Tokio {}
85 
86 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>,87     fn spawn<'a, F1, F2, Fut, A, B, E>(spawn_me: F1, after_spawn: F2) -> BoxFuture<'a, Result<B, E>>
88     where
89         F1: FnOnce() -> A,
90         F2: FnOnce(A) -> Fut,
91         Fut: Future<Output = Result<B, E>>,
92         F1: Send + 'static,
93         F2: Send + 'a,
94         Fut: Send + 'a,
95         A: Send + 'static,
96         B: Send + 'a,
97         E: From<crate::StatusCode>,
98     {
99         if binder::is_handling_transaction() {
100             // We are currently on the thread pool for a binder server, so we should execute the
101             // transaction on the current thread so that the binder kernel driver is able to apply
102             // its deadlock prevention strategy to the sub-call.
103             //
104             // This shouldn't cause issues with blocking the thread as only one task will run in a
105             // call to `block_on`, so there aren't other tasks to block.
106             let result = spawn_me();
107             Box::pin(after_spawn(result))
108         } else {
109             let handle = tokio::task::spawn_blocking(spawn_me);
110             Box::pin(async move {
111                 // The `is_panic` branch is not actually reachable in Android as we compile
112                 // with `panic = abort`.
113                 match handle.await {
114                     Ok(res) => after_spawn(res).await,
115                     Err(e) if e.is_panic() => std::panic::resume_unwind(e.into_panic()),
116                     Err(e) if e.is_cancelled() => Err(StatusCode::FAILED_TRANSACTION.into()),
117                     Err(_) => Err(StatusCode::UNKNOWN_ERROR.into()),
118                 }
119             })
120         }
121     }
122 }
123 
124 /// Wrapper around Tokio runtime types for providing a runtime to a binder server.
125 pub struct TokioRuntime<R>(pub R);
126 
127 impl BinderAsyncRuntime for TokioRuntime<tokio::runtime::Runtime> {
block_on<F: Future>(&self, future: F) -> F::Output128     fn block_on<F: Future>(&self, future: F) -> F::Output {
129         self.0.block_on(future)
130     }
131 }
132 
133 impl BinderAsyncRuntime for TokioRuntime<std::sync::Arc<tokio::runtime::Runtime>> {
block_on<F: Future>(&self, future: F) -> F::Output134     fn block_on<F: Future>(&self, future: F) -> F::Output {
135         self.0.block_on(future)
136     }
137 }
138 
139 impl BinderAsyncRuntime for TokioRuntime<tokio::runtime::Handle> {
block_on<F: Future>(&self, future: F) -> F::Output140     fn block_on<F: Future>(&self, future: F) -> F::Output {
141         self.0.block_on(future)
142     }
143 }
144