diff options
29 files changed, 599 insertions, 38 deletions
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp index 12de33f2db..47a513be81 100644 --- a/cmds/dumpstate/dumpstate.cpp +++ b/cmds/dumpstate/dumpstate.cpp @@ -185,6 +185,7 @@ void add_mountinfo(); #define SYSTEM_TRACE_SNAPSHOT "/data/misc/perfetto-traces/bugreport/systrace.pftrace" #define CGROUPFS_DIR "/sys/fs/cgroup" #define SDK_EXT_INFO "/apex/com.android.sdkext/bin/derive_sdk" +#define DROPBOX_DIR "/data/system/dropbox" // TODO(narayan): Since this information has to be kept in sync // with tombstoned, we should just put it in a common header. @@ -524,6 +525,15 @@ static bool skip_not_stat(const char *path) { return strcmp(path + len - sizeof(stat) + 1, stat); /* .../stat? */ } +static bool skip_wtf_strictmode(const char *path) { + if (strstr(path, "_wtf")) { + return true; + } else if (strstr(path, "_strictmode")) { + return true; + } + return false; +} + static bool skip_none(const char* path __attribute__((unused))) { return false; } @@ -1888,6 +1898,11 @@ Dumpstate::RunStatus Dumpstate::DumpstateDefaultAfterCritical() { DumpIpTablesAsRoot(); DumpDynamicPartitionInfo(); ds.AddDir(OTA_METADATA_DIR, true); + if (!PropertiesHelper::IsUserBuild()) { + // Include dropbox entry files inside ZIP, but exclude + // noisy WTF and StrictMode entries + dump_files("", DROPBOX_DIR, skip_wtf_strictmode, _add_file_from_fd); + } // Capture any IPSec policies in play. No keys are exposed here. RunCommand("IP XFRM POLICY", {"ip", "xfrm", "policy"}, CommandOptions::WithTimeout(10).Build()); @@ -3244,6 +3259,15 @@ void Dumpstate::MaybeSnapshotSystemTrace() { } void Dumpstate::MaybeSnapshotWinTrace() { + // Include the proto logging from WMShell. + RunCommand( + // Empty name because it's not intended to be classified as a bugreport section. + // Actual logging files can be found as "/data/misc/wmtrace/shell_log.winscope" + // in the bugreport. + "", {"dumpsys", "activity", "service", "SystemUIService", + "WMShell", "protolog", "save-for-bugreport"}, + CommandOptions::WithTimeout(10).Always().DropRoot().RedirectStderr().Build()); + // Currently WindowManagerService and InputMethodManagerSerivice support WinScope protocol. for (const auto& service : {"window", "input_method"}) { RunCommand( diff --git a/cmds/dumpstate/dumpstate.rc b/cmds/dumpstate/dumpstate.rc index 12a7cfface..a80da4ec55 100644 --- a/cmds/dumpstate/dumpstate.rc +++ b/cmds/dumpstate/dumpstate.rc @@ -8,7 +8,6 @@ service dumpstate /system/bin/dumpstate -s socket dumpstate stream 0660 shell log disabled oneshot - capabilities CHOWN DAC_OVERRIDE DAC_READ_SEARCH FOWNER FSETID KILL NET_ADMIN NET_RAW SETGID SETUID SYS_PTRACE SYS_RESOURCE BLOCK_SUSPEND SYSLOG # dumpstatez generates a zipped bugreport but also uses a socket to print the file location once # it is finished. @@ -17,11 +16,9 @@ service dumpstatez /system/bin/dumpstate -S class main disabled oneshot - capabilities CHOWN DAC_OVERRIDE DAC_READ_SEARCH FOWNER FSETID KILL NET_ADMIN NET_RAW SETGID SETUID SYS_PTRACE SYS_RESOURCE BLOCK_SUSPEND SYSLOG # bugreportd starts dumpstate binder service and makes it wait for a listener to connect. service bugreportd /system/bin/dumpstate -w class main disabled oneshot - capabilities CHOWN DAC_OVERRIDE DAC_READ_SEARCH FOWNER FSETID KILL NET_ADMIN NET_RAW SETGID SETUID SYS_PTRACE SYS_RESOURCE BLOCK_SUSPEND SYSLOG diff --git a/cmds/dumpstate/tests/dumpstate_test.cpp b/cmds/dumpstate/tests/dumpstate_test.cpp index 70b4e5c0d8..7234d419d6 100644 --- a/cmds/dumpstate/tests/dumpstate_test.cpp +++ b/cmds/dumpstate/tests/dumpstate_test.cpp @@ -1023,7 +1023,8 @@ class ZippedBugReportStreamTest : public DumpstateBaseTest { }; // Generate a quick LimitedOnly report redirected to a file, open it and verify entry exist. -TEST_F(ZippedBugReportStreamTest, StreamLimitedOnlyReport) { +// TODO: broken test tracked in b/249983726 +TEST_F(ZippedBugReportStreamTest, DISABLED_StreamLimitedOnlyReport) { std::string out_path = kTestDataPath + "StreamLimitedOnlyReportOut.zip"; android::base::unique_fd out_fd; CreateFd(out_path, &out_fd); diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp index eb130de8ab..da87e03162 100644 --- a/libs/binder/Android.bp +++ b/libs/binder/Android.bp @@ -215,6 +215,8 @@ cc_library_headers { cc_defaults { name: "trusty_mock_defaults", + vendor_available: true, + host_supported: true, header_libs: [ "trusty_mock_headers", @@ -522,6 +524,10 @@ aidl_interface { enabled: false, }, }, + visibility: [ + ":__subpackages__", + "//system/tools/aidl:__subpackages__", + ], } // TODO(b/184872979): remove once the Rust API is created. diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp index d03326eb04..53852d88ed 100644 --- a/libs/binder/BpBinder.cpp +++ b/libs/binder/BpBinder.cpp @@ -388,7 +388,8 @@ status_t BpBinder::linkToDeath( { if (isRpcBinder()) { if (rpcSession()->getMaxIncomingThreads() < 1) { - ALOGE("Cannot register a DeathRecipient without any incoming connections."); + ALOGE("Cannot register a DeathRecipient without any incoming threads. Need to set max " + "incoming threads to a value greater than 0 before calling linkToDeath."); return INVALID_OPERATION; } } else if constexpr (!kEnableKernelIpc) { diff --git a/libs/binder/RpcState.cpp b/libs/binder/RpcState.cpp index 1ea13f9a1c..b27f1028d4 100644 --- a/libs/binder/RpcState.cpp +++ b/libs/binder/RpcState.cpp @@ -1036,8 +1036,8 @@ processTransactInternalTailCall: return DEAD_OBJECT; } - if (it->second.asyncTodo.size() != 0 && - it->second.asyncTodo.top().asyncNumber == it->second.asyncNumber) { + if (it->second.asyncTodo.size() == 0) return OK; + if (it->second.asyncTodo.top().asyncNumber == it->second.asyncNumber) { LOG_RPC_DETAIL("Found next async transaction %" PRIu64 " on %" PRIu64, it->second.asyncNumber, addr); diff --git a/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp b/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp index 3ebbed6965..42d226b805 100644 --- a/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp +++ b/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp @@ -57,6 +57,15 @@ enum class ARpcSession_FileDescriptorTransportMode { // could not be started. [[nodiscard]] ARpcServer* ARpcServer_newUnixDomainBootstrap(AIBinder* service, int bootstrapFd); +// Starts an RPC server on a given IP address+port and a given IBinder object. +// Returns an opaque handle to the running server instance, or null if the server +// could not be started. +// Does not take ownership of `service`. +// Returns an opaque handle to the running service instance, or null if the server +// could not be started. +[[nodiscard]] ARpcServer* ARpcServer_newInet(AIBinder* service, const char* address, + unsigned int port); + // Sets the list of supported file descriptor transport modes of this RPC server. void ARpcServer_setSupportedFileDescriptorTransportModes( ARpcServer* handle, @@ -98,6 +107,10 @@ AIBinder* ARpcSession_setupUnixDomainClient(ARpcSession* session, const char* na AIBinder* ARpcSession_setupUnixDomainBootstrapClient(ARpcSession* session, int bootstrapFd); +// Connects to an RPC server over an INET socket at a given IP address on a given port. +// Returns the root Binder object of the server. +AIBinder* ARpcSession_setupInet(ARpcSession* session, const char* address, unsigned int port); + // Connects to an RPC server with preconnected file descriptors. // // requestFd should connect to the server and return a valid file descriptor, or diff --git a/libs/binder/libbinder_rpc_unstable.cpp b/libs/binder/libbinder_rpc_unstable.cpp index e7943ddf2f..daff8c1e16 100644 --- a/libs/binder/libbinder_rpc_unstable.cpp +++ b/libs/binder/libbinder_rpc_unstable.cpp @@ -145,6 +145,17 @@ ARpcServer* ARpcServer_newUnixDomainBootstrap(AIBinder* service, int bootstrapFd return createObjectHandle<ARpcServer>(server); } +ARpcServer* ARpcServer_newInet(AIBinder* service, const char* address, unsigned int port) { + auto server = RpcServer::make(); + if (status_t status = server->setupInetServer(address, port, nullptr); status != OK) { + LOG(ERROR) << "Failed to set up inet RPC server with address " << address << " and port " + << port << " error: " << statusToString(status).c_str(); + return nullptr; + } + server->setRootObject(AIBinder_toPlatformBinder(service)); + return createObjectHandle<ARpcServer>(server); +} + void ARpcServer_setSupportedFileDescriptorTransportModes( ARpcServer* handle, const ARpcSession_FileDescriptorTransportMode modes[], size_t modes_len) { @@ -222,6 +233,16 @@ AIBinder* ARpcSession_setupUnixDomainBootstrapClient(ARpcSession* handle, int bo return AIBinder_fromPlatformBinder(session->getRootObject()); } +AIBinder* ARpcSession_setupInet(ARpcSession* handle, const char* address, unsigned int port) { + auto session = handleToStrongPointer<RpcSession>(handle); + if (status_t status = session->setupInetClient(address, port); status != OK) { + LOG(ERROR) << "Failed to set up inet RPC client with address " << address << " and port " + << port << " error: " << statusToString(status).c_str(); + return nullptr; + } + return AIBinder_fromPlatformBinder(session->getRootObject()); +} + AIBinder* ARpcSession_setupPreconnectedClient(ARpcSession* handle, int (*requestFd)(void* param), void* param) { auto session = handleToStrongPointer<RpcSession>(handle); diff --git a/libs/binder/libbinder_rpc_unstable.map.txt b/libs/binder/libbinder_rpc_unstable.map.txt index 1bc2416533..63679c28d0 100644 --- a/libs/binder/libbinder_rpc_unstable.map.txt +++ b/libs/binder/libbinder_rpc_unstable.map.txt @@ -2,6 +2,7 @@ LIBBINDER_RPC_UNSTABLE_SHIM { # platform-only global: ARpcServer_free; ARpcServer_join; + ARpcServer_newInet; ARpcServer_newInitUnixDomain; ARpcServer_newVsock; ARpcServer_shutdown; diff --git a/libs/binder/ndk/include_platform/android/binder_manager.h b/libs/binder/ndk/include_platform/android/binder_manager.h index ad4188f499..86d5ed27b8 100644 --- a/libs/binder/ndk/include_platform/android/binder_manager.h +++ b/libs/binder/ndk/include_platform/android/binder_manager.h @@ -38,6 +38,22 @@ __attribute__((warn_unused_result)) binder_exception_t AServiceManager_addServic AIBinder* binder, const char* instance) __INTRODUCED_IN(29); /** + * This registers the service with the default service manager under this instance name. This does + * not take ownership of binder. + * + * WARNING: when using this API across an APEX boundary, do not use with unstable + * AIDL services. TODO(b/139325195) + * + * \param binder object to register globally with the service manager. + * \param instance identifier of the service. This will be used to lookup the service. + * \param allowIsolated allows if this service can be isolated. + * + * \return EX_NONE on success. + */ +__attribute__((warn_unused_result)) binder_exception_t AServiceManager_addServiceWithAllowIsolated( + AIBinder* binder, const char* instance, bool allowIsolated) __INTRODUCED_IN(34); + +/** * Gets a binder object with this specific instance name. Will return nullptr immediately if the * service is not available This also implicitly calls AIBinder_incStrong (so the caller of this * function is responsible for calling AIBinder_decStrong). diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt index 54e46287a9..5f2f617946 100644 --- a/libs/binder/ndk/libbinder_ndk.map.txt +++ b/libs/binder/ndk/libbinder_ndk.map.txt @@ -163,6 +163,7 @@ LIBBINDER_NDK34 { # introduced=UpsideDownCake LIBBINDER_NDK_PLATFORM { global: AParcel_getAllowFds; + AServiceManager_addServiceWithAllowIsolated; extern "C++" { AIBinder_fromPlatformBinder*; AIBinder_toPlatformBinder*; diff --git a/libs/binder/ndk/service_manager.cpp b/libs/binder/ndk/service_manager.cpp index e107c83d14..2763ddb622 100644 --- a/libs/binder/ndk/service_manager.cpp +++ b/libs/binder/ndk/service_manager.cpp @@ -41,6 +41,19 @@ binder_exception_t AServiceManager_addService(AIBinder* binder, const char* inst status_t exception = sm->addService(String16(instance), binder->getBinder()); return PruneException(exception); } + +binder_exception_t AServiceManager_addServiceWithAllowIsolated(AIBinder* binder, + const char* instance, + bool allowIsolated) { + if (binder == nullptr || instance == nullptr) { + return EX_ILLEGAL_ARGUMENT; + } + + sp<IServiceManager> sm = defaultServiceManager(); + status_t exception = sm->addService(String16(instance), binder->getBinder(), allowIsolated); + return PruneException(exception); +} + AIBinder* AServiceManager_checkService(const char* instance) { if (instance == nullptr) { return nullptr; diff --git a/libs/binder/rust/rpcbinder/Android.bp b/libs/binder/rust/rpcbinder/Android.bp index afb73e920f..38dd4fe187 100644 --- a/libs/binder/rust/rpcbinder/Android.bp +++ b/libs/binder/rust/rpcbinder/Android.bp @@ -23,7 +23,13 @@ rust_library { "liblibc", "liblog_rust", ], + visibility: [ + "//device/google/cuttlefish/shared/minidroid/sample", + "//packages/modules/Uwb", + "//packages/modules/Virtualization:__subpackages__", + ], apex_available: [ + "//apex_available:platform", "com.android.compos", "com.android.uwb", "com.android.virt", @@ -51,6 +57,7 @@ rust_library { "libutils", ], apex_available: [ + "//apex_available:platform", "com.android.compos", "com.android.uwb", "com.android.virt", @@ -84,6 +91,7 @@ rust_bindgen { "libutils", ], apex_available: [ + "//apex_available:platform", "com.android.compos", "com.android.uwb", "com.android.virt", diff --git a/libs/binder/rust/rpcbinder/src/server.rs b/libs/binder/rust/rpcbinder/src/server.rs index 761b306a1e..c87876ac15 100644 --- a/libs/binder/rust/rpcbinder/src/server.rs +++ b/libs/binder/rust/rpcbinder/src/server.rs @@ -102,6 +102,29 @@ impl RpcServer { } } + /// Creates a binder RPC server, serving the supplied binder service implementation on the given + /// IP address and port. + pub fn new_inet(mut service: SpIBinder, address: &str, port: u32) -> Result<RpcServer, Error> { + let address = match CString::new(address) { + Ok(s) => s, + Err(e) => { + log::error!("Cannot convert {} to CString. Error: {:?}", address, e); + return Err(Error::from(ErrorKind::InvalidInput)); + } + }; + let service = service.as_native_mut(); + + // SAFETY: Service ownership is transferring to the server and won't be valid afterward. + // Plus the binder objects are threadsafe. + unsafe { + Self::checked_from_ptr(binder_rpc_unstable_bindgen::ARpcServer_newInet( + service, + address.as_ptr(), + port, + )) + } + } + unsafe fn checked_from_ptr(ptr: *mut ARpcServer) -> Result<RpcServer, Error> { if ptr.is_null() { return Err(Error::new(ErrorKind::Other, "Failed to start server")); diff --git a/libs/binder/rust/rpcbinder/src/session.rs b/libs/binder/rust/rpcbinder/src/session.rs index 62fedb1ffa..0b517cf613 100644 --- a/libs/binder/rust/rpcbinder/src/session.rs +++ b/libs/binder/rust/rpcbinder/src/session.rs @@ -144,6 +144,32 @@ impl RpcSessionRef { Self::get_interface(service) } + /// Connects to an RPC Binder server over inet socket at the given address and port. + pub fn setup_inet_client<T: FromIBinder + ?Sized>( + &self, + address: &str, + port: u32, + ) -> Result<Strong<T>, StatusCode> { + let address = match CString::new(address) { + Ok(s) => s, + Err(e) => { + log::error!("Cannot convert {} to CString. Error: {:?}", address, e); + return Err(StatusCode::BAD_VALUE); + } + }; + + // SAFETY: AIBinder returned by ARpcSession_setupInet has correct reference + // count, and the ownership can safely be taken by new_spibinder. + let service = unsafe { + new_spibinder(binder_rpc_unstable_bindgen::ARpcSession_setupInet( + self.as_ptr(), + address.as_ptr(), + port, + )) + }; + Self::get_interface(service) + } + /// Connects to an RPC Binder server, using the given callback to get (and /// take ownership of) file descriptors already connected to it. pub fn setup_preconnected_client<T: FromIBinder + ?Sized>( diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp index 7006f87314..e609987725 100644 --- a/libs/binder/tests/Android.bp +++ b/libs/binder/tests/Android.bp @@ -370,6 +370,31 @@ cc_binary { ], } +cc_binary { + name: "binderRpcTest_on_trusty_mock", + defaults: [ + "trusty_mock_defaults", + ], + + srcs: [ + "binderRpcUniversalTests.cpp", + "binderRpcTestCommon.cpp", + "binderRpcTestTrusty.cpp", + ], + + shared_libs: [ + "libbinder_on_trusty_mock", + "libbase", + "libutils", + "libcutils", + ], + + static_libs: [ + "binderRpcTestIface-cpp", + "libgtest", + ], +} + cc_test { name: "binderRpcTest", defaults: [ @@ -382,6 +407,7 @@ cc_test { required: [ "libbinder_on_trusty_mock", "binderRpcTestService_on_trusty_mock", + "binderRpcTest_on_trusty_mock", ], } diff --git a/libs/binder/tests/binderRpcTestTrusty.cpp b/libs/binder/tests/binderRpcTestTrusty.cpp new file mode 100644 index 0000000000..b3bb5ebda7 --- /dev/null +++ b/libs/binder/tests/binderRpcTestTrusty.cpp @@ -0,0 +1,105 @@ +/* + * 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. + */ + +#define LOG_TAG "binderRpcTest" + +#include <android-base/stringprintf.h> +#include <binder/RpcTransportTipcTrusty.h> +#include <trusty-gtest.h> +#include <trusty_ipc.h> + +#include "binderRpcTestFixture.h" + +namespace android { + +// Destructors need to be defined, even if pure virtual +ProcessSession::~ProcessSession() {} + +class TrustyProcessSession : public ProcessSession { +public: + ~TrustyProcessSession() override {} + + void setCustomExitStatusCheck(std::function<void(int wstatus)> /*f*/) override { + LOG_ALWAYS_FATAL("setCustomExitStatusCheck() not supported"); + } + + void terminate() override { LOG_ALWAYS_FATAL("terminate() not supported"); } +}; + +std::string BinderRpc::PrintParamInfo(const testing::TestParamInfo<ParamType>& info) { + auto [type, security, clientVersion, serverVersion, singleThreaded, noKernel] = info.param; + auto ret = PrintToString(type) + "_clientV" + std::to_string(clientVersion) + "_serverV" + + std::to_string(serverVersion); + if (singleThreaded) { + ret += "_single_threaded"; + } + if (noKernel) { + ret += "_no_kernel"; + } + return ret; +} + +// This creates a new process serving an interface on a certain number of +// threads. +std::unique_ptr<ProcessSession> BinderRpc::createRpcTestSocketServerProcessEtc( + const BinderRpcOptions& options) { + LOG_ALWAYS_FATAL_IF(options.numIncomingConnections != 0, + "Non-zero incoming connections %zu on Trusty", + options.numIncomingConnections); + + uint32_t clientVersion = std::get<2>(GetParam()); + uint32_t serverVersion = std::get<3>(GetParam()); + + auto ret = std::make_unique<TrustyProcessSession>(); + + status_t status; + for (size_t i = 0; i < options.numSessions; i++) { + auto factory = android::RpcTransportCtxFactoryTipcTrusty::make(); + auto session = android::RpcSession::make(std::move(factory)); + + EXPECT_TRUE(session->setProtocolVersion(clientVersion)); + session->setMaxOutgoingThreads(options.numOutgoingConnections); + session->setFileDescriptorTransportMode(options.clientFileDescriptorTransportMode); + + status = session->setupPreconnectedClient({}, [&]() { + auto port = trustyIpcPort(serverVersion); + int rc = connect(port.c_str(), IPC_CONNECT_WAIT_FOR_PORT); + LOG_ALWAYS_FATAL_IF(rc < 0, "Failed to connect to service: %d", rc); + return base::unique_fd(rc); + }); + if (options.allowConnectFailure && status != OK) { + ret->sessions.clear(); + break; + } + LOG_ALWAYS_FATAL_IF(status != OK, "Failed to connect to service: %s", + statusToString(status).c_str()); + ret->sessions.push_back({session, session->getRootObject()}); + } + + return ret; +} + +INSTANTIATE_TEST_CASE_P(Trusty, BinderRpc, + ::testing::Combine(::testing::Values(SocketType::TIPC), + ::testing::Values(RpcSecurity::RAW), + ::testing::ValuesIn(testVersions()), + ::testing::ValuesIn(testVersions()), + ::testing::Values(false), ::testing::Values(true)), + BinderRpc::PrintParamInfo); + +} // namespace android + +PORT_GTEST(BinderRpcTest, "com.android.trusty.binderRpcTest"); diff --git a/libs/binder/tests/binderRpcUniversalTests.cpp b/libs/binder/tests/binderRpcUniversalTests.cpp index 2249e5ca0a..11a22b0fb6 100644 --- a/libs/binder/tests/binderRpcUniversalTests.cpp +++ b/libs/binder/tests/binderRpcUniversalTests.cpp @@ -386,11 +386,11 @@ TEST_P(BinderRpc, SameBinderEqualityWeak) { EXPECT_EQ(b, weak.promote()); } -#define expectSessions(expected, iface) \ +#define EXPECT_SESSIONS(expected, iface) \ do { \ int session; \ EXPECT_OK((iface)->getNumOpenSessions(&session)); \ - EXPECT_EQ(expected, session); \ + EXPECT_EQ(static_cast<int>(expected), session); \ } while (false) TEST_P(BinderRpc, SingleSession) { @@ -402,9 +402,9 @@ TEST_P(BinderRpc, SingleSession) { EXPECT_OK(session->getName(&out)); EXPECT_EQ("aoeu", out); - expectSessions(1, proc.rootIface); + EXPECT_SESSIONS(1, proc.rootIface); session = nullptr; - expectSessions(0, proc.rootIface); + EXPECT_SESSIONS(0, proc.rootIface); } TEST_P(BinderRpc, ManySessions) { @@ -413,24 +413,24 @@ TEST_P(BinderRpc, ManySessions) { std::vector<sp<IBinderRpcSession>> sessions; for (size_t i = 0; i < 15; i++) { - expectSessions(i, proc.rootIface); + EXPECT_SESSIONS(i, proc.rootIface); sp<IBinderRpcSession> session; EXPECT_OK(proc.rootIface->openSession(std::to_string(i), &session)); sessions.push_back(session); } - expectSessions(sessions.size(), proc.rootIface); + EXPECT_SESSIONS(sessions.size(), proc.rootIface); for (size_t i = 0; i < sessions.size(); i++) { std::string out; EXPECT_OK(sessions.at(i)->getName(&out)); EXPECT_EQ(std::to_string(i), out); } - expectSessions(sessions.size(), proc.rootIface); + EXPECT_SESSIONS(sessions.size(), proc.rootIface); while (!sessions.empty()) { sessions.pop_back(); - expectSessions(sessions.size(), proc.rootIface); + EXPECT_SESSIONS(sessions.size(), proc.rootIface); } - expectSessions(0, proc.rootIface); + EXPECT_SESSIONS(0, proc.rootIface); } TEST_P(BinderRpc, OnewayCallDoesNotWait) { @@ -483,7 +483,7 @@ TEST_P(BinderRpc, Callbacks) { cb->mCv.wait_for(_l, 1s, [&] { return !cb->mValues.empty(); }); } - EXPECT_EQ(cb->mValues.size(), 1) + EXPECT_EQ(cb->mValues.size(), 1UL) << "callIsOneway: " << callIsOneway << " callbackIsOneway: " << callbackIsOneway << " delayed: " << delayed; if (cb->mValues.empty()) continue; diff --git a/libs/binder/trusty/binderRpcTest/manifest.json b/libs/binder/trusty/binderRpcTest/manifest.json new file mode 100644 index 0000000000..d8b080f0d4 --- /dev/null +++ b/libs/binder/trusty/binderRpcTest/manifest.json @@ -0,0 +1,6 @@ +{ + "uuid": "9dbe9fb8-60fd-4bdd-af86-03e95d7ad78b", + "app_name": "binderRpcTest", + "min_heap": 163840, + "min_stack": 16384 +} diff --git a/libs/binder/trusty/binderRpcTest/rules.mk b/libs/binder/trusty/binderRpcTest/rules.mk new file mode 100644 index 0000000000..ae3949246d --- /dev/null +++ b/libs/binder/trusty/binderRpcTest/rules.mk @@ -0,0 +1,35 @@ +# 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. +# + +LOCAL_DIR := $(GET_LOCAL_DIR) +LIBBINDER_TESTS_DIR := frameworks/native/libs/binder/tests + +MODULE := $(LOCAL_DIR) + +MANIFEST := $(LOCAL_DIR)/manifest.json + +MODULE_SRCS += \ + $(LIBBINDER_TESTS_DIR)/binderRpcUniversalTests.cpp \ + $(LIBBINDER_TESTS_DIR)/binderRpcTestCommon.cpp \ + $(LIBBINDER_TESTS_DIR)/binderRpcTestTrusty.cpp \ + +MODULE_LIBRARY_DEPS += \ + $(LOCAL_DIR)/aidl \ + frameworks/native/libs/binder/trusty \ + frameworks/native/libs/binder/trusty/ndk \ + trusty/user/base/lib/googletest \ + trusty/user/base/lib/libstdc++-trusty \ + +include make/trusted_app.mk diff --git a/libs/binder/trusty/build-config-usertests b/libs/binder/trusty/build-config-usertests new file mode 100644 index 0000000000..d0a1fbca49 --- /dev/null +++ b/libs/binder/trusty/build-config-usertests @@ -0,0 +1,19 @@ +# 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. + +# This file lists userspace tests + +[ + porttest("com.android.trusty.binderRpcTest"), +] diff --git a/libs/binder/trusty/include_mock/trusty-gtest.h b/libs/binder/trusty/include_mock/trusty-gtest.h new file mode 100644 index 0000000000..046b403553 --- /dev/null +++ b/libs/binder/trusty/include_mock/trusty-gtest.h @@ -0,0 +1,21 @@ +/* + * 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 + +#define PORT_GTEST(suite, port) \ + int main(void) { \ + return 0; \ + } diff --git a/libs/binder/trusty/include_mock/trusty_ipc.h b/libs/binder/trusty/include_mock/trusty_ipc.h index 43ab84a424..db044c2c04 100644 --- a/libs/binder/trusty/include_mock/trusty_ipc.h +++ b/libs/binder/trusty/include_mock/trusty_ipc.h @@ -27,6 +27,8 @@ #define IPC_PORT_ALLOW_TA_CONNECT 0x1 #define IPC_PORT_ALLOW_NS_CONNECT 0x2 +#define IPC_CONNECT_WAIT_FOR_PORT 0x1 + #define IPC_HANDLE_POLL_HUP 0x1 #define IPC_HANDLE_POLL_MSG 0x2 #define IPC_HANDLE_POLL_SEND_UNBLOCKED 0x4 diff --git a/libs/binder/trusty/usertests-inc.mk b/libs/binder/trusty/usertests-inc.mk index 2f5a7f479b..13001219d4 100644 --- a/libs/binder/trusty/usertests-inc.mk +++ b/libs/binder/trusty/usertests-inc.mk @@ -14,4 +14,6 @@ # TRUSTY_USER_TESTS += \ + frameworks/native/libs/binder/trusty/binderRpcTest \ frameworks/native/libs/binder/trusty/binderRpcTest/service \ + diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index b0f5932610..eb97a68a9a 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -2276,6 +2276,20 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( tempTouchState.addOrUpdateWindow(newTouchedWindowHandle, targetFlags, pointerIds); } } + + // Update the pointerIds for non-splittable when it received pointer down. + if (!isSplit && maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN) { + // If no split, we suppose all touched windows should receive pointer down. + const int32_t pointerIndex = getMotionEventActionPointerIndex(action); + for (size_t i = 0; i < tempTouchState.windows.size(); i++) { + TouchedWindow& touchedWindow = tempTouchState.windows[i]; + // Ignore drag window for it should just track one pointer. + if (mDragState && mDragState->dragWindow == touchedWindow.windowHandle) { + continue; + } + touchedWindow.pointerIds.markBit(entry.pointerProperties[pointerIndex].id); + } + } } // Update dispatching for hover enter and exit. @@ -2384,13 +2398,15 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( if (info->displayId == displayId && windowHandle->getInfo()->inputConfig.test( WindowInfo::InputConfig::IS_WALLPAPER)) { + BitSet32 pointerIds; + pointerIds.markBit(entry.pointerProperties[0].id); tempTouchState .addOrUpdateWindow(windowHandle, InputTarget::FLAG_WINDOW_IS_OBSCURED | InputTarget:: FLAG_WINDOW_IS_PARTIALLY_OBSCURED | InputTarget::FLAG_DISPATCH_AS_IS, - BitSet32(0)); + pointerIds); } } } @@ -2460,17 +2476,6 @@ Failed: } i += 1; } - } else if (!isSplit && maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN) { - // If no split, we suppose all touched windows should receive pointer down. - const int32_t pointerIndex = getMotionEventActionPointerIndex(action); - for (size_t i = 0; i < tempTouchState.windows.size(); i++) { - TouchedWindow& touchedWindow = tempTouchState.windows[i]; - // Ignore drag window for it should just track one pointer. - if (mDragState && mDragState->dragWindow == touchedWindow.windowHandle) { - continue; - } - touchedWindow.pointerIds.markBit(entry.pointerProperties[pointerIndex].id); - } } // Save changes unless the action was scroll in which case the temporary touch diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index 4977c39b2f..fce0f999b5 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -1887,6 +1887,64 @@ TEST_F(InputDispatcherTest, TwoWindows_SplitWallpaperTouch) { wallpaperWindow->assertNoEvents(); } +TEST_F(InputDispatcherTest, WallpaperWindowReceivesMultiTouch) { + std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); + sp<FakeWindowHandle> window = + sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT); + window->setDupTouchToWallpaper(true); + + sp<FakeWindowHandle> wallpaperWindow = + sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT); + wallpaperWindow->setIsWallpaper(true); + constexpr int expectedWallpaperFlags = + AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED; + wallpaperWindow->setPreventSplitting(true); + + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window, wallpaperWindow}}}); + + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + {50, 50})) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + window->consumeMotionDown(ADISPLAY_ID_DEFAULT); + wallpaperWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); + + const MotionEvent secondFingerDownEvent = + MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .displayId(ADISPLAY_ID_DEFAULT) + .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) + .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50)) + .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(10).y(10)) + .build(); + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, + InputEventInjectionSync::WAIT_FOR_RESULT)) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + + window->consumeMotionPointerDown(1); + wallpaperWindow->consumeMotionPointerDown(1, ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); + + const MotionEvent secondFingerUpEvent = + MotionEventBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN) + .displayId(ADISPLAY_ID_DEFAULT) + .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) + .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50)) + .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(10).y(10)) + .build(); + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionEvent(mDispatcher, secondFingerUpEvent, INJECT_EVENT_TIMEOUT, + InputEventInjectionSync::WAIT_FOR_RESULT)) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + window->consumeMotionPointerUp(1); + wallpaperWindow->consumeMotionPointerUp(1, ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); + + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionUp(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {50, 50})) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + window->consumeMotionUp(ADISPLAY_ID_DEFAULT); + wallpaperWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); +} + /** * On the display, have a single window, and also an area where there's no window. * First pointer touches the "no window" area of the screen. Second pointer touches the window. @@ -2375,6 +2433,43 @@ TEST_F(InputDispatcherTest, OnWindowInfosChanged_RemoveAllWindowsOnDisplay) { window->assertNoEvents(); } +TEST_F(InputDispatcherTest, NonSplitTouchableWindowReceivesMultiTouch) { + std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); + sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, + "Fake Window", ADISPLAY_ID_DEFAULT); + // Ensure window is non-split and have some transform. + window->setPreventSplitting(true); + window->setWindowOffset(20, 40); + mDispatcher->onWindowInfosChanged({*window->getInfo()}, {}); + + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + {50, 50})) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + window->consumeMotionDown(ADISPLAY_ID_DEFAULT); + + const MotionEvent secondFingerDownEvent = + MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .displayId(ADISPLAY_ID_DEFAULT) + .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) + .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50)) + .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER) + .x(-30) + .y(-50)) + .build(); + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, + InputEventInjectionSync::WAIT_FOR_RESULT)) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + + const MotionEvent* event = window->consumeMotion(); + EXPECT_EQ(POINTER_1_DOWN, event->getAction()); + EXPECT_EQ(70, event->getX(0)); // 50 + 20 + EXPECT_EQ(90, event->getY(0)); // 50 + 40 + EXPECT_EQ(-10, event->getX(1)); // -30 + 20 + EXPECT_EQ(-10, event->getY(1)); // -50 + 40 +} + /** * Ensure the correct coordinate spaces are used by InputDispatcher. * diff --git a/services/stats/StatsAidl.cpp b/services/stats/StatsAidl.cpp index 13485481a5..0f01507c9f 100644 --- a/services/stats/StatsAidl.cpp +++ b/services/stats/StatsAidl.cpp @@ -17,19 +17,72 @@ #define DEBUG false // STOPSHIP if true #define LOG_TAG "StatsAidl" +#define VLOG(...) \ + if (DEBUG) ALOGD(__VA_ARGS__); + #include "StatsAidl.h" #include <log/log.h> +#include <stats_annotations.h> +#include <stats_event.h> #include <statslog.h> +#include <unordered_map> + namespace aidl { namespace android { namespace frameworks { namespace stats { +template <typename E> +constexpr typename std::underlying_type<E>::type to_underlying(E e) noexcept { + return static_cast<typename std::underlying_type<E>::type>(e); +} + StatsHal::StatsHal() { } +bool write_annotation(AStatsEvent* event, const Annotation& annotation) { + switch (annotation.value.getTag()) { + case AnnotationValue::boolValue: { + AStatsEvent_addBoolAnnotation(event, to_underlying(annotation.annotationId), + annotation.value.get<AnnotationValue::boolValue>()); + break; + } + case AnnotationValue::intValue: { + AStatsEvent_addInt32Annotation(event, to_underlying(annotation.annotationId), + annotation.value.get<AnnotationValue::intValue>()); + break; + } + default: { + return false; + } + } + return true; +} + +bool write_atom_annotations(AStatsEvent* event, + const std::vector<std::optional<Annotation>>& annotations) { + for (const auto& atomAnnotation : annotations) { + if (!atomAnnotation) { + return false; + } + if (!write_annotation(event, *atomAnnotation)) { + return false; + } + } + return true; +} + +bool write_field_annotations(AStatsEvent* event, const std::vector<Annotation>& annotations) { + for (const auto& fieldAnnotation : annotations) { + if (!write_annotation(event, fieldAnnotation)) { + return false; + } + } + return true; +} + ndk::ScopedAStatus StatsHal::reportVendorAtom(const VendorAtom& vendorAtom) { if (vendorAtom.atomId < 100000 || vendorAtom.atomId >= 200000) { ALOGE("Atom ID %ld is not a valid vendor atom ID", (long)vendorAtom.atomId); @@ -44,7 +97,30 @@ ndk::ScopedAStatus StatsHal::reportVendorAtom(const VendorAtom& vendorAtom) { } AStatsEvent* event = AStatsEvent_obtain(); AStatsEvent_setAtomId(event, vendorAtom.atomId); + + if (vendorAtom.atomAnnotations) { + if (!write_atom_annotations(event, *vendorAtom.atomAnnotations)) { + ALOGE("Atom ID %ld has incompatible atom level annotation", (long)vendorAtom.atomId); + AStatsEvent_release(event); + return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage( + -1, "invalid atom annotation"); + } + } + + // populate map for quickier access for VendorAtomValue associated annotations by value index + std::unordered_map<int, int> fieldIndexToAnnotationSetMap; + if (vendorAtom.valuesAnnotations) { + const std::vector<std::optional<AnnotationSet>>& valuesAnnotations = + *vendorAtom.valuesAnnotations; + for (int i = 0; i < valuesAnnotations.size(); i++) { + if (valuesAnnotations[i]) { + fieldIndexToAnnotationSetMap[valuesAnnotations[i]->valueIndex] = i; + } + } + } + AStatsEvent_writeString(event, vendorAtom.reverseDomainName.c_str()); + size_t atomValueIdx = 0; for (const auto& atomValue : vendorAtom.values) { switch (atomValue.getTag()) { case VendorAtomValue::intValue: @@ -143,12 +219,37 @@ ndk::ScopedAStatus StatsHal::reportVendorAtom(const VendorAtom& vendorAtom) { AStatsEvent_writeByteArray(event, byteArrayValue->data(), byteArrayValue->size()); break; } + default: { + AStatsEvent_release(event); + ALOGE("Atom ID %ld has invalid atomValue.getTag", (long)vendorAtom.atomId); + return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage( + -1, "invalid atomValue.getTag"); + break; + } + } + + const auto& valueAnnotationIndex = fieldIndexToAnnotationSetMap.find(atomValueIdx); + if (valueAnnotationIndex != fieldIndexToAnnotationSetMap.end()) { + const std::vector<Annotation>& fieldAnnotations = + (*vendorAtom.valuesAnnotations)[valueAnnotationIndex->second]->annotations; + VLOG("Atom ID %ld has %ld annotations for field #%ld", (long)vendorAtom.atomId, + (long)fieldAnnotations.size(), (long)atomValueIdx + 2); + if (!write_field_annotations(event, fieldAnnotations)) { + ALOGE("Atom ID %ld has incompatible field level annotation for field #%ld", + (long)vendorAtom.atomId, (long)atomValueIdx + 2); + AStatsEvent_release(event); + return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage( + -1, "invalid atom field annotation"); + } } + atomValueIdx++; } AStatsEvent_build(event); const int ret = AStatsEvent_write(event); AStatsEvent_release(event); - + if (ret <= 0) { + ALOGE("Error writing Atom ID %ld. Result: %d", (long)vendorAtom.atomId, ret); + } return ret <= 0 ? ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(ret, "report atom failed") : ndk::ScopedAStatus::ok(); diff --git a/services/surfaceflinger/main_surfaceflinger.cpp b/services/surfaceflinger/main_surfaceflinger.cpp index ec180548e1..883766b334 100644 --- a/services/surfaceflinger/main_surfaceflinger.cpp +++ b/services/surfaceflinger/main_surfaceflinger.cpp @@ -139,11 +139,6 @@ int main(int, char**) { set_sched_policy(0, SP_FOREGROUND); - // Put most SurfaceFlinger threads in the system-background cpuset - // Keeps us from unnecessarily using big cores - // Do this after the binder thread pool init - if (cpusets_enabled()) set_cpuset_policy(0, SP_SYSTEM); - // initialize before clients can connect flinger->init(); diff --git a/vulkan/vkjson/Android.bp b/vulkan/vkjson/Android.bp index b6d3a0b45f..b544245a7a 100644 --- a/vulkan/vkjson/Android.bp +++ b/vulkan/vkjson/Android.bp @@ -25,10 +25,8 @@ cc_library_shared { ".", ], shared_libs: [ - "libvulkan", - ], - whole_static_libs: [ "libjsoncpp", + "libvulkan", ], export_shared_lib_headers: [ "libvulkan", |