| /* |
| * Copyright (C) 2022, The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| //! Test Rust service for the AIDL compiler. |
| |
| use aidl_test_interface::aidl::android::aidl::tests::nested::{ |
| INestedService, ParcelableWithNested, |
| }; |
| use aidl_test_interface::aidl::android::aidl::tests::ITestService::{ |
| self, BnTestService, BpTestService, Empty::Empty, |
| }; |
| use aidl_test_interface::aidl::android::aidl::tests::{ |
| extension::ExtendableParcelable::ExtendableParcelable, extension::MyExt::MyExt, |
| BackendType::BackendType, ByteEnum::ByteEnum, ConstantExpressionEnum::ConstantExpressionEnum, |
| INamedCallback, INewName, IOldName, IntEnum::IntEnum, LongEnum::LongEnum, |
| RecursiveList::RecursiveList, StructuredParcelable, Union, |
| }; |
| use aidl_test_interface::binder::{ |
| self, BinderFeatures, Interface, ParcelFileDescriptor, SpIBinder, |
| }; |
| use aidl_test_versioned_interface::aidl::android::aidl::versioned::tests::{ |
| BazUnion::BazUnion, Foo::Foo, IFooInterface, IFooInterface::BnFooInterface, |
| IFooInterface::BpFooInterface, |
| }; |
| use std::collections::HashMap; |
| use std::sync::Mutex; |
| |
| use async_trait::async_trait; |
| |
| fn dup_fd(fd: &ParcelFileDescriptor) -> ParcelFileDescriptor { |
| ParcelFileDescriptor::new(fd.as_ref().try_clone().unwrap()) |
| } |
| |
| struct NamedCallback(String); |
| |
| impl Interface for NamedCallback {} |
| |
| #[async_trait] |
| impl INamedCallback::INamedCallbackAsyncServer for NamedCallback { |
| async fn GetName(&self) -> binder::Result<String> { |
| Ok(self.0.clone()) |
| } |
| } |
| |
| struct OldName; |
| |
| impl Interface for OldName {} |
| |
| #[async_trait] |
| impl IOldName::IOldNameAsyncServer for OldName { |
| async fn RealName(&self) -> binder::Result<String> { |
| Ok("OldName".into()) |
| } |
| } |
| |
| #[derive(Debug, Default)] |
| struct NewName; |
| |
| impl Interface for NewName {} |
| |
| #[async_trait] |
| impl INewName::INewNameAsyncServer for NewName { |
| async fn RealName(&self) -> binder::Result<String> { |
| Ok("NewName".into()) |
| } |
| } |
| |
| #[derive(Default)] |
| struct TestService { |
| service_map: Mutex<HashMap<String, binder::Strong<dyn INamedCallback::INamedCallback>>>, |
| } |
| |
| impl Interface for TestService {} |
| |
| // Macros are expanded in the wrong order, so async_trait does not apply to |
| // functions defined by declarative macros. |
| |
| type BoxFuture<'a, T> = std::pin::Pin<Box<dyn std::future::Future<Output = T> + Send + 'a>>; |
| |
| macro_rules! impl_repeat { |
| ($repeat_name:ident, $type:ty) => { |
| fn $repeat_name<'a, 'b>(&'a self, token: $type) -> BoxFuture<'b, binder::Result<$type>> |
| where |
| 'a: 'b, |
| Self: 'b, |
| { |
| Box::pin(async move { Ok(token) }) |
| } |
| }; |
| } |
| |
| macro_rules! impl_reverse { |
| ($reverse_name:ident, $type:ty) => { |
| fn $reverse_name<'a, 'b, 'c, 'd>( |
| &'a self, |
| input: &'b [$type], |
| repeated: &'c mut Vec<$type>, |
| ) -> BoxFuture<'d, binder::Result<Vec<$type>>> |
| where |
| 'a: 'd, |
| 'b: 'd, |
| 'c: 'd, |
| Self: 'd, |
| { |
| Box::pin(async move { |
| repeated.clear(); |
| repeated.extend_from_slice(input); |
| Ok(input.iter().rev().cloned().collect()) |
| }) |
| } |
| }; |
| } |
| |
| macro_rules! impl_repeat_reverse { |
| ($repeat_name:ident, $reverse_name:ident, $type:ty) => { |
| impl_repeat! {$repeat_name, $type} |
| impl_reverse! {$reverse_name, $type} |
| }; |
| } |
| |
| macro_rules! impl_repeat_nullable { |
| ($repeat_nullable_name:ident, $type:ty) => { |
| fn $repeat_nullable_name<'a, 'b, 'c>( |
| &'a self, |
| input: Option<&'b [$type]>, |
| ) -> BoxFuture<'c, binder::Result<Option<Vec<$type>>>> |
| where |
| 'a: 'c, |
| 'b: 'c, |
| Self: 'c, |
| { |
| Box::pin(async move { Ok(input.map(<[$type]>::to_vec)) }) |
| } |
| }; |
| } |
| |
| #[async_trait] |
| impl ITestService::ITestServiceAsyncServer for TestService { |
| impl_repeat! {RepeatByte, i8} |
| impl_reverse! {ReverseByte, u8} |
| |
| async fn UnimplementedMethod(&self, _: i32) -> binder::Result<i32> { |
| // Pretend this method hasn't been implemented |
| Err(binder::StatusCode::UNKNOWN_TRANSACTION.into()) |
| } |
| |
| async fn TestOneway(&self) -> binder::Result<()> { |
| Err(binder::StatusCode::UNKNOWN_ERROR.into()) |
| } |
| |
| async fn Deprecated(&self) -> binder::Result<()> { |
| Ok(()) |
| } |
| |
| impl_repeat_reverse! {RepeatBoolean, ReverseBoolean, bool} |
| impl_repeat_reverse! {RepeatChar, ReverseChar, u16} |
| impl_repeat_reverse! {RepeatInt, ReverseInt, i32} |
| impl_repeat_reverse! {RepeatLong, ReverseLong, i64} |
| impl_repeat_reverse! {RepeatFloat, ReverseFloat, f32} |
| impl_repeat_reverse! {RepeatDouble, ReverseDouble, f64} |
| impl_repeat_reverse! {RepeatByteEnum, ReverseByteEnum, ByteEnum} |
| impl_repeat_reverse! {RepeatIntEnum, ReverseIntEnum, IntEnum} |
| impl_repeat_reverse! {RepeatLongEnum, ReverseLongEnum, LongEnum} |
| impl_reverse! {ReverseString, String} |
| impl_reverse! {ReverseStringList, String} |
| impl_reverse! {ReverseUtf8CppString, String} |
| |
| async fn RepeatString(&self, input: &str) -> binder::Result<String> { |
| Ok(input.into()) |
| } |
| |
| async fn RepeatUtf8CppString(&self, input: &str) -> binder::Result<String> { |
| Ok(input.into()) |
| } |
| |
| async fn GetOtherTestService( |
| &self, |
| name: &str, |
| ) -> binder::Result<binder::Strong<dyn INamedCallback::INamedCallback>> { |
| let mut service_map = self.service_map.lock().unwrap(); |
| let other_service = service_map.entry(name.into()).or_insert_with(|| { |
| let named_callback = NamedCallback(name.into()); |
| INamedCallback::BnNamedCallback::new_async_binder( |
| named_callback, |
| rt(), |
| BinderFeatures::default(), |
| ) |
| }); |
| Ok(other_service.to_owned()) |
| } |
| |
| async fn VerifyName( |
| &self, |
| service: &binder::Strong<dyn INamedCallback::INamedCallback>, |
| name: &str, |
| ) -> binder::Result<bool> { |
| service.GetName().map(|found_name| found_name == name) |
| } |
| |
| async fn GetInterfaceArray( |
| &self, |
| names: &[String], |
| ) -> binder::Result<Vec<binder::Strong<dyn INamedCallback::INamedCallback>>> { |
| let mut res = Vec::new(); |
| for name in names { |
| res.push(self.GetOtherTestService(name).await?); |
| } |
| Ok(res) |
| } |
| |
| async fn VerifyNamesWithInterfaceArray( |
| &self, |
| services: &[binder::Strong<dyn INamedCallback::INamedCallback>], |
| names: &[String], |
| ) -> binder::Result<bool> { |
| if services.len() == names.len() { |
| for (s, n) in services.iter().zip(names) { |
| if !self.VerifyName(s, n).await? { |
| return Ok(false); |
| } |
| } |
| Ok(true) |
| } else { |
| Ok(false) |
| } |
| } |
| |
| async fn GetNullableInterfaceArray( |
| &self, |
| names: Option<&[Option<String>]>, |
| ) -> binder::Result<Option<Vec<Option<binder::Strong<dyn INamedCallback::INamedCallback>>>>> |
| { |
| if let Some(names) = names { |
| let mut services = vec![]; |
| for name in names { |
| if let Some(name) = name { |
| services.push(Some(self.GetOtherTestService(name).await?)); |
| } else { |
| services.push(None); |
| } |
| } |
| Ok(Some(services)) |
| } else { |
| Ok(None) |
| } |
| } |
| |
| async fn VerifyNamesWithNullableInterfaceArray( |
| &self, |
| services: Option<&[Option<binder::Strong<dyn INamedCallback::INamedCallback>>]>, |
| names: Option<&[Option<String>]>, |
| ) -> binder::Result<bool> { |
| if let (Some(services), Some(names)) = (services, names) { |
| for (s, n) in services.iter().zip(names) { |
| if let (Some(s), Some(n)) = (s, n) { |
| if !self.VerifyName(s, n).await? { |
| return Ok(false); |
| } |
| } else if s.is_some() || n.is_some() { |
| return Ok(false); |
| } |
| } |
| Ok(true) |
| } else { |
| Ok(services.is_none() && names.is_none()) |
| } |
| } |
| |
| async fn GetInterfaceList( |
| &self, |
| names: Option<&[Option<String>]>, |
| ) -> binder::Result<Option<Vec<Option<binder::Strong<dyn INamedCallback::INamedCallback>>>>> |
| { |
| self.GetNullableInterfaceArray(names).await |
| } |
| |
| async fn VerifyNamesWithInterfaceList( |
| &self, |
| services: Option<&[Option<binder::Strong<dyn INamedCallback::INamedCallback>>]>, |
| names: Option<&[Option<String>]>, |
| ) -> binder::Result<bool> { |
| self.VerifyNamesWithNullableInterfaceArray(services, names).await |
| } |
| |
| async fn RepeatParcelFileDescriptor( |
| &self, |
| read: &ParcelFileDescriptor, |
| ) -> binder::Result<ParcelFileDescriptor> { |
| Ok(dup_fd(read)) |
| } |
| |
| async fn ReverseParcelFileDescriptorArray( |
| &self, |
| input: &[ParcelFileDescriptor], |
| repeated: &mut Vec<Option<ParcelFileDescriptor>>, |
| ) -> binder::Result<Vec<ParcelFileDescriptor>> { |
| repeated.clear(); |
| repeated.extend(input.iter().map(dup_fd).map(Some)); |
| Ok(input.iter().rev().map(dup_fd).collect()) |
| } |
| |
| async fn ThrowServiceException(&self, code: i32) -> binder::Result<()> { |
| Err(binder::Status::new_service_specific_error(code, None)) |
| } |
| |
| impl_repeat_nullable! {RepeatNullableIntArray, i32} |
| impl_repeat_nullable! {RepeatNullableByteEnumArray, ByteEnum} |
| impl_repeat_nullable! {RepeatNullableIntEnumArray, IntEnum} |
| impl_repeat_nullable! {RepeatNullableLongEnumArray, LongEnum} |
| impl_repeat_nullable! {RepeatNullableStringList, Option<String>} |
| |
| async fn RepeatNullableString(&self, input: Option<&str>) -> binder::Result<Option<String>> { |
| Ok(input.map(String::from)) |
| } |
| |
| async fn RepeatNullableUtf8CppString( |
| &self, |
| input: Option<&str>, |
| ) -> binder::Result<Option<String>> { |
| Ok(input.map(String::from)) |
| } |
| |
| async fn RepeatNullableParcelable( |
| &self, |
| input: Option<&Empty>, |
| ) -> binder::Result<Option<Empty>> { |
| Ok(input.cloned()) |
| } |
| |
| impl_repeat_nullable! {RepeatNullableParcelableArray, Option<Empty>} |
| impl_repeat_nullable! {RepeatNullableParcelableList, Option<Empty>} |
| |
| async fn TakesAnIBinder(&self, _: &SpIBinder) -> binder::Result<()> { |
| Ok(()) |
| } |
| |
| async fn TakesANullableIBinder(&self, _: Option<&SpIBinder>) -> binder::Result<()> { |
| Ok(()) |
| } |
| |
| async fn TakesAnIBinderList(&self, _: &[SpIBinder]) -> binder::Result<()> { |
| Ok(()) |
| } |
| |
| async fn TakesANullableIBinderList( |
| &self, |
| _: Option<&[Option<SpIBinder>]>, |
| ) -> binder::Result<()> { |
| Ok(()) |
| } |
| |
| async fn ReverseNullableUtf8CppString( |
| &self, |
| input: Option<&[Option<String>]>, |
| repeated: &mut Option<Vec<Option<String>>>, |
| ) -> binder::Result<Option<Vec<Option<String>>>> { |
| if let Some(input) = input { |
| *repeated = Some(input.to_vec()); |
| Ok(Some(input.iter().rev().cloned().collect())) |
| } else { |
| // We don't touch `repeated` here, since |
| // the C++ test service doesn't either |
| Ok(None) |
| } |
| } |
| |
| async fn ReverseUtf8CppStringList( |
| &self, |
| input: Option<&[Option<String>]>, |
| repeated: &mut Option<Vec<Option<String>>>, |
| ) -> binder::Result<Option<Vec<Option<String>>>> { |
| self.ReverseNullableUtf8CppString(input, repeated).await |
| } |
| |
| async fn GetCallback( |
| &self, |
| return_null: bool, |
| ) -> binder::Result<Option<binder::Strong<dyn INamedCallback::INamedCallback>>> { |
| if return_null { |
| Ok(None) |
| } else { |
| self.GetOtherTestService("ABT: always be testing").await.map(Some) |
| } |
| } |
| |
| async fn FillOutStructuredParcelable( |
| &self, |
| parcelable: &mut StructuredParcelable::StructuredParcelable, |
| ) -> binder::Result<()> { |
| parcelable.shouldBeJerry = "Jerry".into(); |
| parcelable.shouldContainThreeFs = vec![parcelable.f, parcelable.f, parcelable.f]; |
| parcelable.shouldBeByteBar = ByteEnum::BAR; |
| parcelable.shouldBeIntBar = IntEnum::BAR; |
| parcelable.shouldBeLongBar = LongEnum::BAR; |
| parcelable.shouldContainTwoByteFoos = vec![ByteEnum::FOO, ByteEnum::FOO]; |
| parcelable.shouldContainTwoIntFoos = vec![IntEnum::FOO, IntEnum::FOO]; |
| parcelable.shouldContainTwoLongFoos = vec![LongEnum::FOO, LongEnum::FOO]; |
| |
| parcelable.const_exprs_1 = ConstantExpressionEnum::decInt32_1; |
| parcelable.const_exprs_2 = ConstantExpressionEnum::decInt32_2; |
| parcelable.const_exprs_3 = ConstantExpressionEnum::decInt64_1; |
| parcelable.const_exprs_4 = ConstantExpressionEnum::decInt64_2; |
| parcelable.const_exprs_5 = ConstantExpressionEnum::decInt64_3; |
| parcelable.const_exprs_6 = ConstantExpressionEnum::decInt64_4; |
| parcelable.const_exprs_7 = ConstantExpressionEnum::hexInt32_1; |
| parcelable.const_exprs_8 = ConstantExpressionEnum::hexInt32_2; |
| parcelable.const_exprs_9 = ConstantExpressionEnum::hexInt32_3; |
| parcelable.const_exprs_10 = ConstantExpressionEnum::hexInt64_1; |
| |
| parcelable.shouldSetBit0AndBit2 = StructuredParcelable::BIT0 | StructuredParcelable::BIT2; |
| |
| parcelable.u = Some(Union::Union::Ns(vec![1, 2, 3])); |
| parcelable.shouldBeConstS1 = Some(Union::Union::S(Union::S1.to_string())); |
| Ok(()) |
| } |
| |
| async fn RepeatExtendableParcelable( |
| &self, |
| ep: &ExtendableParcelable, |
| ep2: &mut ExtendableParcelable, |
| ) -> binder::Result<()> { |
| ep2.a = ep.a; |
| ep2.b = ep.b.clone(); |
| |
| let my_ext = ep.ext.get_parcelable::<MyExt>()?; |
| if let Some(my_ext) = my_ext { |
| ep2.ext.set_parcelable(my_ext)?; |
| } else { |
| ep2.ext.reset(); |
| } |
| |
| Ok(()) |
| } |
| |
| async fn ReverseList(&self, list: &RecursiveList) -> binder::Result<RecursiveList> { |
| let mut reversed: Option<RecursiveList> = None; |
| let mut cur: Option<&RecursiveList> = Some(list); |
| while let Some(node) = cur { |
| reversed = Some(RecursiveList { value: node.value, next: reversed.map(Box::new) }); |
| cur = node.next.as_ref().map(|n| n.as_ref()); |
| } |
| // `list` is always not empty, so is `reversed`. |
| Ok(reversed.unwrap()) |
| } |
| |
| async fn ReverseIBinderArray( |
| &self, |
| input: &[SpIBinder], |
| repeated: &mut Vec<Option<SpIBinder>>, |
| ) -> binder::Result<Vec<SpIBinder>> { |
| *repeated = input.iter().cloned().map(Some).collect(); |
| Ok(input.iter().rev().cloned().collect()) |
| } |
| |
| async fn ReverseNullableIBinderArray( |
| &self, |
| input: Option<&[Option<SpIBinder>]>, |
| repeated: &mut Option<Vec<Option<SpIBinder>>>, |
| ) -> binder::Result<Option<Vec<Option<SpIBinder>>>> { |
| let input = input.expect("input is null"); |
| *repeated = Some(input.to_vec()); |
| Ok(Some(input.iter().rev().cloned().collect())) |
| } |
| |
| async fn GetOldNameInterface(&self) -> binder::Result<binder::Strong<dyn IOldName::IOldName>> { |
| Ok(IOldName::BnOldName::new_async_binder(OldName, rt(), BinderFeatures::default())) |
| } |
| |
| async fn GetNewNameInterface(&self) -> binder::Result<binder::Strong<dyn INewName::INewName>> { |
| Ok(INewName::BnNewName::new_async_binder(NewName, rt(), BinderFeatures::default())) |
| } |
| |
| async fn GetCppJavaTests(&self) -> binder::Result<Option<SpIBinder>> { |
| Ok(None) |
| } |
| |
| async fn getBackendType(&self) -> binder::Result<BackendType> { |
| Ok(BackendType::RUST) |
| } |
| } |
| |
| struct FooInterface; |
| |
| impl Interface for FooInterface {} |
| |
| #[async_trait] |
| impl IFooInterface::IFooInterfaceAsyncServer for FooInterface { |
| async fn originalApi(&self) -> binder::Result<()> { |
| Ok(()) |
| } |
| async fn acceptUnionAndReturnString(&self, u: &BazUnion) -> binder::Result<String> { |
| match u { |
| BazUnion::IntNum(n) => Ok(n.to_string()), |
| } |
| } |
| async fn returnsLengthOfFooArray(&self, foos: &[Foo]) -> binder::Result<i32> { |
| Ok(foos.len() as i32) |
| } |
| async fn ignoreParcelablesAndRepeatInt( |
| &self, |
| _in_foo: &Foo, |
| _inout_foo: &mut Foo, |
| _out_foo: &mut Foo, |
| value: i32, |
| ) -> binder::Result<i32> { |
| Ok(value) |
| } |
| } |
| |
| struct NestedService; |
| |
| impl Interface for NestedService {} |
| |
| #[async_trait] |
| impl INestedService::INestedServiceAsyncServer for NestedService { |
| async fn flipStatus( |
| &self, |
| p: &ParcelableWithNested::ParcelableWithNested, |
| ) -> binder::Result<INestedService::Result::Result> { |
| if p.status == ParcelableWithNested::Status::Status::OK { |
| Ok(INestedService::Result::Result { |
| status: ParcelableWithNested::Status::Status::NOT_OK, |
| }) |
| } else { |
| Ok(INestedService::Result::Result { status: ParcelableWithNested::Status::Status::OK }) |
| } |
| } |
| async fn flipStatusWithCallback( |
| &self, |
| st: ParcelableWithNested::Status::Status, |
| cb: &binder::Strong<dyn INestedService::ICallback::ICallback>, |
| ) -> binder::Result<()> { |
| if st == ParcelableWithNested::Status::Status::OK { |
| cb.done(ParcelableWithNested::Status::Status::NOT_OK) |
| } else { |
| cb.done(ParcelableWithNested::Status::Status::OK) |
| } |
| } |
| } |
| |
| fn rt() -> binder_tokio::TokioRuntime<tokio::runtime::Runtime> { |
| let rt = tokio::runtime::Builder::new_current_thread().enable_all().build().unwrap(); |
| binder_tokio::TokioRuntime(rt) |
| } |
| |
| fn main() { |
| binder::ProcessState::set_thread_pool_max_thread_count(0); |
| binder::ProcessState::start_thread_pool(); |
| |
| let service_name = <BpTestService as ITestService::ITestService>::get_descriptor(); |
| let service = |
| BnTestService::new_async_binder(TestService::default(), rt(), BinderFeatures::default()); |
| binder::add_service(service_name, service.as_binder()).expect("Could not register service"); |
| |
| let versioned_service_name = <BpFooInterface as IFooInterface::IFooInterface>::get_descriptor(); |
| let versioned_service = |
| BnFooInterface::new_async_binder(FooInterface, rt(), BinderFeatures::default()); |
| binder::add_service(versioned_service_name, versioned_service.as_binder()) |
| .expect("Could not register service"); |
| |
| let nested_service_name = |
| <INestedService::BpNestedService as INestedService::INestedService>::get_descriptor(); |
| let nested_service = INestedService::BnNestedService::new_async_binder( |
| NestedService, |
| rt(), |
| BinderFeatures::default(), |
| ); |
| binder::add_service(nested_service_name, nested_service.as_binder()) |
| .expect("Could not register service"); |
| |
| binder::ProcessState::join_thread_pool(); |
| } |