diff options
27 files changed, 779 insertions, 201 deletions
diff --git a/cmds/atrace/atrace_userdebug.rc b/cmds/atrace/atrace_userdebug.rc index 9186514d0a..fa7be1816a 100644 --- a/cmds/atrace/atrace_userdebug.rc +++ b/cmds/atrace/atrace_userdebug.rc @@ -18,3 +18,9 @@ on post-fs chmod 0666 /sys/kernel/tracing/events/filemap/enable chmod 0666 /sys/kernel/debug/tracing/events/filemap/enable + # Allow traced_probes to use the raw_syscall filters to trace only a subset + # of syscalls. + chmod 0666 /sys/kernel/tracing/events/raw_syscalls/sys_enter/filter + chmod 0666 /sys/kernel/debug/tracing/events/raw_syscalls/sys_enter/filter + chmod 0666 /sys/kernel/tracing/events/raw_syscalls/sys_exit/filter + chmod 0666 /sys/kernel/debug/tracing/events/raw_syscalls/sys_exit/filter diff --git a/cmds/servicemanager/Android.bp b/cmds/servicemanager/Android.bp index edeb2a4a33..fd879c6c34 100644 --- a/cmds/servicemanager/Android.bp +++ b/cmds/servicemanager/Android.bp @@ -90,27 +90,11 @@ cc_test { cc_fuzz { name: "servicemanager_fuzzer", - defaults: ["servicemanager_defaults"], - host_supported: true, - static_libs: [ - "libbase", - "libbinder_random_parcel", - "libcutils", + defaults: [ + "servicemanager_defaults", + "service_fuzzer_defaults", ], - target: { - android: { - shared_libs: [ - "libbinder_ndk", - "libbinder", - ], - }, - host: { - static_libs: [ - "libbinder_ndk", - "libbinder", - ], - }, - }, + host_supported: true, srcs: ["ServiceManagerFuzzer.cpp"], fuzz_config: { libfuzzer_options: [ diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp index fabf3ebdae..2cb6821ae7 100644 --- a/libs/binder/Android.bp +++ b/libs/binder/Android.bp @@ -446,6 +446,7 @@ cc_library { // This library is intentionally limited to these targets, and it will be removed later. // Do not expand the visibility. visibility: [ + ":__subpackages__", "//packages/modules/Virtualization:__subpackages__", ], } diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp index b5ea60f102..402995717c 100644 --- a/libs/binder/Binder.cpp +++ b/libs/binder/Binder.cpp @@ -202,6 +202,17 @@ void IBinder::withLock(const std::function<void()>& doWithLock) { proxy->withLock(doWithLock); } +sp<IBinder> IBinder::lookupOrCreateWeak(const void* objectID, object_make_func make, + const void* makeArgs) { + BBinder* local = localBinder(); + if (local) { + return local->lookupOrCreateWeak(objectID, make, makeArgs); + } + BpBinder* proxy = this->remoteBinder(); + LOG_ALWAYS_FATAL_IF(proxy == nullptr, "binder object must be either local or remote"); + return proxy->lookupOrCreateWeak(objectID, make, makeArgs); +} + // --------------------------------------------------------------------------- class BBinder::RpcServerLink : public IBinder::DeathRecipient { @@ -272,11 +283,9 @@ status_t BBinder::pingBinder() const String16& BBinder::getInterfaceDescriptor() const { - // This is a local static rather than a global static, - // to avoid static initializer ordering issues. - static String16 sEmptyDescriptor; - ALOGW("reached BBinder::getInterfaceDescriptor (this=%p)", this); - return sEmptyDescriptor; + static StaticString16 sBBinder(u"BBinder"); + ALOGW("Reached BBinder::getInterfaceDescriptor (this=%p). Override?", this); + return sBBinder; } // NOLINTNEXTLINE(google-default-arguments) @@ -378,6 +387,14 @@ void BBinder::withLock(const std::function<void()>& doWithLock) { doWithLock(); } +sp<IBinder> BBinder::lookupOrCreateWeak(const void* objectID, object_make_func make, + const void* makeArgs) { + Extras* e = getOrCreateExtras(); + LOG_ALWAYS_FATAL_IF(!e, "no memory"); + AutoMutex _l(e->mLock); + return e->mObjects.lookupOrCreateWeak(objectID, make, makeArgs); +} + BBinder* BBinder::localBinder() { return this; diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp index b6d35ef3ef..d9b723108e 100644 --- a/libs/binder/BpBinder.cpp +++ b/libs/binder/BpBinder.cpp @@ -100,6 +100,36 @@ void* BpBinder::ObjectManager::detach(const void* objectID) { return value; } +namespace { +struct Tag { + wp<IBinder> binder; +}; +} // namespace + +static void cleanWeak(const void* /* id */, void* obj, void* /* cookie */) { + delete static_cast<Tag*>(obj); +} + +sp<IBinder> BpBinder::ObjectManager::lookupOrCreateWeak(const void* objectID, object_make_func make, + const void* makeArgs) { + entry_t& e = mObjects[objectID]; + if (e.object != nullptr) { + if (auto attached = static_cast<Tag*>(e.object)->binder.promote()) { + return attached; + } + } else { + e.object = new Tag; + LOG_ALWAYS_FATAL_IF(!e.object, "no more memory"); + } + sp<IBinder> newObj = make(makeArgs); + + static_cast<Tag*>(e.object)->binder = newObj; + e.cleanupCookie = nullptr; + e.func = cleanWeak; + + return newObj; +} + void BpBinder::ObjectManager::kill() { const size_t N = mObjects.size(); @@ -516,6 +546,12 @@ void BpBinder::withLock(const std::function<void()>& doWithLock) { doWithLock(); } +sp<IBinder> BpBinder::lookupOrCreateWeak(const void* objectID, object_make_func make, + const void* makeArgs) { + AutoMutex _l(mLock); + return mObjects.lookupOrCreateWeak(objectID, make, makeArgs); +} + BpBinder* BpBinder::remoteBinder() { return this; diff --git a/libs/binder/RpcSession.cpp b/libs/binder/RpcSession.cpp index d347262040..8ddfa93c00 100644 --- a/libs/binder/RpcSession.cpp +++ b/libs/binder/RpcSession.cpp @@ -484,6 +484,9 @@ status_t RpcSession::setupClient(const std::function<status_t(const std::vector< mProtocolVersion = oldProtocolVersion; mConnections = {}; + + // clear mStartedSetup so that we can reuse this RpcSession + mStartedSetup = false; }); if (status_t status = connectAndInit({}, false /*incoming*/); status != OK) return status; diff --git a/libs/binder/RpcTransportTipcAndroid.cpp b/libs/binder/RpcTransportTipcAndroid.cpp index 79983f46d3..c82201b28b 100644 --- a/libs/binder/RpcTransportTipcAndroid.cpp +++ b/libs/binder/RpcTransportTipcAndroid.cpp @@ -103,7 +103,10 @@ public: // read and call readFn as many times as needed to get all the data status_t ret = fillReadBuffer(); if (ret != OK) { - return ret; + // We need to emulate a Linux read call, which sets errno on + // error and returns -1 + errno = -ret; + return -1; } ssize_t processSize = 0; diff --git a/libs/binder/include/binder/Binder.h b/libs/binder/include/binder/Binder.h index 46223bb00e..88d9ca1d58 100644 --- a/libs/binder/include/binder/Binder.h +++ b/libs/binder/include/binder/Binder.h @@ -59,6 +59,8 @@ public: virtual void* findObject(const void* objectID) const final; virtual void* detachObject(const void* objectID) final; void withLock(const std::function<void()>& doWithLock); + sp<IBinder> lookupOrCreateWeak(const void* objectID, IBinder::object_make_func make, + const void* makeArgs); virtual BBinder* localBinder(); diff --git a/libs/binder/include/binder/BpBinder.h b/libs/binder/include/binder/BpBinder.h index 19ad5e6efe..4172cc511e 100644 --- a/libs/binder/include/binder/BpBinder.h +++ b/libs/binder/include/binder/BpBinder.h @@ -72,6 +72,8 @@ public: virtual void* findObject(const void* objectID) const final; virtual void* detachObject(const void* objectID) final; void withLock(const std::function<void()>& doWithLock); + sp<IBinder> lookupOrCreateWeak(const void* objectID, IBinder::object_make_func make, + const void* makeArgs); virtual BpBinder* remoteBinder(); @@ -96,6 +98,8 @@ public: IBinder::object_cleanup_func func); void* find(const void* objectID) const; void* detach(const void* objectID); + sp<IBinder> lookupOrCreateWeak(const void* objectID, IBinder::object_make_func make, + const void* makeArgs); void kill(); @@ -104,9 +108,9 @@ public: ObjectManager& operator=(const ObjectManager&); struct entry_t { - void* object; - void* cleanupCookie; - IBinder::object_cleanup_func func; + void* object = nullptr; + void* cleanupCookie = nullptr; + IBinder::object_cleanup_func func = nullptr; }; std::map<const void*, entry_t> mObjects; diff --git a/libs/binder/include/binder/Delegate.h b/libs/binder/include/binder/Delegate.h new file mode 100644 index 0000000000..8b3fc1cc10 --- /dev/null +++ b/libs/binder/include/binder/Delegate.h @@ -0,0 +1,93 @@ +/* + * 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. + */ + +#pragma once + +#include <binder/IBinder.h> + +#ifndef __BIONIC__ +#ifndef __assert + +// defined differently by liblog +#pragma push_macro("LOG_PRI") +#ifdef LOG_PRI +#undef LOG_PRI +#endif +#include <syslog.h> +#pragma pop_macro("LOG_PRI") + +#define __assert(a, b, c) \ + do { \ + syslog(LOG_ERR, a ": " c); \ + abort(); \ + } while (false) +#endif // __assert +#endif // __BIONIC__ + +namespace android { + +/* + * Used to manage AIDL's *Delegator types. + * This is used to: + * - create a new *Delegator object that delegates to the binder argument. + * - or return an existing *Delegator object that already delegates to the + * binder argument. + * - or return the underlying delegate binder if the binder argument is a + * *Delegator itself. + * + * @param binder - the binder to delegate to or unwrap + * + * @return pointer to the *Delegator object or the unwrapped binder object + */ +template <typename T> +sp<T> delegate(const sp<T>& binder) { + const void* isDelegatorId = &T::descriptor; + const void* hasDelegatorId = &T::descriptor + 1; + // is binder itself a delegator? + if (T::asBinder(binder)->findObject(isDelegatorId)) { + if (T::asBinder(binder)->findObject(hasDelegatorId)) { + __assert(__FILE__, __LINE__, + "This binder has a delegator and is also delegator itself! This is " + "likely an unintended mixing of binders."); + return nullptr; + } + // unwrap the delegator + return static_cast<typename T::DefaultDelegator*>(binder.get())->getImpl(); + } + + struct MakeArgs { + const sp<T>* binder; + const void* id; + } makeArgs; + makeArgs.binder = &binder; + makeArgs.id = isDelegatorId; + + // the binder is not a delegator, so construct one + sp<IBinder> newDelegator = T::asBinder(binder)->lookupOrCreateWeak( + hasDelegatorId, + [](const void* args) -> sp<IBinder> { + auto delegator = sp<typename T::DefaultDelegator>::make( + *static_cast<const MakeArgs*>(args)->binder); + // make sure we know this binder is a delegator by attaching a unique ID + (void)delegator->attachObject(static_cast<const MakeArgs*>(args)->id, + reinterpret_cast<void*>(0x1), nullptr, nullptr); + return delegator; + }, + static_cast<const void*>(&makeArgs)); + return sp<typename T::DefaultDelegator>::cast(newDelegator); +} + +} // namespace android diff --git a/libs/binder/include/binder/IBinder.h b/libs/binder/include/binder/IBinder.h index 43fc5ff1a9..83aaca7f95 100644 --- a/libs/binder/include/binder/IBinder.h +++ b/libs/binder/include/binder/IBinder.h @@ -284,6 +284,9 @@ public: virtual BBinder* localBinder(); virtual BpBinder* remoteBinder(); + typedef sp<IBinder> (*object_make_func)(const void* makeArgs); + sp<IBinder> lookupOrCreateWeak(const void* objectID, object_make_func make, + const void* makeArgs); protected: virtual ~IBinder(); diff --git a/libs/binder/rust/Android.bp b/libs/binder/rust/Android.bp index c0d4487e09..0ec618352a 100644 --- a/libs/binder/rust/Android.bp +++ b/libs/binder/rust/Android.bp @@ -144,24 +144,6 @@ rust_bindgen { min_sdk_version: "Tiramisu", } -// TODO(b/184872979): remove once the Rust API is created. -rust_bindgen { - name: "libbinder_rpc_unstable_bindgen", - wrapper_src: ":libbinder_rpc_unstable_header", - crate_name: "binder_rpc_unstable_bindgen", - visibility: ["//packages/modules/Virtualization:__subpackages__"], - source_stem: "bindings", - shared_libs: [ - "libutils", - ], - apex_available: [ - "com.android.compos", - "com.android.uwb", - "com.android.virt", - ], - min_sdk_version: "Tiramisu", -} - rust_test { name: "libbinder_rs-internal_test", crate_name: "binder", @@ -188,13 +170,3 @@ rust_test { clippy_lints: "none", lints: "none", } - -rust_test { - name: "libbinder_rpc_unstable_bindgen_test", - srcs: [":libbinder_rpc_unstable_bindgen"], - crate_name: "binder_rpc_unstable_bindgen", - test_suites: ["general-tests"], - auto_gen_config: true, - clippy_lints: "none", - lints: "none", -} diff --git a/libs/binder/rust/rpcbinder/Android.bp b/libs/binder/rust/rpcbinder/Android.bp new file mode 100644 index 0000000000..067ca0dcdd --- /dev/null +++ b/libs/binder/rust/rpcbinder/Android.bp @@ -0,0 +1,50 @@ +rust_library { + name: "librpcbinder_rs", + crate_name: "rpcbinder", + srcs: ["src/lib.rs"], + shared_libs: [ + "libutils", + ], + rustlibs: [ + "libbinder_ndk_sys", + "libbinder_rpc_unstable_bindgen", + "libbinder_rs", + "libdowncast_rs", + "liblibc", + ], + apex_available: [ + "com.android.compos", + "com.android.uwb", + "com.android.virt", + ], + min_sdk_version: "Tiramisu", +} + +// TODO(b/184872979): remove once the RPC Binder API is stabilised. +rust_bindgen { + name: "libbinder_rpc_unstable_bindgen", + wrapper_src: ":libbinder_rpc_unstable_header", + crate_name: "binder_rpc_unstable_bindgen", + visibility: [":__subpackages__"], + source_stem: "bindings", + shared_libs: [ + "libbinder_rpc_unstable", + "libutils", + ], + apex_available: [ + "com.android.compos", + "com.android.uwb", + "com.android.virt", + ], + min_sdk_version: "Tiramisu", +} + +rust_test { + name: "libbinder_rpc_unstable_bindgen_test", + srcs: [":libbinder_rpc_unstable_bindgen"], + crate_name: "binder_rpc_unstable_bindgen", + test_suites: ["general-tests"], + auto_gen_config: true, + clippy_lints: "none", + lints: "none", +} diff --git a/libs/binder/rust/rpcbinder/src/client.rs b/libs/binder/rust/rpcbinder/src/client.rs new file mode 100644 index 0000000000..dfc6f06b14 --- /dev/null +++ b/libs/binder/rust/rpcbinder/src/client.rs @@ -0,0 +1,92 @@ +/* + * 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. + */ + +use binder::{ + unstable_api::{new_spibinder, AIBinder}, + FromIBinder, SpIBinder, StatusCode, Strong, +}; +use std::os::{ + raw::{c_int, c_void}, + unix::io::RawFd, +}; + +/// Connects to an RPC Binder server over vsock. +pub fn get_vsock_rpc_service(cid: u32, port: u32) -> Option<SpIBinder> { + // SAFETY: AIBinder returned by RpcClient has correct reference count, and the ownership can + // safely be taken by new_spibinder. + unsafe { new_spibinder(binder_rpc_unstable_bindgen::RpcClient(cid, port) as *mut AIBinder) } +} + +/// Connects to an RPC Binder server for a particular interface over vsock. +pub fn get_vsock_rpc_interface<T: FromIBinder + ?Sized>( + cid: u32, + port: u32, +) -> Result<Strong<T>, StatusCode> { + interface_cast(get_vsock_rpc_service(cid, port)) +} + +/// Connects to an RPC Binder server, using the given callback to get (and take ownership of) +/// file descriptors already connected to it. +pub fn get_preconnected_rpc_service( + mut request_fd: impl FnMut() -> Option<RawFd>, +) -> Option<SpIBinder> { + // Double reference the factory because trait objects aren't FFI safe. + let mut request_fd_ref: RequestFd = &mut request_fd; + let param = &mut request_fd_ref as *mut RequestFd as *mut c_void; + + // SAFETY: AIBinder returned by RpcPreconnectedClient has correct reference count, and the + // ownership can be safely taken by new_spibinder. RpcPreconnectedClient does not take ownership + // of param, only passing it to request_fd_wrapper. + unsafe { + new_spibinder(binder_rpc_unstable_bindgen::RpcPreconnectedClient( + Some(request_fd_wrapper), + param, + ) as *mut AIBinder) + } +} + +type RequestFd<'a> = &'a mut dyn FnMut() -> Option<RawFd>; + +unsafe extern "C" fn request_fd_wrapper(param: *mut c_void) -> c_int { + // SAFETY: This is only ever called by RpcPreconnectedClient, within the lifetime of the + // BinderFdFactory reference, with param being a properly aligned non-null pointer to an + // initialized instance. + let request_fd_ptr = param as *mut RequestFd; + let request_fd = request_fd_ptr.as_mut().unwrap(); + if let Some(fd) = request_fd() { + fd + } else { + -1 + } +} + +/// Connects to an RPC Binder server for a particular interface, using the given callback to get +/// (and take ownership of) file descriptors already connected to it. +pub fn get_preconnected_rpc_interface<T: FromIBinder + ?Sized>( + request_fd: impl FnMut() -> Option<RawFd>, +) -> Result<Strong<T>, StatusCode> { + interface_cast(get_preconnected_rpc_service(request_fd)) +} + +fn interface_cast<T: FromIBinder + ?Sized>( + service: Option<SpIBinder>, +) -> Result<Strong<T>, StatusCode> { + if let Some(service) = service { + FromIBinder::try_from(service) + } else { + Err(StatusCode::NAME_NOT_FOUND) + } +} diff --git a/libs/binder/rust/rpcbinder/src/lib.rs b/libs/binder/rust/rpcbinder/src/lib.rs new file mode 100644 index 0000000000..a5eea61798 --- /dev/null +++ b/libs/binder/rust/rpcbinder/src/lib.rs @@ -0,0 +1,26 @@ +/* + * 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. + */ + +//! API for RPC Binder services. + +mod client; +mod server; + +pub use client::{ + get_preconnected_rpc_interface, get_preconnected_rpc_service, get_vsock_rpc_interface, + get_vsock_rpc_service, +}; +pub use server::{run_rpc_server, run_rpc_server_with_factory}; diff --git a/libs/binder/rust/rpcbinder/src/server.rs b/libs/binder/rust/rpcbinder/src/server.rs new file mode 100644 index 0000000000..d98a439da4 --- /dev/null +++ b/libs/binder/rust/rpcbinder/src/server.rs @@ -0,0 +1,124 @@ +/* + * 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. + */ + +use binder::{unstable_api::AsNative, SpIBinder}; +use std::{os::raw, ptr::null_mut}; + +/// Runs a binder RPC server, serving the supplied binder service implementation on the given vsock +/// port. +/// +/// If and when the server is ready for connections (it is listening on the port), `on_ready` is +/// called to allow appropriate action to be taken - e.g. to notify clients that they may now +/// attempt to connect. +/// +/// The current thread is joined to the binder thread pool to handle incoming messages. +/// +/// Returns true if the server has shutdown normally, false if it failed in some way. +pub fn run_rpc_server<F>(service: SpIBinder, port: u32, on_ready: F) -> bool +where + F: FnOnce(), +{ + let mut ready_notifier = ReadyNotifier(Some(on_ready)); + ready_notifier.run_server(service, port) +} + +struct ReadyNotifier<F>(Option<F>) +where + F: FnOnce(); + +impl<F> ReadyNotifier<F> +where + F: FnOnce(), +{ + fn run_server(&mut self, mut service: SpIBinder, port: u32) -> bool { + let service = service.as_native_mut() as *mut binder_rpc_unstable_bindgen::AIBinder; + let param = self.as_void_ptr(); + + // SAFETY: Service ownership is transferring to the server and won't be valid afterward. + // Plus the binder objects are threadsafe. + // RunRpcServerCallback does not retain a reference to `ready_callback` or `param`; it only + // uses them before it returns, which is during the lifetime of `self`. + unsafe { + binder_rpc_unstable_bindgen::RunRpcServerCallback( + service, + port, + Some(Self::ready_callback), + param, + ) + } + } + + fn as_void_ptr(&mut self) -> *mut raw::c_void { + self as *mut _ as *mut raw::c_void + } + + unsafe extern "C" fn ready_callback(param: *mut raw::c_void) { + // SAFETY: This is only ever called by `RunRpcServerCallback`, within the lifetime of the + // `ReadyNotifier`, with `param` taking the value returned by `as_void_ptr` (so a properly + // aligned non-null pointer to an initialized instance). + let ready_notifier = param as *mut Self; + ready_notifier.as_mut().unwrap().notify() + } + + fn notify(&mut self) { + if let Some(on_ready) = self.0.take() { + on_ready(); + } + } +} + +type RpcServerFactoryRef<'a> = &'a mut (dyn FnMut(u32) -> Option<SpIBinder> + Send + Sync); + +/// Runs a binder RPC server, using the given factory function to construct a binder service +/// implementation for each connection. +/// +/// The current thread is joined to the binder thread pool to handle incoming messages. +/// +/// Returns true if the server has shutdown normally, false if it failed in some way. +pub fn run_rpc_server_with_factory( + port: u32, + mut factory: impl FnMut(u32) -> Option<SpIBinder> + Send + Sync, +) -> bool { + // Double reference the factory because trait objects aren't FFI safe. + // NB: The type annotation is necessary to ensure that we have a `dyn` rather than an `impl`. + let mut factory_ref: RpcServerFactoryRef = &mut factory; + let context = &mut factory_ref as *mut RpcServerFactoryRef as *mut raw::c_void; + + // SAFETY: `factory_wrapper` is only ever called by `RunRpcServerWithFactory`, with context + // taking the pointer value above (so a properly aligned non-null pointer to an initialized + // `RpcServerFactoryRef`), within the lifetime of `factory_ref` (i.e. no more calls will be made + // after `RunRpcServerWithFactory` returns). + unsafe { + binder_rpc_unstable_bindgen::RunRpcServerWithFactory(Some(factory_wrapper), context, port) + } +} + +unsafe extern "C" fn factory_wrapper( + cid: u32, + context: *mut raw::c_void, +) -> *mut binder_rpc_unstable_bindgen::AIBinder { + // SAFETY: `context` was created from an `&mut RpcServerFactoryRef` by + // `run_rpc_server_with_factory`, and we are still within the lifetime of the value it is + // pointing to. + let factory_ptr = context as *mut RpcServerFactoryRef; + let factory = factory_ptr.as_mut().unwrap(); + + if let Some(mut service) = factory(cid) { + service.as_native_mut() as *mut binder_rpc_unstable_bindgen::AIBinder + } else { + null_mut() + } +} diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp index d7c6d4966e..1babfd5813 100644 --- a/libs/binder/tests/Android.bp +++ b/libs/binder/tests/Android.bp @@ -684,3 +684,37 @@ cc_test { ], test_suites: ["general-tests"], } + +cc_defaults { + name: "service_fuzzer_defaults", + static_libs: [ + "libbase", + "libbinder_random_parcel", + "libcutils", + ], + target: { + android: { + shared_libs: [ + "libbinder_ndk", + "libbinder", + "libutils", + ], + }, + host: { + static_libs: [ + "libbinder_ndk", + "libbinder", + "libutils", + ], + }, + darwin: { + enabled: false, + }, + }, + fuzz_config: { + cc: [ + "smoreland@google.com", + "waghpawan@google.com", + ], + }, +} diff --git a/libs/binder/tests/binderBinderUnitTest.cpp b/libs/binder/tests/binderBinderUnitTest.cpp index ce2770f943..b6aed0db28 100644 --- a/libs/binder/tests/binderBinderUnitTest.cpp +++ b/libs/binder/tests/binderBinderUnitTest.cpp @@ -15,10 +15,11 @@ */ #include <binder/Binder.h> -#include <binder/IBinder.h> +#include <binder/IInterface.h> #include <gtest/gtest.h> using android::BBinder; +using android::IBinder; using android::OK; using android::sp; @@ -48,3 +49,49 @@ TEST(Binder, AttachExtension) { binder->setExtension(ext); EXPECT_EQ(ext, binder->getExtension()); } + +struct MyCookie { + bool* deleted; +}; + +class UniqueBinder : public BBinder { +public: + UniqueBinder(const void* c) : cookie(reinterpret_cast<const MyCookie*>(c)) { + *cookie->deleted = false; + } + ~UniqueBinder() { *cookie->deleted = true; } + const MyCookie* cookie; +}; + +static sp<IBinder> make(const void* arg) { + return sp<UniqueBinder>::make(arg); +} + +TEST(Binder, LookupOrCreateWeak) { + auto binder = sp<BBinder>::make(); + bool deleted; + MyCookie cookie = {&deleted}; + sp<IBinder> createdBinder = binder->lookupOrCreateWeak(kObjectId1, make, &cookie); + EXPECT_NE(binder, createdBinder); + + sp<IBinder> lookedUpBinder = binder->lookupOrCreateWeak(kObjectId1, make, &cookie); + EXPECT_EQ(createdBinder, lookedUpBinder); + EXPECT_FALSE(deleted); +} + +TEST(Binder, LookupOrCreateWeakDropSp) { + auto binder = sp<BBinder>::make(); + bool deleted1 = false; + bool deleted2 = false; + MyCookie cookie1 = {&deleted1}; + MyCookie cookie2 = {&deleted2}; + sp<IBinder> createdBinder = binder->lookupOrCreateWeak(kObjectId1, make, &cookie1); + EXPECT_NE(binder, createdBinder); + + createdBinder.clear(); + EXPECT_TRUE(deleted1); + + sp<IBinder> lookedUpBinder = binder->lookupOrCreateWeak(kObjectId1, make, &cookie2); + EXPECT_EQ(&cookie2, sp<UniqueBinder>::cast(lookedUpBinder)->cookie); + EXPECT_FALSE(deleted2); +} diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp index 501a604026..4c037b77db 100644 --- a/libs/binder/tests/binderRpcTest.cpp +++ b/libs/binder/tests/binderRpcTest.cpp @@ -54,27 +54,6 @@ TEST(BinderRpcParcel, EntireParcelFormatted) { EXPECT_DEATH(p.markForBinder(sp<BBinder>::make()), "format must be set before data is written"); } -class BinderRpcServerOnly : public ::testing::TestWithParam<std::tuple<RpcSecurity, uint32_t>> { -public: - static std::string PrintTestParam(const ::testing::TestParamInfo<ParamType>& info) { - return std::string(newFactory(std::get<0>(info.param))->toCString()) + "_serverV" + - std::to_string(std::get<1>(info.param)); - } -}; - -TEST_P(BinderRpcServerOnly, SetExternalServerTest) { - base::unique_fd sink(TEMP_FAILURE_RETRY(open("/dev/null", O_RDWR))); - int sinkFd = sink.get(); - auto server = RpcServer::make(newFactory(std::get<0>(GetParam()))); - server->setProtocolVersion(std::get<1>(GetParam())); - ASSERT_FALSE(server->hasServer()); - ASSERT_EQ(OK, server->setupExternalServer(std::move(sink))); - ASSERT_TRUE(server->hasServer()); - base::unique_fd retrieved = server->releaseServer(); - ASSERT_FALSE(server->hasServer()); - ASSERT_EQ(sinkFd, retrieved.get()); -} - TEST(BinderRpc, CannotUseNextWireVersion) { auto session = RpcSession::make(); EXPECT_FALSE(session->setProtocolVersion(RPC_WIRE_PROTOCOL_VERSION_NEXT)); @@ -264,9 +243,13 @@ public: RpcSecurity rpcSecurity() const { return std::get<1>(GetParam()); } uint32_t clientVersion() const { return std::get<2>(GetParam()); } uint32_t serverVersion() const { return std::get<3>(GetParam()); } - bool singleThreaded() const { return std::get<4>(GetParam()); } + bool serverSingleThreaded() const { return std::get<4>(GetParam()); } bool noKernel() const { return std::get<5>(GetParam()); } + bool clientOrServerSingleThreaded() const { + return !kEnableRpcThreads || serverSingleThreaded(); + } + // Whether the test params support sending FDs in parcels. bool supportsFdTransport() const { return clientVersion() >= 1 && serverVersion() >= 1 && rpcSecurity() != RpcSecurity::TLS && @@ -404,18 +387,6 @@ public: size_t sleepMs = 500); }; -// Test fixture for tests that start multiple threads. -// This includes tests with one thread but multiple sessions, -// since a server uses one thread per session. -class BinderRpcThreads : public BinderRpc { -public: - void SetUp() override { - if constexpr (!kEnableRpcThreads) { - GTEST_SKIP() << "Test skipped because threads were disabled at build time"; - } - } -}; - TEST_P(BinderRpc, Ping) { auto proc = createRpcTestSocketServerProcess({}); ASSERT_NE(proc.rootBinder, nullptr); @@ -428,7 +399,13 @@ TEST_P(BinderRpc, GetInterfaceDescriptor) { EXPECT_EQ(IBinderRpcTest::descriptor, proc.rootBinder->getInterfaceDescriptor()); } -TEST_P(BinderRpcThreads, MultipleSessions) { +TEST_P(BinderRpc, MultipleSessions) { + if (serverSingleThreaded()) { + // Tests with multiple sessions require a multi-threaded service, + // but work fine on a single-threaded client + GTEST_SKIP() << "This test requires a multi-threaded service"; + } + auto proc = createRpcTestSocketServerProcess({.numThreads = 1, .numSessions = 5}); for (auto session : proc.proc.sessions) { ASSERT_NE(nullptr, session.root); @@ -436,7 +413,11 @@ TEST_P(BinderRpcThreads, MultipleSessions) { } } -TEST_P(BinderRpcThreads, SeparateRootObject) { +TEST_P(BinderRpc, SeparateRootObject) { + if (serverSingleThreaded()) { + GTEST_SKIP() << "This test requires a multi-threaded service"; + } + SocketType type = std::get<0>(GetParam()); if (type == SocketType::PRECONNECTED || type == SocketType::UNIX) { // we can't get port numbers for unix sockets @@ -619,7 +600,11 @@ TEST_P(BinderRpc, CannotMixBindersBetweenUnrelatedSocketSessions) { proc1.rootIface->repeatBinder(proc2.rootBinder, &outBinder).transactionError()); } -TEST_P(BinderRpcThreads, CannotMixBindersBetweenTwoSessionsToTheSameServer) { +TEST_P(BinderRpc, CannotMixBindersBetweenTwoSessionsToTheSameServer) { + if (serverSingleThreaded()) { + GTEST_SKIP() << "This test requires a multi-threaded service"; + } + auto proc = createRpcTestSocketServerProcess({.numThreads = 1, .numSessions = 2}); sp<IBinder> outBinder; @@ -775,7 +760,11 @@ size_t epochMillis() { return duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count(); } -TEST_P(BinderRpcThreads, ThreadPoolGreaterThanEqualRequested) { +TEST_P(BinderRpc, ThreadPoolGreaterThanEqualRequested) { + if (clientOrServerSingleThreaded()) { + GTEST_SKIP() << "This test requires multiple threads"; + } + constexpr size_t kNumThreads = 10; auto proc = createRpcTestSocketServerProcess({.numThreads = kNumThreads}); @@ -826,14 +815,22 @@ void BinderRpc::testThreadPoolOverSaturated(sp<IBinderRpcTest> iface, size_t num EXPECT_LE(epochMsAfter, epochMsBefore + 3 * sleepMs); } -TEST_P(BinderRpcThreads, ThreadPoolOverSaturated) { +TEST_P(BinderRpc, ThreadPoolOverSaturated) { + if (clientOrServerSingleThreaded()) { + GTEST_SKIP() << "This test requires multiple threads"; + } + constexpr size_t kNumThreads = 10; constexpr size_t kNumCalls = kNumThreads + 3; auto proc = createRpcTestSocketServerProcess({.numThreads = kNumThreads}); testThreadPoolOverSaturated(proc.rootIface, kNumCalls); } -TEST_P(BinderRpcThreads, ThreadPoolLimitOutgoing) { +TEST_P(BinderRpc, ThreadPoolLimitOutgoing) { + if (clientOrServerSingleThreaded()) { + GTEST_SKIP() << "This test requires multiple threads"; + } + constexpr size_t kNumThreads = 20; constexpr size_t kNumOutgoingConnections = 10; constexpr size_t kNumCalls = kNumOutgoingConnections + 3; @@ -842,7 +839,11 @@ TEST_P(BinderRpcThreads, ThreadPoolLimitOutgoing) { testThreadPoolOverSaturated(proc.rootIface, kNumCalls); } -TEST_P(BinderRpcThreads, ThreadingStressTest) { +TEST_P(BinderRpc, ThreadingStressTest) { + if (clientOrServerSingleThreaded()) { + GTEST_SKIP() << "This test requires multiple threads"; + } + constexpr size_t kNumClientThreads = 10; constexpr size_t kNumServerThreads = 10; constexpr size_t kNumCalls = 100; @@ -871,7 +872,11 @@ static void saturateThreadPool(size_t threadCount, const sp<IBinderRpcTest>& ifa for (auto& t : threads) t.join(); } -TEST_P(BinderRpcThreads, OnewayStressTest) { +TEST_P(BinderRpc, OnewayStressTest) { + if (clientOrServerSingleThreaded()) { + GTEST_SKIP() << "This test requires multiple threads"; + } + constexpr size_t kNumClientThreads = 10; constexpr size_t kNumServerThreads = 10; constexpr size_t kNumCalls = 1000; @@ -906,7 +911,11 @@ TEST_P(BinderRpc, OnewayCallDoesNotWait) { EXPECT_LT(epochMsAfter, epochMsBefore + kReallyLongTimeMs); } -TEST_P(BinderRpcThreads, OnewayCallQueueing) { +TEST_P(BinderRpc, OnewayCallQueueing) { + if (clientOrServerSingleThreaded()) { + GTEST_SKIP() << "This test requires multiple threads"; + } + constexpr size_t kNumSleeps = 10; constexpr size_t kNumExtraServerThreads = 4; constexpr size_t kSleepMs = 50; @@ -935,7 +944,11 @@ TEST_P(BinderRpcThreads, OnewayCallQueueing) { saturateThreadPool(1 + kNumExtraServerThreads, proc.rootIface); } -TEST_P(BinderRpcThreads, OnewayCallExhaustion) { +TEST_P(BinderRpc, OnewayCallExhaustion) { + if (clientOrServerSingleThreaded()) { + GTEST_SKIP() << "This test requires multiple threads"; + } + constexpr size_t kNumClients = 2; constexpr size_t kTooLongMs = 1000; @@ -978,17 +991,16 @@ TEST_P(BinderRpcThreads, OnewayCallExhaustion) { TEST_P(BinderRpc, Callbacks) { const static std::string kTestString = "good afternoon!"; - bool bothSingleThreaded = !kEnableRpcThreads || singleThreaded(); - for (bool callIsOneway : {true, false}) { for (bool callbackIsOneway : {true, false}) { for (bool delayed : {true, false}) { - if (bothSingleThreaded && (callIsOneway || callbackIsOneway || delayed)) { + if (clientOrServerSingleThreaded() && + (callIsOneway || callbackIsOneway || delayed)) { // we have no incoming connections to receive the callback continue; } - size_t numIncomingConnections = bothSingleThreaded ? 0 : 1; + size_t numIncomingConnections = clientOrServerSingleThreaded() ? 0 : 1; auto proc = createRpcTestSocketServerProcess( {.numThreads = 1, .numSessions = 1, @@ -1036,7 +1048,7 @@ TEST_P(BinderRpc, Callbacks) { } TEST_P(BinderRpc, SingleDeathRecipient) { - if (singleThreaded() || !kEnableRpcThreads) { + if (clientOrServerSingleThreaded()) { GTEST_SKIP() << "This test requires multiple threads"; } class MyDeathRec : public IBinder::DeathRecipient { @@ -1062,10 +1074,7 @@ TEST_P(BinderRpc, SingleDeathRecipient) { } std::unique_lock<std::mutex> lock(dr->mMtx); - if (!dr->dead) { - EXPECT_EQ(std::cv_status::no_timeout, dr->mCv.wait_for(lock, 1000ms)); - } - EXPECT_TRUE(dr->dead) << "Failed to receive the death notification."; + ASSERT_TRUE(dr->mCv.wait_for(lock, 1000ms, [&]() { return dr->dead; })); // need to wait for the session to shutdown so we don't "Leak session" EXPECT_TRUE(proc.proc.sessions.at(0).session->shutdownAndWait(true)); @@ -1073,7 +1082,7 @@ TEST_P(BinderRpc, SingleDeathRecipient) { } TEST_P(BinderRpc, SingleDeathRecipientOnShutdown) { - if (singleThreaded() || !kEnableRpcThreads) { + if (clientOrServerSingleThreaded()) { GTEST_SKIP() << "This test requires multiple threads"; } class MyDeathRec : public IBinder::DeathRecipient { @@ -1127,7 +1136,7 @@ TEST_P(BinderRpc, DeathRecipientFatalWithoutIncoming) { } TEST_P(BinderRpc, UnlinkDeathRecipient) { - if (singleThreaded() || !kEnableRpcThreads) { + if (clientOrServerSingleThreaded()) { GTEST_SKIP() << "This test requires multiple threads"; } class MyDeathRec : public IBinder::DeathRecipient { @@ -1193,7 +1202,7 @@ TEST_P(BinderRpc, UseKernelBinderCallingId) { // libbinder.so (when using static libraries, even a client and service // using the same kind of static library should have separate copies of the // variables). - if (!kEnableSharedLibs || singleThreaded() || noKernel()) { + if (!kEnableSharedLibs || serverSingleThreaded() || noKernel()) { GTEST_SKIP() << "Test disabled because Binder kernel driver was disabled " "at build time."; } @@ -1393,7 +1402,11 @@ ssize_t countFds() { return ret; } -TEST_P(BinderRpcThreads, Fds) { +TEST_P(BinderRpc, Fds) { + if (serverSingleThreaded()) { + GTEST_SKIP() << "This test requires multiple threads"; + } + ssize_t beforeFds = countFds(); ASSERT_GE(beforeFds, 0); { @@ -1534,15 +1547,6 @@ INSTANTIATE_TEST_CASE_P(PerSocket, BinderRpc, ::testing::Values(false, true)), BinderRpc::PrintParamInfo); -INSTANTIATE_TEST_CASE_P(PerSocket, BinderRpcThreads, - ::testing::Combine(::testing::ValuesIn(testSocketTypes()), - ::testing::ValuesIn(RpcSecurityValues()), - ::testing::ValuesIn(testVersions()), - ::testing::ValuesIn(testVersions()), - ::testing::Values(false), - ::testing::Values(false, true)), - BinderRpc::PrintParamInfo); - class BinderRpcServerRootObject : public ::testing::TestWithParam<std::tuple<bool, bool, RpcSecurity>> {}; @@ -1594,36 +1598,6 @@ private: bool mValue = false; }; -TEST_P(BinderRpcServerOnly, Shutdown) { - if constexpr (!kEnableRpcThreads) { - GTEST_SKIP() << "Test skipped because threads were disabled at build time"; - } - - auto addr = allocateSocketAddress(); - auto server = RpcServer::make(newFactory(std::get<0>(GetParam()))); - server->setProtocolVersion(std::get<1>(GetParam())); - ASSERT_EQ(OK, server->setupUnixDomainServer(addr.c_str())); - auto joinEnds = std::make_shared<OneOffSignal>(); - - // If things are broken and the thread never stops, don't block other tests. Because the thread - // may run after the test finishes, it must not access the stack memory of the test. Hence, - // shared pointers are passed. - std::thread([server, joinEnds] { - server->join(); - joinEnds->notify(); - }).detach(); - - bool shutdown = false; - for (int i = 0; i < 10 && !shutdown; i++) { - usleep(300 * 1000); // 300ms; total 3s - if (server->shutdown()) shutdown = true; - } - ASSERT_TRUE(shutdown) << "server->shutdown() never returns true"; - - ASSERT_TRUE(joinEnds->wait(2s)) - << "After server->shutdown() returns true, join() did not stop after 2s"; -} - TEST(BinderRpc, Java) { #if !defined(__ANDROID__) GTEST_SKIP() << "This test is only run on Android. Though it can technically run on host on" @@ -1676,6 +1650,57 @@ TEST(BinderRpc, Java) { ASSERT_EQ(OK, rpcBinder->pingBinder()); } +class BinderRpcServerOnly : public ::testing::TestWithParam<std::tuple<RpcSecurity, uint32_t>> { +public: + static std::string PrintTestParam(const ::testing::TestParamInfo<ParamType>& info) { + return std::string(newFactory(std::get<0>(info.param))->toCString()) + "_serverV" + + std::to_string(std::get<1>(info.param)); + } +}; + +TEST_P(BinderRpcServerOnly, SetExternalServerTest) { + base::unique_fd sink(TEMP_FAILURE_RETRY(open("/dev/null", O_RDWR))); + int sinkFd = sink.get(); + auto server = RpcServer::make(newFactory(std::get<0>(GetParam()))); + server->setProtocolVersion(std::get<1>(GetParam())); + ASSERT_FALSE(server->hasServer()); + ASSERT_EQ(OK, server->setupExternalServer(std::move(sink))); + ASSERT_TRUE(server->hasServer()); + base::unique_fd retrieved = server->releaseServer(); + ASSERT_FALSE(server->hasServer()); + ASSERT_EQ(sinkFd, retrieved.get()); +} + +TEST_P(BinderRpcServerOnly, Shutdown) { + if constexpr (!kEnableRpcThreads) { + GTEST_SKIP() << "Test skipped because threads were disabled at build time"; + } + + auto addr = allocateSocketAddress(); + auto server = RpcServer::make(newFactory(std::get<0>(GetParam()))); + server->setProtocolVersion(std::get<1>(GetParam())); + ASSERT_EQ(OK, server->setupUnixDomainServer(addr.c_str())); + auto joinEnds = std::make_shared<OneOffSignal>(); + + // If things are broken and the thread never stops, don't block other tests. Because the thread + // may run after the test finishes, it must not access the stack memory of the test. Hence, + // shared pointers are passed. + std::thread([server, joinEnds] { + server->join(); + joinEnds->notify(); + }).detach(); + + bool shutdown = false; + for (int i = 0; i < 10 && !shutdown; i++) { + usleep(300 * 1000); // 300ms; total 3s + if (server->shutdown()) shutdown = true; + } + ASSERT_TRUE(shutdown) << "server->shutdown() never returns true"; + + ASSERT_TRUE(joinEnds->wait(2s)) + << "After server->shutdown() returns true, join() did not stop after 2s"; +} + INSTANTIATE_TEST_CASE_P(BinderRpc, BinderRpcServerOnly, ::testing::Combine(::testing::ValuesIn(RpcSecurityValues()), ::testing::ValuesIn(testVersions())), diff --git a/libs/binder/tests/parcel_fuzzer/random_fd.cpp b/libs/binder/tests/parcel_fuzzer/random_fd.cpp index 3fcf104e81..e4dbb2d955 100644 --- a/libs/binder/tests/parcel_fuzzer/random_fd.cpp +++ b/libs/binder/tests/parcel_fuzzer/random_fd.cpp @@ -26,9 +26,12 @@ namespace android { using base::unique_fd; std::vector<unique_fd> getRandomFds(FuzzedDataProvider* provider) { + const char* fdType; + std::vector<unique_fd> fds = provider->PickValueInArray< std::function<std::vector<unique_fd>()>>({ [&]() { + fdType = "ashmem"; std::vector<unique_fd> ret; ret.push_back(unique_fd( ashmem_create_region("binder test region", @@ -36,18 +39,21 @@ std::vector<unique_fd> getRandomFds(FuzzedDataProvider* provider) { return ret; }, [&]() { + fdType = "/dev/null"; std::vector<unique_fd> ret; ret.push_back(unique_fd(open("/dev/null", O_RDWR))); return ret; }, [&]() { + fdType = "pipefd"; + int pipefds[2]; int flags = O_CLOEXEC; if (provider->ConsumeBool()) flags |= O_DIRECT; if (provider->ConsumeBool()) flags |= O_NONBLOCK; - CHECK_EQ(0, pipe2(pipefds, flags)); + CHECK_EQ(0, pipe2(pipefds, flags)) << flags; if (provider->ConsumeBool()) std::swap(pipefds[0], pipefds[1]); @@ -58,7 +64,7 @@ std::vector<unique_fd> getRandomFds(FuzzedDataProvider* provider) { }, })(); - for (const auto& fd : fds) CHECK(fd.ok()) << fd.get(); + for (const auto& fd : fds) CHECK(fd.ok()) << fd.get() << " " << fdType; return fds; } diff --git a/libs/binder/trusty/OS.cpp b/libs/binder/trusty/OS.cpp index bbfa3818ea..b21fe6acf5 100644 --- a/libs/binder/trusty/OS.cpp +++ b/libs/binder/trusty/OS.cpp @@ -14,7 +14,11 @@ * limitations under the License. */ +#if defined(TRUSTY_USERSPACE) #include <openssl/rand.h> +#else +#include <lib/rand/rand.h> +#endif #include "../OS.h" @@ -28,8 +32,13 @@ Result<void> setNonBlocking(android::base::borrowed_fd fd) { } status_t getRandomBytes(uint8_t* data, size_t size) { +#if defined(TRUSTY_USERSPACE) int res = RAND_bytes(data, size); return res == 1 ? OK : UNKNOWN_ERROR; +#else + int res = rand_get_bytes(data, size); + return res == 0 ? OK : UNKNOWN_ERROR; +#endif // TRUSTY_USERSPACE } status_t dupFileDescriptor(int oldFd, int* newFd) { diff --git a/libs/binder/trusty/README.md b/libs/binder/trusty/README.md index 1a273aab10..8a60af8b23 100644 --- a/libs/binder/trusty/README.md +++ b/libs/binder/trusty/README.md @@ -1,39 +1,45 @@ # Binder for Trusty This is the Trusty port of the libbinder library. -To build it, take the following steps: - -* Check out copies of the Trusty and AOSP repositories. -* Apply the patches from the `trusty_binder` topic on both repositories. -* Build Trusty normally using `build.py`. -* Run the sample AIDL test for Trusty: - ```shell - $ ./build-root/.../run --headless --boot-test com.android.trusty.aidl.test - ``` - -To run the Android-Trusty IPC test, do the following: - -* Build AOSP for the `qemu_trusty_arm64-userdebug` target: - ```shell - $ lunch qemu_trusty_arm64-userdebug - $ m - ``` -* In the Trusty directory, run the emulator with the newly built Android: - ```shell - $ ./build-root/.../run --android /path/to/aosp - ``` -* Using either `adb` or the shell inside the emulator itself, run the Trusty - Binder test as root: - ```shell - # /data/nativetest64/vendor/trusty_binder_test/trusty_binder_test - ``` - -## Running the AIDL compiler -For now, you will need to run the AIDL compiler manually to generate the C++ -source code for Trusty clients and services. The general syntax is: +To build it, first you will need a checkout of the Trusty tree: ```shell -$ aidl --lang=cpp -o <output directory> -h <output header directory> <AIDL files...> +$ mkdir /path/to/trusty +$ cd /path/to/trusty +$ repo init -u https://android.googlesource.com/trusty/manifest -b master +$ repo sync -j$(nproc) -c --no-tags ``` -The compiler will emit some `.cpp` files in the output directory and their -corresponding `.h` files in the header directory. +After the checkout is complete, you can use the `build.py` script for both +building and testing Trusty. For a quick build without any tests, run: +```shell +$ ./trusty/vendor/google/aosp/scripts/build.py generic-arm64-test-debug +``` +This will build the smaller `generic-arm64-test-debug` project which +does not run any tests. + +The qemu-generic-arm64-test-debug` project includes the QEMU emulator and +a full Trusty test suite, including a set of libbinder tests. +To run the latter, use the command: +```shell +$ ./trusty/vendor/google/aosp/scripts/build.py \ + --test "boot-test:com.android.trusty.binder.test" \ + qemu-generic-arm64-test-debug +``` + +## Building AIDL files on Trusty +To compile AIDL interfaces into Trusty libraries, include the `make/aidl.mk` +in your `rules.mk` file, e.g.: +``` +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_AIDLS := \ + $(LOCAL_DIR)/IFoo.aidl \ + +include make/aidl.mk +``` + +## Examples +The Trusty tree contains some sample test apps at +`trusty/user/app/sample/binder-test`. diff --git a/libs/binder/trusty/RpcServerTrusty.cpp b/libs/binder/trusty/RpcServerTrusty.cpp index e8b91e7a4c..c789614c0b 100644 --- a/libs/binder/trusty/RpcServerTrusty.cpp +++ b/libs/binder/trusty/RpcServerTrusty.cpp @@ -104,8 +104,17 @@ int RpcServerTrusty::handleConnect(const tipc_port* port, handle_t chan, const u return; } - /* Save the session for easy access */ - *ctx_p = session.get(); + /* Save the session and connection for the other callbacks */ + auto* channelContext = new (std::nothrow) ChannelContext; + if (channelContext == nullptr) { + rc = ERR_NO_MEMORY; + return; + } + + channelContext->session = std::move(session); + channelContext->connection = std::move(result.connection); + + *ctx_p = channelContext; }; base::unique_fd clientFd(chan); @@ -119,9 +128,14 @@ int RpcServerTrusty::handleConnect(const tipc_port* port, handle_t chan, const u } int RpcServerTrusty::handleMessage(const tipc_port* port, handle_t chan, void* ctx) { - auto* session = reinterpret_cast<RpcSession*>(ctx); - status_t status = session->state()->drainCommands(session->mConnections.mIncoming[0], session, - RpcState::CommandType::ANY); + auto* channelContext = reinterpret_cast<ChannelContext*>(ctx); + LOG_ALWAYS_FATAL_IF(channelContext == nullptr, + "bad state: message received on uninitialized channel"); + + auto& session = channelContext->session; + auto& connection = channelContext->connection; + status_t status = + session->state()->drainCommands(connection, session, RpcState::CommandType::ANY); if (status != OK) { LOG_RPC_DETAIL("Binder connection thread closing w/ status %s", statusToString(status).c_str()); @@ -133,10 +147,17 @@ int RpcServerTrusty::handleMessage(const tipc_port* port, handle_t chan, void* c void RpcServerTrusty::handleDisconnect(const tipc_port* port, handle_t chan, void* ctx) {} void RpcServerTrusty::handleChannelCleanup(void* ctx) { - auto* session = reinterpret_cast<RpcSession*>(ctx); - auto& connection = session->mConnections.mIncoming.at(0); + auto* channelContext = reinterpret_cast<ChannelContext*>(ctx); + if (channelContext == nullptr) { + return; + } + + auto& session = channelContext->session; + auto& connection = channelContext->connection; LOG_ALWAYS_FATAL_IF(!session->removeIncomingConnection(connection), "bad state: connection object guaranteed to be in list"); + + delete channelContext; } } // namespace android diff --git a/libs/binder/trusty/include/binder/RpcServerTrusty.h b/libs/binder/trusty/include/binder/RpcServerTrusty.h index e8fc9f988d..cc31c95da1 100644 --- a/libs/binder/trusty/include/binder/RpcServerTrusty.h +++ b/libs/binder/trusty/include/binder/RpcServerTrusty.h @@ -77,6 +77,12 @@ private: explicit RpcServerTrusty(std::unique_ptr<RpcTransportCtx> ctx, std::string&& portName, std::shared_ptr<const PortAcl>&& portAcl, size_t msgMaxSize); + // The Rpc-specific context maintained for every open TIPC channel. + struct ChannelContext { + sp<RpcSession> session; + sp<RpcSession::RpcConnection> connection; + }; + static int handleConnect(const tipc_port* port, handle_t chan, const uuid* peer, void** ctx_p); static int handleMessage(const tipc_port* port, handle_t chan, void* ctx); static void handleDisconnect(const tipc_port* port, handle_t chan, void* ctx); diff --git a/libs/input/KeyLayoutMap.cpp b/libs/input/KeyLayoutMap.cpp index 59cc7d1dcd..d6b4579a94 100644 --- a/libs/input/KeyLayoutMap.cpp +++ b/libs/input/KeyLayoutMap.cpp @@ -25,8 +25,10 @@ #include <utils/Errors.h> #include <utils/Timers.h> #include <utils/Tokenizer.h> +#if defined(__ANDROID__) #include <vintf/RuntimeInfo.h> #include <vintf/VintfObject.h> +#endif #include <cstdlib> #include <string_view> @@ -79,6 +81,7 @@ static const std::unordered_map<std::string_view, InputDeviceSensorType> SENSOR_ sensorPair<InputDeviceSensorType::SIGNIFICANT_MOTION>()}; bool kernelConfigsArePresent(const std::set<std::string>& configs) { +#if defined(__ANDROID__) std::shared_ptr<const android::vintf::RuntimeInfo> runtimeInfo = android::vintf::VintfObject::GetInstance()->getRuntimeInfo( vintf::RuntimeInfo::FetchFlag::CONFIG_GZ); @@ -99,6 +102,10 @@ bool kernelConfigsArePresent(const std::set<std::string>& configs) { } } return true; +#else + (void)configs; // Suppress 'unused variable' warning + return true; +#endif } } // namespace diff --git a/services/vibratorservice/Android.bp b/services/vibratorservice/Android.bp index 2002bdf628..5403baf2e7 100644 --- a/services/vibratorservice/Android.bp +++ b/services/vibratorservice/Android.bp @@ -59,6 +59,12 @@ cc_library_shared { "-Wunreachable-code", ], + // FIXME: Workaround LTO build breakage + // http://b/241699694 + lto: { + never: true, + }, + local_include_dirs: ["include"], export_include_dirs: ["include"], diff --git a/services/vibratorservice/test/Android.bp b/services/vibratorservice/test/Android.bp index adba3dbcd5..32947246d8 100644 --- a/services/vibratorservice/test/Android.bp +++ b/services/vibratorservice/test/Android.bp @@ -57,9 +57,4 @@ cc_test { static_libs: [ "libgmock", ], - // FIXME: Workaround LTO build breakage - // http://b/241699694 - lto: { - never: true, - }, } |