diff options
77 files changed, 2613 insertions, 499 deletions
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp index 6576ffdc54..c407f486f0 100644 --- a/cmds/dumpstate/dumpstate.cpp +++ b/cmds/dumpstate/dumpstate.cpp @@ -170,6 +170,7 @@ void add_mountinfo(); #define ALT_PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops-0" #define BLK_DEV_SYS_DIR "/sys/block" +#define AFLAGS "/system/bin/aflags" #define RECOVERY_DIR "/cache/recovery" #define RECOVERY_DATA_DIR "/data/misc/recovery" #define UPDATE_ENGINE_LOG_DIR "/data/misc/update_engine_log" @@ -1785,6 +1786,10 @@ Dumpstate::RunStatus Dumpstate::dumpstate() { RunCommand("ACONFIG FLAGS", {PRINT_FLAGS}, CommandOptions::WithTimeout(10).Always().DropRoot().Build()); + RunCommand("ACONFIG FLAGS DUMP", {AFLAGS, "list"}, + CommandOptions::WithTimeout(10).Always().AsRootIfAvailable().Build()); + RunCommand("WHICH ACONFIG FLAG STORAGE", {AFLAGS, "which-backing"}, + CommandOptions::WithTimeout(10).Always().AsRootIfAvailable().Build()); RunCommand("STORAGED IO INFO", {"storaged", "-u", "-p"}); diff --git a/libs/arect/Android.bp b/libs/arect/Android.bp index 319716ec81..cbba7118b6 100644 --- a/libs/arect/Android.bp +++ b/libs/arect/Android.bp @@ -40,6 +40,7 @@ ndk_headers { cc_library_headers { name: "libarect_headers", + host_supported: true, vendor_available: true, min_sdk_version: "29", // TODO(b/153609531): remove when no longer needed. diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp index 379b609e9f..6903cb5d68 100644 --- a/libs/binder/Android.bp +++ b/libs/binder/Android.bp @@ -489,6 +489,7 @@ cc_defaults { "ProcessState.cpp", "Static.cpp", ":libbinder_aidl", + ":libbinder_accessor_aidl", ":libbinder_device_interface_sources", ], target: { @@ -801,7 +802,6 @@ filegroup { "aidl/android/os/IServiceManager.aidl", "aidl/android/os/Service.aidl", "aidl/android/os/ServiceDebugInfo.aidl", - ":libbinder_accessor_aidl", ], path: "aidl", } @@ -812,26 +812,7 @@ filegroup { "aidl/android/os/IAccessor.aidl", ], path: "aidl", -} - -// TODO(b/353492849): Make this interface private to libbinder. -aidl_interface { - name: "android.os.accessor", - srcs: [":libbinder_accessor_aidl"], - unstable: true, - backend: { - rust: { - enabled: true, - apex_available: [ - "com.android.virt", - ], - }, - }, - visibility: [ - ":__subpackages__", - "//system/tools/aidl:__subpackages__", - "//packages/modules/Virtualization:__subpackages__", - ], + visibility: [":__subpackages__"], } aidl_interface { diff --git a/libs/binder/BackendUnifiedServiceManager.cpp b/libs/binder/BackendUnifiedServiceManager.cpp index 5680798d0d..52b485a6f6 100644 --- a/libs/binder/BackendUnifiedServiceManager.cpp +++ b/libs/binder/BackendUnifiedServiceManager.cpp @@ -34,37 +34,47 @@ using AidlServiceManager = android::os::IServiceManager; using IAccessor = android::os::IAccessor; static const char* kStaticCachableList[] = { + // go/keep-sorted start + "accessibility", + "account", "activity", - "android.hardware.thermal.IThermal/default", - "android.hardware.power.IPower/default", - "android.frameworks.stats.IStats/default", - "android.system.suspend.ISystemSuspend/default", + "alarm", + "android.system.keystore2.IKeystoreService/default", "appops", "audio", "batterystats", "carrier_config", "connectivity", + "content", "content_capture", "device_policy", "display", "dropbox", "econtroller", + "graphicsstats", + "input", + "input_method", "isub", + "jobscheduler", "legacy_permission", "location", "media.extractor", "media.metrics", "media.player", "media.resource_manager", + "media_resource_monitor", + "mount", "netd_listener", "netstats", "network_management", "nfc", + "notification", + "package", "package_native", "performance_hint", "permission", - "permissionmgr", "permission_checker", + "permissionmgr", "phone", "platform_compat", "power", @@ -76,9 +86,12 @@ static const char* kStaticCachableList[] = { "time_detector", "trust", "uimode", + "user", "virtualdevice", "virtualdevice_native", "webviewupdate", + "window", + // go/keep-sorted end }; bool BinderCacheWithInvalidation::isClientSideCachingEnabled(const std::string& serviceName) { diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp index 1d26d8543d..6698d0c0cd 100644 --- a/libs/binder/IPCThreadState.cpp +++ b/libs/binder/IPCThreadState.cpp @@ -232,6 +232,15 @@ static const void* printReturnCommand(std::ostream& out, const void* _cmd) { return cmd; } +static void printReturnCommandParcel(std::ostream& out, const Parcel& parcel) { + const void* cmds = parcel.data(); + out << "\t" << HexDump(cmds, parcel.dataSize()) << "\n"; + IF_LOG_COMMANDS() { + const void* end = parcel.data() + parcel.dataSize(); + while (cmds < end) cmds = printReturnCommand(out, cmds); + } +} + static const void* printCommand(std::ostream& out, const void* _cmd) { static const size_t N = sizeof(kCommandStrings)/sizeof(kCommandStrings[0]); const int32_t* cmd = (const int32_t*)_cmd; @@ -1235,13 +1244,15 @@ status_t IPCThreadState::talkWithDriver(bool doReceive) if (err >= NO_ERROR) { if (bwr.write_consumed > 0) { - if (bwr.write_consumed < mOut.dataSize()) + if (bwr.write_consumed < mOut.dataSize()) { + std::ostringstream logStream; + printReturnCommandParcel(logStream, mIn); LOG_ALWAYS_FATAL("Driver did not consume write buffer. " - "err: %s consumed: %zu of %zu", - statusToString(err).c_str(), - (size_t)bwr.write_consumed, - mOut.dataSize()); - else { + "err: %s consumed: %zu of %zu.\n" + "Return command: %s", + statusToString(err).c_str(), (size_t)bwr.write_consumed, + mOut.dataSize(), logStream.str().c_str()); + } else { mOut.setDataSize(0); processPostWriteDerefs(); } @@ -1252,14 +1263,8 @@ status_t IPCThreadState::talkWithDriver(bool doReceive) } IF_LOG_COMMANDS() { std::ostringstream logStream; - logStream << "Remaining data size: " << mOut.dataSize() << "\n"; - logStream << "Received commands from driver: "; - const void* cmds = mIn.data(); - const void* end = mIn.data() + mIn.dataSize(); - logStream << "\t" << HexDump(cmds, mIn.dataSize()) << "\n"; - while (cmds < end) cmds = printReturnCommand(logStream, cmds); - std::string message = logStream.str(); - ALOGI("%s", message.c_str()); + printReturnCommandParcel(logStream, mIn); + ALOGI("%s", logStream.str().c_str()); } return NO_ERROR; } diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp index 88761d772f..32388db076 100644 --- a/libs/binder/IServiceManager.cpp +++ b/libs/binder/IServiceManager.cpp @@ -157,12 +157,21 @@ protected: class AccessorProvider { public: - AccessorProvider(RpcAccessorProvider&& provider) : mProvider(std::move(provider)) {} - sp<IBinder> provide(const String16& name) { return mProvider(name); } + AccessorProvider(std::set<std::string>&& instances, RpcAccessorProvider&& provider) + : mInstances(std::move(instances)), mProvider(std::move(provider)) {} + sp<IBinder> provide(const String16& name) { + if (mInstances.count(String8(name).c_str()) > 0) { + return mProvider(name); + } else { + return nullptr; + } + } + const std::set<std::string>& instances() { return mInstances; } private: AccessorProvider() = delete; + std::set<std::string> mInstances; RpcAccessorProvider mProvider; }; @@ -318,10 +327,32 @@ sp<IServiceManager> getServiceManagerShimFromAidlServiceManagerForTests( return sp<CppBackendShim>::make(sp<BackendUnifiedServiceManager>::make(sm)); } -std::weak_ptr<AccessorProvider> addAccessorProvider(RpcAccessorProvider&& providerCallback) { +// gAccessorProvidersMutex must be locked already +static bool isInstanceProvidedLocked(const std::string& instance) { + return gAccessorProviders.end() != + std::find_if(gAccessorProviders.begin(), gAccessorProviders.end(), + [&instance](const AccessorProviderEntry& entry) { + return entry.mProvider->instances().count(instance) > 0; + }); +} + +std::weak_ptr<AccessorProvider> addAccessorProvider(std::set<std::string>&& instances, + RpcAccessorProvider&& providerCallback) { + if (instances.empty()) { + ALOGE("Set of instances is empty! Need a non empty set of instances to provide for."); + return std::weak_ptr<AccessorProvider>(); + } std::lock_guard<std::mutex> lock(gAccessorProvidersMutex); + for (const auto& instance : instances) { + if (isInstanceProvidedLocked(instance)) { + ALOGE("The instance %s is already provided for by a previously added " + "RpcAccessorProvider.", + instance.c_str()); + return std::weak_ptr<AccessorProvider>(); + } + } std::shared_ptr<AccessorProvider> provider = - std::make_shared<AccessorProvider>(std::move(providerCallback)); + std::make_shared<AccessorProvider>(std::move(instances), std::move(providerCallback)); std::weak_ptr<AccessorProvider> receipt = provider; gAccessorProviders.push_back(AccessorProviderEntry(std::move(provider))); @@ -331,8 +362,9 @@ std::weak_ptr<AccessorProvider> addAccessorProvider(RpcAccessorProvider&& provid status_t removeAccessorProvider(std::weak_ptr<AccessorProvider> wProvider) { std::shared_ptr<AccessorProvider> provider = wProvider.lock(); if (provider == nullptr) { - ALOGE("The provider supplied to removeAccessorProvider has already been removed."); - return NAME_NOT_FOUND; + ALOGE("The provider supplied to removeAccessorProvider has already been removed or the " + "argument to this function was nullptr."); + return BAD_VALUE; } std::lock_guard<std::mutex> lock(gAccessorProvidersMutex); size_t sizeBefore = gAccessorProviders.size(); @@ -354,7 +386,7 @@ status_t validateAccessor(const String16& instance, const sp<IBinder>& binder) { ALOGE("Binder is null"); return BAD_VALUE; } - sp<IAccessor> accessor = interface_cast<IAccessor>(binder); + sp<IAccessor> accessor = checked_interface_cast<IAccessor>(binder); if (accessor == nullptr) { ALOGE("This binder for %s is not an IAccessor binder", String8(instance).c_str()); return BAD_TYPE; @@ -388,6 +420,28 @@ sp<IBinder> createAccessor(const String16& instance, return binder; } +status_t delegateAccessor(const String16& name, const sp<IBinder>& accessor, + sp<IBinder>* delegator) { + LOG_ALWAYS_FATAL_IF(delegator == nullptr, "delegateAccessor called with a null out param"); + if (accessor == nullptr) { + ALOGW("Accessor argument to delegateAccessor is null."); + *delegator = nullptr; + return OK; + } + status_t status = validateAccessor(name, accessor); + if (status != OK) { + ALOGE("The provided accessor binder is not an IAccessor for instance %s. Status: " + "%s", + String8(name).c_str(), statusToString(status).c_str()); + return status; + } + // validateAccessor already called checked_interface_cast and made sure this + // is a valid accessor object. + *delegator = sp<android::os::IAccessorDelegator>::make(interface_cast<IAccessor>(accessor)); + + return OK; +} + #if !defined(__ANDROID_VNDK__) // IPermissionController is not accessible to vendors diff --git a/libs/binder/OS.h b/libs/binder/OS.h index 04869a170f..64b1fd48fd 100644 --- a/libs/binder/OS.h +++ b/libs/binder/OS.h @@ -27,6 +27,7 @@ namespace android::binder::os { LIBBINDER_EXPORTED void trace_begin(uint64_t tag, const char* name); LIBBINDER_EXPORTED void trace_end(uint64_t tag); LIBBINDER_EXPORTED void trace_int(uint64_t tag, const char* name, int32_t value); +LIBBINDER_EXPORTED uint64_t get_trace_enabled_tags(); status_t setNonBlocking(borrowed_fd fd); diff --git a/libs/binder/OS_android.cpp b/libs/binder/OS_android.cpp index 893ee15578..4e9230ce58 100644 --- a/libs/binder/OS_android.cpp +++ b/libs/binder/OS_android.cpp @@ -48,6 +48,10 @@ void trace_int(uint64_t tag, const char* name, int32_t value) { atrace_int(tag, name, value); } +uint64_t get_trace_enabled_tags() { + return atrace_enabled_tags; +} + } // namespace os // Legacy trace symbol. To be removed once all of downstream rebuilds. diff --git a/libs/binder/OS_non_android_linux.cpp b/libs/binder/OS_non_android_linux.cpp index 0c64eb61c6..6bba823897 100644 --- a/libs/binder/OS_non_android_linux.cpp +++ b/libs/binder/OS_non_android_linux.cpp @@ -41,6 +41,10 @@ void trace_end(uint64_t) {} void trace_int(uint64_t, const char*, int32_t) {} +uint64_t get_trace_enabled_tags() { + return 0; +} + uint64_t GetThreadId() { return syscall(__NR_gettid); } diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp index 4b7af45739..37113629a8 100644 --- a/libs/binder/Parcel.cpp +++ b/libs/binder/Parcel.cpp @@ -683,7 +683,7 @@ status_t Parcel::appendFrom(const Parcel* parcel, size_t offset, size_t len) { return err; } -int Parcel::compareData(const Parcel& other) { +int Parcel::compareData(const Parcel& other) const { size_t size = dataSize(); if (size != other.dataSize()) { return size < other.dataSize() ? -1 : 1; diff --git a/libs/binder/Status.cpp b/libs/binder/Status.cpp index dba65878fb..9a98097af8 100644 --- a/libs/binder/Status.cpp +++ b/libs/binder/Status.cpp @@ -99,27 +99,28 @@ status_t Status::readFromParcel(const Parcel& parcel) { return status; } - // Skip over fat response headers. Not used (or propagated) in native code. - if (mException == EX_HAS_REPLY_HEADER) { - // Note that the header size includes the 4 byte size field. - const size_t header_start = parcel.dataPosition(); - // Get available size before reading more - const size_t header_avail = parcel.dataAvail(); - - int32_t header_size; - status = parcel.readInt32(&header_size); + if (mException == EX_HAS_NOTED_APPOPS_REPLY_HEADER) { + status = skipUnusedHeader(parcel); + if (status != OK) { + setFromStatusT(status); + return status; + } + // Read next exception code. + status = parcel.readInt32(&mException); if (status != OK) { setFromStatusT(status); return status; } + } - if (header_size < 0 || static_cast<size_t>(header_size) > header_avail) { - android_errorWriteLog(0x534e4554, "132650049"); - setFromStatusT(UNKNOWN_ERROR); - return UNKNOWN_ERROR; + // Skip over fat response headers. Not used (or propagated) in native code. + if (mException == EX_HAS_REPLY_HEADER) { + status = skipUnusedHeader(parcel); + if (status != OK) { + setFromStatusT(status); + return status; } - parcel.setDataPosition(header_start + header_size); // And fat response headers are currently only used when there are no // exceptions, so act like there was no error. mException = EX_NONE; @@ -257,5 +258,28 @@ String8 Status::toString8() const { return ret; } +status_t Status::skipUnusedHeader(const Parcel& parcel) { + // Note that the header size includes the 4 byte size field. + const size_t header_start = parcel.dataPosition(); + // Get available size before reading more + const size_t header_avail = parcel.dataAvail(); + + int32_t header_size; + status_t status = parcel.readInt32(&header_size); + ALOGD("Skip unused header. exception code: %d, start: %zu, size: %d.", + mException, header_start, header_size); + if (status != OK) { + return status; + } + + if (header_size < 0 || static_cast<size_t>(header_size) > header_avail) { + android_errorWriteLog(0x534e4554, "132650049"); + return UNKNOWN_ERROR; + } + + parcel.setDataPosition(header_start + header_size); + return OK; +} + } // namespace binder } // namespace android diff --git a/libs/binder/include/binder/IServiceManager.h b/libs/binder/include/binder/IServiceManager.h index 879f319c5e..81f7cdbcb1 100644 --- a/libs/binder/include/binder/IServiceManager.h +++ b/libs/binder/include/binder/IServiceManager.h @@ -24,6 +24,7 @@ #include <utils/String16.h> #include <utils/Vector.h> #include <optional> +#include <set> namespace android { @@ -224,20 +225,36 @@ LIBBINDER_EXPORTED bool checkPermission(const String16& permission, pid_t pid, u typedef std::function<status_t(const String16& name, sockaddr* outAddr, socklen_t addrSize)> RpcSocketAddressProvider; -typedef std::function<sp<IBinder>(const String16& name)> RpcAccessorProvider; +/** + * This callback provides a way for clients to get access to remote services by + * providing an Accessor object from libbinder that can connect to the remote + * service over sockets. + * + * \param instance name of the service that the callback will provide an + * Accessor for. The provided accessor will be used to set up a client + * RPC connection in libbinder in order to return a binder for the + * associated remote service. + * + * \return IBinder of the Accessor object that libbinder implements. + * nullptr if the provider callback doesn't know how to reach the + * service or doesn't want to provide access for any other reason. + */ +typedef std::function<sp<IBinder>(const String16& instance)> RpcAccessorProvider; class AccessorProvider; /** - * Register an accessor provider for the service manager APIs. + * Register a RpcAccessorProvider for the service manager APIs. * + * \param instances that the RpcAccessorProvider knows about and can provide an + * Accessor for. * \param provider callback that generates Accessors. * * \return A pointer used as a recept for the successful addition of the * AccessorProvider. This is needed to unregister it later. */ [[nodiscard]] LIBBINDER_EXPORTED std::weak_ptr<AccessorProvider> addAccessorProvider( - RpcAccessorProvider&& providerCallback); + std::set<std::string>&& instances, RpcAccessorProvider&& providerCallback); /** * Remove an accessor provider using the pointer provided by addAccessorProvider @@ -274,6 +291,28 @@ LIBBINDER_EXPORTED sp<IBinder> createAccessor(const String16& instance, * \return OK if the binder is an IAccessor for `instance` */ LIBBINDER_EXPORTED status_t validateAccessor(const String16& instance, const sp<IBinder>& binder); + +/** + * Have libbinder wrap this IAccessor binder in an IAccessorDelegator and return + * it. + * + * This is required only in very specific situations when the process that has + * permissions to connect the to RPC service's socket and create the FD for it + * is in a separate process from this process that wants to service the Accessor + * binder and the communication between these two processes is binder RPC. This + * is needed because the binder passed over the binder RPC connection can not be + * used as a kernel binder, and needs to be wrapped by a kernel binder that can + * then be registered with service manager. + * + * \param instance name of the Accessor. + * \param binder to wrap in a Delegator and register with service manager. + * \param outDelegator the wrapped kernel binder for IAccessorDelegator + * + * \return OK if the binder is an IAccessor for `instance` and the delegator was + * successfully created. + */ +LIBBINDER_EXPORTED status_t delegateAccessor(const String16& name, const sp<IBinder>& accessor, + sp<IBinder>* delegator); #endif // __TRUSTY__ #ifndef __ANDROID__ diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h index 5cc0830c88..15a0da765e 100644 --- a/libs/binder/include/binder/Parcel.h +++ b/libs/binder/include/binder/Parcel.h @@ -92,7 +92,7 @@ public: LIBBINDER_EXPORTED status_t appendFrom(const Parcel* parcel, size_t start, size_t len); - LIBBINDER_EXPORTED int compareData(const Parcel& other); + LIBBINDER_EXPORTED int compareData(const Parcel& other) const; LIBBINDER_EXPORTED status_t compareDataInRange(size_t thisOffset, const Parcel& other, size_t otherOffset, size_t length, int* result) const; @@ -637,9 +637,6 @@ public: LIBBINDER_EXPORTED const flat_binder_object* readObject(bool nullMetaData) const; - // Explicitly close all file descriptors in the parcel. - LIBBINDER_EXPORTED void closeFileDescriptors(); - // Debugging: get metrics on current allocations. LIBBINDER_EXPORTED static size_t getGlobalAllocSize(); LIBBINDER_EXPORTED static size_t getGlobalAllocCount(); @@ -652,6 +649,9 @@ public: LIBBINDER_EXPORTED void print(std::ostream& to, uint32_t flags = 0) const; private: + // Explicitly close all file descriptors in the parcel. + void closeFileDescriptors(); + // `objects` and `objectsSize` always 0 for RPC Parcels. typedef void (*release_func)(const uint8_t* data, size_t dataSize, const binder_size_t* objects, size_t objectsSize); @@ -1240,7 +1240,7 @@ private: if (__builtin_mul_overflow(size, sizeof(T), &dataLen)) { return -EOVERFLOW; } - auto data = reinterpret_cast<const T*>(readInplace(dataLen)); + auto data = readInplace(dataLen); if (data == nullptr) return BAD_VALUE; // std::vector::insert and similar methods will require type-dependent // byte alignment when inserting from a const iterator such as `data`, diff --git a/libs/binder/include/binder/Status.h b/libs/binder/include/binder/Status.h index 49ccf7c36c..d69f662891 100644 --- a/libs/binder/include/binder/Status.h +++ b/libs/binder/include/binder/Status.h @@ -67,6 +67,9 @@ public: EX_SERVICE_SPECIFIC = -8, EX_PARCELABLE = -9, + // See android/os/Parcel.java. We need to handle this in native code. + EX_HAS_NOTED_APPOPS_REPLY_HEADER = -127, + // This is special and Java specific; see Parcel.java. EX_HAS_REPLY_HEADER = -128, // This is special, and indicates to C++ binder proxies that the @@ -150,6 +153,8 @@ private: Status(int32_t exceptionCode, int32_t errorCode); Status(int32_t exceptionCode, int32_t errorCode, const String8& message); + status_t skipUnusedHeader(const Parcel& parcel); + // If |mException| == EX_TRANSACTION_FAILED, generated code will return // |mErrorCode| as the result of the transaction rather than write an // exception to the reply parcel. diff --git a/libs/binder/include/binder/Trace.h b/libs/binder/include/binder/Trace.h index 2f450cb36b..a3e6c8a12b 100644 --- a/libs/binder/include/binder/Trace.h +++ b/libs/binder/include/binder/Trace.h @@ -42,6 +42,7 @@ namespace os { void trace_begin(uint64_t tag, const char* name); void trace_end(uint64_t tag); void trace_int(uint64_t tag, const char* name, int32_t value); +uint64_t get_trace_enabled_tags(); } // namespace os class LIBBINDER_EXPORTED ScopedTrace { diff --git a/libs/binder/ndk/Android.bp b/libs/binder/ndk/Android.bp index 5f45cb2f07..a7423b3d2a 100644 --- a/libs/binder/ndk/Android.bp +++ b/libs/binder/ndk/Android.bp @@ -95,6 +95,7 @@ cc_library { "persistable_bundle.cpp", "process.cpp", "service_manager.cpp", + "binder_rpc.cpp", ], static_libs: [ diff --git a/libs/binder/ndk/binder_rpc.cpp b/libs/binder/ndk/binder_rpc.cpp new file mode 100644 index 0000000000..07b8c40740 --- /dev/null +++ b/libs/binder/ndk/binder_rpc.cpp @@ -0,0 +1,377 @@ +/* + * Copyright (C) 2024 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 <android/binder_rpc.h> +#include <arpa/inet.h> +#include <binder/IServiceManager.h> +#include <linux/vm_sockets.h> +#include <netinet/in.h> +#include <sys/socket.h> +#include <sys/un.h> + +#include <variant> + +#include "ibinder_internal.h" +#include "status_internal.h" + +using ::android::defaultServiceManager; +using ::android::IBinder; +using ::android::IServiceManager; +using ::android::OK; +using ::android::sp; +using ::android::status_t; +using ::android::String16; +using ::android::String8; +using ::android::binder::Status; + +#define LOG_ACCESSOR_DEBUG(...) +// #define LOG_ACCESSOR_DEBUG(...) ALOGW(__VA_ARGS__) + +struct ABinderRpc_ConnectionInfo { + std::variant<sockaddr_vm, sockaddr_un, sockaddr_in> addr; +}; + +struct ABinderRpc_Accessor final : public ::android::RefBase { + static ABinderRpc_Accessor* make(const char* instance, const sp<IBinder>& binder) { + LOG_ALWAYS_FATAL_IF(binder == nullptr, "ABinderRpc_Accessor requires a non-null binder"); + status_t status = android::validateAccessor(String16(instance), binder); + if (status != OK) { + ALOGE("The given binder is not a valid IAccessor for %s. Status: %s", instance, + android::statusToString(status).c_str()); + return nullptr; + } + return new ABinderRpc_Accessor(binder); + } + + sp<IBinder> asBinder() { return mAccessorBinder; } + + ~ABinderRpc_Accessor() { LOG_ACCESSOR_DEBUG("ABinderRpc_Accessor dtor"); } + + private: + ABinderRpc_Accessor(sp<IBinder> accessor) : mAccessorBinder(accessor) {} + ABinderRpc_Accessor() = delete; + sp<IBinder> mAccessorBinder; +}; + +struct ABinderRpc_AccessorProvider { + public: + static ABinderRpc_AccessorProvider* make(std::weak_ptr<android::AccessorProvider> cookie) { + if (cookie.expired()) { + ALOGE("Null AccessorProvider cookie from libbinder"); + return nullptr; + } + return new ABinderRpc_AccessorProvider(cookie); + } + std::weak_ptr<android::AccessorProvider> mProviderCookie; + + private: + ABinderRpc_AccessorProvider() = delete; + + ABinderRpc_AccessorProvider(std::weak_ptr<android::AccessorProvider> provider) + : mProviderCookie(provider) {} +}; + +struct OnDeleteProviderHolder { + OnDeleteProviderHolder(void* data, ABinderRpc_AccessorProviderUserData_deleteCallback onDelete) + : mData(data), mOnDelete(onDelete) {} + ~OnDeleteProviderHolder() { + if (mOnDelete) { + mOnDelete(mData); + } + } + void* mData; + ABinderRpc_AccessorProviderUserData_deleteCallback mOnDelete; + // needs to be copy-able for std::function, but we will never copy it + OnDeleteProviderHolder(const OnDeleteProviderHolder&) { + LOG_ALWAYS_FATAL("This object can't be copied!"); + } + + private: + OnDeleteProviderHolder() = delete; +}; + +ABinderRpc_AccessorProvider* ABinderRpc_registerAccessorProvider( + ABinderRpc_AccessorProvider_getAccessorCallback provider, const char** instances, + size_t numInstances, void* data, + ABinderRpc_AccessorProviderUserData_deleteCallback onDelete) { + if (provider == nullptr) { + ALOGE("Null provider passed to ABinderRpc_registerAccessorProvider"); + return nullptr; + } + if (data && onDelete == nullptr) { + ALOGE("If a non-null data ptr is passed to ABinderRpc_registerAccessorProvider, then a " + "ABinderRpc_AccessorProviderUserData_deleteCallback must also be passed to delete " + "the data object once the ABinderRpc_AccessorProvider is removed."); + return nullptr; + } + if (numInstances == 0 || instances == nullptr) { + ALOGE("No instances passed to ABinderRpc_registerAccessorProvider. numInstances: %zu", + numInstances); + return nullptr; + } + std::set<std::string> instanceStrings; + for (size_t i = 0; i < numInstances; i++) { + instanceStrings.emplace(instances[i]); + } + // call the onDelete when the last reference of this goes away (when the + // last reference to the generate std::function goes away). + std::shared_ptr<OnDeleteProviderHolder> onDeleteHolder = + std::make_shared<OnDeleteProviderHolder>(data, onDelete); + android::RpcAccessorProvider generate = [provider, + onDeleteHolder](const String16& name) -> sp<IBinder> { + ABinderRpc_Accessor* accessor = provider(String8(name).c_str(), onDeleteHolder->mData); + if (accessor == nullptr) { + ALOGE("The supplied ABinderRpc_AccessorProvider_getAccessorCallback returned nullptr"); + return nullptr; + } + sp<IBinder> binder = accessor->asBinder(); + ABinderRpc_Accessor_delete(accessor); + return binder; + }; + + std::weak_ptr<android::AccessorProvider> cookie = + android::addAccessorProvider(std::move(instanceStrings), std::move(generate)); + return ABinderRpc_AccessorProvider::make(cookie); +} + +void ABinderRpc_unregisterAccessorProvider(ABinderRpc_AccessorProvider* provider) { + if (provider == nullptr) { + LOG_ALWAYS_FATAL("Attempting to remove a null ABinderRpc_AccessorProvider"); + } + + status_t status = android::removeAccessorProvider(provider->mProviderCookie); + // There shouldn't be a way to get here because the caller won't have a + // ABinderRpc_AccessorProvider* without calling ABinderRpc_registerAccessorProvider + LOG_ALWAYS_FATAL_IF(status == android::BAD_VALUE, "Provider (%p) is not valid. Status: %s", + provider, android::statusToString(status).c_str()); + LOG_ALWAYS_FATAL_IF(status == android::NAME_NOT_FOUND, + "Provider (%p) was already unregistered. Status: %s", provider, + android::statusToString(status).c_str()); + LOG_ALWAYS_FATAL_IF(status != OK, + "Unknown error when attempting to unregister ABinderRpc_AccessorProvider " + "(%p). Status: %s", + provider, android::statusToString(status).c_str()); + + delete provider; +} + +struct OnDeleteConnectionInfoHolder { + OnDeleteConnectionInfoHolder(void* data, + ABinderRpc_ConnectionInfoProviderUserData_delete onDelete) + : mData(data), mOnDelete(onDelete) {} + ~OnDeleteConnectionInfoHolder() { + if (mOnDelete) { + mOnDelete(mData); + } + } + void* mData; + ABinderRpc_ConnectionInfoProviderUserData_delete mOnDelete; + // needs to be copy-able for std::function, but we will never copy it + OnDeleteConnectionInfoHolder(const OnDeleteConnectionInfoHolder&) { + LOG_ALWAYS_FATAL("This object can't be copied!"); + } + + private: + OnDeleteConnectionInfoHolder() = delete; +}; + +ABinderRpc_Accessor* ABinderRpc_Accessor_new( + const char* instance, ABinderRpc_ConnectionInfoProvider provider, void* data, + ABinderRpc_ConnectionInfoProviderUserData_delete onDelete) { + if (instance == nullptr) { + ALOGE("Instance argument must be valid when calling ABinderRpc_Accessor_new"); + return nullptr; + } + if (data && onDelete == nullptr) { + ALOGE("If a non-null data ptr is passed to ABinderRpc_Accessor_new, then a " + "ABinderRpc_ConnectionInfoProviderUserData_delete callback must also be passed to " + "delete " + "the data object once the ABinderRpc_Accessor is deleted."); + return nullptr; + } + std::shared_ptr<OnDeleteConnectionInfoHolder> onDeleteHolder = + std::make_shared<OnDeleteConnectionInfoHolder>(data, onDelete); + if (provider == nullptr) { + ALOGE("Can't create a new ABinderRpc_Accessor without a ABinderRpc_ConnectionInfoProvider " + "and it is " + "null"); + return nullptr; + } + android::RpcSocketAddressProvider generate = [provider, onDeleteHolder]( + const String16& name, sockaddr* outAddr, + size_t addrLen) -> status_t { + std::unique_ptr<ABinderRpc_ConnectionInfo> info( + provider(String8(name).c_str(), onDeleteHolder->mData)); + if (info == nullptr) { + ALOGE("The supplied ABinderRpc_ConnectionInfoProvider returned nullptr"); + return android::NAME_NOT_FOUND; + } + if (auto addr = std::get_if<sockaddr_vm>(&info->addr)) { + LOG_ALWAYS_FATAL_IF(addr->svm_family != AF_VSOCK, + "ABinderRpc_ConnectionInfo invalid family"); + if (addrLen < sizeof(sockaddr_vm)) { + ALOGE("Provided outAddr is too small! Expecting %zu, got %zu", sizeof(sockaddr_vm), + addrLen); + return android::BAD_VALUE; + } + LOG_ACCESSOR_DEBUG( + "Connection info provider found AF_VSOCK. family %d, port %d, cid %d", + addr->svm_family, addr->svm_port, addr->svm_cid); + *reinterpret_cast<sockaddr_vm*>(outAddr) = *addr; + } else if (auto addr = std::get_if<sockaddr_un>(&info->addr)) { + LOG_ALWAYS_FATAL_IF(addr->sun_family != AF_UNIX, + "ABinderRpc_ConnectionInfo invalid family"); + if (addrLen < sizeof(sockaddr_un)) { + ALOGE("Provided outAddr is too small! Expecting %zu, got %zu", sizeof(sockaddr_un), + addrLen); + return android::BAD_VALUE; + } + *reinterpret_cast<sockaddr_un*>(outAddr) = *addr; + } else if (auto addr = std::get_if<sockaddr_in>(&info->addr)) { + LOG_ALWAYS_FATAL_IF(addr->sin_family != AF_INET, + "ABinderRpc_ConnectionInfo invalid family"); + if (addrLen < sizeof(sockaddr_in)) { + ALOGE("Provided outAddr is too small! Expecting %zu, got %zu", sizeof(sockaddr_in), + addrLen); + return android::BAD_VALUE; + } + *reinterpret_cast<sockaddr_in*>(outAddr) = *addr; + } else { + LOG_ALWAYS_FATAL( + "Unsupported address family type when trying to get ARpcConnection info. A " + "new variant was added to the ABinderRpc_ConnectionInfo and this needs to be " + "updated."); + } + return OK; + }; + sp<IBinder> accessorBinder = android::createAccessor(String16(instance), std::move(generate)); + if (accessorBinder == nullptr) { + ALOGE("service manager did not get us an accessor"); + return nullptr; + } + LOG_ACCESSOR_DEBUG("service manager found an accessor, so returning one now from _new"); + return ABinderRpc_Accessor::make(instance, accessorBinder); +} + +void ABinderRpc_Accessor_delete(ABinderRpc_Accessor* accessor) { + delete accessor; +} + +AIBinder* ABinderRpc_Accessor_asBinder(ABinderRpc_Accessor* accessor) { + if (!accessor) { + ALOGE("ABinderRpc_Accessor argument is null."); + return nullptr; + } + + sp<IBinder> binder = accessor->asBinder(); + sp<AIBinder> aBinder = ABpBinder::lookupOrCreateFromBinder(binder); + AIBinder* ptr = aBinder.get(); + if (ptr == nullptr) { + LOG_ALWAYS_FATAL("Failed to lookupOrCreateFromBinder"); + } + ptr->incStrong(nullptr); + return ptr; +} + +ABinderRpc_Accessor* ABinderRpc_Accessor_fromBinder(const char* instance, AIBinder* binder) { + if (!binder) { + ALOGE("binder argument is null"); + return nullptr; + } + sp<IBinder> accessorBinder = binder->getBinder(); + if (accessorBinder) { + return ABinderRpc_Accessor::make(instance, accessorBinder); + } else { + ALOGE("Attempting to get an ABinderRpc_Accessor for %s but AIBinder::getBinder returned " + "null", + instance); + return nullptr; + } +} + +binder_status_t ABinderRpc_Accessor_delegateAccessor(const char* instance, AIBinder* accessor, + AIBinder** outDelegator) { + LOG_ALWAYS_FATAL_IF(outDelegator == nullptr, "The outDelegator argument is null"); + if (instance == nullptr || accessor == nullptr) { + ALOGW("instance or accessor arguments to ABinderRpc_Accessor_delegateBinder are null"); + *outDelegator = nullptr; + return STATUS_UNEXPECTED_NULL; + } + sp<IBinder> accessorBinder = accessor->getBinder(); + + sp<IBinder> delegator; + status_t status = android::delegateAccessor(String16(instance), accessorBinder, &delegator); + if (status != OK) { + return PruneStatusT(status); + } + sp<AIBinder> binder = ABpBinder::lookupOrCreateFromBinder(delegator); + // This AIBinder needs a strong ref to pass ownership to the caller + binder->incStrong(nullptr); + *outDelegator = binder.get(); + return OK; +} + +ABinderRpc_ConnectionInfo* ABinderRpc_ConnectionInfo_new(const sockaddr* addr, socklen_t len) { + if (addr == nullptr || len < 0 || static_cast<size_t>(len) < sizeof(sa_family_t)) { + ALOGE("Invalid arguments in ABinderRpc_Connection_new"); + return nullptr; + } + // socklen_t was int32_t on 32-bit and uint32_t on 64 bit. + size_t socklen = len < 0 || static_cast<uintmax_t>(len) > SIZE_MAX ? 0 : len; + + if (addr->sa_family == AF_VSOCK) { + if (len != sizeof(sockaddr_vm)) { + ALOGE("Incorrect size of %zu for AF_VSOCK sockaddr_vm. Expecting %zu", socklen, + sizeof(sockaddr_vm)); + return nullptr; + } + sockaddr_vm vm = *reinterpret_cast<const sockaddr_vm*>(addr); + LOG_ACCESSOR_DEBUG( + "ABinderRpc_ConnectionInfo_new found AF_VSOCK. family %d, port %d, cid %d", + vm.svm_family, vm.svm_port, vm.svm_cid); + return new ABinderRpc_ConnectionInfo(vm); + } else if (addr->sa_family == AF_UNIX) { + if (len != sizeof(sockaddr_un)) { + ALOGE("Incorrect size of %zu for AF_UNIX sockaddr_un. Expecting %zu", socklen, + sizeof(sockaddr_un)); + return nullptr; + } + sockaddr_un un = *reinterpret_cast<const sockaddr_un*>(addr); + LOG_ACCESSOR_DEBUG("ABinderRpc_ConnectionInfo_new found AF_UNIX. family %d, path %s", + un.sun_family, un.sun_path); + return new ABinderRpc_ConnectionInfo(un); + } else if (addr->sa_family == AF_INET) { + if (len != sizeof(sockaddr_in)) { + ALOGE("Incorrect size of %zu for AF_INET sockaddr_in. Expecting %zu", socklen, + sizeof(sockaddr_in)); + return nullptr; + } + sockaddr_in in = *reinterpret_cast<const sockaddr_in*>(addr); + LOG_ACCESSOR_DEBUG( + "ABinderRpc_ConnectionInfo_new found AF_INET. family %d, address %s, port %d", + in.sin_family, inet_ntoa(in.sin_addr), ntohs(in.sin_port)); + return new ABinderRpc_ConnectionInfo(in); + } + + ALOGE("ABinderRpc APIs only support AF_VSOCK right now but the supplied sockaddr::sa_family " + "is: %hu", + addr->sa_family); + return nullptr; +} + +void ABinderRpc_ConnectionInfo_delete(ABinderRpc_ConnectionInfo* info) { + delete info; +} diff --git a/libs/binder/ndk/ibinder.cpp b/libs/binder/ndk/ibinder.cpp index af280d38a3..ff31dd0193 100644 --- a/libs/binder/ndk/ibinder.cpp +++ b/libs/binder/ndk/ibinder.cpp @@ -18,8 +18,10 @@ #include <android/binder_ibinder_platform.h> #include <android/binder_stability.h> #include <android/binder_status.h> +#include <binder/Functional.h> #include <binder/IPCThreadState.h> #include <binder/IResultReceiver.h> +#include <binder/Trace.h> #if __has_include(<private/android_filesystem_config.h>) #include <private/android_filesystem_config.h> #endif @@ -40,6 +42,23 @@ using ::android::statusToString; using ::android::String16; using ::android::String8; using ::android::wp; +using ::android::binder::impl::make_scope_guard; +using ::android::binder::impl::scope_guard; +using ::android::binder::os::get_trace_enabled_tags; +using ::android::binder::os::trace_begin; +using ::android::binder::os::trace_end; + +// transaction codes for getInterfaceHash and getInterfaceVersion are defined +// in file : system/tools/aidl/aidl.cpp +static constexpr int kGetInterfaceVersionId = 0x00fffffe; +static const char* kInterfaceVersion = "getInterfaceVersion"; +static constexpr int kGetInterfaceHashId = 0x00fffffd; +static const char* kInterfaceHash = "getInterfaceHash"; +static const char* kNdkTrace = "AIDL::ndk::"; +static const char* kServerTrace = "::server"; +static const char* kClientTrace = "::client"; +static const char* kSeparator = "::"; +static const char* kUnknownCode = "Unknown_Transaction_Code:"; namespace ABBinderTag { @@ -90,6 +109,51 @@ static std::string SanitizeString(const String16& str) { return sanitized; } +const std::string getMethodName(const AIBinder_Class* clazz, transaction_code_t code) { + // TODO(b/150155678) - Move getInterfaceHash and getInterfaceVersion to libbinder and remove + // hardcoded cases. + if (code <= clazz->getTransactionCodeToFunctionLength() && code >= FIRST_CALL_TRANSACTION) { + // Codes have FIRST_CALL_TRANSACTION as added offset. Subtract to access function name + return clazz->getFunctionName(code); + } else if (code == kGetInterfaceVersionId) { + return kInterfaceVersion; + } else if (code == kGetInterfaceHashId) { + return kInterfaceHash; + } + return kUnknownCode + std::to_string(code); +} + +const std::string getTraceSectionName(const AIBinder_Class* clazz, transaction_code_t code, + bool isServer) { + if (clazz == nullptr) { + ALOGE("class associated with binder is null. Class is needed to add trace with interface " + "name and function name"); + return kNdkTrace; + } + + const std::string descriptor = clazz->getInterfaceDescriptorUtf8(); + const std::string methodName = getMethodName(clazz, code); + + size_t traceSize = + strlen(kNdkTrace) + descriptor.size() + strlen(kSeparator) + methodName.size(); + traceSize += isServer ? strlen(kServerTrace) : strlen(kClientTrace); + + std::string trace; + // reserve to avoid repeated allocations + trace.reserve(traceSize); + + trace += kNdkTrace; + trace += clazz->getInterfaceDescriptorUtf8(); + trace += kSeparator; + trace += methodName; + trace += isServer ? kServerTrace : kClientTrace; + + LOG_ALWAYS_FATAL_IF(trace.size() != traceSize, "Trace size mismatch. Expected %zu, got %zu", + traceSize, trace.size()); + + return trace; +} + bool AIBinder::associateClass(const AIBinder_Class* clazz) { if (clazz == nullptr) return false; @@ -203,6 +267,17 @@ status_t ABBinder::dump(int fd, const ::android::Vector<String16>& args) { status_t ABBinder::onTransact(transaction_code_t code, const Parcel& data, Parcel* reply, binder_flags_t flags) { + std::string sectionName; + bool tracingEnabled = get_trace_enabled_tags() & ATRACE_TAG_AIDL; + if (tracingEnabled) { + sectionName = getTraceSectionName(getClass(), code, true /*isServer*/); + trace_begin(ATRACE_TAG_AIDL, sectionName.c_str()); + } + + scope_guard guard = make_scope_guard([&]() { + if (tracingEnabled) trace_end(ATRACE_TAG_AIDL); + }); + if (isUserCommand(code)) { if (getClass()->writeHeader && !data.checkInterface(this)) { return STATUS_BAD_TYPE; @@ -385,6 +460,31 @@ AIBinder_Class::AIBinder_Class(const char* interfaceDescriptor, AIBinder_Class_o mInterfaceDescriptor(interfaceDescriptor), mWideInterfaceDescriptor(interfaceDescriptor) {} +bool AIBinder_Class::setTransactionCodeMap(const char** transactionCodeMap, size_t length) { + if (mTransactionCodeToFunction != nullptr) { + ALOGE("mTransactionCodeToFunction is already set!"); + return false; + } + mTransactionCodeToFunction = transactionCodeMap; + mTransactionCodeToFunctionLength = length; + return true; +} + +const char* AIBinder_Class::getFunctionName(transaction_code_t code) const { + if (mTransactionCodeToFunction == nullptr) { + ALOGE("mTransactionCodeToFunction is not set!"); + return nullptr; + } + + if (code < FIRST_CALL_TRANSACTION || + code - FIRST_CALL_TRANSACTION >= mTransactionCodeToFunctionLength) { + ALOGE("Function name for requested code not found!"); + return nullptr; + } + + return mTransactionCodeToFunction[code - FIRST_CALL_TRANSACTION]; +} + AIBinder_Class* AIBinder_Class_define(const char* interfaceDescriptor, AIBinder_Class_onCreate onCreate, AIBinder_Class_onDestroy onDestroy, @@ -404,6 +504,24 @@ void AIBinder_Class_setOnDump(AIBinder_Class* clazz, AIBinder_onDump onDump) { clazz->onDump = onDump; } +void AIBinder_Class_setTransactionCodeToFunctionNameMap(AIBinder_Class* clazz, + const char** transactionCodeToFunction, + size_t length) { + LOG_ALWAYS_FATAL_IF(clazz == nullptr || transactionCodeToFunction == nullptr, + "Valid clazz and transactionCodeToFunction are needed to set code to " + "function mapping."); + LOG_ALWAYS_FATAL_IF(!clazz->setTransactionCodeMap(transactionCodeToFunction, length), + "Failed to set transactionCodeToFunction to clazz! Is " + "transactionCodeToFunction already set?"); +} + +const char* AIBinder_Class_getFunctionName(AIBinder_Class* clazz, transaction_code_t code) { + LOG_ALWAYS_FATAL_IF( + clazz == nullptr, + "Valid clazz is needed to get function name for requested transaction code"); + return clazz->getFunctionName(code); +} + void AIBinder_Class_disableInterfaceTokenHeader(AIBinder_Class* clazz) { LOG_ALWAYS_FATAL_IF(clazz == nullptr, "disableInterfaceTokenHeader requires non-null clazz"); @@ -734,6 +852,19 @@ static void DestroyParcel(AParcel** parcel) { binder_status_t AIBinder_transact(AIBinder* binder, transaction_code_t code, AParcel** in, AParcel** out, binder_flags_t flags) { + const AIBinder_Class* clazz = binder ? binder->getClass() : nullptr; + + std::string sectionName; + bool tracingEnabled = get_trace_enabled_tags() & ATRACE_TAG_AIDL; + if (tracingEnabled) { + sectionName = getTraceSectionName(clazz, code, false /*isServer*/); + trace_begin(ATRACE_TAG_AIDL, sectionName.c_str()); + } + + scope_guard guard = make_scope_guard([&]() { + if (tracingEnabled) trace_end(ATRACE_TAG_AIDL); + }); + if (in == nullptr) { ALOGE("%s: requires non-null in parameter", __func__); return STATUS_UNEXPECTED_NULL; @@ -872,4 +1003,4 @@ void AIBinder_setInheritRt(AIBinder* binder, bool inheritRt) { "AIBinder_setInheritRt must be called on a local binder"); localBinder->setInheritRt(inheritRt); -} +}
\ No newline at end of file diff --git a/libs/binder/ndk/ibinder_internal.h b/libs/binder/ndk/ibinder_internal.h index f5b738c1ef..a93dc1f674 100644 --- a/libs/binder/ndk/ibinder_internal.h +++ b/libs/binder/ndk/ibinder_internal.h @@ -132,6 +132,9 @@ struct AIBinder_Class { const ::android::String16& getInterfaceDescriptor() const { return mWideInterfaceDescriptor; } const char* getInterfaceDescriptorUtf8() const { return mInterfaceDescriptor.c_str(); } + bool setTransactionCodeMap(const char** transactionCodeMap, size_t transactionCodeMapSize); + const char* getFunctionName(transaction_code_t code) const; + size_t getTransactionCodeToFunctionLength() const { return mTransactionCodeToFunctionLength; } // whether a transaction header should be written bool writeHeader = true; @@ -151,6 +154,10 @@ struct AIBinder_Class { // This must be a String16 since BBinder virtual getInterfaceDescriptor returns a reference to // one. const ::android::String16 mWideInterfaceDescriptor; + // Array which holds names of the functions + const char** mTransactionCodeToFunction = nullptr; + // length of mmTransactionCodeToFunctionLength array + size_t mTransactionCodeToFunctionLength = 0; }; // Ownership is like this (when linked to death): diff --git a/libs/binder/ndk/include_cpp/android/binder_interface_utils.h b/libs/binder/ndk/include_cpp/android/binder_interface_utils.h index af56bf0da1..0ad110ee83 100644 --- a/libs/binder/ndk/include_cpp/android/binder_interface_utils.h +++ b/libs/binder/ndk/include_cpp/android/binder_interface_utils.h @@ -30,6 +30,17 @@ #include <android/binder_auto_utils.h> #include <android/binder_ibinder.h> +#if defined(__ANDROID_VENDOR_API__) +#include <android/llndk-versioning.h> +#elif !defined(API_LEVEL_AT_LEAST) +#if defined(__BIONIC__) +#define API_LEVEL_AT_LEAST(sdk_api_level, vendor_api_level) \ + (__builtin_available(android sdk_api_level, *)) +#else +#define API_LEVEL_AT_LEAST(sdk_api_level, vendor_api_level) (true) +#endif // __BIONIC__ +#endif // __ANDROID_VENDOR_API__ + #if __has_include(<android/binder_shell.h>) #include <android/binder_shell.h> #define HAS_BINDER_SHELL_COMMAND @@ -164,6 +175,10 @@ class ICInterface : public SharedRefBase { * Helper method to create a class */ static inline AIBinder_Class* defineClass(const char* interfaceDescriptor, + AIBinder_Class_onTransact onTransact, + const char** codeToFunction, size_t functionCount); + + static inline AIBinder_Class* defineClass(const char* interfaceDescriptor, AIBinder_Class_onTransact onTransact); private: @@ -256,6 +271,13 @@ std::shared_ptr<ICInterface> ICInterface::asInterface(AIBinder* binder) { AIBinder_Class* ICInterface::defineClass(const char* interfaceDescriptor, AIBinder_Class_onTransact onTransact) { + + return defineClass(interfaceDescriptor, onTransact, nullptr, 0); +} + +AIBinder_Class* ICInterface::defineClass(const char* interfaceDescriptor, + AIBinder_Class_onTransact onTransact, + const char** codeToFunction, size_t functionCount) { AIBinder_Class* clazz = AIBinder_Class_define(interfaceDescriptor, ICInterfaceData::onCreate, ICInterfaceData::onDestroy, onTransact); if (clazz == nullptr) { @@ -274,6 +296,19 @@ AIBinder_Class* ICInterface::defineClass(const char* interfaceDescriptor, AIBinder_Class_setHandleShellCommand(clazz, ICInterfaceData::handleShellCommand); } #endif + +#if defined(__ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__) || __ANDROID_API__ >= 36 + if API_LEVEL_AT_LEAST (36, 202504) { + if (codeToFunction != nullptr && + (&AIBinder_Class_setTransactionCodeToFunctionNameMap != nullptr)) { + AIBinder_Class_setTransactionCodeToFunctionNameMap(clazz, codeToFunction, + functionCount); + } + } +#else + (void)codeToFunction; + (void)functionCount; +#endif // defined(__ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__) || __ANDROID_API__ >= 36 return clazz; } diff --git a/libs/binder/ndk/include_cpp/android/persistable_bundle_aidl.h b/libs/binder/ndk/include_cpp/android/persistable_bundle_aidl.h index c1d0e9f9fe..83976b3771 100644 --- a/libs/binder/ndk/include_cpp/android/persistable_bundle_aidl.h +++ b/libs/binder/ndk/include_cpp/android/persistable_bundle_aidl.h @@ -22,8 +22,8 @@ #include <set> #include <sstream> -// Include llndk-versioning.h only for vendor build as it is not available for NDK headers. -#if defined(__ANDROID_VENDOR__) +// Include llndk-versioning.h only for non-system build as it is not available for NDK headers. +#if defined(__ANDROID_VENDOR_API__) #include <android/llndk-versioning.h> #elif !defined(API_LEVEL_AT_LEAST) #if defined(__BIONIC__) @@ -32,7 +32,7 @@ #else #define API_LEVEL_AT_LEAST(sdk_api_level, vendor_api_level) (true) #endif // __BIONIC__ -#endif // __ANDROID_VENDOR__ +#endif // __ANDROID_VENDOR_API__ namespace aidl::android::os { diff --git a/libs/binder/ndk/include_ndk/android/binder_ibinder.h b/libs/binder/ndk/include_ndk/android/binder_ibinder.h index 72d255e816..bd46c473b4 100644 --- a/libs/binder/ndk/include_ndk/android/binder_ibinder.h +++ b/libs/binder/ndk/include_ndk/android/binder_ibinder.h @@ -219,6 +219,50 @@ typedef binder_status_t (*AIBinder_onDump)(AIBinder* binder, int fd, const char* void AIBinder_Class_setOnDump(AIBinder_Class* clazz, AIBinder_onDump onDump) __INTRODUCED_IN(29); /** + * Associates a mapping of transaction codes(transaction_code_t) to function names for the given + * class. + * + * Trace messages will use the provided names instead of bare integer codes when set. If not set by + * this function, trace messages will only be identified by the bare code. This should be called one + * time during clazz initialization. clazz is defined using AIBinder_Class_define and + * transactionCodeToFunctionMap should have same scope as clazz. Resetting/clearing the + * transactionCodeToFunctionMap is not allowed. Passing null for either clazz or + * transactionCodeToFunctionMap will abort. + * + * Available since API level 36. + * + * \param clazz class which should use this transaction to code function map. + * \param transactionCodeToFunctionMap array of function names indexed by transaction code. + * Transaction codes start from 1, functions with transaction code 1 will correspond to index 0 in + * transactionCodeToFunctionMap. When defining methods, transaction codes are expected to be + * contiguous, and this is required for maximum memory efficiency. + * You can use nullptr if certain transaction codes are not used. Lifetime should be same as clazz. + * \param length number of elements in the transactionCodeToFunctionMap + */ +void AIBinder_Class_setTransactionCodeToFunctionNameMap(AIBinder_Class* clazz, + const char** transactionCodeToFunctionMap, + size_t length) __INTRODUCED_IN(36); + +/** + * Get function name associated with transaction code for given class + * + * This function returns function name associated with provided transaction code for given class. + * AIBinder_Class_setTransactionCodeToFunctionNameMap should be called first to associate function + * to transaction code mapping. + * + * Available since API level 36. + * + * \param clazz class for which function name is requested + * \param transactionCode transaction_code_t for which function name is requested. + * + * \return function name in form of const char* if transaction code is valid for given class. + * The value returned is valid for the lifetime of clazz. if transaction code is invalid or + * transactionCodeToFunctionMap is not set, nullptr is returned. + */ +const char* AIBinder_Class_getFunctionName(AIBinder_Class* clazz, transaction_code_t code) + __INTRODUCED_IN(36); + +/** * This tells users of this class not to use a transaction header. By default, libbinder_ndk users * read/write transaction headers implicitly (in the SDK, this must be manually written by * android.os.Parcel#writeInterfaceToken, and it is read/checked with diff --git a/libs/binder/ndk/include_ndk/android/persistable_bundle.h b/libs/binder/ndk/include_ndk/android/persistable_bundle.h index 5e0d4da97b..1d516aea9d 100644 --- a/libs/binder/ndk/include_ndk/android/persistable_bundle.h +++ b/libs/binder/ndk/include_ndk/android/persistable_bundle.h @@ -17,13 +17,6 @@ #pragma once #include <android/binder_parcel.h> -#if defined(__ANDROID_VENDOR__) -#include <android/llndk-versioning.h> -#else -#if !defined(__INTRODUCED_IN_LLNDK) -#define __INTRODUCED_IN_LLNDK(level) __attribute__((annotate("introduced_in_llndk=" #level))) -#endif -#endif // __ANDROID_VENDOR__ #include <stdbool.h> #include <stdint.h> #include <sys/cdefs.h> @@ -83,8 +76,7 @@ typedef char* _Nullable (*_Nonnull APersistableBundle_stringAllocator)(int32_t s * * \return Pointer to a new APersistableBundle */ -APersistableBundle* _Nullable APersistableBundle_new() __INTRODUCED_IN(__ANDROID_API_V__) - __INTRODUCED_IN_LLNDK(202404); +APersistableBundle* _Nullable APersistableBundle_new() __INTRODUCED_IN(__ANDROID_API_V__); /** * Create a new APersistableBundle based off an existing APersistableBundle. @@ -98,7 +90,7 @@ APersistableBundle* _Nullable APersistableBundle_new() __INTRODUCED_IN(__ANDROID * \return Pointer to a new APersistableBundle */ APersistableBundle* _Nullable APersistableBundle_dup(const APersistableBundle* _Nonnull pBundle) - __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404); + __INTRODUCED_IN(__ANDROID_API_V__); /** * Delete an APersistableBundle. This must always be called when finished using @@ -109,7 +101,7 @@ APersistableBundle* _Nullable APersistableBundle_dup(const APersistableBundle* _ * Available since API level 202404. */ void APersistableBundle_delete(APersistableBundle* _Nullable pBundle) - __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404); + __INTRODUCED_IN(__ANDROID_API_V__); /** * Check for equality of APersistableBundles. @@ -123,7 +115,7 @@ void APersistableBundle_delete(APersistableBundle* _Nullable pBundle) */ bool APersistableBundle_isEqual(const APersistableBundle* _Nonnull lhs, const APersistableBundle* _Nonnull rhs) - __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404); + __INTRODUCED_IN(__ANDROID_API_V__); /** * Read an APersistableBundle from an AParcel. @@ -142,7 +134,7 @@ bool APersistableBundle_isEqual(const APersistableBundle* _Nonnull lhs, */ binder_status_t APersistableBundle_readFromParcel( const AParcel* _Nonnull parcel, APersistableBundle* _Nullable* _Nonnull outPBundle) - __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404); + __INTRODUCED_IN(__ANDROID_API_V__); /** * Write an APersistableBundle to an AParcel. @@ -162,7 +154,7 @@ binder_status_t APersistableBundle_readFromParcel( */ binder_status_t APersistableBundle_writeToParcel(const APersistableBundle* _Nonnull pBundle, AParcel* _Nonnull parcel) - __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404); + __INTRODUCED_IN(__ANDROID_API_V__); /** * Get the size of an APersistableBundle. This is the number of mappings in the @@ -175,7 +167,7 @@ binder_status_t APersistableBundle_writeToParcel(const APersistableBundle* _Nonn * \return number of mappings in the object */ int32_t APersistableBundle_size(const APersistableBundle* _Nonnull pBundle) - __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404); + __INTRODUCED_IN(__ANDROID_API_V__); /** * Erase any entries added with the provided key. @@ -188,7 +180,7 @@ int32_t APersistableBundle_size(const APersistableBundle* _Nonnull pBundle) * \return number of entries erased. Either 0 or 1. */ int32_t APersistableBundle_erase(APersistableBundle* _Nonnull pBundle, const char* _Nonnull key) - __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404); + __INTRODUCED_IN(__ANDROID_API_V__); /** * Put a boolean associated with the provided key. @@ -201,8 +193,7 @@ int32_t APersistableBundle_erase(APersistableBundle* _Nonnull pBundle, const cha * Available since API level 202404. */ void APersistableBundle_putBoolean(APersistableBundle* _Nonnull pBundle, const char* _Nonnull key, - bool val) __INTRODUCED_IN(__ANDROID_API_V__) - __INTRODUCED_IN_LLNDK(202404); + bool val) __INTRODUCED_IN(__ANDROID_API_V__); /** * Put an int32_t associated with the provided key. @@ -215,8 +206,7 @@ void APersistableBundle_putBoolean(APersistableBundle* _Nonnull pBundle, const c * Available since API level 202404. */ void APersistableBundle_putInt(APersistableBundle* _Nonnull pBundle, const char* _Nonnull key, - int32_t val) __INTRODUCED_IN(__ANDROID_API_V__) - __INTRODUCED_IN_LLNDK(202404); + int32_t val) __INTRODUCED_IN(__ANDROID_API_V__); /** * Put an int64_t associated with the provided key. @@ -229,8 +219,7 @@ void APersistableBundle_putInt(APersistableBundle* _Nonnull pBundle, const char* * Available since API level 202404. */ void APersistableBundle_putLong(APersistableBundle* _Nonnull pBundle, const char* _Nonnull key, - int64_t val) __INTRODUCED_IN(__ANDROID_API_V__) - __INTRODUCED_IN_LLNDK(202404); + int64_t val) __INTRODUCED_IN(__ANDROID_API_V__); /** * Put a double associated with the provided key. @@ -243,8 +232,7 @@ void APersistableBundle_putLong(APersistableBundle* _Nonnull pBundle, const char * Available since API level 202404. */ void APersistableBundle_putDouble(APersistableBundle* _Nonnull pBundle, const char* _Nonnull key, - double val) __INTRODUCED_IN(__ANDROID_API_V__) - __INTRODUCED_IN_LLNDK(202404); + double val) __INTRODUCED_IN(__ANDROID_API_V__); /** * Put a string associated with the provided key. @@ -258,8 +246,7 @@ void APersistableBundle_putDouble(APersistableBundle* _Nonnull pBundle, const ch * Available since API level 202404. */ void APersistableBundle_putString(APersistableBundle* _Nonnull pBundle, const char* _Nonnull key, - const char* _Nonnull val) __INTRODUCED_IN(__ANDROID_API_V__) - __INTRODUCED_IN_LLNDK(202404); + const char* _Nonnull val) __INTRODUCED_IN(__ANDROID_API_V__); /** * Put a boolean vector associated with the provided key. @@ -275,8 +262,7 @@ void APersistableBundle_putString(APersistableBundle* _Nonnull pBundle, const ch */ void APersistableBundle_putBooleanVector(APersistableBundle* _Nonnull pBundle, const char* _Nonnull key, const bool* _Nonnull vec, - int32_t num) __INTRODUCED_IN(__ANDROID_API_V__) - __INTRODUCED_IN_LLNDK(202404); + int32_t num) __INTRODUCED_IN(__ANDROID_API_V__); /** * Put an int32_t vector associated with the provided key. @@ -292,7 +278,7 @@ void APersistableBundle_putBooleanVector(APersistableBundle* _Nonnull pBundle, */ void APersistableBundle_putIntVector(APersistableBundle* _Nonnull pBundle, const char* _Nonnull key, const int32_t* _Nonnull vec, int32_t num) - __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404); + __INTRODUCED_IN(__ANDROID_API_V__); /** * Put an int64_t vector associated with the provided key. @@ -308,8 +294,7 @@ void APersistableBundle_putIntVector(APersistableBundle* _Nonnull pBundle, const */ void APersistableBundle_putLongVector(APersistableBundle* _Nonnull pBundle, const char* _Nonnull key, const int64_t* _Nonnull vec, - int32_t num) __INTRODUCED_IN(__ANDROID_API_V__) - __INTRODUCED_IN_LLNDK(202404); + int32_t num) __INTRODUCED_IN(__ANDROID_API_V__); /** * Put a double vector associated with the provided key. @@ -325,8 +310,7 @@ void APersistableBundle_putLongVector(APersistableBundle* _Nonnull pBundle, */ void APersistableBundle_putDoubleVector(APersistableBundle* _Nonnull pBundle, const char* _Nonnull key, const double* _Nonnull vec, - int32_t num) __INTRODUCED_IN(__ANDROID_API_V__) - __INTRODUCED_IN_LLNDK(202404); + int32_t num) __INTRODUCED_IN(__ANDROID_API_V__); /** * Put a string vector associated with the provided key. @@ -343,7 +327,7 @@ void APersistableBundle_putDoubleVector(APersistableBundle* _Nonnull pBundle, void APersistableBundle_putStringVector(APersistableBundle* _Nonnull pBundle, const char* _Nonnull key, const char* _Nullable const* _Nullable vec, int32_t num) - __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404); + __INTRODUCED_IN(__ANDROID_API_V__); /** * Put an APersistableBundle associated with the provided key. @@ -359,7 +343,7 @@ void APersistableBundle_putStringVector(APersistableBundle* _Nonnull pBundle, void APersistableBundle_putPersistableBundle(APersistableBundle* _Nonnull pBundle, const char* _Nonnull key, const APersistableBundle* _Nonnull val) - __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404); + __INTRODUCED_IN(__ANDROID_API_V__); /** * Get a boolean associated with the provided key. @@ -374,7 +358,7 @@ void APersistableBundle_putPersistableBundle(APersistableBundle* _Nonnull pBundl */ bool APersistableBundle_getBoolean(const APersistableBundle* _Nonnull pBundle, const char* _Nonnull key, bool* _Nonnull val) - __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404); + __INTRODUCED_IN(__ANDROID_API_V__); /** * Get an int32_t associated with the provided key. @@ -388,8 +372,7 @@ bool APersistableBundle_getBoolean(const APersistableBundle* _Nonnull pBundle, * \return true if a value exists for the provided key */ bool APersistableBundle_getInt(const APersistableBundle* _Nonnull pBundle, const char* _Nonnull key, - int32_t* _Nonnull val) __INTRODUCED_IN(__ANDROID_API_V__) - __INTRODUCED_IN_LLNDK(202404); + int32_t* _Nonnull val) __INTRODUCED_IN(__ANDROID_API_V__); /** * Get an int64_t associated with the provided key. @@ -404,7 +387,7 @@ bool APersistableBundle_getInt(const APersistableBundle* _Nonnull pBundle, const */ bool APersistableBundle_getLong(const APersistableBundle* _Nonnull pBundle, const char* _Nonnull key, int64_t* _Nonnull val) - __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404); + __INTRODUCED_IN(__ANDROID_API_V__); /** * Get a double associated with the provided key. @@ -419,7 +402,7 @@ bool APersistableBundle_getLong(const APersistableBundle* _Nonnull pBundle, */ bool APersistableBundle_getDouble(const APersistableBundle* _Nonnull pBundle, const char* _Nonnull key, double* _Nonnull val) - __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404); + __INTRODUCED_IN(__ANDROID_API_V__); /** * Get a string associated with the provided key. @@ -440,8 +423,7 @@ bool APersistableBundle_getDouble(const APersistableBundle* _Nonnull pBundle, int32_t APersistableBundle_getString(const APersistableBundle* _Nonnull pBundle, const char* _Nonnull key, char* _Nullable* _Nonnull val, APersistableBundle_stringAllocator stringAllocator, - void* _Nullable context) __INTRODUCED_IN(__ANDROID_API_V__) - __INTRODUCED_IN_LLNDK(202404); + void* _Nullable context) __INTRODUCED_IN(__ANDROID_API_V__); /** * Get a boolean vector associated with the provided key and place it in the @@ -468,7 +450,7 @@ int32_t APersistableBundle_getString(const APersistableBundle* _Nonnull pBundle, int32_t APersistableBundle_getBooleanVector(const APersistableBundle* _Nonnull pBundle, const char* _Nonnull key, bool* _Nullable buffer, int32_t bufferSizeBytes) - __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404); + __INTRODUCED_IN(__ANDROID_API_V__); /** * Get an int32_t vector associated with the provided key and place it in the @@ -494,8 +476,7 @@ int32_t APersistableBundle_getBooleanVector(const APersistableBundle* _Nonnull p */ int32_t APersistableBundle_getIntVector(const APersistableBundle* _Nonnull pBundle, const char* _Nonnull key, int32_t* _Nullable buffer, - int32_t bufferSizeBytes) __INTRODUCED_IN(__ANDROID_API_V__) - __INTRODUCED_IN_LLNDK(202404); + int32_t bufferSizeBytes) __INTRODUCED_IN(__ANDROID_API_V__); /** * Get an int64_t vector associated with the provided key and place it in the @@ -521,8 +502,8 @@ int32_t APersistableBundle_getIntVector(const APersistableBundle* _Nonnull pBund */ int32_t APersistableBundle_getLongVector(const APersistableBundle* _Nonnull pBundle, const char* _Nonnull key, int64_t* _Nullable buffer, - int32_t bufferSizeBytes) __INTRODUCED_IN(__ANDROID_API_V__) - __INTRODUCED_IN_LLNDK(202404); + int32_t bufferSizeBytes) + __INTRODUCED_IN(__ANDROID_API_V__); /** * Get a double vector associated with the provided key and place it in the @@ -549,7 +530,7 @@ int32_t APersistableBundle_getLongVector(const APersistableBundle* _Nonnull pBun int32_t APersistableBundle_getDoubleVector(const APersistableBundle* _Nonnull pBundle, const char* _Nonnull key, double* _Nullable buffer, int32_t bufferSizeBytes) - __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404); + __INTRODUCED_IN(__ANDROID_API_V__); /** * Get a string vector associated with the provided key and place it in the @@ -586,7 +567,7 @@ int32_t APersistableBundle_getStringVector(const APersistableBundle* _Nonnull pB int32_t bufferSizeBytes, APersistableBundle_stringAllocator stringAllocator, void* _Nullable context) - __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404); + __INTRODUCED_IN(__ANDROID_API_V__); /** * Get an APersistableBundle* associated with the provided key. @@ -605,7 +586,7 @@ int32_t APersistableBundle_getStringVector(const APersistableBundle* _Nonnull pB bool APersistableBundle_getPersistableBundle(const APersistableBundle* _Nonnull pBundle, const char* _Nonnull key, APersistableBundle* _Nullable* _Nonnull outBundle) - __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404); + __INTRODUCED_IN(__ANDROID_API_V__); /** * Get all of the keys associated with this specific type and place it in the @@ -638,7 +619,7 @@ int32_t APersistableBundle_getBooleanKeys(const APersistableBundle* _Nonnull pBu int32_t bufferSizeBytes, APersistableBundle_stringAllocator stringAllocator, void* _Nullable context) - __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404); + __INTRODUCED_IN(__ANDROID_API_V__); /** * Get all of the keys associated with this specific type and place it in the @@ -669,8 +650,7 @@ int32_t APersistableBundle_getBooleanKeys(const APersistableBundle* _Nonnull pBu int32_t APersistableBundle_getIntKeys(const APersistableBundle* _Nonnull pBundle, char* _Nullable* _Nullable outKeys, int32_t bufferSizeBytes, APersistableBundle_stringAllocator stringAllocator, - void* _Nullable context) __INTRODUCED_IN(__ANDROID_API_V__) - __INTRODUCED_IN_LLNDK(202404); + void* _Nullable context) __INTRODUCED_IN(__ANDROID_API_V__); /** * Get all of the keys associated with this specific type and place it in the @@ -701,8 +681,7 @@ int32_t APersistableBundle_getIntKeys(const APersistableBundle* _Nonnull pBundle int32_t APersistableBundle_getLongKeys(const APersistableBundle* _Nonnull pBundle, char* _Nullable* _Nullable outKeys, int32_t bufferSizeBytes, APersistableBundle_stringAllocator stringAllocator, - void* _Nullable context) __INTRODUCED_IN(__ANDROID_API_V__) - __INTRODUCED_IN_LLNDK(202404); + void* _Nullable context) __INTRODUCED_IN(__ANDROID_API_V__); /** * Get all of the keys associated with this specific type and place it in the @@ -734,8 +713,8 @@ int32_t APersistableBundle_getDoubleKeys(const APersistableBundle* _Nonnull pBun char* _Nullable* _Nullable outKeys, int32_t bufferSizeBytes, APersistableBundle_stringAllocator stringAllocator, - void* _Nullable context) __INTRODUCED_IN(__ANDROID_API_V__) - __INTRODUCED_IN_LLNDK(202404); + void* _Nullable context) + __INTRODUCED_IN(__ANDROID_API_V__); /** * Get all of the keys associated with this specific type and place it in the @@ -767,8 +746,8 @@ int32_t APersistableBundle_getStringKeys(const APersistableBundle* _Nonnull pBun char* _Nullable* _Nullable outKeys, int32_t bufferSizeBytes, APersistableBundle_stringAllocator stringAllocator, - void* _Nullable context) __INTRODUCED_IN(__ANDROID_API_V__) - __INTRODUCED_IN_LLNDK(202404); + void* _Nullable context) + __INTRODUCED_IN(__ANDROID_API_V__); /** * Get all of the keys associated with this specific type and place it in the @@ -801,7 +780,7 @@ int32_t APersistableBundle_getBooleanVectorKeys(const APersistableBundle* _Nonnu int32_t bufferSizeBytes, APersistableBundle_stringAllocator stringAllocator, void* _Nullable context) - __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404); + __INTRODUCED_IN(__ANDROID_API_V__); /** * Get all of the keys associated with this specific type and place it in the @@ -834,7 +813,7 @@ int32_t APersistableBundle_getIntVectorKeys(const APersistableBundle* _Nonnull p int32_t bufferSizeBytes, APersistableBundle_stringAllocator stringAllocator, void* _Nullable context) - __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404); + __INTRODUCED_IN(__ANDROID_API_V__); /** * Get all of the keys associated with this specific type and place it in the @@ -867,7 +846,7 @@ int32_t APersistableBundle_getLongVectorKeys(const APersistableBundle* _Nonnull int32_t bufferSizeBytes, APersistableBundle_stringAllocator stringAllocator, void* _Nullable context) - __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404); + __INTRODUCED_IN(__ANDROID_API_V__); /** * Get all of the keys associated with this specific type and place it in the @@ -899,7 +878,7 @@ int32_t APersistableBundle_getDoubleVectorKeys(const APersistableBundle* _Nonnul int32_t bufferSizeBytes, APersistableBundle_stringAllocator stringAllocator, void* _Nullable context) - __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404); + __INTRODUCED_IN(__ANDROID_API_V__); /** * Get all of the keys associated with this specific type and place it in the @@ -932,7 +911,7 @@ int32_t APersistableBundle_getStringVectorKeys(const APersistableBundle* _Nonnul int32_t bufferSizeBytes, APersistableBundle_stringAllocator stringAllocator, void* _Nullable context) - __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404); + __INTRODUCED_IN(__ANDROID_API_V__); /** * Get all of the keys associated with this specific type and place it in the @@ -963,6 +942,6 @@ int32_t APersistableBundle_getStringVectorKeys(const APersistableBundle* _Nonnul int32_t APersistableBundle_getPersistableBundleKeys( const APersistableBundle* _Nonnull pBundle, char* _Nullable* _Nullable outKeys, int32_t bufferSizeBytes, APersistableBundle_stringAllocator stringAllocator, - void* _Nullable context) __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404); + void* _Nullable context) __INTRODUCED_IN(__ANDROID_API_V__); __END_DECLS diff --git a/libs/binder/ndk/include_platform/android/binder_manager.h b/libs/binder/ndk/include_platform/android/binder_manager.h index 41b30a0a0f..cc4943b9c3 100644 --- a/libs/binder/ndk/include_platform/android/binder_manager.h +++ b/libs/binder/ndk/include_platform/android/binder_manager.h @@ -18,7 +18,6 @@ #include <android/binder_ibinder.h> #include <android/binder_status.h> -#include <android/llndk-versioning.h> #include <sys/cdefs.h> __BEGIN_DECLS @@ -257,8 +256,7 @@ void AServiceManager_getUpdatableApexName(const char* instance, void* context, * \return the result of dlopen of the specified HAL */ void* AServiceManager_openDeclaredPassthroughHal(const char* interface, const char* instance, - int flag) __INTRODUCED_IN(__ANDROID_API_V__) - __INTRODUCED_IN_LLNDK(202404); + int flag) __INTRODUCED_IN(__ANDROID_API_V__); /** * Prevent lazy services without client from shutting down their process diff --git a/libs/binder/ndk/include_platform/android/binder_rpc.h b/libs/binder/ndk/include_platform/android/binder_rpc.h new file mode 100644 index 0000000000..9fe5d788b4 --- /dev/null +++ b/libs/binder/ndk/include_platform/android/binder_rpc.h @@ -0,0 +1,320 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <android/binder_ibinder.h> +#include <sys/socket.h> + +__BEGIN_DECLS + +/** + * @defgroup ABinderRpc Binder RPC + * + * This set of APIs makes it possible for a process to use the AServiceManager + * APIs to get binder objects for services that are available over sockets + * instead of the traditional kernel binder with the extra ServiceManager + * process. + * + * These APIs are used to supply libbinder with enough information to create + * and manage the socket connections underneath the ServiceManager APIs so the + * clients do not need to know the service implementation details or what + * transport they use for communication. + * + * @{ + */ + +/** + * This represents an IAccessor implementation from libbinder that is + * responsible for providing a pre-connected socket file descriptor for a + * specific service. The service is an RpcServer and the pre-connected socket is + * used to set up a client RpcSession underneath libbinder's IServiceManager APIs + * to provide the client with the service's binder for remote communication. + */ +typedef struct ABinderRpc_Accessor ABinderRpc_Accessor; + +/** + * This represents an object that supplies ABinderRpc_Accessors to libbinder + * when they are requested. They are requested any time a client is attempting + * to get a service through IServiceManager APIs when the services aren't known by + * servicemanager. + */ +typedef struct ABinderRpc_AccessorProvider ABinderRpc_AccessorProvider; + +/** + * This represents information necessary for libbinder to be able to connect to a + * remote service. + * It supports connecting to linux sockets and is created using sockaddr + * types for sockets supported by libbinder like sockaddr_in, sockaddr_un, + * sockaddr_vm. + */ +typedef struct ABinderRpc_ConnectionInfo ABinderRpc_ConnectionInfo; + +/** + * These APIs provide a way for clients of binder services to be able to get a + * binder object of that service through the existing libbinder/libbinder_ndk + * Service Manager APIs when that service is using RPC Binder over sockets + * instead kernel binder. + * + * Some of these APIs are used on Android hosts when kernel binder is supported + * and the usual servicemanager process is available. Some of these APIs are + * only required when there is no kernel binder or extra servicemanager process + * such as the case of microdroid or similar VMs. + */ + +/** + * This callback is responsible for returning ABinderRpc_Accessor objects for a given + * service instance. These ABinderRpc_Accessor objects are implemented by + * libbinder_ndk and backed by implementations of android::os::IAccessor in + * libbinder. + * + * \param instance name of the service like + * `android.hardware.vibrator.IVibrator/default`. This string must remain + * valid and unchanged for the duration of this function call. + * \param data the data that was associated with this instance when the callback + * was registered. + * \return The ABinderRpc_Accessor associated with the service `instance`. This + * callback gives up ownership of the object once it returns it. The + * caller of this callback (libbinder_ndk) is responsible for deleting it + * with ABinderRpc_Accessor_delete. + */ +typedef ABinderRpc_Accessor* _Nullable (*ABinderRpc_AccessorProvider_getAccessorCallback)( + const char* _Nonnull instance, void* _Nullable data); + +/** + * This callback is responsible deleting the `void* data` object that is passed + * in to ABinderRpc_registerAccessorProvider for the ABinderRpc_AccessorProvider_getAccessorCallback + * to use. That object is owned by the ABinderRpc_AccessorProvider and must remain valid for the + * lifetime of the callback because it may be called and use the object. + * This _delete callback is called after the ABinderRpc_AccessorProvider is remove and + * is guaranteed never to be called again. + * + * \param data a pointer to data that the ABinderRpc_AccessorProvider_getAccessorCallback uses which + * is to be deleted by this call. + */ +typedef void (*ABinderRpc_AccessorProviderUserData_deleteCallback)(void* _Nullable data); + +/** + * Inject an ABinderRpc_AccessorProvider_getAccessorCallback into the process for + * the Service Manager APIs to use to retrieve ABinderRpc_Accessor objects associated + * with different RPC Binder services. + * + * \param provider callback that returns ABinderRpc_Accessors for libbinder to set up + * RPC clients with. + * \param instances array of instances that are supported by this provider. It + * will only be called if the client is looking for an instance that is + * in this list. These instances must be unique per-process. If an + * instance is being registered that was previously registered, this call + * will fail and the ABinderRpc_AccessorProviderUserData_deleteCallback + * will be called to clean up the data. + * This array of strings must remain valid and unchanged for the duration + * of this function call. + * \param number of instances in the instances array. + * \param data pointer that is passed to the ABinderRpc_AccessorProvider callback. + * IMPORTANT: The ABinderRpc_AccessorProvider now OWNS that object that data + * points to. It can be used as necessary in the callback. The data MUST + * remain valid for the lifetime of the provider callback. + * Do not attempt to give ownership of the same object to different + * providers through multiple calls to this function because the first + * one to be deleted will call the onDelete callback. + * \param onDelete callback used to delete the objects that `data` points to. + * This is called after ABinderRpc_AccessorProvider is guaranteed to never be + * called again. Before this callback is called, `data` must remain + * valid. + * \return nullptr on error if the data pointer is non-null and the onDelete + * callback is null or if an instance in the instances list was previously + * registered. In the error case of duplicate instances, if data was + * provided with a ABinderRpc_AccessorProviderUserData_deleteCallback, + * the callback will be called to delete the data. + * Otherwise returns a pointer to the ABinderRpc_AccessorProvider that + * can be used to remove with ABinderRpc_unregisterAccessorProvider. + */ +ABinderRpc_AccessorProvider* _Nullable ABinderRpc_registerAccessorProvider( + ABinderRpc_AccessorProvider_getAccessorCallback _Nonnull provider, + const char* _Nullable* _Nonnull instances, size_t numInstances, void* _Nullable data, + ABinderRpc_AccessorProviderUserData_deleteCallback _Nullable onDelete) __INTRODUCED_IN(36); + +/** + * Remove an ABinderRpc_AccessorProvider from libbinder. This will remove references + * from the ABinderRpc_AccessorProvider and will no longer call the + * ABinderRpc_AccessorProvider_getAccessorCallback. + * + * Note: The `data` object that was used when adding the accessor will be + * deleted by the ABinderRpc_AccessorProviderUserData_deleteCallback at some + * point after this call. Do not use the object and do not try to delete + * it through any other means. + * Note: This will abort when used incorrectly if this provider was never + * registered or if it were already unregistered. + * + * \param provider to be removed and deleted + * + */ +void ABinderRpc_unregisterAccessorProvider(ABinderRpc_AccessorProvider* _Nonnull provider) + __INTRODUCED_IN(36); + +/** + * Callback which returns the RPC connection information for libbinder to use to + * connect to a socket that a given service is listening on. This is needed to + * create an ABinderRpc_Accessor so it can connect to these services. + * + * \param instance name of the service to connect to. This string must remain + * valid and unchanged for the duration of this function call. + * \param data user data for this callback. The pointer is provided in + * ABinderRpc_Accessor_new. + * \return ABinderRpc_ConnectionInfo with socket connection information for `instance` + */ +typedef ABinderRpc_ConnectionInfo* _Nullable (*ABinderRpc_ConnectionInfoProvider)( + const char* _Nonnull instance, void* _Nullable data) __INTRODUCED_IN(36); +/** + * This callback is responsible deleting the `void* data` object that is passed + * in to ABinderRpc_Accessor_new for the ABinderRpc_ConnectionInfoProvider to use. That + * object is owned by the ABinderRpc_Accessor and must remain valid for the + * lifetime the Accessor because it may be used by the connection info provider + * callback. + * This _delete callback is called after the ABinderRpc_Accessor is removed and + * is guaranteed never to be called again. + * + * \param data a pointer to data that the ABinderRpc_AccessorProvider uses which is to + * be deleted by this call. + */ +typedef void (*ABinderRpc_ConnectionInfoProviderUserData_delete)(void* _Nullable data); + +/** + * Create a new ABinderRpc_Accessor. This creates an IAccessor object in libbinder + * that can use the info from the ABinderRpc_ConnectionInfoProvider to connect to a + * socket that the service with `instance` name is listening to. + * + * \param instance name of the service that is listening on the socket. This + * string must remain valid and unchanged for the duration of this + * function call. + * \param provider callback that can get the socket connection information for the + * instance. This connection information may be dynamic, so the + * provider will be called any time a new connection is required. + * \param data pointer that is passed to the ABinderRpc_ConnectionInfoProvider callback. + * IMPORTANT: The ABinderRpc_ConnectionInfoProvider now OWNS that object that data + * points to. It can be used as necessary in the callback. The data MUST + * remain valid for the lifetime of the provider callback. + * Do not attempt to give ownership of the same object to different + * providers through multiple calls to this function because the first + * one to be deleted will call the onDelete callback. + * \param onDelete callback used to delete the objects that `data` points to. + * This is called after ABinderRpc_ConnectionInfoProvider is guaranteed to never be + * called again. Before this callback is called, `data` must remain + * valid. + * \return an ABinderRpc_Accessor instance. This is deleted by the caller once it is + * no longer needed. + */ +ABinderRpc_Accessor* _Nullable ABinderRpc_Accessor_new( + const char* _Nonnull instance, ABinderRpc_ConnectionInfoProvider _Nonnull provider, + void* _Nullable data, ABinderRpc_ConnectionInfoProviderUserData_delete _Nullable onDelete) + __INTRODUCED_IN(36); + +/** + * Delete an ABinderRpc_Accessor + * + * \param accessor to delete + */ +void ABinderRpc_Accessor_delete(ABinderRpc_Accessor* _Nonnull accessor) __INTRODUCED_IN(36); + +/** + * Return the AIBinder associated with an ABinderRpc_Accessor. This can be used to + * send the Accessor to another process or even register it with servicemanager. + * + * \param accessor to get the AIBinder for + * \return binder of the supplied accessor with one strong ref count + */ +AIBinder* _Nullable ABinderRpc_Accessor_asBinder(ABinderRpc_Accessor* _Nonnull accessor) + __INTRODUCED_IN(36); + +/** + * Return the ABinderRpc_Accessor associated with an AIBinder. The instance must match + * the ABinderRpc_Accessor implementation. + * This can be used when receiving an AIBinder from another process that the + * other process obtained from ABinderRpc_Accessor_asBinder. + * + * \param instance name of the service that the Accessor is responsible for. + * This string must remain valid and unchanged for the duration of this + * function call. + * \param accessorBinder proxy binder from another process's ABinderRpc_Accessor. + * This function preserves the refcount of this binder object and the + * caller still owns it. + * \return ABinderRpc_Accessor representing the other processes ABinderRpc_Accessor + * implementation. The caller owns this ABinderRpc_Accessor instance and + * is responsible for deleting it with ABinderRpc_Accessor_delete or + * passing ownership of it elsewhere, like returning it through + * ABinderRpc_AccessorProvider_getAccessorCallback. + * nullptr on error when the accessorBinder is not a valid binder from + * an IAccessor implementation or the IAccessor implementation is not + * associated with the provided instance. + */ +ABinderRpc_Accessor* _Nullable ABinderRpc_Accessor_fromBinder(const char* _Nonnull instance, + AIBinder* _Nonnull accessorBinder) + __INTRODUCED_IN(36); + +/** + * Wrap an ABinderRpc_Accessor proxy binder with a delegator binder. + * + * The IAccessorDelegator binder delegates all calls to the proxy binder. + * + * This is required only in very specific situations when the process that has + * permissions to connect the to RPC service's socket and create the FD for it + * is in a separate process from this process that wants to serve the Accessor + * binder and the communication between these two processes is binder RPC. This + * is needed because the binder passed over the binder RPC connection can not be + * used as a kernel binder, and needs to be wrapped by a kernel binder that can + * then be registered with service manager. + * + * \param instance name of the service associated with the Accessor + * \param binder the AIBinder* from the ABinderRpc_Accessor from the + * ABinderRpc_Accessor_asBinder. The other process across the binder RPC + * connection will have called this and passed the AIBinder* across a + * binder interface to the process calling this function. + * \param outDelegator the AIBinder* for the kernel binder that wraps the + * 'binder' argument and delegates all calls to it. The caller now owns + * this object with one strong ref count and is responsible for removing + * that ref count with with AIBinder_decStrong when the caller wishes to + * drop the reference. + */ +binder_status_t ABinderRpc_Accessor_delegateAccessor(const char* _Nonnull instance, + AIBinder* _Nonnull binder, + AIBinder* _Nullable* _Nonnull outDelegator) + __INTRODUCED_IN(36); + +/** + * Create a new ABinderRpc_ConnectionInfo with sockaddr. This can be supported socket + * types like sockaddr_vm (vsock) and sockaddr_un (Unix Domain Sockets). + * + * \param addr sockaddr pointer that can come from supported socket + * types like sockaddr_vm (vsock) and sockaddr_un (Unix Domain Sockets). + * \param len length of the concrete sockaddr type being used. Like + * sizeof(sockaddr_vm) when sockaddr_vm is used. + * \return the connection info based on the given sockaddr + */ +ABinderRpc_ConnectionInfo* _Nullable ABinderRpc_ConnectionInfo_new(const sockaddr* _Nonnull addr, + socklen_t len) + __INTRODUCED_IN(36); + +/** + * Delete an ABinderRpc_ConnectionInfo object that was created with + * ABinderRpc_ConnectionInfo_new. + * + * \param info object to be deleted + */ +void ABinderRpc_ConnectionInfo_delete(ABinderRpc_ConnectionInfo* _Nonnull info) __INTRODUCED_IN(36); + +/** @} */ + +__END_DECLS diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt index 826e199093..4d691f8e8a 100644 --- a/libs/binder/ndk/libbinder_ndk.map.txt +++ b/libs/binder/ndk/libbinder_ndk.map.txt @@ -248,6 +248,23 @@ LIBBINDER_NDK35 { # introduced=VanillaIceCream AServiceManager_openDeclaredPassthroughHal; # systemapi llndk=202404 }; +LIBBINDER_NDK36 { # introduced=36 + global: + AIBinder_Class_setTransactionCodeToFunctionNameMap; + AIBinder_Class_setTransactionCodeToFunctionNameMap; # llndk=202504 + AIBinder_Class_getFunctionName; + AIBinder_Class_getFunctionName; # llndk=202504 + ABinderRpc_registerAccessorProvider; # systemapi + ABinderRpc_unregisterAccessorProvider; # systemapi + ABinderRpc_Accessor_new; # systemapi + ABinderRpc_Accessor_delegateAccessor; #systemapi + ABinderRpc_Accessor_delete; # systemapi + ABinderRpc_Accessor_asBinder; # systemapi + ABinderRpc_Accessor_fromBinder; # systemapi + ABinderRpc_ConnectionInfo_new; # systemapi + ABinderRpc_ConnectionInfo_delete; # systemapi +}; + LIBBINDER_NDK_PLATFORM { global: AParcel_getAllowFds; diff --git a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp index f518a22902..e5a3da460e 100644 --- a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp +++ b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp @@ -46,6 +46,7 @@ #include "android/binder_ibinder.h" using namespace android; +using namespace std::chrono_literals; constexpr char kExistingNonNdkService[] = "SurfaceFlinger"; constexpr char kBinderNdkUnitTestService[] = "BinderNdkUnitTest"; @@ -54,7 +55,7 @@ constexpr char kForcePersistNdkUnitTestService[] = "ForcePersistNdkUnitTestServi constexpr char kActiveServicesNdkUnitTestService[] = "ActiveServicesNdkUnitTestService"; constexpr char kBinderNdkUnitTestServiceFlagged[] = "BinderNdkUnitTestFlagged"; -constexpr unsigned int kShutdownWaitTime = 11; +constexpr auto kShutdownWaitTime = 30s; constexpr uint64_t kContextTestValue = 0xb4e42fb4d9a1d715; class MyTestFoo : public IFoo { @@ -253,12 +254,22 @@ int lazyService(const char* instance) { } bool isServiceRunning(const char* serviceName) { - AIBinder* binder = AServiceManager_checkService(serviceName); - if (binder == nullptr) { - return false; + static const sp<android::IServiceManager> sm(android::defaultServiceManager()); + const Vector<String16> services = sm->listServices(); + for (const auto service : services) { + if (service == String16(serviceName)) return true; } - AIBinder_decStrong(binder); + return false; +} +bool isServiceShutdownWithWait(const char* serviceName) { + LOG(INFO) << "About to check and wait for shutdown of " << std::string(serviceName); + const auto before = std::chrono::steady_clock::now(); + while (isServiceRunning(serviceName)) { + sleep(1); + const auto after = std::chrono::steady_clock::now(); + if (after - before >= kShutdownWaitTime) return false; + } return true; } @@ -450,8 +461,8 @@ TEST(NdkBinder, CheckLazyServiceShutDown) { service = nullptr; IPCThreadState::self()->flushCommands(); // Make sure the service is dead after some time of no use - sleep(kShutdownWaitTime); - ASSERT_EQ(nullptr, AServiceManager_checkService(kLazyBinderNdkUnitTestService)); + ASSERT_TRUE(isServiceShutdownWithWait(kLazyBinderNdkUnitTestService)) + << "Service failed to shut down"; } TEST(NdkBinder, ForcedPersistenceTest) { @@ -466,14 +477,12 @@ TEST(NdkBinder, ForcedPersistenceTest) { service = nullptr; IPCThreadState::self()->flushCommands(); - sleep(kShutdownWaitTime); - - bool isRunning = isServiceRunning(kForcePersistNdkUnitTestService); - if (i == 0) { - ASSERT_TRUE(isRunning) << "Service shut down when it shouldn't have."; + ASSERT_TRUE(isServiceRunning(kForcePersistNdkUnitTestService)) + << "Service shut down when it shouldn't have."; } else { - ASSERT_FALSE(isRunning) << "Service failed to shut down."; + ASSERT_TRUE(isServiceShutdownWithWait(kForcePersistNdkUnitTestService)) + << "Service failed to shut down"; } } } @@ -491,10 +500,7 @@ TEST(NdkBinder, ActiveServicesCallbackTest) { service = nullptr; IPCThreadState::self()->flushCommands(); - LOG(INFO) << "ActiveServicesCallbackTest about to sleep"; - sleep(kShutdownWaitTime); - - ASSERT_FALSE(isServiceRunning(kActiveServicesNdkUnitTestService)) + ASSERT_TRUE(isServiceShutdownWithWait(kActiveServicesNdkUnitTestService)) << "Service failed to shut down."; } @@ -1102,6 +1108,37 @@ TEST(NdkBinder_ScopedAResource, Release) { EXPECT_EQ(deleteCount, 0); } +void* EmptyOnCreate(void* args) { + return args; +} +void EmptyOnDestroy(void* /*userData*/) {} +binder_status_t EmptyOnTransact(AIBinder* /*binder*/, transaction_code_t /*code*/, + const AParcel* /*in*/, AParcel* /*out*/) { + return STATUS_OK; +} + +TEST(NdkBinder_DeathTest, SetCodeMapTwice) { + const char* codeToFunction1[] = {"function-1", "function-2", "function-3"}; + const char* codeToFunction2[] = {"function-4", "function-5"}; + const char* interfaceName = "interface_descriptor"; + AIBinder_Class* clazz = + AIBinder_Class_define(interfaceName, EmptyOnCreate, EmptyOnDestroy, EmptyOnTransact); + AIBinder_Class_setTransactionCodeToFunctionNameMap(clazz, codeToFunction1, 3); + // Reset/clear is not allowed + EXPECT_DEATH(AIBinder_Class_setTransactionCodeToFunctionNameMap(clazz, codeToFunction2, 2), ""); +} + +TEST(NdkBinder_DeathTest, SetNullCodeMap) { + const char* codeToFunction[] = {"function-1", "function-2", "function-3"}; + const char* interfaceName = "interface_descriptor"; + AIBinder_Class* clazz = + AIBinder_Class_define(interfaceName, EmptyOnCreate, EmptyOnDestroy, EmptyOnTransact); + EXPECT_DEATH(AIBinder_Class_setTransactionCodeToFunctionNameMap(nullptr, codeToFunction, 3), + ""); + EXPECT_DEATH(AIBinder_Class_setTransactionCodeToFunctionNameMap(clazz, nullptr, 0), ""); + EXPECT_DEATH(AIBinder_Class_setTransactionCodeToFunctionNameMap(nullptr, nullptr, 0), ""); +} + int main(int argc, char* argv[]) { ::testing::InitGoogleTest(&argc, argv); diff --git a/libs/binder/rust/Android.bp b/libs/binder/rust/Android.bp index 2deb25457e..4545d7bb2e 100644 --- a/libs/binder/rust/Android.bp +++ b/libs/binder/rust/Android.bp @@ -15,6 +15,8 @@ rust_library { "libbinder_ndk_sys", "libdowncast_rs", "liblibc", + "liblog_rust", + "libnix", ], host_supported: true, vendor_available: true, @@ -79,6 +81,9 @@ rust_library { shared_libs: [ "libbinder_ndk", ], + rustlibs: [ + "liblibc", + ], host_supported: true, vendor_available: true, product_available: true, @@ -129,9 +134,18 @@ rust_bindgen { // rustified "libbinder_ndk_bindgen_flags.txt", ], + bindgen_flags: [ + "--blocklist-type", + "sockaddr", + "--raw-line", + "use libc::sockaddr;", + ], shared_libs: [ "libbinder_ndk", ], + rustlibs: [ + "liblibc", + ], host_supported: true, vendor_available: true, product_available: true, @@ -185,6 +199,8 @@ rust_test { "libbinder_ndk_sys", "libdowncast_rs", "liblibc", + "liblog_rust", + "libnix", ], } @@ -196,4 +212,7 @@ rust_test { auto_gen_config: true, clippy_lints: "none", lints: "none", + rustlibs: [ + "liblibc", + ], } diff --git a/libs/binder/rust/src/binder.rs b/libs/binder/rust/src/binder.rs index 9a252b853b..23026e593c 100644 --- a/libs/binder/rust/src/binder.rs +++ b/libs/binder/rust/src/binder.rs @@ -136,6 +136,31 @@ impl TryFrom<i32> for Stability { } } +/// Same as `Stability`, but in the form of a trait. Used when the stability should be encoded in +/// the type. +/// +/// When/if the `adt_const_params` Rust feature is stabilized, this could be replace by using +/// `Stability` directly with const generics. +pub trait StabilityType { + /// The `Stability` represented by this type. + const VALUE: Stability; +} + +/// `Stability::Local`. +#[derive(Debug)] +pub enum LocalStabilityType {} +/// `Stability::Vintf`. +#[derive(Debug)] +pub enum VintfStabilityType {} + +impl StabilityType for LocalStabilityType { + const VALUE: Stability = Stability::Local; +} + +impl StabilityType for VintfStabilityType { + const VALUE: Stability = Stability::Vintf; +} + /// A local service that can be remotable via Binder. /// /// An object that implement this interface made be made into a Binder service diff --git a/libs/binder/rust/src/lib.rs b/libs/binder/rust/src/lib.rs index e70f4f0232..f7f3f35c9f 100644 --- a/libs/binder/rust/src/lib.rs +++ b/libs/binder/rust/src/lib.rs @@ -104,6 +104,8 @@ mod proxy; mod service; #[cfg(not(trusty))] mod state; +#[cfg(not(any(android_vendor, android_vndk)))] +mod system_only; use binder_ndk_sys as sys; @@ -120,6 +122,8 @@ pub use service::{ }; #[cfg(not(trusty))] pub use state::{ProcessState, ThreadState}; +#[cfg(not(any(android_vendor, android_vndk)))] +pub use system_only::{delegate_accessor, Accessor, ConnectionInfo}; /// Binder result containing a [`Status`] on error. pub type Result<T> = std::result::Result<T, Status>; @@ -128,9 +132,10 @@ pub type Result<T> = std::result::Result<T, Status>; /// without AIDL. pub mod binder_impl { pub use crate::binder::{ - IBinderInternal, InterfaceClass, Remotable, Stability, ToAsyncInterface, ToSyncInterface, - TransactionCode, TransactionFlags, FIRST_CALL_TRANSACTION, FLAG_CLEAR_BUF, FLAG_ONEWAY, - FLAG_PRIVATE_LOCAL, LAST_CALL_TRANSACTION, + IBinderInternal, InterfaceClass, LocalStabilityType, Remotable, Stability, StabilityType, + ToAsyncInterface, ToSyncInterface, TransactionCode, TransactionFlags, VintfStabilityType, + FIRST_CALL_TRANSACTION, FLAG_CLEAR_BUF, FLAG_ONEWAY, FLAG_PRIVATE_LOCAL, + LAST_CALL_TRANSACTION, }; pub use crate::binder_async::BinderAsyncRuntime; pub use crate::error::status_t; diff --git a/libs/binder/rust/src/parcel/parcelable_holder.rs b/libs/binder/rust/src/parcel/parcelable_holder.rs index f90611361f..87b42ab68d 100644 --- a/libs/binder/rust/src/parcel/parcelable_holder.rs +++ b/libs/binder/rust/src/parcel/parcelable_holder.rs @@ -15,6 +15,7 @@ */ use crate::binder::Stability; +use crate::binder::StabilityType; use crate::error::StatusCode; use crate::parcel::{ BorrowedParcel, Deserialize, Parcel, Parcelable, Serialize, NON_NULL_PARCELABLE_FLAG, @@ -60,7 +61,7 @@ enum ParcelableHolderData { /// `Send` nor `Sync`), mainly because it internally contains /// a `Parcel` which in turn is not thread-safe. #[derive(Debug)] -pub struct ParcelableHolder { +pub struct ParcelableHolder<STABILITY: StabilityType> { // This is a `Mutex` because of `get_parcelable` // which takes `&self` for consistency with C++. // We could make `get_parcelable` take a `&mut self` @@ -68,13 +69,17 @@ pub struct ParcelableHolder { // improvement, but then callers would require a mutable // `ParcelableHolder` even for that getter method. data: Mutex<ParcelableHolderData>, - stability: Stability, + + _stability_phantom: std::marker::PhantomData<STABILITY>, } -impl ParcelableHolder { +impl<STABILITY: StabilityType> ParcelableHolder<STABILITY> { /// Construct a new `ParcelableHolder` with the given stability. - pub fn new(stability: Stability) -> Self { - Self { data: Mutex::new(ParcelableHolderData::Empty), stability } + pub fn new() -> Self { + Self { + data: Mutex::new(ParcelableHolderData::Empty), + _stability_phantom: Default::default(), + } } /// Reset the contents of this `ParcelableHolder`. @@ -91,7 +96,7 @@ impl ParcelableHolder { where T: Any + Parcelable + ParcelableMetadata + std::fmt::Debug + Send + Sync, { - if self.stability > p.get_stability() { + if STABILITY::VALUE > p.get_stability() { return Err(StatusCode::BAD_VALUE); } @@ -157,30 +162,36 @@ impl ParcelableHolder { /// Return the stability value of this object. pub fn get_stability(&self) -> Stability { - self.stability + STABILITY::VALUE + } +} + +impl<STABILITY: StabilityType> Default for ParcelableHolder<STABILITY> { + fn default() -> Self { + Self::new() } } -impl Clone for ParcelableHolder { - fn clone(&self) -> ParcelableHolder { +impl<STABILITY: StabilityType> Clone for ParcelableHolder<STABILITY> { + fn clone(&self) -> Self { ParcelableHolder { data: Mutex::new(self.data.lock().unwrap().clone()), - stability: self.stability, + _stability_phantom: Default::default(), } } } -impl Serialize for ParcelableHolder { +impl<STABILITY: StabilityType> Serialize for ParcelableHolder<STABILITY> { fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<(), StatusCode> { parcel.write(&NON_NULL_PARCELABLE_FLAG)?; self.write_to_parcel(parcel) } } -impl Deserialize for ParcelableHolder { +impl<STABILITY: StabilityType> Deserialize for ParcelableHolder<STABILITY> { type UninitType = Self; fn uninit() -> Self::UninitType { - Self::new(Default::default()) + Self::new() } fn from_init(value: Self) -> Self::UninitType { value @@ -191,16 +202,16 @@ impl Deserialize for ParcelableHolder { if status == NULL_PARCELABLE_FLAG { Err(StatusCode::UNEXPECTED_NULL) } else { - let mut parcelable = ParcelableHolder::new(Default::default()); + let mut parcelable = Self::new(); parcelable.read_from_parcel(parcel)?; Ok(parcelable) } } } -impl Parcelable for ParcelableHolder { +impl<STABILITY: StabilityType> Parcelable for ParcelableHolder<STABILITY> { fn write_to_parcel(&self, parcel: &mut BorrowedParcel<'_>) -> Result<(), StatusCode> { - parcel.write(&self.stability)?; + parcel.write(&STABILITY::VALUE)?; let mut data = self.data.lock().unwrap(); match *data { @@ -236,7 +247,7 @@ impl Parcelable for ParcelableHolder { } fn read_from_parcel(&mut self, parcel: &BorrowedParcel<'_>) -> Result<(), StatusCode> { - if self.stability != parcel.read()? { + if self.get_stability() != parcel.read()? { return Err(StatusCode::BAD_VALUE); } diff --git a/libs/binder/rust/src/system_only.rs b/libs/binder/rust/src/system_only.rs new file mode 100644 index 0000000000..08582ab9a3 --- /dev/null +++ b/libs/binder/rust/src/system_only.rs @@ -0,0 +1,213 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use crate::binder::AsNative; +use crate::error::{status_result, Result}; +use crate::proxy::SpIBinder; +use crate::sys; + +use std::ffi::{c_void, CStr, CString}; +use std::os::raw::c_char; + +use libc::sockaddr; +use nix::sys::socket::{SockaddrLike, UnixAddr, VsockAddr}; +use std::sync::Arc; +use std::{fmt, ptr}; + +/// Rust wrapper around ABinderRpc_Accessor objects for RPC binder service management. +/// +/// Dropping the `Accessor` will drop the underlying object and the binder it owns. +pub struct Accessor { + accessor: *mut sys::ABinderRpc_Accessor, +} + +impl fmt::Debug for Accessor { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "ABinderRpc_Accessor({:p})", self.accessor) + } +} + +/// Socket connection info required for libbinder to connect to a service. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum ConnectionInfo { + /// For vsock connection + Vsock(VsockAddr), + /// For unix domain socket connection + Unix(UnixAddr), +} + +/// Safety: A `Accessor` is a wrapper around `ABinderRpc_Accessor` which is +/// `Sync` and `Send`. As +/// `ABinderRpc_Accessor` is threadsafe, this structure is too. +/// The Fn owned the Accessor has `Sync` and `Send` properties +unsafe impl Send for Accessor {} + +/// Safety: A `Accessor` is a wrapper around `ABinderRpc_Accessor` which is +/// `Sync` and `Send`. As `ABinderRpc_Accessor` is threadsafe, this structure is too. +/// The Fn owned the Accessor has `Sync` and `Send` properties +unsafe impl Sync for Accessor {} + +impl Accessor { + /// Create a new accessor that will call the given callback when its + /// connection info is required. + /// The callback object and all objects it captures are owned by the Accessor + /// and will be deleted some time after the Accessor is Dropped. If the callback + /// is being called when the Accessor is Dropped, the callback will not be deleted + /// immediately. + pub fn new<F>(instance: &str, callback: F) -> Accessor + where + F: Fn(&str) -> Option<ConnectionInfo> + Send + Sync + 'static, + { + let callback: *mut c_void = Arc::into_raw(Arc::new(callback)) as *mut c_void; + let inst = CString::new(instance).unwrap(); + + // Safety: The function pointer is a valid connection_info callback. + // This call returns an owned `ABinderRpc_Accessor` pointer which + // must be destroyed via `ABinderRpc_Accessor_delete` when no longer + // needed. + // When the underlying ABinderRpc_Accessor is deleted, it will call + // the cookie_decr_refcount callback to release its strong ref. + let accessor = unsafe { + sys::ABinderRpc_Accessor_new( + inst.as_ptr(), + Some(Self::connection_info::<F>), + callback, + Some(Self::cookie_decr_refcount::<F>), + ) + }; + + Accessor { accessor } + } + + /// Get the underlying binder for this Accessor for when it needs to be either + /// registered with service manager or sent to another process. + pub fn as_binder(&self) -> Option<SpIBinder> { + // Safety: `ABinderRpc_Accessor_asBinder` returns either a null pointer or a + // valid pointer to an owned `AIBinder`. Either of these values is safe to + // pass to `SpIBinder::from_raw`. + unsafe { SpIBinder::from_raw(sys::ABinderRpc_Accessor_asBinder(self.accessor)) } + } + + /// Callback invoked from C++ when the connection info is needed. + /// + /// # Safety + /// + /// The `instance` parameter must be a non-null pointer to a valid C string for + /// CStr::from_ptr. The memory must contain a valid null terminator at the end of + /// the string within isize::MAX from the pointer. The memory must not be mutated for + /// the duration of this function call and must be valid for reads from the pointer + /// to the null terminator. + /// The `cookie` parameter must be the cookie for an `Arc<F>` and + /// the caller must hold a ref-count to it. + unsafe extern "C" fn connection_info<F>( + instance: *const c_char, + cookie: *mut c_void, + ) -> *mut binder_ndk_sys::ABinderRpc_ConnectionInfo + where + F: Fn(&str) -> Option<ConnectionInfo> + Send + Sync + 'static, + { + if cookie.is_null() || instance.is_null() { + log::error!("Cookie({cookie:p}) or instance({instance:p}) is null!"); + return ptr::null_mut(); + } + // Safety: The caller promises that `cookie` is for an Arc<F>. + let callback = unsafe { (cookie as *const F).as_ref().unwrap() }; + + // Safety: The caller in libbinder_ndk will have already verified this is a valid + // C string + let inst = unsafe { + match CStr::from_ptr(instance).to_str() { + Ok(s) => s, + Err(err) => { + log::error!("Failed to get a valid C string! {err:?}"); + return ptr::null_mut(); + } + } + }; + + let connection = match callback(inst) { + Some(con) => con, + None => { + return ptr::null_mut(); + } + }; + + match connection { + ConnectionInfo::Vsock(addr) => { + // Safety: The sockaddr is being copied in the NDK API + unsafe { sys::ABinderRpc_ConnectionInfo_new(addr.as_ptr(), addr.len()) } + } + ConnectionInfo::Unix(addr) => { + // Safety: The sockaddr is being copied in the NDK API + // The cast is from sockaddr_un* to sockaddr*. + unsafe { + sys::ABinderRpc_ConnectionInfo_new(addr.as_ptr() as *const sockaddr, addr.len()) + } + } + } + } + + /// Callback that decrements the ref-count. + /// This is invoked from C++ when a binder is unlinked. + /// + /// # Safety + /// + /// The `cookie` parameter must be the cookie for an `Arc<F>` and + /// the owner must give up a ref-count to it. + unsafe extern "C" fn cookie_decr_refcount<F>(cookie: *mut c_void) + where + F: Fn(&str) -> Option<ConnectionInfo> + Send + Sync + 'static, + { + // Safety: The caller promises that `cookie` is for an Arc<F>. + unsafe { Arc::decrement_strong_count(cookie as *const F) }; + } +} + +impl Drop for Accessor { + fn drop(&mut self) { + // Safety: `self.accessor` is always a valid, owned + // `ABinderRpc_Accessor` pointer returned by + // `ABinderRpc_Accessor_new` when `self` was created. This delete + // method can only be called once when `self` is dropped. + unsafe { + sys::ABinderRpc_Accessor_delete(self.accessor); + } + } +} + +/// Register a new service with the default service manager. +/// +/// Registers the given binder object with the given identifier. If successful, +/// this service can then be retrieved using that identifier. +/// +/// This function will panic if the identifier contains a 0 byte (NUL). +pub fn delegate_accessor(name: &str, mut binder: SpIBinder) -> Result<SpIBinder> { + let instance = CString::new(name).unwrap(); + let mut delegator = ptr::null_mut(); + let status = + // Safety: `AServiceManager_addService` expects valid `AIBinder` and C + // string pointers. Caller retains ownership of both pointers. + // `AServiceManager_addService` creates a new strong reference and copies + // the string, so both pointers need only be valid until the call returns. + unsafe { sys::ABinderRpc_Accessor_delegateAccessor(instance.as_ptr(), + binder.as_native_mut(), &mut delegator) }; + + status_result(status)?; + + // Safety: `delegator` is either null or a valid, owned pointer at this + // point, so can be safely passed to `SpIBinder::from_raw`. + Ok(unsafe { SpIBinder::from_raw(delegator).expect("Expected valid binder at this point") }) +} diff --git a/libs/binder/rust/sys/BinderBindings.hpp b/libs/binder/rust/sys/BinderBindings.hpp index 65fa2ca905..bd666fe0d7 100644 --- a/libs/binder/rust/sys/BinderBindings.hpp +++ b/libs/binder/rust/sys/BinderBindings.hpp @@ -20,6 +20,7 @@ #include <android/binder_parcel.h> #include <android/binder_parcel_platform.h> #include <android/binder_process.h> +#include <android/binder_rpc.h> #include <android/binder_shell.h> #include <android/binder_stability.h> #include <android/binder_status.h> diff --git a/libs/binder/rust/tests/integration.rs b/libs/binder/rust/tests/integration.rs index 5359832da1..489fa0aa69 100644 --- a/libs/binder/rust/tests/integration.rs +++ b/libs/binder/rust/tests/integration.rs @@ -384,8 +384,8 @@ mod tests { use std::time::Duration; use binder::{ - BinderFeatures, DeathRecipient, FromIBinder, IBinder, Interface, SpIBinder, StatusCode, - Strong, + Accessor, BinderFeatures, DeathRecipient, FromIBinder, IBinder, Interface, SpIBinder, + StatusCode, Strong, }; // Import from impl API for testing only, should not be necessary as long as // you are using AIDL. @@ -908,6 +908,80 @@ mod tests { assert_eq!(service.test().unwrap(), service_name); } + struct ToBeDeleted { + deleted: Arc<AtomicBool>, + } + + impl Drop for ToBeDeleted { + fn drop(&mut self) { + assert!(!self.deleted.load(Ordering::Relaxed)); + self.deleted.store(true, Ordering::Relaxed); + } + } + + #[test] + fn test_accessor_callback_destruction() { + let deleted: Arc<AtomicBool> = Arc::new(AtomicBool::new(false)); + { + let accessor: Accessor; + { + let helper = ToBeDeleted { deleted: deleted.clone() }; + let get_connection_info = move |_instance: &str| { + // Capture this object so we can see it get destructed + // after the parent scope + let _ = &helper; + None + }; + accessor = Accessor::new("foo.service", get_connection_info); + } + + match accessor.as_binder() { + Some(_) => { + assert!(!deleted.load(Ordering::Relaxed)); + } + None => panic!("failed to get that accessor binder"), + } + } + assert!(deleted.load(Ordering::Relaxed)); + } + + #[test] + fn test_accessor_delegator_new_each_time() { + let get_connection_info = move |_instance: &str| None; + let accessor = Accessor::new("foo.service", get_connection_info); + let delegator_binder = + binder::delegate_accessor("foo.service", accessor.as_binder().unwrap()); + let delegator_binder2 = + binder::delegate_accessor("foo.service", accessor.as_binder().unwrap()); + + // The delegate_accessor creates new delegators each time + assert!(delegator_binder != delegator_binder2); + } + + #[test] + fn test_accessor_delegate_the_delegator() { + let get_connection_info = move |_instance: &str| None; + let accessor = Accessor::new("foo.service", get_connection_info); + let delegator_binder = + binder::delegate_accessor("foo.service", accessor.as_binder().unwrap()); + let delegator_binder2 = + binder::delegate_accessor("foo.service", delegator_binder.clone().unwrap()); + + assert!(delegator_binder.clone() == delegator_binder); + // The delegate_accessor creates new delegators each time. Even when they are delegators + // of delegators. + assert!(delegator_binder != delegator_binder2); + } + + #[test] + fn test_accessor_delegator_wrong_name() { + let get_connection_info = move |_instance: &str| None; + let accessor = Accessor::new("foo.service", get_connection_info); + let delegator_binder = + binder::delegate_accessor("NOT.foo.service", accessor.as_binder().unwrap()); + assert_eq!(delegator_binder, Err(StatusCode::NAME_NOT_FOUND)); + } + #[tokio::test] async fn reassociate_rust_binder_async() { let service_name = "testing_service"; diff --git a/libs/binder/rust/tests/parcel_fuzzer/parcel_fuzzer.rs b/libs/binder/rust/tests/parcel_fuzzer/parcel_fuzzer.rs index ce0f742934..ee20a22345 100644 --- a/libs/binder/rust/tests/parcel_fuzzer/parcel_fuzzer.rs +++ b/libs/binder/rust/tests/parcel_fuzzer/parcel_fuzzer.rs @@ -21,7 +21,8 @@ mod read_utils; use crate::read_utils::READ_FUNCS; use binder::binder_impl::{ - Binder, BorrowedParcel, IBinderInternal, Parcel, Stability, TransactionCode, + Binder, BorrowedParcel, IBinderInternal, LocalStabilityType, Parcel, TransactionCode, + VintfStabilityType, }; use binder::{ declare_binder_interface, BinderFeatures, Interface, Parcelable, ParcelableHolder, SpIBinder, @@ -121,13 +122,15 @@ fn do_read_fuzz(read_operations: Vec<ReadOperation>, data: &[u8]) { } ReadOperation::ReadParcelableHolder { is_vintf } => { - let stability = if is_vintf { Stability::Vintf } else { Stability::Local }; - let mut holder: ParcelableHolder = ParcelableHolder::new(stability); - match holder.read_from_parcel(parcel.borrowed_ref()) { - Ok(result) => result, - Err(err) => { - println!("error occurred while reading from parcel: {:?}", err) - } + let result = if is_vintf { + ParcelableHolder::<VintfStabilityType>::new() + .read_from_parcel(parcel.borrowed_ref()) + } else { + ParcelableHolder::<LocalStabilityType>::new() + .read_from_parcel(parcel.borrowed_ref()) + }; + if let Err(e) = result { + println!("error occurred while reading from parcel: {e:?}") } } diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp index 0e653af707..8b0dda33dd 100644 --- a/libs/binder/tests/Android.bp +++ b/libs/binder/tests/Android.bp @@ -532,6 +532,9 @@ cc_test { static_libs: [ "libbinder_rpc_single_threaded", ], + shared_libs: [ + "libbinder_ndk", + ], } cc_test { diff --git a/libs/binder/tests/binderCacheUnitTest.cpp b/libs/binder/tests/binderCacheUnitTest.cpp index 92dab19a63..c5ad79391c 100644 --- a/libs/binder/tests/binderCacheUnitTest.cpp +++ b/libs/binder/tests/binderCacheUnitTest.cpp @@ -137,9 +137,9 @@ TEST_F(LibbinderCacheTest, RemoveFromCacheOnServerDeath) { ASSERT_EQ(binder1, result); // Kill the server, this should remove from cache. - foo.killServer(binder1); pid_t pid; ASSERT_EQ(OK, binder1->getDebugPid(&pid)); + foo.killServer(binder1); system(("kill -9 " + std::to_string(pid)).c_str()); sp<IBinder> binder2 = sp<BBinder>::make(); @@ -149,7 +149,16 @@ TEST_F(LibbinderCacheTest, RemoveFromCacheOnServerDeath) { EXPECT_EQ(OK, mServiceManager->addService(kCachedServiceName, binder2)); // Confirm that new service is returned instead of old. - sp<IBinder> result2 = mServiceManager->checkService(kCachedServiceName); + int retry_count = 20; + sp<IBinder> result2; + do { + std::this_thread::sleep_for(std::chrono::milliseconds(50)); + if (retry_count-- == 0) { + break; + } + result2 = mServiceManager->checkService(kCachedServiceName); + } while (result2 != binder2); + ASSERT_EQ(binder2, result2); } diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp index fbca35e81f..506fc716cd 100644 --- a/libs/binder/tests/binderRpcTest.cpp +++ b/libs/binder/tests/binderRpcTest.cpp @@ -46,6 +46,13 @@ #include "binderRpcTestCommon.h" #include "binderRpcTestFixture.h" +// TODO need to add IServiceManager.cpp/.h to libbinder_no_kernel +#ifdef BINDER_WITH_KERNEL_IPC +#include "android-base/logging.h" +#include "android/binder_manager.h" +#include "android/binder_rpc.h" +#endif // BINDER_WITH_KERNEL_IPC + using namespace std::chrono_literals; using namespace std::placeholders; using android::binder::borrowed_fd; @@ -68,6 +75,8 @@ constexpr bool kEnableSharedLibs = true; constexpr char kTrustyIpcDevice[] = "/dev/trusty-ipc-dev0"; #endif +constexpr char kKnownAidlService[] = "activity"; + static std::string WaitStatusToString(int wstatus) { if (WIFEXITED(wstatus)) { return "exit status " + std::to_string(WEXITSTATUS(wstatus)); @@ -454,7 +463,7 @@ TEST_P(BinderRpc, ThreadPoolGreaterThanEqualRequested) { GTEST_SKIP() << "This test requires multiple threads"; } - constexpr size_t kNumThreads = 10; + constexpr size_t kNumThreads = 5; auto proc = createRpcTestSocketServerProcess({.numThreads = kNumThreads}); @@ -499,11 +508,11 @@ static void testThreadPoolOverSaturated(sp<IBinderRpcTest> iface, size_t numCall EXPECT_GE(epochMsAfter, epochMsBefore + 2 * sleepMs); - // Potential flake, but make sure calls are handled in parallel. Due - // to past flakes, this only checks that the amount of time taken has - // some parallelism. Other tests such as ThreadPoolGreaterThanEqualRequested - // check this more exactly. - EXPECT_LE(epochMsAfter, epochMsBefore + (numCalls - 1) * sleepMs); + // b/272429574, b/365294257 + // This flakes too much to test. Parallelization is tested + // in ThreadPoolGreaterThanEqualRequested and other tests. + // Test to make sure calls are handled in parallel. + // EXPECT_LE(epochMsAfter, epochMsBefore + (numCalls - 1) * sleepMs); } TEST_P(BinderRpc, ThreadPoolOverSaturated) { @@ -515,8 +524,7 @@ TEST_P(BinderRpc, ThreadPoolOverSaturated) { constexpr size_t kNumCalls = kNumThreads + 3; auto proc = createRpcTestSocketServerProcess({.numThreads = kNumThreads}); - // b/272429574 - below 500ms, the test fails - testThreadPoolOverSaturated(proc.rootIface, kNumCalls, 500 /*ms*/); + testThreadPoolOverSaturated(proc.rootIface, kNumCalls, 200 /*ms*/); } TEST_P(BinderRpc, ThreadPoolLimitOutgoing) { @@ -530,8 +538,7 @@ TEST_P(BinderRpc, ThreadPoolLimitOutgoing) { auto proc = createRpcTestSocketServerProcess( {.numThreads = kNumThreads, .numOutgoingConnections = kNumOutgoingConnections}); - // b/272429574 - below 500ms, the test fails - testThreadPoolOverSaturated(proc.rootIface, kNumCalls, 500 /*ms*/); + testThreadPoolOverSaturated(proc.rootIface, kNumCalls, 200 /*ms*/); } TEST_P(BinderRpc, ThreadingStressTest) { @@ -1206,27 +1213,29 @@ TEST_P(BinderRpcAccessor, InjectAndGetServiceHappyPath) { auto proc = createRpcTestSocketServerProcess({.numThreads = kNumThreads}); EXPECT_EQ(OK, proc.rootBinder->pingBinder()); - auto receipt = addAccessorProvider([&](const String16& name) -> sp<IBinder> { - return createAccessor(name, - [&](const String16& name, sockaddr* outAddr, - socklen_t addrSize) -> status_t { - if (outAddr == nullptr || - addrSize < proc.proc->sessions[0].addrLen) { - return BAD_VALUE; - } - if (name == kInstanceName) { - if (proc.proc->sessions[0].addr.ss_family == AF_UNIX) { - sockaddr_un* un = reinterpret_cast<sockaddr_un*>( - &proc.proc->sessions[0].addr); - ALOGE("inside callback: %s", un->sun_path); - } - std::memcpy(outAddr, &proc.proc->sessions[0].addr, - proc.proc->sessions[0].addrLen); - return OK; - } - return NAME_NOT_FOUND; - }); - }); + auto receipt = addAccessorProvider( + {String8(kInstanceName).c_str()}, [&](const String16& name) -> sp<IBinder> { + return createAccessor(name, + [&](const String16& name, sockaddr* outAddr, + socklen_t addrSize) -> status_t { + if (outAddr == nullptr || + addrSize < proc.proc->sessions[0].addrLen) { + return BAD_VALUE; + } + if (name == kInstanceName) { + if (proc.proc->sessions[0].addr.ss_family == + AF_UNIX) { + sockaddr_un* un = reinterpret_cast<sockaddr_un*>( + &proc.proc->sessions[0].addr); + ALOGE("inside callback: %s", un->sun_path); + } + std::memcpy(outAddr, &proc.proc->sessions[0].addr, + proc.proc->sessions[0].addrLen); + return OK; + } + return NAME_NOT_FOUND; + }); + }); EXPECT_FALSE(receipt.expired()); @@ -1253,7 +1262,8 @@ TEST_P(BinderRpcAccessor, InjectNoAccessorProvided) { bool isProviderDeleted = false; - auto receipt = addAccessorProvider([&](const String16&) -> sp<IBinder> { return nullptr; }); + auto receipt = addAccessorProvider({String8(kInstanceName).c_str()}, + [&](const String16&) -> sp<IBinder> { return nullptr; }); EXPECT_FALSE(receipt.expired()); sp<IBinder> binder = defaultServiceManager()->checkService(kInstanceName); @@ -1263,6 +1273,32 @@ TEST_P(BinderRpcAccessor, InjectNoAccessorProvided) { EXPECT_EQ(status, OK); } +TEST_P(BinderRpcAccessor, InjectDuplicateAccessorProvider) { + const String16 kInstanceName("super.cool.service/better_than_default"); + const String16 kInstanceName2("super.cool.service/better_than_default2"); + + auto receipt = + addAccessorProvider({String8(kInstanceName).c_str(), String8(kInstanceName2).c_str()}, + [&](const String16&) -> sp<IBinder> { return nullptr; }); + EXPECT_FALSE(receipt.expired()); + // reject this because it's associated with an already used instance name + auto receipt2 = addAccessorProvider({String8(kInstanceName).c_str()}, + [&](const String16&) -> sp<IBinder> { return nullptr; }); + EXPECT_TRUE(receipt2.expired()); + + // the first provider should still be usable + sp<IBinder> binder = defaultServiceManager()->checkService(kInstanceName); + EXPECT_EQ(binder, nullptr); + + status_t status = removeAccessorProvider(receipt); + EXPECT_EQ(status, OK); +} + +TEST_P(BinderRpcAccessor, InjectAccessorProviderNoInstance) { + auto receipt = addAccessorProvider({}, [&](const String16&) -> sp<IBinder> { return nullptr; }); + EXPECT_TRUE(receipt.expired()); +} + TEST_P(BinderRpcAccessor, InjectNoSockaddrProvided) { constexpr size_t kNumThreads = 10; const String16 kInstanceName("super.cool.service/better_than_default"); @@ -1273,12 +1309,15 @@ TEST_P(BinderRpcAccessor, InjectNoSockaddrProvided) { bool isProviderDeleted = false; bool isAccessorDeleted = false; - auto receipt = addAccessorProvider([&](const String16& name) -> sp<IBinder> { - return createAccessor(name, [&](const String16&, sockaddr*, socklen_t) -> status_t { - // don't fill in outAddr - return NAME_NOT_FOUND; - }); - }); + auto receipt = addAccessorProvider({String8(kInstanceName).c_str()}, + [&](const String16& name) -> sp<IBinder> { + return createAccessor(name, + [&](const String16&, sockaddr*, + socklen_t) -> status_t { + // don't fill in outAddr + return NAME_NOT_FOUND; + }); + }); EXPECT_FALSE(receipt.expired()); @@ -1289,6 +1328,324 @@ TEST_P(BinderRpcAccessor, InjectNoSockaddrProvided) { EXPECT_EQ(status, OK); } +constexpr const char* kARpcInstance = "some.instance.name.IFoo/default"; +const char* kARpcSupportedServices[] = { + kARpcInstance, +}; +const uint32_t kARpcNumSupportedServices = 1; + +struct ConnectionInfoData { + sockaddr_storage addr; + socklen_t len; + bool* isDeleted; + ~ConnectionInfoData() { + if (isDeleted) *isDeleted = true; + } +}; + +struct AccessorProviderData { + sockaddr_storage addr; + socklen_t len; + bool* isDeleted; + ~AccessorProviderData() { + if (isDeleted) *isDeleted = true; + } +}; + +void accessorProviderDataOnDelete(void* data) { + delete reinterpret_cast<AccessorProviderData*>(data); +} +void infoProviderDataOnDelete(void* data) { + delete reinterpret_cast<ConnectionInfoData*>(data); +} + +ABinderRpc_ConnectionInfo* infoProvider(const char* instance, void* cookie) { + if (instance == nullptr || cookie == nullptr) return nullptr; + ConnectionInfoData* data = reinterpret_cast<ConnectionInfoData*>(cookie); + return ABinderRpc_ConnectionInfo_new(reinterpret_cast<const sockaddr*>(&data->addr), data->len); +} + +ABinderRpc_Accessor* getAccessor(const char* instance, void* cookie) { + if (instance == nullptr || cookie == nullptr) return nullptr; + if (0 != strcmp(instance, kARpcInstance)) return nullptr; + + AccessorProviderData* data = reinterpret_cast<AccessorProviderData*>(cookie); + + ConnectionInfoData* info = new ConnectionInfoData{ + .addr = data->addr, + .len = data->len, + .isDeleted = nullptr, + }; + + return ABinderRpc_Accessor_new(instance, infoProvider, info, infoProviderDataOnDelete); +} + +class BinderARpcNdk : public ::testing::Test {}; + +TEST_F(BinderARpcNdk, ARpcProviderNewDelete) { + bool isDeleted = false; + + AccessorProviderData* data = new AccessorProviderData{{}, 0, &isDeleted}; + + ABinderRpc_AccessorProvider* provider = + ABinderRpc_registerAccessorProvider(getAccessor, kARpcSupportedServices, + kARpcNumSupportedServices, data, + accessorProviderDataOnDelete); + + ASSERT_NE(provider, nullptr); + EXPECT_FALSE(isDeleted); + + ABinderRpc_unregisterAccessorProvider(provider); + + EXPECT_TRUE(isDeleted); +} + +TEST_F(BinderARpcNdk, ARpcProviderDuplicateInstance) { + const char* instance = "some.instance.name.IFoo/default"; + const uint32_t numInstances = 2; + const char* instances[numInstances] = { + instance, + "some.other.instance/default", + }; + + bool isDeleted = false; + + AccessorProviderData* data = new AccessorProviderData{{}, 0, &isDeleted}; + + ABinderRpc_AccessorProvider* provider = + ABinderRpc_registerAccessorProvider(getAccessor, instances, numInstances, data, + accessorProviderDataOnDelete); + + ASSERT_NE(provider, nullptr); + EXPECT_FALSE(isDeleted); + + const uint32_t numInstances2 = 1; + const char* instances2[numInstances2] = { + instance, + }; + bool isDeleted2 = false; + AccessorProviderData* data2 = new AccessorProviderData{{}, 0, &isDeleted2}; + ABinderRpc_AccessorProvider* provider2 = + ABinderRpc_registerAccessorProvider(getAccessor, instances2, numInstances2, data2, + accessorProviderDataOnDelete); + + EXPECT_EQ(provider2, nullptr); + // If it fails to be registered, the data is still cleaned up with + // accessorProviderDataOnDelete + EXPECT_TRUE(isDeleted2); + + ABinderRpc_unregisterAccessorProvider(provider); + + EXPECT_TRUE(isDeleted); +} + +TEST_F(BinderARpcNdk, ARpcProviderRegisterNoInstance) { + const uint32_t numInstances = 0; + const char* instances[numInstances] = {}; + + bool isDeleted = false; + AccessorProviderData* data = new AccessorProviderData{{}, 0, &isDeleted}; + + ABinderRpc_AccessorProvider* provider = + ABinderRpc_registerAccessorProvider(getAccessor, instances, numInstances, data, + accessorProviderDataOnDelete); + ASSERT_EQ(provider, nullptr); +} + +TEST_F(BinderARpcNdk, ARpcAccessorNewDelete) { + bool isDeleted = false; + + ConnectionInfoData* data = new ConnectionInfoData{{}, 0, &isDeleted}; + + ABinderRpc_Accessor* accessor = + ABinderRpc_Accessor_new("gshoe_service", infoProvider, data, infoProviderDataOnDelete); + ASSERT_NE(accessor, nullptr); + EXPECT_FALSE(isDeleted); + + ABinderRpc_Accessor_delete(accessor); + EXPECT_TRUE(isDeleted); +} + +TEST_F(BinderARpcNdk, ARpcConnectionInfoNewDelete) { + sockaddr_vm addr{ + .svm_family = AF_VSOCK, + .svm_port = VMADDR_PORT_ANY, + .svm_cid = VMADDR_CID_ANY, + }; + + ABinderRpc_ConnectionInfo* info = + ABinderRpc_ConnectionInfo_new(reinterpret_cast<sockaddr*>(&addr), sizeof(sockaddr_vm)); + EXPECT_NE(info, nullptr); + + ABinderRpc_ConnectionInfo_delete(info); +} + +TEST_F(BinderARpcNdk, ARpcAsFromBinderAsBinder) { + bool isDeleted = false; + + ConnectionInfoData* data = new ConnectionInfoData{{}, 0, &isDeleted}; + + ABinderRpc_Accessor* accessor = + ABinderRpc_Accessor_new("gshoe_service", infoProvider, data, infoProviderDataOnDelete); + ASSERT_NE(accessor, nullptr); + EXPECT_FALSE(isDeleted); + + { + ndk::SpAIBinder binder = ndk::SpAIBinder(ABinderRpc_Accessor_asBinder(accessor)); + EXPECT_NE(binder.get(), nullptr); + + ABinderRpc_Accessor* accessor2 = + ABinderRpc_Accessor_fromBinder("wrong_service_name", binder.get()); + // The API checks for the expected service name that is associated with + // the accessor! + EXPECT_EQ(accessor2, nullptr); + + accessor2 = ABinderRpc_Accessor_fromBinder("gshoe_service", binder.get()); + EXPECT_NE(accessor2, nullptr); + + // this is a new ABinderRpc_Accessor object that wraps the underlying + // libbinder object. + EXPECT_NE(accessor, accessor2); + + ndk::SpAIBinder binder2 = ndk::SpAIBinder(ABinderRpc_Accessor_asBinder(accessor2)); + EXPECT_EQ(binder.get(), binder2.get()); + + ABinderRpc_Accessor_delete(accessor2); + } + + EXPECT_FALSE(isDeleted); + ABinderRpc_Accessor_delete(accessor); + EXPECT_TRUE(isDeleted); +} + +TEST_F(BinderARpcNdk, ARpcRequireProviderOnDeleteCallback) { + EXPECT_EQ(nullptr, + ABinderRpc_registerAccessorProvider(getAccessor, kARpcSupportedServices, + kARpcNumSupportedServices, + reinterpret_cast<void*>(1), nullptr)); +} + +TEST_F(BinderARpcNdk, ARpcRequireInfoOnDeleteCallback) { + EXPECT_EQ(nullptr, + ABinderRpc_Accessor_new("the_best_service_name", infoProvider, + reinterpret_cast<void*>(1), nullptr)); +} + +TEST_F(BinderARpcNdk, ARpcNoDataNoProviderOnDeleteCallback) { + ABinderRpc_AccessorProvider* provider = + ABinderRpc_registerAccessorProvider(getAccessor, kARpcSupportedServices, + kARpcNumSupportedServices, nullptr, nullptr); + ASSERT_NE(nullptr, provider); + ABinderRpc_unregisterAccessorProvider(provider); +} + +TEST_F(BinderARpcNdk, ARpcNoDataNoInfoOnDeleteCallback) { + ABinderRpc_Accessor* accessor = + ABinderRpc_Accessor_new("the_best_service_name", infoProvider, nullptr, nullptr); + ASSERT_NE(nullptr, accessor); + ABinderRpc_Accessor_delete(accessor); +} + +TEST_F(BinderARpcNdk, ARpcNullArgs_ConnectionInfo_new) { + sockaddr_storage addr; + EXPECT_EQ(nullptr, ABinderRpc_ConnectionInfo_new(reinterpret_cast<const sockaddr*>(&addr), 0)); +} + +TEST_F(BinderARpcNdk, ARpcDelegateAccessorWrongInstance) { + AccessorProviderData* data = new AccessorProviderData(); + ABinderRpc_Accessor* accessor = getAccessor(kARpcInstance, data); + ASSERT_NE(accessor, nullptr); + AIBinder* localAccessorBinder = ABinderRpc_Accessor_asBinder(accessor); + EXPECT_NE(localAccessorBinder, nullptr); + + AIBinder* delegatorBinder = nullptr; + binder_status_t status = + ABinderRpc_Accessor_delegateAccessor("bar", localAccessorBinder, &delegatorBinder); + EXPECT_EQ(status, NAME_NOT_FOUND); + + AIBinder_decStrong(localAccessorBinder); + ABinderRpc_Accessor_delete(accessor); + delete data; +} + +TEST_F(BinderARpcNdk, ARpcDelegateNonAccessor) { + auto service = defaultServiceManager()->checkService(String16(kKnownAidlService)); + ASSERT_NE(nullptr, service); + ndk::SpAIBinder binder = ndk::SpAIBinder(AIBinder_fromPlatformBinder(service)); + + AIBinder* delegatorBinder = nullptr; + binder_status_t status = + ABinderRpc_Accessor_delegateAccessor("bar", binder.get(), &delegatorBinder); + + EXPECT_EQ(status, BAD_TYPE); +} + +inline void getServiceTest(BinderRpcTestProcessSession& proc, + ABinderRpc_AccessorProvider_getAccessorCallback getAccessor) { + constexpr size_t kNumThreads = 10; + bool isDeleted = false; + + AccessorProviderData* data = + new AccessorProviderData{proc.proc->sessions[0].addr, proc.proc->sessions[0].addrLen, + &isDeleted}; + ABinderRpc_AccessorProvider* provider = + ABinderRpc_registerAccessorProvider(getAccessor, kARpcSupportedServices, + kARpcNumSupportedServices, data, + accessorProviderDataOnDelete); + EXPECT_NE(provider, nullptr); + EXPECT_FALSE(isDeleted); + + { + ndk::SpAIBinder binder = ndk::SpAIBinder(AServiceManager_checkService(kARpcInstance)); + ASSERT_NE(binder.get(), nullptr); + EXPECT_EQ(STATUS_OK, AIBinder_ping(binder.get())); + } + + ABinderRpc_unregisterAccessorProvider(provider); + EXPECT_TRUE(isDeleted); + + waitForExtraSessionCleanup(proc); +} + +TEST_P(BinderRpcAccessor, ARpcGetService) { + constexpr size_t kNumThreads = 10; + auto proc = createRpcTestSocketServerProcess({.numThreads = kNumThreads}); + EXPECT_EQ(OK, proc.rootBinder->pingBinder()); + + getServiceTest(proc, getAccessor); +} + +// Create accessors and wrap each of the accessors in a delegator +ABinderRpc_Accessor* getDelegatedAccessor(const char* instance, void* cookie) { + ABinderRpc_Accessor* accessor = getAccessor(instance, cookie); + AIBinder* accessorBinder = ABinderRpc_Accessor_asBinder(accessor); + // Once we have a handle to the AIBinder which holds a reference to the + // underlying accessor IBinder, we can get rid of the ABinderRpc_Accessor + ABinderRpc_Accessor_delete(accessor); + + AIBinder* delegatorBinder = nullptr; + binder_status_t status = + ABinderRpc_Accessor_delegateAccessor(instance, accessorBinder, &delegatorBinder); + // No longer need this AIBinder. The delegator has a reference to the + // underlying IBinder on success, and on failure we are done here. + AIBinder_decStrong(accessorBinder); + if (status != OK || delegatorBinder == nullptr) { + ALOGE("Unexpected behavior. Status: %s, delegator ptr: %p", statusToString(status).c_str(), + delegatorBinder); + return nullptr; + } + + return ABinderRpc_Accessor_fromBinder(instance, delegatorBinder); +} + +TEST_P(BinderRpcAccessor, ARpcGetServiceWithDelegator) { + constexpr size_t kNumThreads = 10; + auto proc = createRpcTestSocketServerProcess({.numThreads = kNumThreads}); + EXPECT_EQ(OK, proc.rootBinder->pingBinder()); + + getServiceTest(proc, getDelegatedAccessor); +} + #endif // BINDER_WITH_KERNEL_IPC #ifdef BINDER_RPC_TO_TRUSTY_TEST @@ -1554,7 +1911,7 @@ TEST(BinderRpc, Java) { ASSERT_NE(nullptr, sm); // Any Java service with non-empty getInterfaceDescriptor() would do. // Let's pick activity. - auto binder = sm->checkService(String16("activity")); + auto binder = sm->checkService(String16(kKnownAidlService)); ASSERT_NE(nullptr, binder); auto descriptor = binder->getInterfaceDescriptor(); ASSERT_GE(descriptor.size(), 0u); diff --git a/libs/binder/tests/parcel_fuzzer/Android.bp b/libs/binder/tests/parcel_fuzzer/Android.bp index fbab8f08a9..cac054eb1b 100644 --- a/libs/binder/tests/parcel_fuzzer/Android.bp +++ b/libs/binder/tests/parcel_fuzzer/Android.bp @@ -39,6 +39,7 @@ cc_fuzz { "smoreland@google.com", "waghpawan@google.com", ], + triage_assignee: "smoreland@google.com", use_for_presubmit: true, }, diff --git a/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp b/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp index 3a1471eabe..e3a337171f 100644 --- a/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp +++ b/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp @@ -49,7 +49,8 @@ static binder_status_t onTransact(AIBinder*, transaction_code_t, const AParcel*, return STATUS_UNKNOWN_TRANSACTION; } -static AIBinder_Class* g_class = ::ndk::ICInterface::defineClass("ISomeInterface", onTransact); +static AIBinder_Class* g_class = + ::ndk::ICInterface::defineClass("ISomeInterface", onTransact, nullptr, 0); class BpSomeInterface : public ::ndk::BpCInterface<ISomeInterface> { public: diff --git a/libs/binder/trusty/OS.cpp b/libs/binder/trusty/OS.cpp index 157ab3c85d..ba9e457a75 100644 --- a/libs/binder/trusty/OS.cpp +++ b/libs/binder/trusty/OS.cpp @@ -42,6 +42,10 @@ void trace_end(uint64_t) {} void trace_int(uint64_t, const char*, int32_t) {} +uint64_t get_trace_enabled_tags() { + return 0; +} + uint64_t GetThreadId() { return 0; } diff --git a/libs/binder/trusty/ndk/include/android/llndk-versioning.h b/libs/binder/trusty/ndk/include/android/llndk-versioning.h index 3ae3d8f577..e955a34bdf 100644 --- a/libs/binder/trusty/ndk/include/android/llndk-versioning.h +++ b/libs/binder/trusty/ndk/include/android/llndk-versioning.h @@ -15,4 +15,5 @@ */ #pragma once -#define __INTRODUCED_IN_LLNDK(x) /* nothing on Trusty */ +// TODO(b/349936395): set to true for Trusty +#define API_LEVEL_AT_LEAST(sdk_api_level, vendor_api_level) (false) diff --git a/libs/binder/trusty/rust/binder_rpc_test/main.rs b/libs/binder/trusty/rust/binder_rpc_test/main.rs index baea5a827b..da1a86fef4 100644 --- a/libs/binder/trusty/rust/binder_rpc_test/main.rs +++ b/libs/binder/trusty/rust/binder_rpc_test/main.rs @@ -19,7 +19,7 @@ use binder::{BinderFeatures, IBinder, Status, StatusCode, Strong}; use binder_rpc_test_aidl::aidl::IBinderRpcSession::{BnBinderRpcSession, IBinderRpcSession}; use binder_rpc_test_aidl::aidl::IBinderRpcTest::{BnBinderRpcTest, IBinderRpcTest}; use binder_rpc_test_session::MyBinderRpcSession; -use libc::{clock_gettime, CLOCK_REALTIME}; +use libc::{clock_gettime, CLOCK_BOOTTIME}; use rpcbinder::RpcSession; use trusty_std::ffi::{CString, FallibleCString}; @@ -56,7 +56,7 @@ fn get_time_ns() -> u64 { let mut ts = libc::timespec { tv_sec: 0, tv_nsec: 0 }; // Safety: Passing valid pointer to variable ts which lives past end of call - assert_eq!(unsafe { clock_gettime(CLOCK_REALTIME, &mut ts) }, 0); + assert_eq!(unsafe { clock_gettime(CLOCK_BOOTTIME, &mut ts) }, 0); ts.tv_sec as u64 * 1_000_000_000u64 + ts.tv_nsec as u64 } diff --git a/libs/binder/trusty/rust/rpcbinder/rules.mk b/libs/binder/trusty/rust/rpcbinder/rules.mk index 97f5c03cba..04c63f72f8 100644 --- a/libs/binder/trusty/rust/rpcbinder/rules.mk +++ b/libs/binder/trusty/rust/rpcbinder/rules.mk @@ -29,8 +29,8 @@ MODULE_LIBRARY_DEPS += \ $(LIBBINDER_DIR)/trusty/rust/binder_ndk_sys \ $(LIBBINDER_DIR)/trusty/rust/binder_rpc_unstable_bindgen \ $(LIBBINDER_DIR)/trusty/rust/binder_rpc_server_bindgen \ - external/rust/crates/cfg-if \ - external/rust/crates/foreign-types \ + $(call FIND_CRATE,cfg-if) \ + $(call FIND_CRATE,foreign-types) \ trusty/user/base/lib/tipc/rust \ trusty/user/base/lib/trusty-sys \ diff --git a/libs/binder/trusty/rust/rules.mk b/libs/binder/trusty/rust/rules.mk index 36bd3a2e75..e622b22246 100644 --- a/libs/binder/trusty/rust/rules.mk +++ b/libs/binder/trusty/rust/rules.mk @@ -27,8 +27,8 @@ MODULE_LIBRARY_DEPS += \ $(LIBBINDER_DIR)/trusty/ndk \ $(LIBBINDER_DIR)/trusty/rust/binder_ndk_sys \ $(LIBBINDER_DIR)/trusty/rust/binder_rpc_unstable_bindgen \ - external/rust/crates/downcast-rs \ - external/rust/crates/libc \ + $(call FIND_CRATE,downcast-rs) \ + $(call FIND_CRATE,libc) \ trusty/user/base/lib/trusty-sys \ MODULE_RUSTFLAGS += \ diff --git a/libs/debugstore/OWNERS b/libs/debugstore/OWNERS index 428a1a2215..c8e22b70ff 100644 --- a/libs/debugstore/OWNERS +++ b/libs/debugstore/OWNERS @@ -1,3 +1,2 @@ benmiles@google.com -gaillard@google.com mohamadmahmoud@google.com diff --git a/libs/debugstore/rust/Android.bp b/libs/debugstore/rust/Android.bp index 55ba3c32d1..9475333a72 100644 --- a/libs/debugstore/rust/Android.bp +++ b/libs/debugstore/rust/Android.bp @@ -23,7 +23,6 @@ rust_defaults { rustlibs: [ "libcrossbeam_queue", "libparking_lot", - "libonce_cell", "libcxx", ], shared_libs: ["libutils"], diff --git a/libs/debugstore/rust/src/core.rs b/libs/debugstore/rust/src/core.rs index 1dfa512151..6bf79d4e57 100644 --- a/libs/debugstore/rust/src/core.rs +++ b/libs/debugstore/rust/src/core.rs @@ -17,12 +17,14 @@ use super::event::Event; use super::event_type::EventType; use super::storage::Storage; use crate::cxxffi::uptimeMillis; -use once_cell::sync::Lazy; use std::fmt; -use std::sync::atomic::{AtomicU64, Ordering}; +use std::sync::{ + atomic::{AtomicU64, Ordering}, + LazyLock, +}; // Lazily initialized static instance of DebugStore. -static INSTANCE: Lazy<DebugStore> = Lazy::new(DebugStore::new); +static INSTANCE: LazyLock<DebugStore> = LazyLock::new(DebugStore::new); /// The `DebugStore` struct is responsible for managing debug events and data. pub struct DebugStore { diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index 739c3c2a41..044170c378 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -1096,6 +1096,17 @@ public: AsyncWorker::getInstance().post( [listener = mListener, slots = slots]() { listener->onBuffersDiscarded(slots); }); } + + void onBufferDetached(int slot) override { + AsyncWorker::getInstance().post( + [listener = mListener, slot = slot]() { listener->onBufferDetached(slot); }); + } + +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_CONSUMER_ATTACH_CALLBACK) + void onBufferAttached() override { + AsyncWorker::getInstance().post([listener = mListener]() { listener->onBufferAttached(); }); + } +#endif }; // Extends the BufferQueueProducer to create a wrapper around the listener so the listener calls diff --git a/libs/gui/IProducerListener.cpp b/libs/gui/IProducerListener.cpp index 7700795e1d..8b9b090496 100644 --- a/libs/gui/IProducerListener.cpp +++ b/libs/gui/IProducerListener.cpp @@ -184,4 +184,10 @@ bool BnProducerListener::needsReleaseNotify() { void BnProducerListener::onBuffersDiscarded(const std::vector<int32_t>& /*discardedSlots*/) { } +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_CONSUMER_ATTACH_CALLBACK) +bool BnProducerListener::needsAttachNotify() { + return true; +} +#endif + } // namespace android diff --git a/libs/gui/include/gui/IProducerListener.h b/libs/gui/include/gui/IProducerListener.h index 3dcc6b6670..43bf6a7d4b 100644 --- a/libs/gui/include/gui/IProducerListener.h +++ b/libs/gui/include/gui/IProducerListener.h @@ -90,6 +90,9 @@ public: Parcel* reply, uint32_t flags = 0); virtual bool needsReleaseNotify(); virtual void onBuffersDiscarded(const std::vector<int32_t>& slots); +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_CONSUMER_ATTACH_CALLBACK) + virtual bool needsAttachNotify(); +#endif }; #else @@ -103,6 +106,9 @@ public: virtual ~StubProducerListener(); virtual void onBufferReleased() {} virtual bool needsReleaseNotify() { return false; } +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_CONSUMER_ATTACH_CALLBACK) + virtual bool needsAttachNotify() { return false; } +#endif }; } // namespace android diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp index e9d799ed3f..9c0a41eafe 100644 --- a/libs/input/tests/Android.bp +++ b/libs/input/tests/Android.bp @@ -91,6 +91,7 @@ cc_test { }, }, }, + native_coverage: false, } // NOTE: This is a compile time test, and does not need to be diff --git a/libs/nativewindow/rust/Android.bp b/libs/nativewindow/rust/Android.bp index d68d6ba1af..c572ee7811 100644 --- a/libs/nativewindow/rust/Android.bp +++ b/libs/nativewindow/rust/Android.bp @@ -26,6 +26,7 @@ rust_bindgen { source_stem: "bindings", bindgen_flags: [ "--constified-enum-module=AHardwareBuffer_Format", + "--bitfield-enum=ADataSpace", "--bitfield-enum=AHardwareBuffer_UsageFlags", "--allowlist-file=.*/nativewindow/include/.*\\.h", @@ -110,6 +111,7 @@ rust_defaults { srcs: ["src/lib.rs"], rustlibs: [ "libbinder_rs", + "libbitflags", "libnativewindow_bindgen", ], } diff --git a/libs/nativewindow/rust/src/handle.rs b/libs/nativewindow/rust/src/handle.rs index a3a9dc6258..c41ab8d1b8 100644 --- a/libs/nativewindow/rust/src/handle.rs +++ b/libs/nativewindow/rust/src/handle.rs @@ -12,7 +12,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::{mem::forget, ptr::NonNull}; +use std::{ + ffi::c_int, + mem::forget, + os::fd::{BorrowedFd, FromRawFd, IntoRawFd, OwnedFd}, + ptr::NonNull, +}; /// Rust wrapper around `native_handle_t`. /// @@ -22,6 +27,108 @@ use std::{mem::forget, ptr::NonNull}; pub struct NativeHandle(NonNull<ffi::native_handle_t>); impl NativeHandle { + /// Creates a new `NativeHandle` with the given file descriptors and integer values. + /// + /// The `NativeHandle` will take ownership of the file descriptors and close them when it is + /// dropped. + pub fn new(fds: Vec<OwnedFd>, ints: &[c_int]) -> Option<Self> { + let fd_count = fds.len(); + // SAFETY: native_handle_create doesn't have any safety requirements. + let handle = unsafe { + ffi::native_handle_create(fd_count.try_into().unwrap(), ints.len().try_into().unwrap()) + }; + let handle = NonNull::new(handle)?; + for (i, fd) in fds.into_iter().enumerate() { + // SAFETY: `handle` must be valid because it was just created, and the array offset is + // within the bounds of what we allocated above. + unsafe { + *(*handle.as_ptr()).data.as_mut_ptr().add(i) = fd.into_raw_fd(); + } + } + for (i, value) in ints.iter().enumerate() { + // SAFETY: `handle` must be valid because it was just created, and the array offset is + // within the bounds of what we allocated above. Note that `data` is uninitialized + // until after this so we can't use `slice::from_raw_parts_mut` or similar to create a + // reference to it so we use raw pointers arithmetic instead. + unsafe { + *(*handle.as_ptr()).data.as_mut_ptr().add(fd_count + i) = *value; + } + } + // SAFETY: `handle` must be valid because it was just created. + unsafe { + ffi::native_handle_set_fdsan_tag(handle.as_ptr()); + } + Some(Self(handle)) + } + + /// Returns a borrowed view of all the file descriptors in this native handle. + pub fn fds(&self) -> Vec<BorrowedFd> { + self.data()[..self.fd_count()] + .iter() + .map(|fd| { + // SAFETY: The `native_handle_t` maintains ownership of the file descriptor so it + // won't be closed until this `NativeHandle` is destroyed. The `BorrowedFd` will + // have a lifetime constrained to that of `&self`, so it can't outlive it. + unsafe { BorrowedFd::borrow_raw(*fd) } + }) + .collect() + } + + /// Returns the integer values in this native handle. + pub fn ints(&self) -> &[c_int] { + &self.data()[self.fd_count()..] + } + + /// Destroys the `NativeHandle`, taking ownership of the file descriptors it contained. + pub fn into_fds(self) -> Vec<OwnedFd> { + let fds = self.data()[..self.fd_count()] + .iter() + .map(|fd| { + // SAFETY: The `native_handle_t` has ownership of the file descriptor, and + // after this we destroy it without closing the file descriptor so we can take over + // ownership of it. + unsafe { OwnedFd::from_raw_fd(*fd) } + }) + .collect(); + + // SAFETY: Our wrapped `native_handle_t` pointer is always valid, and it won't be accessed + // after this because we own it and forget it. + unsafe { + assert_eq!(ffi::native_handle_delete(self.0.as_ptr()), 0); + } + // Don't drop self, as that would cause `native_handle_close` to be called and close the + // file descriptors. + forget(self); + fds + } + + /// Returns a reference to the underlying `native_handle_t`. + fn as_ref(&self) -> &ffi::native_handle_t { + // SAFETY: All the ways of creating a `NativeHandle` ensure that the `native_handle_t` is + // valid and initialised, and lives as long as the `NativeHandle`. We enforce Rust's + // aliasing rules by giving the reference a lifetime matching that of `&self`. + unsafe { self.0.as_ref() } + } + + /// Returns the number of file descriptors included in the native handle. + fn fd_count(&self) -> usize { + self.as_ref().numFds.try_into().unwrap() + } + + /// Returns the number of integer values included in the native handle. + fn int_count(&self) -> usize { + self.as_ref().numInts.try_into().unwrap() + } + + /// Returns a slice reference for all the used `data` field of the native handle, including both + /// file descriptors and integers. + fn data(&self) -> &[c_int] { + let total_count = self.fd_count() + self.int_count(); + // SAFETY: The data must have been initialised with this number of elements when the + // `NativeHandle` was created. + unsafe { self.as_ref().data.as_slice(total_count) } + } + /// Wraps a raw `native_handle_t` pointer, taking ownership of it. /// /// # Safety @@ -90,3 +197,47 @@ unsafe impl Send for NativeHandle {} // SAFETY: A `NativeHandle` can be used from different threads simultaneously, as is is just // integers and file descriptors. unsafe impl Sync for NativeHandle {} + +#[cfg(test)] +mod test { + use super::*; + use std::fs::File; + + #[test] + fn create_empty() { + let handle = NativeHandle::new(vec![], &[]).unwrap(); + assert_eq!(handle.fds().len(), 0); + assert_eq!(handle.ints(), &[]); + } + + #[test] + fn create_with_ints() { + let handle = NativeHandle::new(vec![], &[1, 2, 42]).unwrap(); + assert_eq!(handle.fds().len(), 0); + assert_eq!(handle.ints(), &[1, 2, 42]); + } + + #[test] + fn create_with_fd() { + let file = File::open("/dev/null").unwrap(); + let handle = NativeHandle::new(vec![file.into()], &[]).unwrap(); + assert_eq!(handle.fds().len(), 1); + assert_eq!(handle.ints(), &[]); + } + + #[test] + fn clone() { + let file = File::open("/dev/null").unwrap(); + let original = NativeHandle::new(vec![file.into()], &[42]).unwrap(); + assert_eq!(original.ints(), &[42]); + assert_eq!(original.fds().len(), 1); + + let cloned = original.clone(); + drop(original); + + assert_eq!(cloned.ints(), &[42]); + assert_eq!(cloned.fds().len(), 1); + + drop(cloned); + } +} diff --git a/libs/nativewindow/rust/src/surface.rs b/libs/nativewindow/rust/src/surface.rs index 25fea807b5..9eddfcd497 100644 --- a/libs/nativewindow/rust/src/surface.rs +++ b/libs/nativewindow/rust/src/surface.rs @@ -20,10 +20,14 @@ use binder::{ unstable_api::{status_result, AsNative}, StatusCode, }; +use bitflags::bitflags; use nativewindow_bindgen::{ - AHardwareBuffer_Format, ANativeWindow, ANativeWindow_acquire, ANativeWindow_getFormat, - ANativeWindow_getHeight, ANativeWindow_getWidth, ANativeWindow_readFromParcel, - ANativeWindow_release, ANativeWindow_writeToParcel, + ADataSpace, AHardwareBuffer_Format, ANativeWindow, ANativeWindow_acquire, + ANativeWindow_getBuffersDataSpace, ANativeWindow_getBuffersDefaultDataSpace, + ANativeWindow_getFormat, ANativeWindow_getHeight, ANativeWindow_getWidth, + ANativeWindow_readFromParcel, ANativeWindow_release, ANativeWindow_setBuffersDataSpace, + ANativeWindow_setBuffersGeometry, ANativeWindow_setBuffersTransform, + ANativeWindow_writeToParcel, }; use std::error::Error; use std::fmt::{self, Debug, Display, Formatter}; @@ -60,6 +64,95 @@ impl Surface { let format = unsafe { ANativeWindow_getFormat(self.0.as_ptr()) }; format.try_into().map_err(|_| ErrorCode(format)) } + + /// Changes the format and size of the window buffers. + /// + /// The width and height control the number of pixels in the buffers, not the dimensions of the + /// window on screen. If these are different than the window's physical size, then its buffer + /// will be scaled to match that size when compositing it to the screen. The width and height + /// must be either both zero or both non-zero. If both are 0 then the window's base value will + /// come back in force. + pub fn set_buffers_geometry( + &mut self, + width: i32, + height: i32, + format: AHardwareBuffer_Format::Type, + ) -> Result<(), ErrorCode> { + // SAFETY: The ANativeWindow pointer we pass is guaranteed to be non-null and valid because + // it must have been allocated by `ANativeWindow_allocate` or `ANativeWindow_readFromParcel` + // and we have not yet released it. + let status = unsafe { + ANativeWindow_setBuffersGeometry( + self.0.as_ptr(), + width, + height, + format.try_into().expect("Invalid format"), + ) + }; + + if status == 0 { + Ok(()) + } else { + Err(ErrorCode(status)) + } + } + + /// Sets a transfom that will be applied to future buffers posted to the window. + pub fn set_buffers_transform(&mut self, transform: Transform) -> Result<(), ErrorCode> { + // SAFETY: The ANativeWindow pointer we pass is guaranteed to be non-null and valid because + // it must have been allocated by `ANativeWindow_allocate` or `ANativeWindow_readFromParcel` + // and we have not yet released it. + let status = + unsafe { ANativeWindow_setBuffersTransform(self.0.as_ptr(), transform.bits() as i32) }; + + if status == 0 { + Ok(()) + } else { + Err(ErrorCode(status)) + } + } + + /// Sets the data space that will be applied to future buffers posted to the window. + pub fn set_buffers_data_space(&mut self, data_space: ADataSpace) -> Result<(), ErrorCode> { + // SAFETY: The ANativeWindow pointer we pass is guaranteed to be non-null and valid because + // it must have been allocated by `ANativeWindow_allocate` or `ANativeWindow_readFromParcel` + // and we have not yet released it. + let status = unsafe { ANativeWindow_setBuffersDataSpace(self.0.as_ptr(), data_space.0) }; + + if status == 0 { + Ok(()) + } else { + Err(ErrorCode(status)) + } + } + + /// Gets the data space of the buffers in the window. + pub fn get_buffers_data_space(&mut self) -> Result<ADataSpace, ErrorCode> { + // SAFETY: The ANativeWindow pointer we pass is guaranteed to be non-null and valid because + // it must have been allocated by `ANativeWindow_allocate` or `ANativeWindow_readFromParcel` + // and we have not yet released it. + let data_space = unsafe { ANativeWindow_getBuffersDataSpace(self.0.as_ptr()) }; + + if data_space < 0 { + Err(ErrorCode(data_space)) + } else { + Ok(ADataSpace(data_space)) + } + } + + /// Gets the default data space of the buffers in the window as set by the consumer. + pub fn get_buffers_default_data_space(&mut self) -> Result<ADataSpace, ErrorCode> { + // SAFETY: The ANativeWindow pointer we pass is guaranteed to be non-null and valid because + // it must have been allocated by `ANativeWindow_allocate` or `ANativeWindow_readFromParcel` + // and we have not yet released it. + let data_space = unsafe { ANativeWindow_getBuffersDefaultDataSpace(self.0.as_ptr()) }; + + if data_space < 0 { + Err(ErrorCode(data_space)) + } else { + Ok(ADataSpace(data_space)) + } + } } impl Drop for Surface { @@ -141,3 +234,19 @@ impl Display for ErrorCode { write!(f, "Error {}", self.0) } } + +bitflags! { + /// Transforms that can be applied to buffers as they are displayed to a window. + #[derive(Copy, Clone, Debug, Eq, PartialEq)] + pub struct Transform: u32 { + const MIRROR_HORIZONTAL = 0x01; + const MIRROR_VERTICAL = 0x02; + const ROTATE_90 = 0x04; + } +} + +impl Transform { + pub const IDENTITY: Self = Self::empty(); + pub const ROTATE_180: Self = Self::MIRROR_HORIZONTAL.union(Self::MIRROR_VERTICAL); + pub const ROTATE_270: Self = Self::ROTATE_180.union(Self::ROTATE_90); +} diff --git a/libs/renderengine/OWNERS b/libs/renderengine/OWNERS index 66e1aa1ca1..17ab29fd29 100644 --- a/libs/renderengine/OWNERS +++ b/libs/renderengine/OWNERS @@ -5,4 +5,6 @@ alecmouri@google.com djsollen@google.com jreck@google.com lpy@google.com +nscobie@google.com +sallyqi@google.com scroggo@google.com diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp index ffb6cdb6ef..b0c6e44b2b 100644 --- a/libs/ui/GraphicBuffer.cpp +++ b/libs/ui/GraphicBuffer.cpp @@ -388,8 +388,8 @@ status_t GraphicBuffer::lockAsync(uint64_t inProducerUsage, uint64_t inConsumerU } } - const uint64_t usage = static_cast<uint64_t>( - android_convertGralloc1To0Usage(inProducerUsage, inConsumerUsage)); + const uint64_t usage = static_cast<uint64_t>(ANDROID_NATIVE_UNSIGNED_CAST( + android_convertGralloc1To0Usage(inProducerUsage, inConsumerUsage))); auto result = getBufferMapper().lock(handle, usage, rect, base::unique_fd{fenceFd}); diff --git a/libs/ui/GraphicBufferMapper.cpp b/libs/ui/GraphicBufferMapper.cpp index b6ab2f5a47..7b5a27d9e1 100644 --- a/libs/ui/GraphicBufferMapper.cpp +++ b/libs/ui/GraphicBufferMapper.cpp @@ -208,8 +208,10 @@ status_t GraphicBufferMapper::lockAsync(buffer_handle_t handle, uint32_t usage, status_t GraphicBufferMapper::lockAsync(buffer_handle_t handle, uint64_t producerUsage, uint64_t consumerUsage, const Rect& bounds, void** vaddr, int fenceFd) { - return lockAsync(handle, android_convertGralloc1To0Usage(producerUsage, consumerUsage), bounds, - vaddr, fenceFd); + return lockAsync(handle, + ANDROID_NATIVE_UNSIGNED_CAST( + android_convertGralloc1To0Usage(producerUsage, consumerUsage)), + bounds, vaddr, fenceFd); } status_t GraphicBufferMapper::lockAsyncYCbCr(buffer_handle_t handle, uint32_t usage, diff --git a/libs/ultrahdr/Android.bp b/libs/ultrahdr/Android.bp deleted file mode 100644 index eda5ea4578..0000000000 --- a/libs/ultrahdr/Android.bp +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright 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. - -package { - // See: http://go/android-license-faq - default_applicable_licenses: [ - "frameworks_native_license", - "adobe_hdr_gain_map_license", - ], -} - -cc_library { - name: "libultrahdr-deprecated", - enabled: false, - host_supported: true, - vendor_available: true, - export_include_dirs: ["include"], - local_include_dirs: ["include"], - - srcs: [ - "icc.cpp", - "jpegr.cpp", - "gainmapmath.cpp", - "jpegrutils.cpp", - "multipictureformat.cpp", - ], - - shared_libs: [ - "libimage_io", - "libjpeg", - "libjpegencoder", - "libjpegdecoder", - "liblog", - "libutils", - ], -} - -cc_library { - name: "libjpegencoder-deprecated", - enabled: false, - host_supported: true, - vendor_available: true, - - shared_libs: [ - "libjpeg", - "liblog", - "libutils", - ], - - export_include_dirs: ["include"], - - srcs: [ - "jpegencoderhelper.cpp", - ], -} - -cc_library { - name: "libjpegdecoder-deprecated", - enabled: false, - host_supported: true, - vendor_available: true, - - shared_libs: [ - "libjpeg", - "liblog", - "libutils", - ], - - export_include_dirs: ["include"], - - srcs: [ - "jpegdecoderhelper.cpp", - ], -} diff --git a/libs/ultrahdr/fuzzer/Android.bp b/libs/ultrahdr/fuzzer/Android.bp deleted file mode 100644 index 8d9132fd4d..0000000000 --- a/libs/ultrahdr/fuzzer/Android.bp +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright 2023 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. - -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_defaults { - name: "ultrahdr_fuzzer_defaults-deprecated", - enabled: false, - host_supported: true, - shared_libs: [ - "libimage_io", - "libjpeg", - ], - static_libs: [ - "libjpegdecoder", - "libjpegencoder", - "libultrahdr", - "libutils", - "liblog", - ], - target: { - darwin: { - enabled: false, - }, - }, - fuzz_config: { - cc: [ - "android-media-fuzzing-reports@google.com", - ], - description: "The fuzzers target the APIs of jpeg hdr", - service_privilege: "constrained", - users: "multi_user", - fuzzed_code_usage: "future_version", - vector: "local_no_privileges_required", - }, -} - -cc_fuzz { - name: "ultrahdr_enc_fuzzer-deprecated", - enabled: false, - defaults: ["ultrahdr_fuzzer_defaults"], - srcs: [ - "ultrahdr_enc_fuzzer.cpp", - ], -} - -cc_fuzz { - name: "ultrahdr_dec_fuzzer-deprecated", - enabled: false, - defaults: ["ultrahdr_fuzzer_defaults"], - srcs: [ - "ultrahdr_dec_fuzzer.cpp", - ], -} diff --git a/libs/ultrahdr/tests/Android.bp b/libs/ultrahdr/tests/Android.bp deleted file mode 100644 index 00cc797591..0000000000 --- a/libs/ultrahdr/tests/Android.bp +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 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. - -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_test { - name: "ultrahdr_unit_test-deprecated", - enabled: false, - test_suites: ["device-tests"], - srcs: [ - "gainmapmath_test.cpp", - "icchelper_test.cpp", - "jpegr_test.cpp", - "jpegencoderhelper_test.cpp", - "jpegdecoderhelper_test.cpp", - ], - shared_libs: [ - "libimage_io", - "libjpeg", - "liblog", - ], - static_libs: [ - "libgmock", - "libgtest", - "libjpegdecoder", - "libjpegencoder", - "libultrahdr", - "libutils", - ], - data: [ - "./data/*.*", - ], -} diff --git a/opengl/libs/EGL/egl_platform_entries.cpp b/opengl/libs/EGL/egl_platform_entries.cpp index a6af713830..0bfefd6706 100644 --- a/opengl/libs/EGL/egl_platform_entries.cpp +++ b/opengl/libs/EGL/egl_platform_entries.cpp @@ -2111,6 +2111,10 @@ EGLBoolean eglPresentationTimeANDROIDImpl(EGLDisplay dpy, EGLSurface surface, } egl_surface_t const* const s = get_surface(surface); + if (!s->getNativeWindow()) { + setError(EGL_BAD_SURFACE, EGL_FALSE); + return EGL_FALSE; + } native_window_set_buffers_timestamp(s->getNativeWindow(), time); return EGL_TRUE; @@ -2375,7 +2379,7 @@ EGLBoolean eglGetFrameTimestampsANDROIDImpl(EGLDisplay dpy, EGLSurface surface, case 0: return EGL_TRUE; case -ENOENT: - return setError(EGL_BAD_ACCESS, (EGLBoolean)EGL_FALSE); + return setErrorQuiet(EGL_BAD_ACCESS, (EGLBoolean)EGL_FALSE); case -ENOSYS: return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); case -EINVAL: diff --git a/services/inputflinger/PointerChoreographer.cpp b/services/inputflinger/PointerChoreographer.cpp index 00dd6ba62b..ed7714698e 100644 --- a/services/inputflinger/PointerChoreographer.cpp +++ b/services/inputflinger/PointerChoreographer.cpp @@ -367,7 +367,8 @@ void PointerChoreographer::processTouchscreenAndStylusEventLocked(const NotifyMo const uint8_t actionIndex = MotionEvent::getActionIndex(args.action); std::array<uint32_t, MAX_POINTER_ID + 1> idToIndex; BitSet32 idBits; - if (maskedAction != AMOTION_EVENT_ACTION_UP && maskedAction != AMOTION_EVENT_ACTION_CANCEL) { + if (maskedAction != AMOTION_EVENT_ACTION_UP && maskedAction != AMOTION_EVENT_ACTION_CANCEL && + maskedAction != AMOTION_EVENT_ACTION_HOVER_EXIT) { for (size_t i = 0; i < args.getPointerCount(); i++) { if (maskedAction == AMOTION_EVENT_ACTION_POINTER_UP && actionIndex == i) { continue; diff --git a/services/inputflinger/dispatcher/DragState.h b/services/inputflinger/dispatcher/DragState.h index 9809148853..1ed6c29851 100644 --- a/services/inputflinger/dispatcher/DragState.h +++ b/services/inputflinger/dispatcher/DragState.h @@ -17,6 +17,7 @@ #pragma once #include <gui/WindowInfo.h> +#include <input/Input.h> #include <utils/StrongPointer.h> #include <string> @@ -25,8 +26,9 @@ namespace android { namespace inputdispatcher { struct DragState { - DragState(const sp<android::gui::WindowInfoHandle>& windowHandle, int32_t pointerId) - : dragWindow(windowHandle), pointerId(pointerId) {} + DragState(const sp<android::gui::WindowInfoHandle>& windowHandle, DeviceId deviceId, + int32_t pointerId) + : dragWindow(windowHandle), deviceId(deviceId), pointerId(pointerId) {} void dump(std::string& dump, const char* prefix = ""); // The window being dragged. @@ -37,6 +39,8 @@ struct DragState { bool isStartDrag = false; // Indicate if the stylus button is down at the start of the drag. bool isStylusButtonDownAtStart = false; + // Indicate which device started this drag and drop. + const DeviceId deviceId; // Indicate which pointer id is tracked by the drag and drop. const int32_t pointerId; }; diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index f9fbfef3ec..2161e0985b 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -2870,7 +2870,8 @@ void InputDispatcher::finishDragAndDrop(ui::LogicalDisplayId displayId, float x, } void InputDispatcher::addDragEventLocked(const MotionEntry& entry) { - if (!mDragState || mDragState->dragWindow->getInfo()->displayId != entry.displayId) { + if (!mDragState || mDragState->dragWindow->getInfo()->displayId != entry.displayId || + mDragState->deviceId != entry.deviceId) { return; } @@ -5758,7 +5759,7 @@ bool InputDispatcher::transferTouchGesture(const sp<IBinder>& fromToken, const s } // Track the pointer id for drag window and generate the drag state. const size_t id = pointers.begin()->id; - mDragState = std::make_unique<DragState>(toWindowHandle, id); + mDragState = std::make_unique<DragState>(toWindowHandle, deviceId, id); } // Synthesize cancel for old window and down for new window. diff --git a/services/inputflinger/tests/Android.bp b/services/inputflinger/tests/Android.bp index cf0d46a75d..18b6c5e47b 100644 --- a/services/inputflinger/tests/Android.bp +++ b/services/inputflinger/tests/Android.bp @@ -116,4 +116,5 @@ cc_test { unit_test: true, }, test_suites: ["device-tests"], + native_coverage: false, } diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index 2056372f2d..73ab0dae41 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -12192,6 +12192,87 @@ TEST_F(InputDispatcherDragTests, NoDragAndDropWithHoveringPointer) { << "Drag and drop should not work with a hovering pointer"; } +/** + * Two devices, we use the second pointer of Device A to start the drag, during the drag process, if + * we perform a click using Device B, the dispatcher should work well. + */ +TEST_F(InputDispatcherDragTests, DragAndDropWhenSplitTouchAndMultiDevice) { + const DeviceId deviceA = 1; + const DeviceId deviceB = 2; + // First down on second window with deviceA. + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .deviceId(deviceA) + .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50)) + .build()); + mSecondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceA), + WithDisplayId(ui::LogicalDisplayId::DEFAULT))); + + // Second down on first window with deviceA + mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .deviceId(deviceA) + .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50)) + .pointer(PointerBuilder(1, ToolType::FINGER).x(50).y(50)) + .build()); + mWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceA), + WithDisplayId(ui::LogicalDisplayId::DEFAULT))); + mSecondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(deviceA), + WithDisplayId(ui::LogicalDisplayId::DEFAULT))); + + // Perform drag and drop from first window. + ASSERT_TRUE(startDrag(/*sendDown=*/false)); + + // Click first window with device B, we should ensure dispatcher work well. + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE) + .deviceId(deviceB) + .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50)) + .build()); + mWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceB), + WithDisplayId(ui::LogicalDisplayId::DEFAULT))); + + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_MOUSE) + .deviceId(deviceB) + .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50)) + .build()); + mWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_UP), WithDeviceId(deviceB), + WithDisplayId(ui::LogicalDisplayId::DEFAULT))); + + // Move with device A. + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) + .deviceId(deviceA) + .pointer(PointerBuilder(0, ToolType::FINGER).x(151).y(51)) + .pointer(PointerBuilder(1, ToolType::FINGER).x(51).y(51)) + .build()); + + mDragWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(deviceA), + WithDisplayId(ui::LogicalDisplayId::DEFAULT), + WithFlags(AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE))); + mWindow->consumeDragEvent(false, 51, 51); + mSecondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(deviceA), + WithDisplayId(ui::LogicalDisplayId::DEFAULT))); + + // Releasing the drag pointer should cause drop. + mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN) + .deviceId(deviceA) + .pointer(PointerBuilder(0, ToolType::FINGER).x(151).y(51)) + .pointer(PointerBuilder(1, ToolType::FINGER).x(51).y(51)) + .build()); + mDragWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_UP), WithDeviceId(deviceA), + WithDisplayId(ui::LogicalDisplayId::DEFAULT), + WithFlags(AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE))); + mFakePolicy->assertDropTargetEquals(*mDispatcher, mWindow->getToken()); + mSecondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(deviceA), + WithDisplayId(ui::LogicalDisplayId::DEFAULT))); + + // Release all pointers. + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN) + .deviceId(deviceA) + .pointer(PointerBuilder(0, ToolType::FINGER).x(151).y(51)) + .build()); + mSecondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_UP), WithDeviceId(deviceA), + WithDisplayId(ui::LogicalDisplayId::DEFAULT))); + mWindow->assertNoEvents(); +} + class InputDispatcherDropInputFeatureTest : public InputDispatcherTest {}; TEST_F(InputDispatcherDropInputFeatureTest, WindowDropsInput) { diff --git a/services/inputflinger/tests/PointerChoreographer_test.cpp b/services/inputflinger/tests/PointerChoreographer_test.cpp index 9a5b6a73f5..a1279ff61b 100644 --- a/services/inputflinger/tests/PointerChoreographer_test.cpp +++ b/services/inputflinger/tests/PointerChoreographer_test.cpp @@ -830,15 +830,20 @@ TEST_F(PointerChoreographerTest, TouchSetsSpots) { pc->assertSpotCount(DISPLAY_ID, 0); } +/** + * In this test, we simulate the complete event of the stylus approaching and clicking on the + * screen, and then leaving the screen. We should ensure that spots are displayed correctly. + */ TEST_F(PointerChoreographerTest, TouchSetsSpotsForStylusEvent) { mChoreographer.setShowTouchesEnabled(true); + mChoreographer.setStylusPointerIconEnabled(false); mChoreographer.notifyInputDevicesChanged( {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS, DISPLAY_ID)}}); - // Emit down event with stylus properties. - mChoreographer.notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, + // First, the stylus begin to approach the screen. + mChoreographer.notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS) .pointer(STYLUS_POINTER) .deviceId(DEVICE_ID) @@ -846,6 +851,72 @@ TEST_F(PointerChoreographerTest, TouchSetsSpotsForStylusEvent) { .build()); auto pc = assertPointerControllerCreated(ControllerType::TOUCH); pc->assertSpotCount(DISPLAY_ID, 1); + + mChoreographer.notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, + AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS) + .pointer(STYLUS_POINTER) + .deviceId(DEVICE_ID) + .displayId(DISPLAY_ID) + .build()); + pc->assertSpotCount(DISPLAY_ID, 1); + + mChoreographer.notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_EXIT, + AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS) + .pointer(STYLUS_POINTER) + .deviceId(DEVICE_ID) + .displayId(DISPLAY_ID) + .build()); + pc->assertSpotCount(DISPLAY_ID, 0); + + // Now, use stylus touch the screen. + mChoreographer.notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, + AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS) + .pointer(STYLUS_POINTER) + .deviceId(DEVICE_ID) + .displayId(DISPLAY_ID) + .build()); + pc->assertSpotCount(DISPLAY_ID, 1); + + mChoreographer.notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, + AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS) + .pointer(STYLUS_POINTER) + .deviceId(DEVICE_ID) + .displayId(DISPLAY_ID) + .build()); + pc->assertSpotCount(DISPLAY_ID, 1); + + mChoreographer.notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_UP, + AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS) + .pointer(STYLUS_POINTER) + .deviceId(DEVICE_ID) + .displayId(DISPLAY_ID) + .build()); + pc->assertSpotCount(DISPLAY_ID, 0); + + // Then, the stylus start leave from the screen. + mChoreographer.notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, + AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS) + .pointer(STYLUS_POINTER) + .deviceId(DEVICE_ID) + .displayId(DISPLAY_ID) + .build()); + pc->assertSpotCount(DISPLAY_ID, 1); + + mChoreographer.notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, + AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS) + .pointer(STYLUS_POINTER) + .deviceId(DEVICE_ID) + .displayId(DISPLAY_ID) + .build()); + pc->assertSpotCount(DISPLAY_ID, 1); + + mChoreographer.notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_EXIT, + AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS) + .pointer(STYLUS_POINTER) + .deviceId(DEVICE_ID) + .displayId(DISPLAY_ID) + .build()); + pc->assertSpotCount(DISPLAY_ID, 0); } TEST_F(PointerChoreographerTest, TouchSetsSpotsForTwoDisplays) { diff --git a/services/surfaceflinger/OWNERS b/services/surfaceflinger/OWNERS index ffc1dd7979..fa0ecee6b5 100644 --- a/services/surfaceflinger/OWNERS +++ b/services/surfaceflinger/OWNERS @@ -5,6 +5,8 @@ alecmouri@google.com domlaskowski@google.com jreck@google.com lpy@google.com +mattbuckley@google.com +melodymhsu@google.com pdwilliams@google.com racarr@google.com ramindani@google.com @@ -12,3 +14,4 @@ rnlee@google.com sallyqi@google.com scroggo@google.com vishnun@google.com +xwxw@google.com diff --git a/services/surfaceflinger/PowerAdvisor/OWNERS b/services/surfaceflinger/PowerAdvisor/OWNERS new file mode 100644 index 0000000000..9f40e27a10 --- /dev/null +++ b/services/surfaceflinger/PowerAdvisor/OWNERS @@ -0,0 +1 @@ +file:platform/frameworks/base:/ADPF_OWNERS
\ No newline at end of file diff --git a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp index dd86e4f426..a4368a6db1 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp +++ b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp @@ -841,7 +841,8 @@ auto RefreshRateSelector::getRankedFrameRatesLocked(const std::vector<LayerRequi return score.overallScore == 0; }); - if (policy->primaryRangeIsSingleRate()) { + // TODO(b/364651864): Evaluate correctness of primaryRangeIsSingleRate. + if (!isVrrDevice() && policy->primaryRangeIsSingleRate()) { // If we never scored any layers, then choose the rate from the primary // range instead of picking a random score from the app range. if (noLayerScore) { @@ -887,10 +888,10 @@ auto RefreshRateSelector::getRankedFrameRatesLocked(const std::vector<LayerRequi const auto touchRefreshRates = rankFrameRates(anchorGroup, RefreshRateOrder::Descending); using fps_approx_ops::operator<; - if (scores.front().frameRateMode.fps < touchRefreshRates.front().frameRateMode.fps) { - ALOGV("Touch Boost"); + if (scores.front().frameRateMode.fps <= touchRefreshRates.front().frameRateMode.fps) { + ALOGV("Touch Boost [late]"); ATRACE_FORMAT_INSTANT("%s (Touch Boost [late])", - to_string(touchRefreshRates.front().frameRateMode.fps).c_str()); + to_string(touchRefreshRates.front().frameRateMode.fps).c_str()); return {touchRefreshRates, GlobalSignals{.touch = true}}; } } diff --git a/services/surfaceflinger/Scheduler/include/scheduler/FrameTargeter.h b/services/surfaceflinger/Scheduler/include/scheduler/FrameTargeter.h index 2c397bd18d..a54d43582e 100644 --- a/services/surfaceflinger/Scheduler/include/scheduler/FrameTargeter.h +++ b/services/surfaceflinger/Scheduler/include/scheduler/FrameTargeter.h @@ -134,8 +134,11 @@ private: } size_t getPresentFenceShift(Period minFramePeriod) const { - const bool isTwoVsyncsAhead = targetsVsyncsAhead<2>(minFramePeriod); size_t shift = 0; + if (minFramePeriod.ns() == 0) { + return shift; + } + const bool isTwoVsyncsAhead = targetsVsyncsAhead<2>(minFramePeriod); if (isTwoVsyncsAhead) { shift = static_cast<size_t>(expectedFrameDuration().ns() / minFramePeriod.ns()); if (shift >= mPresentFences.size()) { diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 1aaa1281fe..d4d32aa37a 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -2334,7 +2334,7 @@ bool SurfaceFlinger::updateLayerSnapshotsLegacy(VsyncId vsyncId, nsecs_t frameTi if (flushTransactions) { needsTraversal |= commitMirrorDisplays(vsyncId); needsTraversal |= commitCreatedLayers(vsyncId, update.layerCreatedStates); - needsTraversal |= applyTransactions(update.transactions, vsyncId); + needsTraversal |= applyTransactions(update.transactions); } outTransactionsAreEmpty = !needsTraversal; const bool shouldCommit = (getTransactionFlags() & ~eTransactionFlushNeeded) || needsTraversal; @@ -2515,7 +2515,7 @@ bool SurfaceFlinger::updateLayerSnapshots(VsyncId vsyncId, nsecs_t frameTimeNs, bool newDataLatched = false; ATRACE_NAME("DisplayCallbackAndStatsUpdates"); - mustComposite |= applyTransactionsLocked(update.transactions, vsyncId); + mustComposite |= applyTransactionsLocked(update.transactions); traverseLegacyLayers([&](Layer* layer) { layer->commitTransaction(); }); const nsecs_t latchTime = systemTime(); bool unused = false; @@ -5090,20 +5090,18 @@ void SurfaceFlinger::addTransactionReadyFilters() { } // For tests only -bool SurfaceFlinger::flushTransactionQueues(VsyncId vsyncId) { +bool SurfaceFlinger::flushTransactionQueues() { mTransactionHandler.collectTransactions(); std::vector<TransactionState> transactions = mTransactionHandler.flushTransactions(); - return applyTransactions(transactions, vsyncId); + return applyTransactions(transactions); } -bool SurfaceFlinger::applyTransactions(std::vector<TransactionState>& transactions, - VsyncId vsyncId) { +bool SurfaceFlinger::applyTransactions(std::vector<TransactionState>& transactions) { Mutex::Autolock lock(mStateLock); - return applyTransactionsLocked(transactions, vsyncId); + return applyTransactionsLocked(transactions); } -bool SurfaceFlinger::applyTransactionsLocked(std::vector<TransactionState>& transactions, - VsyncId vsyncId) { +bool SurfaceFlinger::applyTransactionsLocked(std::vector<TransactionState>& transactions) { bool needsTraversal = false; // Now apply all transactions. for (auto& transaction : transactions) { diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index a3534b582c..2369043821 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -814,9 +814,9 @@ private: REQUIRES(mStateLock, kMainThreadContext); // Flush pending transactions that were presented after desiredPresentTime. // For test only - bool flushTransactionQueues(VsyncId) REQUIRES(kMainThreadContext); + bool flushTransactionQueues() REQUIRES(kMainThreadContext); - bool applyTransactions(std::vector<TransactionState>&, VsyncId) REQUIRES(kMainThreadContext); + bool applyTransactions(std::vector<TransactionState>&) REQUIRES(kMainThreadContext); bool applyAndCommitDisplayTransactionStatesLocked(std::vector<TransactionState>& transactions) REQUIRES(kMainThreadContext, mStateLock); @@ -854,7 +854,7 @@ private: static LatchUnsignaledConfig getLatchUnsignaledConfig(); bool shouldLatchUnsignaled(const layer_state_t&, size_t numStates, bool firstTransaction) const; - bool applyTransactionsLocked(std::vector<TransactionState>& transactions, VsyncId) + bool applyTransactionsLocked(std::vector<TransactionState>& transactions) REQUIRES(mStateLock, kMainThreadContext); uint32_t setDisplayStateLocked(const DisplayState& s) REQUIRES(mStateLock); uint32_t addInputWindowCommands(const InputWindowCommands& inputWindowCommands) diff --git a/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp index cf9a7d3e69..d64cf2f52b 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp @@ -100,7 +100,9 @@ struct TestableRefreshRateSelector : RefreshRateSelector { const std::vector<Fps>& knownFrameRates() const { return mKnownFrameRates; } using RefreshRateSelector::GetRankedFrameRatesCache; - auto& mutableGetRankedRefreshRatesCache() { return mGetRankedFrameRatesCache; } + auto& mutableGetRankedRefreshRatesCache() NO_THREAD_SAFETY_ANALYSIS { + return mGetRankedFrameRatesCache; + } auto getRankedFrameRates(const std::vector<LayerRequirement>& layers, GlobalSignals signals = {}, Fps pacesetterFps = {}) const { @@ -138,7 +140,9 @@ struct TestableRefreshRateSelector : RefreshRateSelector { return setPolicy(policy); } - const auto& getPrimaryFrameRates() const { return mPrimaryFrameRates; } + const auto& getPrimaryFrameRates() const NO_THREAD_SAFETY_ANALYSIS { + return mPrimaryFrameRates; + } }; class RefreshRateSelectorTest : public testing::TestWithParam<Config::FrameRateOverride> { @@ -1766,6 +1770,43 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_withFrameRateCategory_60_12 } } +TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_vrrHighHintTouch_primaryRangeIsSingleRate) { + if (GetParam() != Config::FrameRateOverride::Enabled) { + return; + } + + SET_FLAG_FOR_TEST(flags::vrr_config, true); + + auto selector = createSelector(kVrrMode_120, kModeId120); + selector.setActiveMode(kModeId120, 60_Hz); + + // Change primary physical range to be single rate, which on VRR device should not affect + // fps scoring. + EXPECT_EQ(SetPolicyResult::Changed, + selector.setDisplayManagerPolicy({kModeId120, {120_Hz, 120_Hz}})); + + std::vector<LayerRequirement> layers = {{.weight = 1.f}, {.weight = 1.f}}; + layers[0].vote = LayerVoteType::ExplicitCategory; + layers[0].frameRateCategory = FrameRateCategory::HighHint; + layers[0].name = "ExplicitCategory HighHint"; + + auto actualRankedFrameRates = selector.getRankedFrameRates(layers); + // Expect late touch boost from HighHint. + EXPECT_EQ(120_Hz, actualRankedFrameRates.ranking.front().frameRateMode.fps); + EXPECT_EQ(kModeId120, actualRankedFrameRates.ranking.front().frameRateMode.modePtr->getId()); + EXPECT_TRUE(actualRankedFrameRates.consideredSignals.touch); + + layers[1].vote = LayerVoteType::ExplicitExactOrMultiple; + layers[1].desiredRefreshRate = 30_Hz; + layers[1].name = "ExplicitExactOrMultiple 30Hz"; + + actualRankedFrameRates = selector.getRankedFrameRates(layers); + // Expect late touch boost from HighHint. + EXPECT_EQ(120_Hz, actualRankedFrameRates.ranking.front().frameRateMode.fps); + EXPECT_EQ(kModeId120, actualRankedFrameRates.ranking.front().frameRateMode.modePtr->getId()); + EXPECT_TRUE(actualRankedFrameRates.consideredSignals.touch); +} + TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_withFrameRateCategory_HighHint) { auto selector = createSelector(makeModes(kMode24, kMode30, kMode60, kMode120), kModeId60); @@ -1884,7 +1925,7 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_withFrameRateCategory_HighH // Gets touch boost EXPECT_EQ(120_Hz, actualRankedFrameRates.ranking.front().frameRateMode.fps); EXPECT_EQ(kModeId120, actualRankedFrameRates.ranking.front().frameRateMode.modePtr->getId()); - EXPECT_FALSE(actualRankedFrameRates.consideredSignals.touch); + EXPECT_TRUE(actualRankedFrameRates.consideredSignals.touch); } TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_withFrameRateCategory_TouchBoost) { @@ -1978,7 +2019,7 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_withFrameRateCategory_Touch lr2.name = "Max"; actualRankedFrameRates = selector.getRankedFrameRates(layers, {.touch = true}); EXPECT_FRAME_RATE_MODE(kMode120, 120_Hz, actualRankedFrameRates.ranking.front().frameRateMode); - EXPECT_FALSE(actualRankedFrameRates.consideredSignals.touch); + EXPECT_TRUE(actualRankedFrameRates.consideredSignals.touch); lr1.vote = LayerVoteType::ExplicitCategory; lr1.frameRateCategory = FrameRateCategory::Normal; diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h index f0638094c7..1f7bf5f2a8 100644 --- a/services/surfaceflinger/tests/unittests/TestableScheduler.h +++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h @@ -133,7 +133,9 @@ public: using Scheduler::resyncAllToHardwareVsync; auto& mutableLayerHistory() { return mLayerHistory; } - auto& mutableAttachedChoreographers() { return mAttachedChoreographers; } + auto& mutableAttachedChoreographers() NO_THREAD_SAFETY_ANALYSIS { + return mAttachedChoreographers; + } size_t layerHistorySize() NO_THREAD_SAFETY_ANALYSIS { return mLayerHistory.mActiveLayerInfos.size() + mLayerHistory.mInactiveLayerInfos.size(); diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 4197cbd271..0d13dc563d 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -516,8 +516,10 @@ public: return mFlinger->SurfaceFlinger::getDisplayNativePrimaries(displayToken, primaries); } - auto& getTransactionQueue() { return mFlinger->mTransactionHandler.mLocklessTransactionQueue; } - auto& getPendingTransactionQueue() { + auto& getTransactionQueue() NO_THREAD_SAFETY_ANALYSIS { + return mFlinger->mTransactionHandler.mLocklessTransactionQueue; + } + auto& getPendingTransactionQueue() NO_THREAD_SAFETY_ANALYSIS { ftl::FakeGuard guard(kMainThreadContext); return mFlinger->mTransactionHandler.mPendingTransactionQueues; } @@ -547,7 +549,7 @@ public: } auto flushTransactionQueues() { - return FTL_FAKE_GUARD(kMainThreadContext, mFlinger->flushTransactionQueues(kVsyncId)); + return FTL_FAKE_GUARD(kMainThreadContext, mFlinger->flushTransactionQueues()); } auto onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { @@ -663,8 +665,10 @@ public: * post-conditions. */ - const auto& displays() const { return mFlinger->mDisplays; } - const auto& physicalDisplays() const { return mFlinger->mPhysicalDisplays; } + const auto& displays() const NO_THREAD_SAFETY_ANALYSIS { return mFlinger->mDisplays; } + const auto& physicalDisplays() const NO_THREAD_SAFETY_ANALYSIS { + return mFlinger->mPhysicalDisplays; + } const auto& currentState() const { return mFlinger->mCurrentState; } const auto& drawingState() const { return mFlinger->mDrawingState; } const auto& transactionFlags() const { return mFlinger->mTransactionFlags; } @@ -677,13 +681,17 @@ public: auto& mutableDisplayModeController() { return mFlinger->mDisplayModeController; } auto& mutableCurrentState() { return mFlinger->mCurrentState; } auto& mutableDisplayColorSetting() { return mFlinger->mDisplayColorSetting; } - auto& mutableDisplays() { return mFlinger->mDisplays; } - auto& mutablePhysicalDisplays() { return mFlinger->mPhysicalDisplays; } + auto& mutableDisplays() NO_THREAD_SAFETY_ANALYSIS { return mFlinger->mDisplays; } + auto& mutablePhysicalDisplays() NO_THREAD_SAFETY_ANALYSIS { + return mFlinger->mPhysicalDisplays; + } auto& mutableDrawingState() { return mFlinger->mDrawingState; } auto& mutableGeometryDirty() { return mFlinger->mGeometryDirty; } auto& mutableVisibleRegionsDirty() { return mFlinger->mVisibleRegionsDirty; } auto& mutableMainThreadId() { return mFlinger->mMainThreadId; } - auto& mutablePendingHotplugEvents() { return mFlinger->mPendingHotplugEvents; } + auto& mutablePendingHotplugEvents() NO_THREAD_SAFETY_ANALYSIS { + return mFlinger->mPendingHotplugEvents; + } auto& mutableTransactionFlags() { return mFlinger->mTransactionFlags; } auto& mutableDebugDisableHWC() { return mFlinger->mDebugDisableHWC; } auto& mutableMaxRenderTargetSize() { return mFlinger->mMaxRenderTargetSize; } @@ -691,7 +699,7 @@ public: auto& mutableHwcDisplayData() { return getHwComposer().mDisplayData; } auto& mutableHwcPhysicalDisplayIdMap() { return getHwComposer().mPhysicalDisplayIdMap; } auto& mutablePrimaryHwcDisplayId() { return getHwComposer().mPrimaryHwcDisplayId; } - auto& mutableActiveDisplayId() { return mFlinger->mActiveDisplayId; } + auto& mutableActiveDisplayId() NO_THREAD_SAFETY_ANALYSIS { return mFlinger->mActiveDisplayId; } auto& mutablePreviouslyComposedLayers() { return mFlinger->mPreviouslyComposedLayers; } auto& mutableActiveDisplayRotationFlags() { @@ -700,7 +708,9 @@ public: auto& mutableMinAcquiredBuffers() { return SurfaceFlinger::minAcquiredBuffers; } auto& mutableLayersPendingRemoval() { return mFlinger->mLayersPendingRemoval; } - auto& mutableLayerSnapshotBuilder() { return mFlinger->mLayerSnapshotBuilder; }; + auto& mutableLayerSnapshotBuilder() NO_THREAD_SAFETY_ANALYSIS { + return mFlinger->mLayerSnapshotBuilder; + } auto fromHandle(const sp<IBinder>& handle) { return LayerHandle::getLayer(handle); } |