diff options
39 files changed, 753 insertions, 220 deletions
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp index ee1c63a3ff..12de33f2db 100644 --- a/cmds/dumpstate/dumpstate.cpp +++ b/cmds/dumpstate/dumpstate.cpp @@ -194,6 +194,8 @@ static const std::string TOMBSTONE_DIR = "/data/tombstones/"; static const std::string TOMBSTONE_FILE_PREFIX = "tombstone_"; static const std::string ANR_DIR = "/data/anr/"; static const std::string ANR_FILE_PREFIX = "anr_"; +static const std::string SHUTDOWN_CHECKPOINTS_DIR = "/data/system/shutdown-checkpoints/"; +static const std::string SHUTDOWN_CHECKPOINTS_FILE_PREFIX = "checkpoints-"; // TODO: temporary variables and functions used during C++ refactoring @@ -1109,6 +1111,16 @@ static void DumpIpTablesAsRoot() { RunCommand("IP6TABLES RAW", {"ip6tables", "-t", "raw", "-L", "-nvx"}); } +static void DumpShutdownCheckpoints() { + const bool shutdown_checkpoints_dumped = AddDumps( + ds.shutdown_checkpoints_.begin(), ds.shutdown_checkpoints_.end(), + "SHUTDOWN CHECKPOINTS", false /* add_to_zip */); + if (!shutdown_checkpoints_dumped) { + printf("*** NO SHUTDOWN CHECKPOINTS to dump in %s\n\n", + SHUTDOWN_CHECKPOINTS_DIR.c_str()); + } +} + static void DumpDynamicPartitionInfo() { if (!::android::base::GetBoolProperty("ro.boot.dynamic_partitions", false)) { return; @@ -1701,6 +1713,8 @@ static Dumpstate::RunStatus dumpstate() { DoKmsg(); + DumpShutdownCheckpoints(); + DumpIpAddrAndRules(); dump_route_tables(); @@ -1855,6 +1869,8 @@ Dumpstate::RunStatus Dumpstate::DumpstateDefaultAfterCritical() { if (!PropertiesHelper::IsDryRun()) { ds.tombstone_data_ = GetDumpFds(TOMBSTONE_DIR, TOMBSTONE_FILE_PREFIX); ds.anr_data_ = GetDumpFds(ANR_DIR, ANR_FILE_PREFIX); + ds.shutdown_checkpoints_ = GetDumpFds( + SHUTDOWN_CHECKPOINTS_DIR, SHUTDOWN_CHECKPOINTS_FILE_PREFIX); } ds.AddDir(RECOVERY_DIR, true); @@ -2907,6 +2923,7 @@ void Dumpstate::Cancel() { } tombstone_data_.clear(); anr_data_.clear(); + shutdown_checkpoints_.clear(); // Instead of shutdown the pool, we delete temporary files directly since // shutdown blocking the call. @@ -3190,6 +3207,7 @@ Dumpstate::RunStatus Dumpstate::RunInternal(int32_t calling_uid, tombstone_data_.clear(); anr_data_.clear(); + shutdown_checkpoints_.clear(); return (consent_callback_ != nullptr && consent_callback_->getResult() == UserConsentResult::UNAVAILABLE) diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h index 66f84cb1c1..7ffe80eba3 100644 --- a/cmds/dumpstate/dumpstate.h +++ b/cmds/dumpstate/dumpstate.h @@ -499,6 +499,9 @@ class Dumpstate { // List of open ANR dump files. std::vector<DumpData> anr_data_; + // List of open shutdown checkpoint files. + std::vector<DumpData> shutdown_checkpoints_; + // A thread pool to execute dump tasks simultaneously if the parallel run is enabled. std::unique_ptr<android::os::dumpstate::DumpPool> dump_pool_; diff --git a/cmds/servicemanager/Android.bp b/cmds/servicemanager/Android.bp index 61f931e0d2..1386660eb6 100644 --- a/cmds/servicemanager/Android.bp +++ b/cmds/servicemanager/Android.bp @@ -48,17 +48,6 @@ cc_binary { } cc_binary { - name: "servicemanager.microdroid", - defaults: ["servicemanager_defaults"], - init_rc: ["servicemanager.microdroid.rc"], - srcs: ["main.cpp"], - bootstrap: true, - // Prevent this from being installed when running tests in this directory. - // This is okay because microdorid build rule can bundle this anyway. - installable: false, -} - -cc_binary { name: "servicemanager.recovery", stem: "servicemanager", recovery: true, diff --git a/cmds/servicemanager/servicemanager.microdroid.rc b/cmds/servicemanager/servicemanager.microdroid.rc deleted file mode 100644 index 8819e1e8bf..0000000000 --- a/cmds/servicemanager/servicemanager.microdroid.rc +++ /dev/null @@ -1,8 +0,0 @@ -service servicemanager /system/bin/servicemanager.microdroid - class core - user system - group system readproc - critical - onrestart setprop servicemanager.ready false - onrestart restart apexd - shutdown critical diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp index 11c8e5dcea..77703749a1 100644 --- a/libs/binder/IPCThreadState.cpp +++ b/libs/binder/IPCThreadState.cpp @@ -45,11 +45,11 @@ #define IF_LOG_TRANSACTIONS() if (false) #define IF_LOG_COMMANDS() if (false) -#define LOG_REMOTEREFS(...) +#define LOG_REMOTEREFS(...) #define IF_LOG_REMOTEREFS() if (false) -#define LOG_THREADPOOL(...) -#define LOG_ONEWAY(...) +#define LOG_THREADPOOL(...) +#define LOG_ONEWAY(...) #else @@ -394,14 +394,92 @@ void IPCThreadState::checkContextIsBinderForUse(const char* use) const { // context, so we don't abort } +constexpr uint32_t encodeExplicitIdentity(bool hasExplicitIdentity, pid_t callingPid) { + uint32_t as_unsigned = static_cast<uint32_t>(callingPid); + if (hasExplicitIdentity) { + return as_unsigned | (1 << 30); + } else { + return as_unsigned & ~(1 << 30); + } +} + +constexpr int64_t packCallingIdentity(bool hasExplicitIdentity, uid_t callingUid, + pid_t callingPid) { + // Calling PID is a 32-bit signed integer, but doesn't consume the entire 32 bit space. + // To future-proof this and because we have extra capacity, we decided to also support -1, + // since this constant is used to represent invalid UID in other places of the system. + // Thus, we pack hasExplicitIdentity into the 2nd bit from the left. This allows us to + // preserve the (left-most) bit for the sign while also encoding the value of + // hasExplicitIdentity. + // 32b | 1b | 1b | 30b + // token = [ calling uid | calling pid(sign) | has explicit identity | calling pid(rest) ] + uint64_t token = (static_cast<uint64_t>(callingUid) << 32) | + encodeExplicitIdentity(hasExplicitIdentity, callingPid); + return static_cast<int64_t>(token); +} + +constexpr bool unpackHasExplicitIdentity(int64_t token) { + return static_cast<int32_t>(token) & (1 << 30); +} + +constexpr uid_t unpackCallingUid(int64_t token) { + return static_cast<uid_t>(token >> 32); +} + +constexpr pid_t unpackCallingPid(int64_t token) { + int32_t encodedPid = static_cast<int32_t>(token); + if (encodedPid & (1 << 31)) { + return encodedPid | (1 << 30); + } else { + return encodedPid & ~(1 << 30); + } +} + +static_assert(unpackHasExplicitIdentity(packCallingIdentity(true, 1000, 9999)) == true, + "pack true hasExplicit"); + +static_assert(unpackCallingUid(packCallingIdentity(true, 1000, 9999)) == 1000, "pack true uid"); + +static_assert(unpackCallingPid(packCallingIdentity(true, 1000, 9999)) == 9999, "pack true pid"); + +static_assert(unpackHasExplicitIdentity(packCallingIdentity(false, 1000, 9999)) == false, + "pack false hasExplicit"); + +static_assert(unpackCallingUid(packCallingIdentity(false, 1000, 9999)) == 1000, "pack false uid"); + +static_assert(unpackCallingPid(packCallingIdentity(false, 1000, 9999)) == 9999, "pack false pid"); + +static_assert(unpackHasExplicitIdentity(packCallingIdentity(true, 1000, -1)) == true, + "pack true (negative) hasExplicit"); + +static_assert(unpackCallingUid(packCallingIdentity(true, 1000, -1)) == 1000, + "pack true (negative) uid"); + +static_assert(unpackCallingPid(packCallingIdentity(true, 1000, -1)) == -1, + "pack true (negative) pid"); + +static_assert(unpackHasExplicitIdentity(packCallingIdentity(false, 1000, -1)) == false, + "pack false (negative) hasExplicit"); + +static_assert(unpackCallingUid(packCallingIdentity(false, 1000, -1)) == 1000, + "pack false (negative) uid"); + +static_assert(unpackCallingPid(packCallingIdentity(false, 1000, -1)) == -1, + "pack false (negative) pid"); + int64_t IPCThreadState::clearCallingIdentity() { // ignore mCallingSid for legacy reasons - int64_t token = ((int64_t)mCallingUid<<32) | mCallingPid; + int64_t token = packCallingIdentity(mHasExplicitIdentity, mCallingUid, mCallingPid); clearCaller(); + mHasExplicitIdentity = true; return token; } +bool IPCThreadState::hasExplicitIdentity() { + return mHasExplicitIdentity; +} + void IPCThreadState::setStrictModePolicy(int32_t policy) { mStrictModePolicy = policy; @@ -474,9 +552,10 @@ ProcessState::CallRestriction IPCThreadState::getCallRestriction() const { void IPCThreadState::restoreCallingIdentity(int64_t token) { - mCallingUid = (int)(token>>32); + mCallingUid = unpackCallingUid(token); mCallingSid = nullptr; // not enough data to restore - mCallingPid = (int)token; + mCallingPid = unpackCallingPid(token); + mHasExplicitIdentity = unpackHasExplicitIdentity(token); } void IPCThreadState::clearCaller() @@ -889,6 +968,7 @@ IPCThreadState::IPCThreadState() mCallRestriction(mProcess->mCallRestriction) { pthread_setspecific(gTLS, this); clearCaller(); + mHasExplicitIdentity = false; mIn.setDataCapacity(256); mOut.setDataCapacity(256); } @@ -1279,6 +1359,7 @@ status_t IPCThreadState::executeCommand(int32_t cmd) const pid_t origPid = mCallingPid; const char* origSid = mCallingSid; const uid_t origUid = mCallingUid; + const bool origHasExplicitIdentity = mHasExplicitIdentity; const int32_t origStrictModePolicy = mStrictModePolicy; const int32_t origTransactionBinderFlags = mLastTransactionBinderFlags; const int32_t origWorkSource = mWorkSource; @@ -1292,6 +1373,7 @@ status_t IPCThreadState::executeCommand(int32_t cmd) mCallingPid = tr.sender_pid; mCallingSid = reinterpret_cast<const char*>(tr_secctx.secctx); mCallingUid = tr.sender_euid; + mHasExplicitIdentity = false; mLastTransactionBinderFlags = tr.flags; // ALOGI(">>>> TRANSACT from pid %d sid %s uid %d\n", mCallingPid, @@ -1367,6 +1449,7 @@ status_t IPCThreadState::executeCommand(int32_t cmd) mCallingPid = origPid; mCallingSid = origSid; mCallingUid = origUid; + mHasExplicitIdentity = origHasExplicitIdentity; mStrictModePolicy = origStrictModePolicy; mLastTransactionBinderFlags = origTransactionBinderFlags; mWorkSource = origWorkSource; diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp index 4b07608a79..ee081c485c 100644 --- a/libs/binder/Parcel.cpp +++ b/libs/binder/Parcel.cpp @@ -614,11 +614,14 @@ status_t Parcel::appendFrom(const Parcel* parcel, size_t offset, size_t len) { if (status_t status = readInt32(&fdIndex); status != OK) { return status; } - const auto& oldFd = otherRpcFields->mFds->at(fdIndex); + int oldFd = toRawFd(otherRpcFields->mFds->at(fdIndex)); // To match kernel binder behavior, we always dup, even if the // FD was unowned in the source parcel. - rpcFields->mFds->emplace_back( - base::unique_fd(fcntl(toRawFd(oldFd), F_DUPFD_CLOEXEC, 0))); + int newFd = -1; + if (status_t status = dupFileDescriptor(oldFd, &newFd); status != OK) { + ALOGW("Failed to duplicate file descriptor %d: %s", oldFd, strerror(-status)); + } + rpcFields->mFds->emplace_back(base::unique_fd(newFd)); // Fixup the index in the data. mDataPos = newDataPos + 4; if (status_t status = writeInt32(rpcFields->mFds->size() - 1); status != OK) { diff --git a/libs/binder/include/binder/IPCThreadState.h b/libs/binder/include/binder/IPCThreadState.h index c01e92f043..65b77c6736 100644 --- a/libs/binder/include/binder/IPCThreadState.h +++ b/libs/binder/include/binder/IPCThreadState.h @@ -139,6 +139,7 @@ public: int64_t clearCallingIdentity(); // Restores PID/UID (not SID) void restoreCallingIdentity(int64_t token); + bool hasExplicitIdentity(); status_t setupPolling(int* fd); status_t handlePolledCommands(); @@ -241,6 +242,7 @@ private: bool mPropagateWorkSource; bool mIsLooper; bool mIsFlushing; + bool mHasExplicitIdentity; int32_t mStrictModePolicy; int32_t mLastTransactionBinderFlags; CallRestriction mCallRestriction; diff --git a/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp b/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp index dd177aff7f..f08bde8b80 100644 --- a/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp +++ b/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp @@ -17,20 +17,41 @@ #pragma once #include <sys/socket.h> +#include <stdint.h> extern "C" { struct AIBinder; +struct ARpcServer; // Starts an RPC server on a given port and a given root IBinder object. -// This function sets up the server and joins before returning. -bool RunVsockRpcServer(AIBinder* service, unsigned int port); +// Returns an opaque handle to the running server instance, or null if the server +// could not be started. +[[nodiscard]] ARpcServer* ARpcServer_newVsock(AIBinder* service, unsigned int port); -// Starts an RPC server on a given port and a given root IBinder object. -// This function sets up the server, calls readyCallback with a given param, and -// then joins before returning. -bool RunVsockRpcServerCallback(AIBinder* service, unsigned int port, - void (*readyCallback)(void* param), void* param); +// Starts a Unix domain RPC server with a given init-managed Unix domain `name` +// and a given root IBinder object. +// The socket should be created in init.rc with the same `name`. +// Returns an opaque handle to the running server instance, or null if the server +// could not be started. +[[nodiscard]] ARpcServer* ARpcServer_newInitUnixDomain(AIBinder* service, const char* name); + +// Runs ARpcServer_join() in a background thread. Immediately returns. +void ARpcServer_start(ARpcServer* server); + +// Joins the thread of a running RpcServer instance. At any given point, there +// can only be one thread calling ARpcServer_join(). +// If a client needs to actively terminate join, call ARpcServer_shutdown() in +// a separate thread. +void ARpcServer_join(ARpcServer* server); + +// Shuts down any running ARpcServer_join(). +void ARpcServer_shutdown(ARpcServer* server); + +// Frees the ARpcServer handle and drops the reference count on the underlying +// RpcServer instance. The handle must not be reused afterwards. +// This automatically calls ARpcServer_shutdown(). +void ARpcServer_free(ARpcServer* server); // Starts an RPC server on a given port and a given root IBinder factory. // RunVsockRpcServerWithFactory acts like RunVsockRpcServerCallback, but instead of @@ -42,15 +63,6 @@ bool RunVsockRpcServerWithFactory(AIBinder* (*factory)(unsigned int cid, void* c AIBinder* VsockRpcClient(unsigned int cid, unsigned int port); -// Starts a Unix domain RPC server with a given init-managed Unix domain `name` and -// a given root IBinder object. -// The socket should be created in init.rc with the same `name`. -// -// This function sets up the server, calls readyCallback with a given param, and -// then joins before returning. -bool RunInitUnixDomainRpcServer(AIBinder* service, const char* name, - void (*readyCallback)(void* param), void* param); - // Gets the service via the RPC binder with Unix domain socket with the given // Unix socket `name`. // The final Unix domain socket path name is /dev/socket/`name`. diff --git a/libs/binder/libbinder_rpc_unstable.cpp b/libs/binder/libbinder_rpc_unstable.cpp index 9edb3b6f99..f55c7796a0 100644 --- a/libs/binder/libbinder_rpc_unstable.cpp +++ b/libs/binder/libbinder_rpc_unstable.cpp @@ -14,6 +14,8 @@ * limitations under the License. */ +#include <binder_rpc_unstable.hpp> + #include <android-base/logging.h> #include <android-base/unique_fd.h> #include <android/binder_libbinder.h> @@ -25,23 +27,32 @@ using android::OK; using android::RpcServer; using android::RpcSession; +using android::sp; using android::status_t; using android::statusToString; using android::base::unique_fd; -extern "C" { +// Opaque handle for RpcServer. +struct ARpcServer {}; -void RunRpcServer(android::sp<RpcServer>& server, AIBinder* service, - void (*readyCallback)(void* param), void* param) { - server->setRootObject(AIBinder_toPlatformBinder(service)); +static sp<RpcServer> toRpcServer(ARpcServer* handle) { + auto ref = reinterpret_cast<RpcServer*>(handle); + return sp<RpcServer>::fromExisting(ref); +} - if (readyCallback) readyCallback(param); - server->join(); +static ARpcServer* createRpcServerHandle(sp<RpcServer>& server) { + auto ref = server.get(); + ref->incStrong(ref); + return reinterpret_cast<ARpcServer*>(ref); +} - // Shutdown any open sessions since server failed. - (void)server->shutdown(); +static void freeRpcServerHandle(ARpcServer* handle) { + auto ref = reinterpret_cast<RpcServer*>(handle); + ref->decStrong(ref); } +extern "C" { + bool RunVsockRpcServerWithFactory(AIBinder* (*factory)(unsigned int cid, void* context), void* factoryContext, unsigned int port) { auto server = RpcServer::make(); @@ -64,47 +75,57 @@ bool RunVsockRpcServerWithFactory(AIBinder* (*factory)(unsigned int cid, void* c return true; } -bool RunVsockRpcServerCallback(AIBinder* service, unsigned int port, - void (*readyCallback)(void* param), void* param) { +ARpcServer* ARpcServer_newVsock(AIBinder* service, unsigned int port) { auto server = RpcServer::make(); if (status_t status = server->setupVsockServer(port); status != OK) { LOG(ERROR) << "Failed to set up vsock server with port " << port << " error: " << statusToString(status).c_str(); - return false; - } - RunRpcServer(server, service, readyCallback, param); - return true; -} - -bool RunVsockRpcServer(AIBinder* service, unsigned int port) { - return RunVsockRpcServerCallback(service, port, nullptr, nullptr); -} - -AIBinder* VsockRpcClient(unsigned int cid, unsigned int port) { - auto session = RpcSession::make(); - if (status_t status = session->setupVsockClient(cid, port); status != OK) { - LOG(ERROR) << "Failed to set up vsock client with CID " << cid << " and port " << port - << " error: " << statusToString(status).c_str(); return nullptr; } - return AIBinder_fromPlatformBinder(session->getRootObject()); + server->setRootObject(AIBinder_toPlatformBinder(service)); + return createRpcServerHandle(server); } -bool RunInitUnixDomainRpcServer(AIBinder* service, const char* name, - void (*readyCallback)(void* param), void* param) { +ARpcServer* ARpcServer_newInitUnixDomain(AIBinder* service, const char* name) { auto server = RpcServer::make(); auto fd = unique_fd(android_get_control_socket(name)); if (!fd.ok()) { LOG(ERROR) << "Failed to get fd for the socket:" << name; - return false; + return nullptr; } if (status_t status = server->setupRawSocketServer(std::move(fd)); status != OK) { LOG(ERROR) << "Failed to set up Unix Domain RPC server with name " << name << " error: " << statusToString(status).c_str(); - return false; + return nullptr; } - RunRpcServer(server, service, readyCallback, param); - return true; + server->setRootObject(AIBinder_toPlatformBinder(service)); + return createRpcServerHandle(server); +} + +void ARpcServer_start(ARpcServer* handle) { + toRpcServer(handle)->start(); +} + +void ARpcServer_join(ARpcServer* handle) { + toRpcServer(handle)->join(); +} + +void ARpcServer_shutdown(ARpcServer* handle) { + toRpcServer(handle)->shutdown(); +} + +void ARpcServer_free(ARpcServer* handle) { + freeRpcServerHandle(handle); +} + +AIBinder* VsockRpcClient(unsigned int cid, unsigned int port) { + auto session = RpcSession::make(); + if (status_t status = session->setupVsockClient(cid, port); status != OK) { + LOG(ERROR) << "Failed to set up vsock client with CID " << cid << " and port " << port + << " error: " << statusToString(status).c_str(); + return nullptr; + } + return AIBinder_fromPlatformBinder(session->getRootObject()); } AIBinder* UnixDomainRpcClient(const char* name) { diff --git a/libs/binder/libbinder_rpc_unstable.map.txt b/libs/binder/libbinder_rpc_unstable.map.txt index f9c7bcf117..1bc2416533 100644 --- a/libs/binder/libbinder_rpc_unstable.map.txt +++ b/libs/binder/libbinder_rpc_unstable.map.txt @@ -1,9 +1,12 @@ LIBBINDER_RPC_UNSTABLE_SHIM { # platform-only global: - RunVsockRpcServer; - RunVsockRpcServerCallback; + ARpcServer_free; + ARpcServer_join; + ARpcServer_newInitUnixDomain; + ARpcServer_newVsock; + ARpcServer_shutdown; + ARpcServer_start; VsockRpcClient; - RunInitUnixDomainRpcServer; UnixDomainRpcClient; RpcPreconnectedClient; local: diff --git a/libs/binder/ndk/include_platform/android/binder_manager.h b/libs/binder/ndk/include_platform/android/binder_manager.h index c23427012a..ad4188f499 100644 --- a/libs/binder/ndk/include_platform/android/binder_manager.h +++ b/libs/binder/ndk/include_platform/android/binder_manager.h @@ -68,6 +68,7 @@ __attribute__((warn_unused_result)) AIBinder* AServiceManager_checkService(const * * \param instance identifier of the service used to lookup the service. */ +[[deprecated("this polls 5s, use AServiceManager_waitForService or AServiceManager_checkService")]] __attribute__((warn_unused_result)) AIBinder* AServiceManager_getService(const char* instance) __INTRODUCED_IN(29); @@ -108,6 +109,67 @@ __attribute__((warn_unused_result)) AIBinder* AServiceManager_waitForService(con __INTRODUCED_IN(31); /** + * Function to call when a service is registered. The instance is passed as well as + * ownership of the binder named 'registered'. + * + * WARNING: a lock is held when this method is called in order to prevent races with + * AServiceManager_NotificationRegistration_delete. Do not make synchronous binder calls when + * implementing this method to avoid deadlocks. + * + * \param instance instance name of service registered + * \param registered ownership-passed instance of service registered + * \param cookie data passed during registration for notifications + */ +typedef void (*AServiceManager_onRegister)(const char* instance, AIBinder* registered, + void* cookie); + +/** + * Represents a registration to servicemanager which can be cleared anytime. + */ +struct AServiceManager_NotificationRegistration; + +/** + * Get notifications when a service is registered. If the service is already registered, + * you will immediately get a notification. + * + * WARNING: it is strongly recommended to use AServiceManager_waitForService API instead. + * That API will wait synchronously, which is what you usually want in cases, including + * using some feature or during boot up. There is a history of bugs where waiting for + * notifications like this races with service startup. Also, when this API is used, a service + * bug will result in silent failure (rather than a debuggable deadlock). Furthermore, there + * is a history of this API being used to know when a service is up as a proxy for whethre + * that service should be started. This should only be used if you are intending to get + * ahold of the service as a client. For lazy services, whether a service is registered + * should not be used as a proxy for when it should be registered, which is only known + * by the real client. + * + * WARNING: if you use this API, you must also ensure that you check missing services are + * started and crash otherwise. If service failures are ignored, the system rots. + * + * \param instance name of service to wait for notifications about + * \param onRegister callback for when service is registered + * \param cookie data associated with this callback + * + * \return the token for this registration. Deleting this token will unregister. + */ +__attribute__((warn_unused_result)) AServiceManager_NotificationRegistration* +AServiceManager_registerForServiceNotifications(const char* instance, + AServiceManager_onRegister onRegister, void* cookie) + __INTRODUCED_IN(34); + +/** + * Unregister for notifications and delete the object. + * + * After this method is called, the callback is guaranteed to no longer be invoked. This will block + * until any in-progress onRegister callbacks have completed. It is therefore safe to immediately + * destroy the void* cookie that was registered when this method returns. + * + * \param notification object to dismiss + */ +void AServiceManager_NotificationRegistration_delete( + AServiceManager_NotificationRegistration* notification) __INTRODUCED_IN(34); + +/** * Check if a service is declared (e.g. VINTF manifest). * * \param instance identifier of the service. diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt index 32ca5649dd..5c7005ceb7 100644 --- a/libs/binder/ndk/libbinder_ndk.map.txt +++ b/libs/binder/ndk/libbinder_ndk.map.txt @@ -155,6 +155,8 @@ LIBBINDER_NDK33 { # introduced=33 LIBBINDER_NDK34 { # introduced=UpsideDownCake global: AServiceManager_getUpdatableApexName; # systemapi + AServiceManager_registerForServiceNotifications; # systemapi llndk + AServiceManager_NotificationRegistration_delete; # systemapi llndk }; LIBBINDER_NDK_PLATFORM { diff --git a/libs/binder/ndk/service_manager.cpp b/libs/binder/ndk/service_manager.cpp index a12d0e9e8d..e107c83d14 100644 --- a/libs/binder/ndk/service_manager.cpp +++ b/libs/binder/ndk/service_manager.cpp @@ -28,6 +28,7 @@ using ::android::IBinder; using ::android::IServiceManager; using ::android::sp; using ::android::status_t; +using ::android::statusToString; using ::android::String16; using ::android::String8; @@ -86,6 +87,67 @@ AIBinder* AServiceManager_waitForService(const char* instance) { AIBinder_incStrong(ret.get()); return ret.get(); } +typedef void (*AServiceManager_onRegister)(const char* instance, AIBinder* registered, + void* cookie); + +struct AServiceManager_NotificationRegistration + : public IServiceManager::LocalRegistrationCallback { + std::mutex m; + const char* instance = nullptr; + void* cookie = nullptr; + AServiceManager_onRegister onRegister = nullptr; + + virtual void onServiceRegistration(const String16& smInstance, const sp<IBinder>& binder) { + std::lock_guard<std::mutex> l(m); + if (onRegister == nullptr) return; + + CHECK_EQ(String8(smInstance), instance); + + sp<AIBinder> ret = ABpBinder::lookupOrCreateFromBinder(binder); + AIBinder_incStrong(ret.get()); + + onRegister(instance, ret.get(), cookie); + } + + void clear() { + std::lock_guard<std::mutex> l(m); + instance = nullptr; + cookie = nullptr; + onRegister = nullptr; + } +}; + +__attribute__((warn_unused_result)) AServiceManager_NotificationRegistration* +AServiceManager_registerForServiceNotifications(const char* instance, + AServiceManager_onRegister onRegister, + void* cookie) { + CHECK_NE(instance, nullptr); + CHECK_NE(onRegister, nullptr) << instance; + // cookie can be nullptr + + auto cb = sp<AServiceManager_NotificationRegistration>::make(); + cb->instance = instance; + cb->onRegister = onRegister; + cb->cookie = cookie; + + sp<IServiceManager> sm = defaultServiceManager(); + if (status_t res = sm->registerForNotifications(String16(instance), cb); res != STATUS_OK) { + LOG(ERROR) << "Failed to register for service notifications for " << instance << ": " + << statusToString(res); + return nullptr; + } + + cb->incStrong(nullptr); + return cb.get(); +} + +void AServiceManager_NotificationRegistration_delete( + AServiceManager_NotificationRegistration* notification) { + CHECK_NE(notification, nullptr); + notification->clear(); + notification->decStrong(nullptr); +} + bool AServiceManager_isDeclared(const char* instance) { if (instance == nullptr) { return false; diff --git a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp index e221e4c2bb..9d5ef6805a 100644 --- a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp +++ b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp @@ -254,6 +254,47 @@ TEST(NdkBinder, CheckServiceThatDoesExist) { AIBinder_decStrong(binder); } +struct ServiceData { + std::string instance; + ndk::SpAIBinder binder; + + static void fillOnRegister(const char* instance, AIBinder* binder, void* cookie) { + ServiceData* d = reinterpret_cast<ServiceData*>(cookie); + d->instance = instance; + d->binder = ndk::SpAIBinder(binder); + } +}; + +TEST(NdkBinder, RegisterForServiceNotificationsNonExisting) { + ServiceData data; + auto* notif = AServiceManager_registerForServiceNotifications( + "DOES_NOT_EXIST", ServiceData::fillOnRegister, (void*)&data); + ASSERT_NE(notif, nullptr); + + sleep(1); // give us a chance to fail + AServiceManager_NotificationRegistration_delete(notif); + + // checking after deleting to avoid needing a mutex over the data - otherwise + // in an environment w/ multiple threads, you would need to guard access + EXPECT_EQ(data.instance, ""); + EXPECT_EQ(data.binder, nullptr); +} + +TEST(NdkBinder, RegisterForServiceNotificationsExisting) { + ServiceData data; + auto* notif = AServiceManager_registerForServiceNotifications( + kExistingNonNdkService, ServiceData::fillOnRegister, (void*)&data); + ASSERT_NE(notif, nullptr); + + sleep(1); // give us a chance to fail + AServiceManager_NotificationRegistration_delete(notif); + + // checking after deleting to avoid needing a mutex over the data - otherwise + // in an environment w/ multiple threads, you would need to guard access + EXPECT_EQ(data.instance, kExistingNonNdkService); + EXPECT_EQ(data.binder, ndk::SpAIBinder(AServiceManager_checkService(kExistingNonNdkService))); +} + TEST(NdkBinder, UnimplementedDump) { sp<IFoo> foo = IFoo::getService(IFoo::kSomeInstanceName); ASSERT_NE(foo, nullptr); diff --git a/libs/binder/rust/Android.bp b/libs/binder/rust/Android.bp index 738d16ac66..afd414a7cb 100644 --- a/libs/binder/rust/Android.bp +++ b/libs/binder/rust/Android.bp @@ -17,7 +17,6 @@ rust_library { rustlibs: [ "libbinder_ndk_sys", "libdowncast_rs", - "liblazy_static", "liblibc", ], host_supported: true, @@ -160,7 +159,6 @@ rust_test { rustlibs: [ "libbinder_ndk_sys", "libdowncast_rs", - "liblazy_static", "liblibc", ], } diff --git a/libs/binder/rust/rpcbinder/Android.bp b/libs/binder/rust/rpcbinder/Android.bp index 9771cc9a89..f70ebfc364 100644 --- a/libs/binder/rust/rpcbinder/Android.bp +++ b/libs/binder/rust/rpcbinder/Android.bp @@ -19,6 +19,7 @@ rust_library { "libbinder_rpc_unstable_bindgen_sys", "libbinder_rs", "libdowncast_rs", + "libforeign_types", "liblibc", "liblog_rust", ], diff --git a/libs/binder/rust/rpcbinder/src/lib.rs b/libs/binder/rust/rpcbinder/src/lib.rs index 89a49a468c..1b719aa7d4 100644 --- a/libs/binder/rust/rpcbinder/src/lib.rs +++ b/libs/binder/rust/rpcbinder/src/lib.rs @@ -23,6 +23,4 @@ pub use client::{ get_preconnected_rpc_interface, get_preconnected_rpc_service, get_unix_domain_rpc_interface, get_unix_domain_rpc_service, get_vsock_rpc_interface, get_vsock_rpc_service, }; -pub use server::{ - run_init_unix_domain_rpc_server, run_vsock_rpc_server, run_vsock_rpc_server_with_factory, -}; +pub use server::{run_vsock_rpc_server_with_factory, RpcServer, RpcServerRef}; diff --git a/libs/binder/rust/rpcbinder/src/server.rs b/libs/binder/rust/rpcbinder/src/server.rs index b350a133a8..42f5567542 100644 --- a/libs/binder/rust/rpcbinder/src/server.rs +++ b/libs/binder/rust/rpcbinder/src/server.rs @@ -18,114 +18,89 @@ use binder::{ unstable_api::{AIBinder, AsNative}, SpIBinder, }; +use binder_rpc_unstable_bindgen::ARpcServer; +use foreign_types::{foreign_type, ForeignType, ForeignTypeRef}; +use std::io::{Error, ErrorKind}; use std::{ffi::CString, 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_vsock_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_vsock_server(service, port) -} +foreign_type! { + type CType = binder_rpc_unstable_bindgen::ARpcServer; + fn drop = binder_rpc_unstable_bindgen::ARpcServer_free; -/// Runs a binder RPC server, serving the supplied binder service implementation on the given -/// socket file name. The socket should be initialized in init.rc with the same name. -/// -/// If and when the server is ready for connections, `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_init_unix_domain_rpc_server<F>( - service: SpIBinder, - socket_name: &str, - on_ready: F, -) -> bool -where - F: FnOnce(), -{ - let mut ready_notifier = ReadyNotifier(Some(on_ready)); - ready_notifier.run_init_unix_domain_server(service, socket_name) + /// A type that represents a foreign instance of RpcServer. + #[derive(Debug)] + pub struct RpcServer; + /// A borrowed RpcServer. + pub struct RpcServerRef; } -struct ReadyNotifier<F>(Option<F>) -where - F: FnOnce(); +/// SAFETY - The opaque handle can be cloned freely. +unsafe impl Send for RpcServer {} +/// SAFETY - The underlying C++ RpcServer class is thread-safe. +unsafe impl Sync for RpcServer {} -impl<F> ReadyNotifier<F> -where - F: FnOnce(), -{ - fn run_vsock_server(&mut self, mut service: SpIBinder, port: u32) -> bool { +impl RpcServer { + /// Creates a binder RPC server, serving the supplied binder service implementation on the given + /// vsock port. + pub fn new_vsock(mut service: SpIBinder, port: u32) -> Result<RpcServer, Error> { let service = service.as_native_mut(); - 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. - // RunVsockRpcServerCallback 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::RunVsockRpcServerCallback( - service, - port, - Some(Self::ready_callback), - param, - ) + Self::checked_from_ptr(binder_rpc_unstable_bindgen::ARpcServer_newVsock(service, port)) } } - fn run_init_unix_domain_server(&mut self, mut service: SpIBinder, socket_name: &str) -> bool { + /// Creates a binder RPC server, serving the supplied binder service implementation on the given + /// socket file name. The socket should be initialized in init.rc with the same name. + pub fn new_init_unix_domain( + mut service: SpIBinder, + socket_name: &str, + ) -> Result<RpcServer, Error> { let socket_name = match CString::new(socket_name) { Ok(s) => s, Err(e) => { log::error!("Cannot convert {} to CString. Error: {:?}", socket_name, e); - return false; + return Err(Error::from(ErrorKind::InvalidInput)); } }; let service = service.as_native_mut(); - 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. - // RunInitUnixDomainRpcServer 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::RunInitUnixDomainRpcServer( + Self::checked_from_ptr(binder_rpc_unstable_bindgen::ARpcServer_newInitUnixDomain( service, socket_name.as_ptr(), - Some(Self::ready_callback), - param, - ) + )) + } + } + + 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")); } + Ok(RpcServer::from_ptr(ptr)) } +} - fn as_void_ptr(&mut self) -> *mut raw::c_void { - self as *mut _ as *mut raw::c_void +impl RpcServerRef { + /// Starts a new background thread and calls join(). Returns immediately. + pub fn start(&self) { + unsafe { binder_rpc_unstable_bindgen::ARpcServer_start(self.as_ptr()) }; } - unsafe extern "C" fn ready_callback(param: *mut raw::c_void) { - // SAFETY: This is only ever called by `RunVsockRpcServerCallback`, 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() + /// Joins the RpcServer thread. The call blocks until the server terminates. + /// This must be called from exactly one thread. + pub fn join(&self) { + unsafe { binder_rpc_unstable_bindgen::ARpcServer_join(self.as_ptr()) }; } - fn notify(&mut self) { - if let Some(on_ready) = self.0.take() { - on_ready(); - } + /// Shuts down the running RpcServer. Can be called multiple times and from + /// multiple threads. Called automatically during drop(). + pub fn shutdown(&self) { + unsafe { binder_rpc_unstable_bindgen::ARpcServer_shutdown(self.as_ptr()) }; } } diff --git a/libs/binder/rust/src/native.rs b/libs/binder/rust/src/native.rs index dee05d07cf..6f686fbd93 100644 --- a/libs/binder/rust/src/native.rs +++ b/libs/binder/rust/src/native.rs @@ -22,7 +22,6 @@ use crate::parcel::{BorrowedParcel, Serialize}; use crate::proxy::SpIBinder; use crate::sys; -use lazy_static::lazy_static; use std::convert::TryFrom; use std::ffi::{c_void, CStr, CString}; use std::fs::File; @@ -508,10 +507,8 @@ pub struct LazyServiceGuard { _private: (), } -lazy_static! { - // Count of how many LazyServiceGuard objects are in existence. - static ref GUARD_COUNT: Mutex<u64> = Mutex::new(0); -} +// Count of how many LazyServiceGuard objects are in existence. +static GUARD_COUNT: Mutex<u64> = Mutex::new(0); impl LazyServiceGuard { /// Create a new LazyServiceGuard to prevent the service manager prematurely killing this diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp index 68a827bb3e..02aa45f916 100644 --- a/libs/binder/tests/binderRpcTest.cpp +++ b/libs/binder/tests/binderRpcTest.cpp @@ -913,6 +913,33 @@ TEST_P(BinderRpc, SendTooManyFiles) { EXPECT_EQ(status.transactionError(), BAD_VALUE) << status; } +TEST_P(BinderRpc, AppendInvalidFd) { + auto proc = createRpcTestSocketServerProcess({ + .clientFileDescriptorTransportMode = RpcSession::FileDescriptorTransportMode::UNIX, + .serverSupportedFileDescriptorTransportModes = + {RpcSession::FileDescriptorTransportMode::UNIX}, + }); + + int badFd = fcntl(STDERR_FILENO, F_DUPFD_CLOEXEC, 0); + ASSERT_NE(badFd, -1); + + // Close the file descriptor so it becomes invalid for dup + close(badFd); + + Parcel p1; + p1.markForBinder(proc.rootBinder); + p1.writeInt32(3); + EXPECT_EQ(OK, p1.writeFileDescriptor(badFd, false)); + + Parcel pRaw; + pRaw.markForBinder(proc.rootBinder); + EXPECT_EQ(OK, pRaw.appendFrom(&p1, 0, p1.dataSize())); + + pRaw.setDataPosition(0); + EXPECT_EQ(3, pRaw.readInt32()); + ASSERT_EQ(-1, pRaw.readFileDescriptor()); +} + TEST_P(BinderRpc, WorksWithLibbinderNdkPing) { if constexpr (!kEnableSharedLibs) { GTEST_SKIP() << "Test disabled because Binder was built as a static library"; diff --git a/libs/binder/trusty/include/log/log.h b/libs/binder/trusty/include/log/log.h index bf877a3179..d88d18a7be 100644 --- a/libs/binder/trusty/include/log/log.h +++ b/libs/binder/trusty/include/log/log.h @@ -120,3 +120,7 @@ static inline void __ignore_va_args__(...) {} do { \ TLOGE("android_errorWriteLog: tag:%x subTag:%s\n", tag, subTag); \ } while (0) + +extern "C" inline void __assert(const char* file, int line, const char* str) { + LOG_ALWAYS_FATAL("%s:%d: assertion \"%s\" failed", file, line, str); +} diff --git a/libs/fakeservicemanager/ServiceManager.cpp b/libs/fakeservicemanager/ServiceManager.cpp index 480ec79725..1109ad8594 100644 --- a/libs/fakeservicemanager/ServiceManager.cpp +++ b/libs/fakeservicemanager/ServiceManager.cpp @@ -36,6 +36,9 @@ sp<IBinder> ServiceManager::checkService( const String16& name) const { status_t ServiceManager::addService(const String16& name, const sp<IBinder>& service, bool /*allowIsolated*/, int /*dumpsysFlags*/) { + if (service == nullptr) { + return UNEXPECTED_NULL; + } mNameToService[name] = service; return NO_ERROR; } @@ -103,4 +106,8 @@ std::vector<IServiceManager::ServiceDebugInfo> ServiceManager::getServiceDebugIn std::vector<IServiceManager::ServiceDebugInfo> ret; return ret; } + +void ServiceManager::clear() { + mNameToService.clear(); +} } // namespace android diff --git a/libs/fakeservicemanager/include/fakeservicemanager/ServiceManager.h b/libs/fakeservicemanager/include/fakeservicemanager/ServiceManager.h index ee0637eb7e..ba6bb7d95b 100644 --- a/libs/fakeservicemanager/include/fakeservicemanager/ServiceManager.h +++ b/libs/fakeservicemanager/include/fakeservicemanager/ServiceManager.h @@ -64,6 +64,9 @@ public: std::vector<IServiceManager::ServiceDebugInfo> getServiceDebugInfo() override; + // Clear all of the registered services + void clear(); + private: std::map<String16, sp<IBinder>> mNameToService; }; diff --git a/libs/fakeservicemanager/test_sm.cpp b/libs/fakeservicemanager/test_sm.cpp index 71e5abe126..8682c1c795 100644 --- a/libs/fakeservicemanager/test_sm.cpp +++ b/libs/fakeservicemanager/test_sm.cpp @@ -50,6 +50,12 @@ TEST(AddService, HappyHappy) { IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT), OK); } +TEST(AddService, SadNullBinder) { + auto sm = new ServiceManager(); + EXPECT_EQ(sm->addService(String16("foo"), nullptr, false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT), android::UNEXPECTED_NULL); +} + TEST(AddService, HappyOverExistingService) { auto sm = new ServiceManager(); EXPECT_EQ(sm->addService(String16("foo"), getBinder(), false /*allowIsolated*/, @@ -58,6 +64,15 @@ TEST(AddService, HappyOverExistingService) { IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT), OK); } +TEST(AddService, HappyClearAddedService) { + auto sm = new ServiceManager(); + EXPECT_EQ(sm->addService(String16("foo"), getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT), OK); + EXPECT_NE(sm->getService(String16("foo")), nullptr); + sm->clear(); + EXPECT_EQ(sm->getService(String16("foo")), nullptr); +} + TEST(GetService, HappyHappy) { auto sm = new ServiceManager(); sp<IBinder> service = getBinder(); diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index 6b544b2b96..3b137080ab 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -1107,9 +1107,12 @@ void Surface::applyGrallocMetadataLocked( ATRACE_CALL(); auto& mapper = GraphicBufferMapper::get(); mapper.setDataspace(buffer->handle, static_cast<ui::Dataspace>(queueBufferInput.dataSpace)); - mapper.setSmpte2086(buffer->handle, queueBufferInput.getHdrMetadata().getSmpte2086()); - mapper.setCta861_3(buffer->handle, queueBufferInput.getHdrMetadata().getCta8613()); - mapper.setSmpte2094_40(buffer->handle, queueBufferInput.getHdrMetadata().getHdr10Plus()); + if (mHdrMetadataIsSet & HdrMetadata::SMPTE2086) + mapper.setSmpte2086(buffer->handle, queueBufferInput.getHdrMetadata().getSmpte2086()); + if (mHdrMetadataIsSet & HdrMetadata::CTA861_3) + mapper.setCta861_3(buffer->handle, queueBufferInput.getHdrMetadata().getCta8613()); + if (mHdrMetadataIsSet & HdrMetadata::HDR10PLUS) + mapper.setSmpte2094_40(buffer->handle, queueBufferInput.getHdrMetadata().getHdr10Plus()); } void Surface::onBufferQueuedLocked(int slot, sp<Fence> fence, @@ -2250,6 +2253,7 @@ int Surface::setBuffersDataSpace(Dataspace dataSpace) int Surface::setBuffersSmpte2086Metadata(const android_smpte2086_metadata* metadata) { ALOGV("Surface::setBuffersSmpte2086Metadata"); Mutex::Autolock lock(mMutex); + mHdrMetadataIsSet |= HdrMetadata::SMPTE2086; if (metadata) { mHdrMetadata.smpte2086 = *metadata; mHdrMetadata.validTypes |= HdrMetadata::SMPTE2086; @@ -2262,6 +2266,7 @@ int Surface::setBuffersSmpte2086Metadata(const android_smpte2086_metadata* metad int Surface::setBuffersCta8613Metadata(const android_cta861_3_metadata* metadata) { ALOGV("Surface::setBuffersCta8613Metadata"); Mutex::Autolock lock(mMutex); + mHdrMetadataIsSet |= HdrMetadata::CTA861_3; if (metadata) { mHdrMetadata.cta8613 = *metadata; mHdrMetadata.validTypes |= HdrMetadata::CTA861_3; @@ -2274,6 +2279,7 @@ int Surface::setBuffersCta8613Metadata(const android_cta861_3_metadata* metadata int Surface::setBuffersHdr10PlusMetadata(const size_t size, const uint8_t* metadata) { ALOGV("Surface::setBuffersBlobMetadata"); Mutex::Autolock lock(mMutex); + mHdrMetadataIsSet |= HdrMetadata::HDR10PLUS; if (size > 0) { mHdrMetadata.hdr10plus.assign(metadata, metadata + size); mHdrMetadata.validTypes |= HdrMetadata::HDR10PLUS; diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h index ab9ebaa882..862a4adf2e 100644 --- a/libs/gui/include/gui/Surface.h +++ b/libs/gui/include/gui/Surface.h @@ -462,6 +462,11 @@ protected: // queue operation. There is no HDR metadata by default. HdrMetadata mHdrMetadata; + // mHdrMetadataIsSet is a bitfield to track which HDR metadata has been set. + // Prevent Surface from resetting HDR metadata that was set on a bufer when + // HDR metadata is not set on this Surface. + uint32_t mHdrMetadataIsSet{0}; + // mCrop is the crop rectangle that will be used for the next buffer // that gets queued. It is set by calling setCrop. Rect mCrop; diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp index 4127f7ce10..f646bd4a13 100644 --- a/libs/input/Input.cpp +++ b/libs/input/Input.cpp @@ -64,9 +64,10 @@ float transformAngle(const ui::Transform& transform, float angleRadians) { } bool shouldDisregardTransformation(uint32_t source) { - // Do not apply any transformations to axes from joysticks or touchpads. + // Do not apply any transformations to axes from joysticks, touchpads, or relative mice. return isFromSource(source, AINPUT_SOURCE_CLASS_JOYSTICK) || - isFromSource(source, AINPUT_SOURCE_CLASS_POSITION); + isFromSource(source, AINPUT_SOURCE_CLASS_POSITION) || + isFromSource(source, AINPUT_SOURCE_MOUSE_RELATIVE); } bool shouldDisregardOffset(uint32_t source) { diff --git a/libs/input/tests/InputEvent_test.cpp b/libs/input/tests/InputEvent_test.cpp index a92016ba3b..4b3124636b 100644 --- a/libs/input/tests/InputEvent_test.cpp +++ b/libs/input/tests/InputEvent_test.cpp @@ -715,10 +715,10 @@ TEST_F(MotionEventTest, ApplyTransform) { } TEST_F(MotionEventTest, JoystickAndTouchpadAreNotTransformed) { - constexpr static std::array kNonTransformedSources = {std::pair(AINPUT_SOURCE_TOUCHPAD, - AMOTION_EVENT_ACTION_DOWN), - std::pair(AINPUT_SOURCE_JOYSTICK, - AMOTION_EVENT_ACTION_MOVE)}; + constexpr static std::array kNonTransformedSources = + {std::pair(AINPUT_SOURCE_TOUCHPAD, AMOTION_EVENT_ACTION_DOWN), + std::pair(AINPUT_SOURCE_JOYSTICK, AMOTION_EVENT_ACTION_MOVE), + std::pair(AINPUT_SOURCE_MOUSE_RELATIVE, AMOTION_EVENT_ACTION_MOVE)}; // Create a rotate-90 transform with an offset (like a window which isn't fullscreen). ui::Transform transform(ui::Transform::ROT_90, 800, 400); transform.set(transform.tx() + 20, transform.ty() + 40); @@ -738,7 +738,7 @@ TEST_F(MotionEventTest, JoystickAndTouchpadAreNotTransformed) { TEST_F(MotionEventTest, NonPointerSourcesAreNotTranslated) { constexpr static std::array kNonPointerSources = {std::pair(AINPUT_SOURCE_TRACKBALL, AMOTION_EVENT_ACTION_DOWN), - std::pair(AINPUT_SOURCE_MOUSE_RELATIVE, + std::pair(AINPUT_SOURCE_TOUCH_NAVIGATION, AMOTION_EVENT_ACTION_MOVE)}; // Create a rotate-90 transform with an offset (like a window which isn't fullscreen). ui::Transform transform(ui::Transform::ROT_90, 800, 400); diff --git a/libs/sensor/Android.bp b/libs/sensor/Android.bp index 2b93c6e85e..b6b9cc4099 100644 --- a/libs/sensor/Android.bp +++ b/libs/sensor/Android.bp @@ -21,9 +21,10 @@ package { default_applicable_licenses: ["frameworks_native_license"], } -cc_library_shared { +cc_library { name: "libsensor", + host_supported: true, cflags: [ "-Wall", "-Werror", diff --git a/services/inputflinger/TEST_MAPPING b/services/inputflinger/TEST_MAPPING index b4b617e188..8d5d8839e8 100644 --- a/services/inputflinger/TEST_MAPPING +++ b/services/inputflinger/TEST_MAPPING @@ -15,6 +15,9 @@ "name": "inputflinger_tests" }, { + "name": "libchrome-gestures_test" + }, + { "name": "libpalmrejection_test" }, { diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 564acc09f9..f634ce7bd2 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -4721,10 +4721,13 @@ void InputDispatcher::setInputWindowsLocked( updateWindowHandlesForDisplayLocked(windowInfoHandles, displayId); const std::vector<sp<WindowInfoHandle>>& windowHandles = getWindowHandlesLocked(displayId); - if (mLastHoverWindowHandle && - std::find(windowHandles.begin(), windowHandles.end(), mLastHoverWindowHandle) == - windowHandles.end()) { - mLastHoverWindowHandle = nullptr; + if (mLastHoverWindowHandle) { + const WindowInfo* lastHoverWindowInfo = mLastHoverWindowHandle->getInfo(); + if (lastHoverWindowInfo->displayId == displayId && + std::find(windowHandles.begin(), windowHandles.end(), mLastHoverWindowHandle) == + windowHandles.end()) { + mLastHoverWindowHandle = nullptr; + } } std::optional<FocusResolver::FocusChanges> changes = diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.cpp b/services/inputflinger/reader/mapper/CursorInputMapper.cpp index 76a87bb301..40e9a3cf22 100644 --- a/services/inputflinger/reader/mapper/CursorInputMapper.cpp +++ b/services/inputflinger/reader/mapper/CursorInputMapper.cpp @@ -80,7 +80,7 @@ uint32_t CursorInputMapper::getSources() const { void CursorInputMapper::populateDeviceInfo(InputDeviceInfo* info) { InputMapper::populateDeviceInfo(info); - if (mParameters.mode == Parameters::MODE_POINTER) { + if (mParameters.mode == Parameters::Mode::POINTER) { float minX, minY, maxX, maxY; if (mPointerController->getBounds(&minX, &minY, &maxX, &maxY)) { info->addMotionRange(AMOTION_EVENT_AXIS_X, mSource, minX, maxX, 0.0f, 0.0f, 0.0f); @@ -135,12 +135,12 @@ void CursorInputMapper::configure(nsecs_t when, const InputReaderConfiguration* // Configure device mode. switch (mParameters.mode) { - case Parameters::MODE_POINTER_RELATIVE: + case Parameters::Mode::POINTER_RELATIVE: // Should not happen during first time configuration. ALOGE("Cannot start a device in MODE_POINTER_RELATIVE, starting in MODE_POINTER"); - mParameters.mode = Parameters::MODE_POINTER; + mParameters.mode = Parameters::Mode::POINTER; [[fallthrough]]; - case Parameters::MODE_POINTER: + case Parameters::Mode::POINTER: mSource = AINPUT_SOURCE_MOUSE; mXPrecision = 1.0f; mYPrecision = 1.0f; @@ -148,7 +148,7 @@ void CursorInputMapper::configure(nsecs_t when, const InputReaderConfiguration* mYScale = 1.0f; mPointerController = getContext()->getPointerController(getDeviceId()); break; - case Parameters::MODE_NAVIGATION: + case Parameters::Mode::NAVIGATION: mSource = AINPUT_SOURCE_TRACKBALL; mXPrecision = TRACKBALL_MOVEMENT_THRESHOLD; mYPrecision = TRACKBALL_MOVEMENT_THRESHOLD; @@ -161,12 +161,13 @@ void CursorInputMapper::configure(nsecs_t when, const InputReaderConfiguration* mHWheelScale = 1.0f; } - const bool configurePointerCapture = (!changes && config->pointerCaptureRequest.enable) || - (changes & InputReaderConfiguration::CHANGE_POINTER_CAPTURE); + const bool configurePointerCapture = mParameters.mode != Parameters::Mode::NAVIGATION && + ((!changes && config->pointerCaptureRequest.enable) || + (changes & InputReaderConfiguration::CHANGE_POINTER_CAPTURE)); if (configurePointerCapture) { if (config->pointerCaptureRequest.enable) { - if (mParameters.mode == Parameters::MODE_POINTER) { - mParameters.mode = Parameters::MODE_POINTER_RELATIVE; + if (mParameters.mode == Parameters::Mode::POINTER) { + mParameters.mode = Parameters::Mode::POINTER_RELATIVE; mSource = AINPUT_SOURCE_MOUSE_RELATIVE; // Keep PointerController around in order to preserve the pointer position. mPointerController->fade(PointerControllerInterface::Transition::IMMEDIATE); @@ -174,8 +175,8 @@ void CursorInputMapper::configure(nsecs_t when, const InputReaderConfiguration* ALOGE("Cannot request pointer capture, device is not in MODE_POINTER"); } } else { - if (mParameters.mode == Parameters::MODE_POINTER_RELATIVE) { - mParameters.mode = Parameters::MODE_POINTER; + if (mParameters.mode == Parameters::Mode::POINTER_RELATIVE) { + mParameters.mode = Parameters::Mode::POINTER; mSource = AINPUT_SOURCE_MOUSE; } else { ALOGE("Cannot release pointer capture, device is not in MODE_POINTER_RELATIVE"); @@ -190,8 +191,8 @@ void CursorInputMapper::configure(nsecs_t when, const InputReaderConfiguration* if (!changes || (changes & InputReaderConfiguration::CHANGE_POINTER_SPEED) || configurePointerCapture) { - if (config->pointerCaptureRequest.enable) { - // Disable any acceleration or scaling when Pointer Capture is enabled. + if (mParameters.mode == Parameters::Mode::POINTER_RELATIVE) { + // Disable any acceleration or scaling for the pointer when Pointer Capture is enabled. mPointerVelocityControl.setParameters(FLAT_VELOCITY_CONTROL_PARAMS); mWheelXVelocityControl.setParameters(FLAT_VELOCITY_CONTROL_PARAMS); mWheelYVelocityControl.setParameters(FLAT_VELOCITY_CONTROL_PARAMS); @@ -202,7 +203,8 @@ void CursorInputMapper::configure(nsecs_t when, const InputReaderConfiguration* } } - if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) { + if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO) || + configurePointerCapture) { mOrientation = DISPLAY_ORIENTATION_0; const bool isOrientedDevice = (mParameters.orientationAware && mParameters.hasAssociatedDisplay); @@ -211,8 +213,9 @@ void CursorInputMapper::configure(nsecs_t when, const InputReaderConfiguration* // anything if the device is already orientation-aware. If the device is not // orientation-aware, then we need to apply the inverse rotation of the display so that // when the display rotation is applied later as a part of the per-window transform, we - // get the expected screen coordinates. - if (!isOrientedDevice) { + // get the expected screen coordinates. When pointer capture is enabled, we do not apply any + // rotations and report values directly from the input device. + if (!isOrientedDevice && mParameters.mode != Parameters::Mode::POINTER_RELATIVE) { std::optional<DisplayViewport> internalViewport = config->getDisplayViewportByType(ViewportType::INTERNAL); if (internalViewport) { @@ -225,12 +228,12 @@ void CursorInputMapper::configure(nsecs_t when, const InputReaderConfiguration* } void CursorInputMapper::configureParameters() { - mParameters.mode = Parameters::MODE_POINTER; + mParameters.mode = Parameters::Mode::POINTER; String8 cursorModeString; if (getDeviceContext().getConfiguration().tryGetProperty(String8("cursor.mode"), cursorModeString)) { if (cursorModeString == "navigation") { - mParameters.mode = Parameters::MODE_NAVIGATION; + mParameters.mode = Parameters::Mode::NAVIGATION; } else if (cursorModeString != "pointer" && cursorModeString != "default") { ALOGW("Invalid value for cursor.mode: '%s'", cursorModeString.string()); } @@ -241,7 +244,7 @@ void CursorInputMapper::configureParameters() { mParameters.orientationAware); mParameters.hasAssociatedDisplay = false; - if (mParameters.mode == Parameters::MODE_POINTER || mParameters.orientationAware) { + if (mParameters.mode == Parameters::Mode::POINTER || mParameters.orientationAware) { mParameters.hasAssociatedDisplay = true; } } @@ -250,21 +253,7 @@ void CursorInputMapper::dumpParameters(std::string& dump) { dump += INDENT3 "Parameters:\n"; dump += StringPrintf(INDENT4 "HasAssociatedDisplay: %s\n", toString(mParameters.hasAssociatedDisplay)); - - switch (mParameters.mode) { - case Parameters::MODE_POINTER: - dump += INDENT4 "Mode: pointer\n"; - break; - case Parameters::MODE_POINTER_RELATIVE: - dump += INDENT4 "Mode: relative pointer\n"; - break; - case Parameters::MODE_NAVIGATION: - dump += INDENT4 "Mode: navigation\n"; - break; - default: - ALOG_ASSERT(false); - } - + dump += StringPrintf(INDENT4 "Mode: %s\n", ftl::enum_string(mParameters.mode).c_str()); dump += StringPrintf(INDENT4 "OrientationAware: %s\n", toString(mParameters.orientationAware)); } @@ -490,7 +479,7 @@ int32_t CursorInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCod std::optional<int32_t> CursorInputMapper::getAssociatedDisplayId() { if (mParameters.hasAssociatedDisplay) { - if (mParameters.mode == Parameters::MODE_POINTER) { + if (mParameters.mode == Parameters::Mode::POINTER) { return std::make_optional(mPointerController->getDisplayId()); } else { // If the device is orientationAware and not a mouse, diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.h b/services/inputflinger/reader/mapper/CursorInputMapper.h index c84c6c4229..75aeffb846 100644 --- a/services/inputflinger/reader/mapper/CursorInputMapper.h +++ b/services/inputflinger/reader/mapper/CursorInputMapper.h @@ -74,10 +74,17 @@ private: // Immutable configuration parameters. struct Parameters { - enum Mode { - MODE_POINTER, - MODE_POINTER_RELATIVE, - MODE_NAVIGATION, + enum class Mode { + // In POINTER mode, the device is a mouse that controls the mouse cursor on the screen, + // reporting absolute screen locations using SOURCE_MOUSE. + POINTER, + // A mouse device in POINTER mode switches to the POINTER_RELATIVE mode when Pointer + // Capture is enabled, and reports relative values only using SOURCE_MOUSE_RELATIVE. + POINTER_RELATIVE, + // A device in NAVIGATION mode emits relative values using SOURCE_TRACKBALL. + NAVIGATION, + + ftl_last = NAVIGATION, }; Mode mode; diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index df4307101f..bb8e5661b6 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -2131,6 +2131,59 @@ TEST_F(InputDispatcherTest, HoverEnterMouseClickAndHoverExit) { ADISPLAY_ID_DEFAULT, 0 /* expectedFlag */); } +TEST_F(InputDispatcherTest, HoverEnterMoveRemoveWindowsInSecondDisplay) { + std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); + sp<FakeWindowHandle> windowDefaultDisplay = + sp<FakeWindowHandle>::make(application, mDispatcher, "DefaultDisplay", + ADISPLAY_ID_DEFAULT); + windowDefaultDisplay->setFrame(Rect(0, 0, 600, 800)); + sp<FakeWindowHandle> windowSecondDisplay = + sp<FakeWindowHandle>::make(application, mDispatcher, "SecondDisplay", + SECOND_DISPLAY_ID); + windowSecondDisplay->setFrame(Rect(0, 0, 600, 800)); + + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {windowDefaultDisplay}}, + {SECOND_DISPLAY_ID, {windowSecondDisplay}}}); + + // Set cursor position in window in default display and check that hover enter and move + // events are generated. + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionEvent(mDispatcher, + MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, + AINPUT_SOURCE_MOUSE) + .displayId(ADISPLAY_ID_DEFAULT) + .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_MOUSE) + .x(300) + .y(600)) + .build())); + windowDefaultDisplay->consumeEvent(AINPUT_EVENT_TYPE_MOTION, AMOTION_EVENT_ACTION_HOVER_ENTER, + ADISPLAY_ID_DEFAULT, 0 /* expectedFlag */); + windowDefaultDisplay->consumeEvent(AINPUT_EVENT_TYPE_MOTION, AMOTION_EVENT_ACTION_HOVER_MOVE, + ADISPLAY_ID_DEFAULT, 0 /* expectedFlag */); + + // Remove all windows in secondary display and check that no event happens on window in + // primary display. + mDispatcher->setInputWindows({{SECOND_DISPLAY_ID, {}}}); + windowDefaultDisplay->assertNoEvents(); + + // Move cursor position in window in default display and check that only hover move + // event is generated and not hover enter event. + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {windowDefaultDisplay}}, + {SECOND_DISPLAY_ID, {windowSecondDisplay}}}); + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionEvent(mDispatcher, + MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, + AINPUT_SOURCE_MOUSE) + .displayId(ADISPLAY_ID_DEFAULT) + .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_MOUSE) + .x(400) + .y(700)) + .build())); + windowDefaultDisplay->consumeEvent(AINPUT_EVENT_TYPE_MOTION, AMOTION_EVENT_ACTION_HOVER_MOVE, + ADISPLAY_ID_DEFAULT, 0 /* expectedFlag */); + windowDefaultDisplay->assertNoEvents(); +} + TEST_F(InputDispatcherTest, DispatchMouseEventsUnderCursor) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index db4669967f..5d6ec7487a 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -4974,6 +4974,48 @@ TEST_F(CursorInputMapperTest, PointerCaptureDisablesVelocityProcessing) { ASSERT_EQ(20, args.pointerCoords[0].getY()); } +TEST_F(CursorInputMapperTest, PointerCaptureDisablesOrientationChanges) { + addConfigurationProperty("cursor.mode", "pointer"); + CursorInputMapper& mapper = addMapperAndConfigure<CursorInputMapper>(); + + NotifyDeviceResetArgs resetArgs; + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs)); + ASSERT_EQ(ARBITRARY_TIME, resetArgs.eventTime); + ASSERT_EQ(DEVICE_ID, resetArgs.deviceId); + + // Ensure the display is rotated. + prepareDisplay(DISPLAY_ORIENTATION_90); + + NotifyMotionArgs args; + + // Verify that the coordinates are rotated. + process(mapper, ARBITRARY_TIME, READ_TIME, EV_REL, REL_X, 10); + process(mapper, ARBITRARY_TIME, READ_TIME, EV_REL, REL_Y, 20); + process(mapper, ARBITRARY_TIME, READ_TIME, EV_SYN, SYN_REPORT, 0); + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); + ASSERT_EQ(AINPUT_SOURCE_MOUSE, args.source); + ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, args.action); + ASSERT_EQ(-20, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X)); + ASSERT_EQ(10, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y)); + + // Enable Pointer Capture. + mFakePolicy->setPointerCapture(true); + configureDevice(InputReaderConfiguration::CHANGE_POINTER_CAPTURE); + NotifyPointerCaptureChangedArgs captureArgs; + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyCaptureWasCalled(&captureArgs)); + ASSERT_TRUE(captureArgs.request.enable); + + // Move and verify rotation is not applied. + process(mapper, ARBITRARY_TIME, READ_TIME, EV_REL, REL_X, 10); + process(mapper, ARBITRARY_TIME, READ_TIME, EV_REL, REL_Y, 20); + process(mapper, ARBITRARY_TIME, READ_TIME, EV_SYN, SYN_REPORT, 0); + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); + ASSERT_EQ(AINPUT_SOURCE_MOUSE_RELATIVE, args.source); + ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action); + ASSERT_EQ(10, args.pointerCoords[0].getX()); + ASSERT_EQ(20, args.pointerCoords[0].getY()); +} + TEST_F(CursorInputMapperTest, Process_ShouldHandleDisplayId) { CursorInputMapper& mapper = addMapperAndConfigure<CursorInputMapper>(); diff --git a/services/sensorservice/aidl/Android.bp b/services/sensorservice/aidl/Android.bp index bbf49dac9e..34d1de72f9 100644 --- a/services/sensorservice/aidl/Android.bp +++ b/services/sensorservice/aidl/Android.bp @@ -7,7 +7,7 @@ package { default_applicable_licenses: ["frameworks_native_license"], } -cc_library_shared { +cc_library { name: "libsensorserviceaidl", srcs: [ "EventQueue.cpp", @@ -15,6 +15,7 @@ cc_library_shared { "SensorManager.cpp", "utils.cpp", ], + host_supported: true, cflags: [ "-Wall", "-Werror", diff --git a/services/sensorservice/aidl/EventQueue.cpp b/services/sensorservice/aidl/EventQueue.cpp index d4e8906b69..c3947098c3 100644 --- a/services/sensorservice/aidl/EventQueue.cpp +++ b/services/sensorservice/aidl/EventQueue.cpp @@ -34,7 +34,7 @@ public: std::shared_ptr<IEventQueueCallback> callback) : mQueue(queue), mCallback(callback) {} - int handleEvent(__unused int fd, __unused int events, __unused void* data) { + int handleEvent(int /* fd */, int /* events */, void* /* data */) { ASensorEvent event; ssize_t actual; @@ -66,7 +66,6 @@ EventQueue::EventQueue(std::shared_ptr<IEventQueueCallback> callback, sp<::andro new EventQueueLooperCallback(internalQueue, callback), nullptr); } -// FIXME why was this on onLastStrongRef instead of dtor? EventQueue::~EventQueue() { mLooper->removeFd(mInternalQueue->getFd()); } diff --git a/services/sensorservice/aidl/fuzzer/Android.bp b/services/sensorservice/aidl/fuzzer/Android.bp new file mode 100644 index 0000000000..0d6e476e70 --- /dev/null +++ b/services/sensorservice/aidl/fuzzer/Android.bp @@ -0,0 +1,52 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + +cc_fuzz { + name: "libsensorserviceaidl_fuzzer", + defaults: [ + "service_fuzzer_defaults", + ], + host_supported: true, + static_libs: [ + "libsensorserviceaidl", + "libpermission", + "android.frameworks.sensorservice-V1-ndk", + "android.hardware.sensors-V1-convert", + "android.hardware.sensors-V1-ndk", + "android.hardware.common-V2-ndk", + "libsensor", + "libfakeservicemanager", + "libcutils", + "liblog", + ], + srcs: [ + "fuzzer.cpp", + ], + fuzz_config: { + cc: [ + "android-sensors@google.com", + "devinmoore@google.com", + ], + }, + sanitize: { + misc_undefined: [ + "signed-integer-overflow", + "unsigned-integer-overflow", + ], + diag: { + misc_undefined: [ + "signed-integer-overflow", + "unsigned-integer-overflow", + ], + }, + address: true, + integer_overflow: true, + }, + +} diff --git a/services/sensorservice/aidl/fuzzer/fuzzer.cpp b/services/sensorservice/aidl/fuzzer/fuzzer.cpp new file mode 100644 index 0000000000..1b63d76953 --- /dev/null +++ b/services/sensorservice/aidl/fuzzer/fuzzer.cpp @@ -0,0 +1,53 @@ +/* + * 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. + */ +#include <fuzzbinder/libbinder_ndk_driver.h> +#include <fuzzer/FuzzedDataProvider.h> + +#include <ServiceManager.h> +#include <android-base/logging.h> +#include <android/binder_interface_utils.h> +#include <fuzzbinder/random_binder.h> +#include <sensorserviceaidl/SensorManagerAidl.h> + +using android::fuzzService; +using android::frameworks::sensorservice::implementation::SensorManagerAidl; +using ndk::SharedRefBase; + +[[clang::no_destroy]] static std::once_flag gSmOnce; + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + static android::sp<android::ServiceManager> fakeServiceManager = new android::ServiceManager(); + std::call_once(gSmOnce, [&] { setDefaultServiceManager(fakeServiceManager); }); + fakeServiceManager->clear(); + + FuzzedDataProvider fdp(data, size); + android::sp<android::IBinder> binder = android::getRandomBinder(&fdp); + if (binder == nullptr) { + // Nothing to do if we get a null binder. It will cause SensorManager to + // hang while trying to get sensorservice. + return 0; + } + + CHECK(android::NO_ERROR == fakeServiceManager->addService(android::String16("sensorservice"), + binder)); + + std::shared_ptr<SensorManagerAidl> sensorService = + ndk::SharedRefBase::make<SensorManagerAidl>(nullptr); + + fuzzService(sensorService->asBinder().get(), std::move(fdp)); + + return 0; +} |