/* * Copyright (C) 2020, 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::ITestService::{ self, BnTestService, BpTestService, }; use aidl_test_interface::aidl::android::aidl::tests::{ BackendType::BackendType, ByteEnum::ByteEnum, ConstantExpressionEnum::ConstantExpressionEnum, INamedCallback, INewName, IOldName, IntEnum::IntEnum, LongEnum::LongEnum, 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; fn dup_fd(fd: &ParcelFileDescriptor) -> ParcelFileDescriptor { ParcelFileDescriptor::new(fd.as_ref().try_clone().unwrap()) } struct NamedCallback(String); impl Interface for NamedCallback {} impl INamedCallback::INamedCallback for NamedCallback { fn GetName(&self) -> binder::Result { Ok(self.0.clone()) } } struct OldName; impl Interface for OldName {} impl IOldName::IOldName for OldName { fn RealName(&self) -> binder::Result { Ok("OldName".into()) } } #[derive(Debug, Default)] struct NewName; impl Interface for NewName {} impl INewName::INewName for NewName { fn RealName(&self) -> binder::Result { Ok("NewName".into()) } } #[derive(Default)] struct TestService { service_map: Mutex>>, } impl Interface for TestService {} macro_rules! impl_repeat { ($repeat_name:ident, $type:ty) => { fn $repeat_name(&self, token: $type) -> binder::Result<$type> { Ok(token) } }; } macro_rules! impl_reverse { ($reverse_name:ident, $type:ty) => { fn $reverse_name( &self, input: &[$type], repeated: &mut Vec<$type>, ) -> binder::Result> { 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( &self, input: Option<&[$type]>, ) -> binder::Result>> { Ok(input.map(<[$type]>::to_vec)) } }; } impl ITestService::ITestService for TestService { impl_repeat! {RepeatByte, i8} impl_reverse! {ReverseByte, u8} fn UnimplementedMethod(&self, _: i32) -> binder::Result { // Pretend this method hasn't been implemented Err(binder::StatusCode::UNKNOWN_TRANSACTION.into()) } fn TestOneway(&self) -> binder::Result<()> { Err(binder::StatusCode::UNKNOWN_ERROR.into()) } 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} fn RepeatString(&self, input: &str) -> binder::Result { Ok(input.into()) } fn RepeatUtf8CppString(&self, input: &str) -> binder::Result { Ok(input.into()) } fn GetOtherTestService( &self, name: &str, ) -> binder::Result> { 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_binder(named_callback, BinderFeatures::default()) }); Ok(other_service.to_owned()) } fn VerifyName( &self, service: &binder::Strong, name: &str, ) -> binder::Result { service.GetName().map(|found_name| found_name == name) } fn RepeatParcelFileDescriptor( &self, read: &ParcelFileDescriptor, ) -> binder::Result { Ok(dup_fd(read)) } fn ReverseParcelFileDescriptorArray( &self, input: &[ParcelFileDescriptor], repeated: &mut Vec>, ) -> binder::Result> { repeated.clear(); repeated.extend(input.iter().map(dup_fd).map(Some)); Ok(input.iter().rev().map(dup_fd).collect()) } 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} fn RepeatNullableString(&self, input: Option<&str>) -> binder::Result> { Ok(input.map(String::from)) } fn RepeatNullableUtf8CppString(&self, input: Option<&str>) -> binder::Result> { Ok(input.map(String::from)) } fn RepeatNullableParcelable( &self, input: Option<&StructuredParcelable::StructuredParcelable>, ) -> binder::Result> { Ok(input.cloned()) } fn TakesAnIBinder(&self, _: &SpIBinder) -> binder::Result<()> { Ok(()) } fn TakesANullableIBinder(&self, _: Option<&SpIBinder>) -> binder::Result<()> { Ok(()) } fn ReverseNullableUtf8CppString( &self, input: Option<&[Option]>, repeated: &mut Option>>, ) -> binder::Result>>> { 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) } } fn ReverseUtf8CppStringList( &self, input: Option<&[Option]>, repeated: &mut Option>>, ) -> binder::Result>>> { self.ReverseNullableUtf8CppString(input, repeated) } fn GetCallback( &self, return_null: bool, ) -> binder::Result>> { if return_null { Ok(None) } else { self.GetOtherTestService("ABT: always be testing").map(Some) } } 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(()) } fn GetOldNameInterface(&self) -> binder::Result> { Ok(IOldName::BnOldName::new_binder( OldName, BinderFeatures::default(), )) } fn GetNewNameInterface(&self) -> binder::Result> { Ok(INewName::BnNewName::new_binder( NewName, BinderFeatures::default(), )) } fn GetCppJavaTests(&self) -> binder::Result> { Ok(None) } fn getBackendType(&self) -> binder::Result { Ok(BackendType::RUST) } } struct FooInterface; impl Interface for FooInterface {} impl IFooInterface::IFooInterface for FooInterface { fn originalApi(&self) -> binder::Result<()> { Ok(()) } fn acceptUnionAndReturnString(&self, u: &BazUnion) -> binder::Result { match u { BazUnion::IntNum(n) => Ok(n.to_string()), } } fn returnsLengthOfFooArray(&self, foos: &[Foo]) -> binder::Result { Ok(foos.len() as i32) } fn ignoreParcelablesAndRepeatInt(&self, _in_foo: &Foo, _inout_foo: &mut Foo, _out_foo: &mut Foo, value: i32) -> binder::Result { Ok(value) } } fn main() { binder::ProcessState::set_thread_pool_max_thread_count(0); binder::ProcessState::start_thread_pool(); let service_name = ::get_descriptor(); let service = BnTestService::new_binder(TestService::default(), BinderFeatures::default()); binder::add_service(service_name, service.as_binder()).expect("Could not register service"); let versioned_service_name = ::get_descriptor(); let versioned_service = BnFooInterface::new_binder(FooInterface, BinderFeatures::default()); binder::add_service(versioned_service_name, versioned_service.as_binder()) .expect("Could not register service"); binder::ProcessState::join_thread_pool(); }