diff options
28 files changed, 579 insertions, 76 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/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp index 695faf8a78..eadf67821f 100644 --- a/cmds/servicemanager/ServiceManager.cpp +++ b/cmds/servicemanager/ServiceManager.cpp @@ -222,6 +222,13 @@ static bool meetsDeclarationRequirements(const sp<IBinder>& binder, const std::s } #endif // !VENDORSERVICEMANAGER +ServiceManager::Service::~Service() { + if (!hasClients) { + // only expected to happen on process death + LOG(WARNING) << "a service was removed when there are clients"; + } +} + ServiceManager::ServiceManager(std::unique_ptr<Access>&& access) : mAccess(std::move(access)) { // TODO(b/151696835): reenable performance hack when we solve bug, since with // this hack and other fixes, it is unlikely we will see even an ephemeral @@ -293,8 +300,13 @@ sp<IBinder> ServiceManager::tryGetService(const std::string& name, bool startIfN } if (out) { - // Setting this guarantee each time we hand out a binder ensures that the client-checking - // loop knows about the event even if the client immediately drops the service + // Force onClients to get sent, and then make sure the timerfd won't clear it + // by setting guaranteeClient again. This logic could be simplified by using + // a time-based guarantee. However, forcing onClients(true) to get sent + // right here is always going to be important for processes serving multiple + // lazy interfaces. + service->guaranteeClient = true; + CHECK(handleServiceClientCallback(2 /* sm + transaction */, name, false)); service->guaranteeClient = true; } @@ -384,8 +396,13 @@ Status ServiceManager::addService(const std::string& name, const sp<IBinder>& bi }; if (auto it = mNameToRegistrationCallback.find(name); it != mNameToRegistrationCallback.end()) { + // See also getService - handles case where client never gets the service, + // we want the service to quit. + mNameToService[name].guaranteeClient = true; + CHECK(handleServiceClientCallback(2 /* sm + transaction */, name, false)); + mNameToService[name].guaranteeClient = true; + for (const sp<IServiceCallback>& cb : it->second) { - mNameToService[name].guaranteeClient = true; // permission checked in registerForNotifications cb->onRegistration(name, binder); } @@ -696,28 +713,28 @@ ssize_t ServiceManager::Service::getNodeStrongRefCount() { void ServiceManager::handleClientCallbacks() { for (const auto& [name, service] : mNameToService) { - handleServiceClientCallback(name, true); + handleServiceClientCallback(1 /* sm has one refcount */, name, true); } } -ssize_t ServiceManager::handleServiceClientCallback(const std::string& serviceName, - bool isCalledOnInterval) { +bool ServiceManager::handleServiceClientCallback(size_t knownClients, + const std::string& serviceName, + bool isCalledOnInterval) { auto serviceIt = mNameToService.find(serviceName); if (serviceIt == mNameToService.end() || mNameToClientCallback.count(serviceName) < 1) { - return -1; + return true; // return we do have clients a.k.a. DON'T DO ANYTHING } Service& service = serviceIt->second; ssize_t count = service.getNodeStrongRefCount(); - // binder driver doesn't support this feature - if (count == -1) return count; + // binder driver doesn't support this feature, consider we have clients + if (count == -1) return true; - bool hasClients = count > 1; // this process holds a strong count + bool hasKernelReportedClients = static_cast<size_t>(count) > knownClients; if (service.guaranteeClient) { - // we have no record of this client - if (!service.hasClients && !hasClients) { + if (!service.hasClients && !hasKernelReportedClients) { sendClientCallbackNotifications(serviceName, true, "service is guaranteed to be in use"); } @@ -726,21 +743,23 @@ ssize_t ServiceManager::handleServiceClientCallback(const std::string& serviceNa service.guaranteeClient = false; } - // only send notifications if this was called via the interval checking workflow - if (isCalledOnInterval) { - if (hasClients && !service.hasClients) { - // client was retrieved in some other way - sendClientCallbackNotifications(serviceName, true, "we now have a record of a client"); - } + // Regardless of this situation, we want to give this notification as soon as possible. + // This way, we have a chance of preventing further thrashing. + if (hasKernelReportedClients && !service.hasClients) { + sendClientCallbackNotifications(serviceName, true, "we now have a record of a client"); + } - // there are no more clients, but the callback has not been called yet - if (!hasClients && service.hasClients) { + // But limit rate of shutting down service. + if (isCalledOnInterval) { + if (!hasKernelReportedClients && service.hasClients) { sendClientCallbackNotifications(serviceName, false, "we now have no record of a client"); } } - return count; + // May be different than 'hasKernelReportedClients'. We intentionally delay + // information about clients going away to reduce thrashing. + return service.hasClients; } void ServiceManager::sendClientCallbackNotifications(const std::string& serviceName, @@ -753,13 +772,10 @@ void ServiceManager::sendClientCallbackNotifications(const std::string& serviceN } Service& service = serviceIt->second; - CHECK(hasClients != service.hasClients) - << "Record shows: " << service.hasClients - << " so we can't tell clients again that we have client: " << hasClients - << " when: " << context; + CHECK_NE(hasClients, service.hasClients) << context; - ALOGI("Notifying %s they %s have clients when %s", serviceName.c_str(), - hasClients ? "do" : "don't", context); + ALOGI("Notifying %s they %s (previously: %s) have clients when %s", serviceName.c_str(), + hasClients ? "do" : "don't", service.hasClients ? "do" : "don't", context); auto ccIt = mNameToClientCallback.find(serviceName); CHECK(ccIt != mNameToClientCallback.end()) @@ -803,26 +819,29 @@ Status ServiceManager::tryUnregisterService(const std::string& name, const sp<IB return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE); } + // important because we don't have timer-based guarantees, we don't want to clear + // this if (serviceIt->second.guaranteeClient) { ALOGI("Tried to unregister %s, but there is about to be a client.", name.c_str()); return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE); } - int clients = handleServiceClientCallback(name, false); - - // clients < 0: feature not implemented or other error. Assume clients. - // Otherwise: // - kernel driver will hold onto one refcount (during this transaction) // - servicemanager has a refcount (guaranteed by this transaction) - // So, if clients > 2, then at least one other service on the system must hold a refcount. - if (clients < 0 || clients > 2) { - // client callbacks are either disabled or there are other clients - ALOGI("Tried to unregister %s, but there are clients: %d", name.c_str(), clients); - // Set this flag to ensure the clients are acknowledged in the next callback + constexpr size_t kKnownClients = 2; + + if (handleServiceClientCallback(kKnownClients, name, false)) { + ALOGI("Tried to unregister %s, but there are clients.", name.c_str()); + + // Since we had a failed registration attempt, and the HIDL implementation of + // delaying service shutdown for multiple periods wasn't ported here... this may + // help reduce thrashing, but we should be able to remove it. serviceIt->second.guaranteeClient = true; + return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE); } + ALOGI("Unregistering %s", name.c_str()); mNameToService.erase(name); return Status::ok(); diff --git a/cmds/servicemanager/ServiceManager.h b/cmds/servicemanager/ServiceManager.h index f9d4f8fd90..3aa6731eb3 100644 --- a/cmds/servicemanager/ServiceManager.h +++ b/cmds/servicemanager/ServiceManager.h @@ -80,6 +80,8 @@ private: // the number of clients of the service, including servicemanager itself ssize_t getNodeStrongRefCount(); + + ~Service(); }; using ServiceCallbackMap = std::map<std::string, std::vector<sp<IServiceCallback>>>; @@ -91,7 +93,9 @@ private: void removeRegistrationCallback(const wp<IBinder>& who, ServiceCallbackMap::iterator* it, bool* found); - ssize_t handleServiceClientCallback(const std::string& serviceName, bool isCalledOnInterval); + // returns whether there are known clients in addition to the count provided + bool handleServiceClientCallback(size_t knownClients, const std::string& serviceName, + bool isCalledOnInterval); // Also updates mHasClients (of what the last callback was) void sendClientCallbackNotifications(const std::string& serviceName, bool hasClients, const char* context); diff --git a/cmds/servicemanager/servicemanager.rc b/cmds/servicemanager/servicemanager.rc index 3bd6db5ef6..4f92b3a374 100644 --- a/cmds/servicemanager/servicemanager.rc +++ b/cmds/servicemanager/servicemanager.rc @@ -5,7 +5,7 @@ service servicemanager /system/bin/servicemanager critical file /dev/kmsg w onrestart setprop servicemanager.ready false - onrestart restart apexd + onrestart restart --only-if-running apexd onrestart restart audioserver onrestart restart gatekeeperd onrestart class_restart --only-enabled main 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/TEST_MAPPING b/libs/binder/TEST_MAPPING index 2615876dbe..1488400007 100644 --- a/libs/binder/TEST_MAPPING +++ b/libs/binder/TEST_MAPPING @@ -89,6 +89,9 @@ "name": "CtsRootRollbackManagerHostTestCases" }, { + "name": "StagedRollbackTest" + }, + { "name": "binderRpcTestNoKernel" }, { 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/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", |