diff options
106 files changed, 2836 insertions, 611 deletions
diff --git a/Android.bp b/Android.bp index 72311f0263..13954ef181 100644 --- a/Android.bp +++ b/Android.bp @@ -125,3 +125,9 @@ filegroup { srcs: ["aidl/android/hardware/display/IDeviceProductInfoConstants.aidl"], path: "aidl", } + +dirgroup { + name: "trusty_dirgroup_frameworks_native", + dirs: ["libs/binder"], + visibility: ["//trusty/vendor/google/aosp/scripts"], +} diff --git a/TEST_MAPPING b/TEST_MAPPING index 9c0116957d..07d16f7a4d 100644 --- a/TEST_MAPPING +++ b/TEST_MAPPING @@ -4,9 +4,6 @@ "name": "SurfaceFlinger_test", "options": [ { - "include-filter": "*" - }, - { // TODO(b/305717998): Deflake and re-enable "exclude-filter": "*ChildLayerTest*" } @@ -23,12 +20,7 @@ ], "hwasan-postsubmit": [ { - "name": "SurfaceFlinger_test", - "options": [ - { - "include-filter": "*" - } - ] + "name": "SurfaceFlinger_test" } ] } diff --git a/cmds/dumpstate/DumpstateInternal.cpp b/cmds/dumpstate/DumpstateInternal.cpp index 6f7fea3432..ce7c55c7b3 100644 --- a/cmds/dumpstate/DumpstateInternal.cpp +++ b/cmds/dumpstate/DumpstateInternal.cpp @@ -108,7 +108,7 @@ bool DropRootUser() { const uint32_t cap_syslog_mask = CAP_TO_MASK(CAP_SYSLOG); const uint32_t cap_syslog_index = CAP_TO_INDEX(CAP_SYSLOG); - bool has_cap_syslog = (capdata[cap_syslog_index].effective & cap_syslog_mask) != 0; + bool has_cap_syslog = (capdata[cap_syslog_index].permitted & cap_syslog_mask) != 0; memset(&capdata, 0, sizeof(capdata)); if (has_cap_syslog) { diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp index 4e3889af61..5e83e3337f 100644 --- a/cmds/dumpstate/dumpstate.cpp +++ b/cmds/dumpstate/dumpstate.cpp @@ -4638,7 +4638,7 @@ void Dumpstate::UpdateProgress(int32_t delta_sec) { void Dumpstate::TakeScreenshot(const std::string& path) { const std::string& real_path = path.empty() ? screenshot_path_ : path; int status = - RunCommand("", {"/system/bin/screencap", "-p", real_path}, + RunCommand("", {"screencap", "-p", real_path}, CommandOptions::WithTimeout(10).Always().DropRoot().RedirectStderr().Build()); if (status == 0) { MYLOGD("Screenshot saved on %s\n", real_path.c_str()); diff --git a/data/etc/go_handheld_core_hardware.xml b/data/etc/go_handheld_core_hardware.xml index 8df7fdbb16..a092842fa9 100644 --- a/data/etc/go_handheld_core_hardware.xml +++ b/data/etc/go_handheld_core_hardware.xml @@ -51,6 +51,9 @@ <!-- Feature to specify if the device supports adding device admins. --> <feature name="android.software.device_admin" /> + <!-- Feature to specify if the device support managed users. --> + <feature name="android.software.managed_users" /> + <!-- Devices with all optimizations required to support VR Mode and pass all CDD requirements for this feature may include android.hardware.vr.high_performance --> diff --git a/include/android/performance_hint.h b/include/android/performance_hint.h index 3f32a5abb3..3486e9b1d7 100644 --- a/include/android/performance_hint.h +++ b/include/android/performance_hint.h @@ -52,7 +52,6 @@ * - DO NOT CHANGE THE LAYOUT OR SIZE OF STRUCTURES */ -#include <android/api-level.h> #include <stdbool.h> #include <stdint.h> #include <unistd.h> diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp index 379b609e9f..2ef642a3a0 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 { @@ -890,6 +871,10 @@ cc_library { symbol_file: "libbinder_rpc_unstable.map.txt", }, + header_abi_checker: { + enabled: false, + }, + // This library is intentionally limited to these targets, and it will be removed later. // Do not expand the visibility. visibility: [ diff --git a/libs/binder/BackendUnifiedServiceManager.cpp b/libs/binder/BackendUnifiedServiceManager.cpp index 52b485a6f6..d32eecdc60 100644 --- a/libs/binder/BackendUnifiedServiceManager.cpp +++ b/libs/binder/BackendUnifiedServiceManager.cpp @@ -31,7 +31,8 @@ constexpr bool kUseCache = false; #endif using AidlServiceManager = android::os::IServiceManager; -using IAccessor = android::os::IAccessor; +using android::os::IAccessor; +using binder::Status; static const char* kStaticCachableList[] = { // go/keep-sorted start @@ -39,10 +40,14 @@ static const char* kStaticCachableList[] = { "account", "activity", "alarm", + "android.frameworks.stats.IStats/default", "android.system.keystore2.IKeystoreService/default", "appops", "audio", + "autofill", + "batteryproperties", "batterystats", + "biometic", "carrier_config", "connectivity", "content", @@ -58,6 +63,7 @@ static const char* kStaticCachableList[] = { "jobscheduler", "legacy_permission", "location", + "lock_settings", "media.extractor", "media.metrics", "media.player", @@ -78,15 +84,19 @@ static const char* kStaticCachableList[] = { "phone", "platform_compat", "power", + "processinfo", "role", + "sensitive_content_protection_service", "sensorservice", "statscompanion", "telephony.registry", "thermalservice", "time_detector", + "tracing.proxy", "trust", "uimode", "user", + "vibrator", "virtualdevice", "virtualdevice_native", "webviewupdate", @@ -95,7 +105,8 @@ static const char* kStaticCachableList[] = { }; bool BinderCacheWithInvalidation::isClientSideCachingEnabled(const std::string& serviceName) { - if (ProcessState::self()->getThreadPoolMaxTotalThreadCount() <= 0) { + sp<ProcessState> self = ProcessState::selfOrNull(); + if (!self || self->getThreadPoolMaxTotalThreadCount() <= 0) { ALOGW("Thread Pool max thread count is 0. Cannot cache binder as linkToDeath cannot be " "implemented. serviceName: %s", serviceName.c_str()); @@ -109,19 +120,38 @@ bool BinderCacheWithInvalidation::isClientSideCachingEnabled(const std::string& return false; } -binder::Status BackendUnifiedServiceManager::updateCache(const std::string& serviceName, - const os::Service& service) { +Status BackendUnifiedServiceManager::updateCache(const std::string& serviceName, + const os::Service& service) { if (!kUseCache) { - return binder::Status::ok(); + return Status::ok(); } + std::string traceStr; + if (atrace_is_tag_enabled(ATRACE_TAG_AIDL)) { + traceStr = "BinderCacheWithInvalidation::updateCache : " + serviceName; + } + binder::ScopedTrace aidlTrace(ATRACE_TAG_AIDL, traceStr.c_str()); + if (service.getTag() == os::Service::Tag::binder) { sp<IBinder> binder = service.get<os::Service::Tag::binder>(); - if (binder && mCacheForGetService->isClientSideCachingEnabled(serviceName) && - binder->isBinderAlive()) { + if (!binder) { + binder::ScopedTrace + aidlTrace(ATRACE_TAG_AIDL, + "BinderCacheWithInvalidation::updateCache failed: binder_null"); + } else if (!binder->isBinderAlive()) { + binder::ScopedTrace aidlTrace(ATRACE_TAG_AIDL, + "BinderCacheWithInvalidation::updateCache failed: " + "isBinderAlive_false"); + } else if (mCacheForGetService->isClientSideCachingEnabled(serviceName)) { + binder::ScopedTrace aidlTrace(ATRACE_TAG_AIDL, + "BinderCacheWithInvalidation::updateCache successful"); return mCacheForGetService->setItem(serviceName, binder); + } else { + binder::ScopedTrace aidlTrace(ATRACE_TAG_AIDL, + "BinderCacheWithInvalidation::updateCache failed: " + "caching_not_enabled"); } } - return binder::Status::ok(); + return Status::ok(); } bool BackendUnifiedServiceManager::returnIfCached(const std::string& serviceName, @@ -143,25 +173,20 @@ BackendUnifiedServiceManager::BackendUnifiedServiceManager(const sp<AidlServiceM mCacheForGetService = std::make_shared<BinderCacheWithInvalidation>(); } -sp<AidlServiceManager> BackendUnifiedServiceManager::getImpl() { - return mTheRealServiceManager; -} - -binder::Status BackendUnifiedServiceManager::getService(const ::std::string& name, - sp<IBinder>* _aidl_return) { +Status BackendUnifiedServiceManager::getService(const ::std::string& name, + sp<IBinder>* _aidl_return) { os::Service service; - binder::Status status = getService2(name, &service); + Status status = getService2(name, &service); *_aidl_return = service.get<os::Service::Tag::binder>(); return status; } -binder::Status BackendUnifiedServiceManager::getService2(const ::std::string& name, - os::Service* _out) { +Status BackendUnifiedServiceManager::getService2(const ::std::string& name, os::Service* _out) { if (returnIfCached(name, _out)) { - return binder::Status::ok(); + return Status::ok(); } os::Service service; - binder::Status status = mTheRealServiceManager->getService2(name, &service); + Status status = mTheRealServiceManager->getService2(name, &service); if (status.isOk()) { status = toBinderService(name, service, _out); @@ -172,14 +197,13 @@ binder::Status BackendUnifiedServiceManager::getService2(const ::std::string& na return status; } -binder::Status BackendUnifiedServiceManager::checkService(const ::std::string& name, - os::Service* _out) { +Status BackendUnifiedServiceManager::checkService(const ::std::string& name, os::Service* _out) { os::Service service; if (returnIfCached(name, _out)) { - return binder::Status::ok(); + return Status::ok(); } - binder::Status status = mTheRealServiceManager->checkService(name, &service); + Status status = mTheRealServiceManager->checkService(name, &service); if (status.isOk()) { status = toBinderService(name, service, _out); if (status.isOk()) { @@ -189,16 +213,15 @@ binder::Status BackendUnifiedServiceManager::checkService(const ::std::string& n return status; } -binder::Status BackendUnifiedServiceManager::toBinderService(const ::std::string& name, - const os::Service& in, - os::Service* _out) { +Status BackendUnifiedServiceManager::toBinderService(const ::std::string& name, + const os::Service& in, os::Service* _out) { switch (in.getTag()) { case os::Service::Tag::binder: { if (in.get<os::Service::Tag::binder>() == nullptr) { // failed to find a service. Check to see if we have any local // injected Accessors for this service. os::Service accessor; - binder::Status status = getInjectedAccessor(name, &accessor); + Status status = getInjectedAccessor(name, &accessor); if (!status.isOk()) { *_out = os::Service::make<os::Service::Tag::binder>(nullptr); return status; @@ -214,7 +237,7 @@ binder::Status BackendUnifiedServiceManager::toBinderService(const ::std::string } *_out = in; - return binder::Status::ok(); + return Status::ok(); } case os::Service::Tag::accessor: { sp<IBinder> accessorBinder = in.get<os::Service::Tag::accessor>(); @@ -222,11 +245,11 @@ binder::Status BackendUnifiedServiceManager::toBinderService(const ::std::string if (accessor == nullptr) { ALOGE("Service#accessor doesn't have accessor. VM is maybe starting..."); *_out = os::Service::make<os::Service::Tag::binder>(nullptr); - return binder::Status::ok(); + return Status::ok(); } auto request = [=] { os::ParcelFileDescriptor fd; - binder::Status ret = accessor->addConnection(&fd); + Status ret = accessor->addConnection(&fd); if (ret.isOk()) { return base::unique_fd(fd.release()); } else { @@ -239,11 +262,11 @@ binder::Status BackendUnifiedServiceManager::toBinderService(const ::std::string if (status != OK) { ALOGE("Failed to set up preconnected binder RPC client: %s", statusToString(status).c_str()); - return binder::Status::fromStatusT(status); + return Status::fromStatusT(status); } session->setSessionSpecificRoot(accessorBinder); *_out = os::Service::make<os::Service::Tag::binder>(session->getRootObject()); - return binder::Status::ok(); + return Status::ok(); } default: { LOG_ALWAYS_FATAL("Unknown service type: %d", in.getTag()); @@ -251,53 +274,52 @@ binder::Status BackendUnifiedServiceManager::toBinderService(const ::std::string } } -binder::Status BackendUnifiedServiceManager::addService(const ::std::string& name, - const sp<IBinder>& service, - bool allowIsolated, int32_t dumpPriority) { +Status BackendUnifiedServiceManager::addService(const ::std::string& name, + const sp<IBinder>& service, bool allowIsolated, + int32_t dumpPriority) { return mTheRealServiceManager->addService(name, service, allowIsolated, dumpPriority); } -binder::Status BackendUnifiedServiceManager::listServices( - int32_t dumpPriority, ::std::vector<::std::string>* _aidl_return) { +Status BackendUnifiedServiceManager::listServices(int32_t dumpPriority, + ::std::vector<::std::string>* _aidl_return) { return mTheRealServiceManager->listServices(dumpPriority, _aidl_return); } -binder::Status BackendUnifiedServiceManager::registerForNotifications( +Status BackendUnifiedServiceManager::registerForNotifications( const ::std::string& name, const sp<os::IServiceCallback>& callback) { return mTheRealServiceManager->registerForNotifications(name, callback); } -binder::Status BackendUnifiedServiceManager::unregisterForNotifications( +Status BackendUnifiedServiceManager::unregisterForNotifications( const ::std::string& name, const sp<os::IServiceCallback>& callback) { return mTheRealServiceManager->unregisterForNotifications(name, callback); } -binder::Status BackendUnifiedServiceManager::isDeclared(const ::std::string& name, - bool* _aidl_return) { +Status BackendUnifiedServiceManager::isDeclared(const ::std::string& name, bool* _aidl_return) { return mTheRealServiceManager->isDeclared(name, _aidl_return); } -binder::Status BackendUnifiedServiceManager::getDeclaredInstances( +Status BackendUnifiedServiceManager::getDeclaredInstances( const ::std::string& iface, ::std::vector<::std::string>* _aidl_return) { return mTheRealServiceManager->getDeclaredInstances(iface, _aidl_return); } -binder::Status BackendUnifiedServiceManager::updatableViaApex( +Status BackendUnifiedServiceManager::updatableViaApex( const ::std::string& name, ::std::optional<::std::string>* _aidl_return) { return mTheRealServiceManager->updatableViaApex(name, _aidl_return); } -binder::Status BackendUnifiedServiceManager::getUpdatableNames( - const ::std::string& apexName, ::std::vector<::std::string>* _aidl_return) { +Status BackendUnifiedServiceManager::getUpdatableNames(const ::std::string& apexName, + ::std::vector<::std::string>* _aidl_return) { return mTheRealServiceManager->getUpdatableNames(apexName, _aidl_return); } -binder::Status BackendUnifiedServiceManager::getConnectionInfo( +Status BackendUnifiedServiceManager::getConnectionInfo( const ::std::string& name, ::std::optional<os::ConnectionInfo>* _aidl_return) { return mTheRealServiceManager->getConnectionInfo(name, _aidl_return); } -binder::Status BackendUnifiedServiceManager::registerClientCallback( +Status BackendUnifiedServiceManager::registerClientCallback( const ::std::string& name, const sp<IBinder>& service, const sp<os::IClientCallback>& callback) { return mTheRealServiceManager->registerClientCallback(name, service, callback); } -binder::Status BackendUnifiedServiceManager::tryUnregisterService(const ::std::string& name, - const sp<IBinder>& service) { +Status BackendUnifiedServiceManager::tryUnregisterService(const ::std::string& name, + const sp<IBinder>& service) { return mTheRealServiceManager->tryUnregisterService(name, service); } -binder::Status BackendUnifiedServiceManager::getServiceDebugInfo( +Status BackendUnifiedServiceManager::getServiceDebugInfo( ::std::vector<os::ServiceDebugInfo>* _aidl_return) { return mTheRealServiceManager->getServiceDebugInfo(_aidl_return); } diff --git a/libs/binder/BackendUnifiedServiceManager.h b/libs/binder/BackendUnifiedServiceManager.h index 47b2ec9f2c..abc0eda7eb 100644 --- a/libs/binder/BackendUnifiedServiceManager.h +++ b/libs/binder/BackendUnifiedServiceManager.h @@ -18,6 +18,7 @@ #include <android/os/BnServiceManager.h> #include <android/os/IServiceManager.h> #include <binder/IPCThreadState.h> +#include <binder/Trace.h> #include <map> #include <memory> @@ -59,6 +60,12 @@ public: } bool removeItem(const std::string& key, const sp<IBinder>& who) { + std::string traceStr; + uint64_t tag = ATRACE_TAG_AIDL; + if (atrace_is_tag_enabled(tag)) { + traceStr = "BinderCacheWithInvalidation::removeItem " + key; + } + binder::ScopedTrace aidlTrace(tag, traceStr.c_str()); std::lock_guard<std::mutex> lock(mCacheMutex); if (auto it = mCache.find(key); it != mCache.end()) { if (it->second.service == who) { @@ -81,11 +88,22 @@ public: if (item->localBinder() == nullptr) { status_t status = item->linkToDeath(deathRecipient); if (status != android::OK) { + std::string traceStr; + uint64_t tag = ATRACE_TAG_AIDL; + if (atrace_is_tag_enabled(tag)) { + traceStr = + "BinderCacheWithInvalidation::setItem Failed LinkToDeath for service " + + key + " : " + std::to_string(status); + } + binder::ScopedTrace aidlTrace(tag, traceStr.c_str()); + ALOGE("Failed to linkToDeath binder for service %s. Error: %d", key.c_str(), status); return binder::Status::fromStatusT(status); } } + binder::ScopedTrace aidlTrace(ATRACE_TAG_AIDL, + "BinderCacheWithInvalidation::setItem Successfully Cached"); std::lock_guard<std::mutex> lock(mCacheMutex); Entry entry = {.service = item, .deathRecipient = deathRecipient}; mCache[key] = entry; @@ -103,7 +121,6 @@ class BackendUnifiedServiceManager : public android::os::BnServiceManager { public: explicit BackendUnifiedServiceManager(const sp<os::IServiceManager>& impl); - sp<os::IServiceManager> getImpl(); binder::Status getService(const ::std::string& name, sp<IBinder>* _aidl_return) override; binder::Status getService2(const ::std::string& name, os::Service* out) override; binder::Status checkService(const ::std::string& name, os::Service* out) override; diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp index eae844ca03..3758b6521c 100644 --- a/libs/binder/BpBinder.cpp +++ b/libs/binder/BpBinder.cpp @@ -197,7 +197,9 @@ sp<BpBinder> BpBinder::create(int32_t handle, std::function<void()>* postTask) { && currentValue < sBinderProxyCountHighWatermark && ((trackedValue & WARNING_REACHED_MASK) == 0)) [[unlikely]] { sTrackingMap[trackedUid] |= WARNING_REACHED_MASK; - if (sWarningCallback) sWarningCallback(trackedUid); + if (sWarningCallback) { + *postTask = [=]() { sWarningCallback(trackedUid); }; + } } else if (currentValue >= sBinderProxyCountHighWatermark) { ALOGE("Too many binder proxy objects sent to uid %d from uid %d (%d proxies held)", getuid(), trackedUid, trackedValue); diff --git a/libs/binder/IMemory.cpp b/libs/binder/IMemory.cpp index c6b0cb7b01..bb03e89c9d 100644 --- a/libs/binder/IMemory.cpp +++ b/libs/binder/IMemory.cpp @@ -330,8 +330,8 @@ void BpMemoryHeap::assertReallyMapped() const if (err != NO_ERROR || // failed transaction size != size64 || offset != offset64) { // ILP32 size check ALOGE("binder=%p transaction failed fd=%d, size=%zu, err=%d (%s)", - IInterface::asBinder(this).get(), - parcel_fd, size, err, strerror(-err)); + IInterface::asBinder(this).get(), parcel_fd, size, err, + statusToString(err).c_str()); return; } diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp index 88761d772f..39d8c2446e 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 @@ -507,8 +561,9 @@ sp<IBinder> CppBackendShim::getService(const String16& name) const { sp<IBinder> svc = checkService(name); if (svc != nullptr) return svc; + sp<ProcessState> self = ProcessState::selfOrNull(); const bool isVendorService = - strcmp(ProcessState::self()->getDriverName().c_str(), "/dev/vndbinder") == 0; + self && strcmp(self->getDriverName().c_str(), "/dev/vndbinder") == 0; constexpr auto timeout = 5s; const auto startTime = std::chrono::steady_clock::now(); // Vendor code can't access system properties @@ -525,7 +580,7 @@ sp<IBinder> CppBackendShim::getService(const String16& name) const { const useconds_t sleepTime = gSystemBootCompleted ? 1000 : 100; ALOGI("Waiting for service '%s' on '%s'...", String8(name).c_str(), - ProcessState::self()->getDriverName().c_str()); + self ? self->getDriverName().c_str() : "RPC accessors only"); int n = 0; while (std::chrono::steady_clock::now() - startTime < timeout) { @@ -607,7 +662,8 @@ sp<IBinder> CppBackendShim::waitForService(const String16& name16) { if (Status status = realGetService(name, &out); !status.isOk()) { ALOGW("Failed to getService in waitForService for %s: %s", name.c_str(), status.toString8().c_str()); - if (0 == ProcessState::self()->getThreadPoolMaxTotalThreadCount()) { + sp<ProcessState> self = ProcessState::selfOrNull(); + if (self && 0 == self->getThreadPoolMaxTotalThreadCount()) { ALOGW("Got service, but may be racey because we could not wait efficiently for it. " "Threadpool has 0 guaranteed threads. " "Is the threadpool configured properly? " @@ -641,9 +697,10 @@ sp<IBinder> CppBackendShim::waitForService(const String16& name16) { if (waiter->mBinder != nullptr) return waiter->mBinder; } + sp<ProcessState> self = ProcessState::selfOrNull(); ALOGW("Waited one second for %s (is service started? Number of threads started in the " "threadpool: %zu. Are binder threads started and available?)", - name.c_str(), ProcessState::self()->getThreadPoolMaxTotalThreadCount()); + name.c_str(), self ? self->getThreadPoolMaxTotalThreadCount() : 0); // Handle race condition for lazy services. Here is what can happen: // - the service dies (not processed by init yet). 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..2d65cf53c8 100644 --- a/libs/binder/Parcel.cpp +++ b/libs/binder/Parcel.cpp @@ -668,7 +668,8 @@ status_t Parcel::appendFrom(const Parcel* parcel, size_t offset, size_t len) { // FD was unowned in the source parcel. int newFd = -1; if (status_t status = binder::os::dupFileDescriptor(oldFd, &newFd); status != OK) { - ALOGW("Failed to duplicate file descriptor %d: %s", oldFd, strerror(-status)); + ALOGW("Failed to duplicate file descriptor %d: %s", oldFd, + statusToString(status).c_str()); } rpcFields->mFds->emplace_back(unique_fd(newFd)); // Fixup the index in the data. @@ -683,7 +684,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/RpcServer.cpp b/libs/binder/RpcServer.cpp index b8742af1f9..c7851dc3fb 100644 --- a/libs/binder/RpcServer.cpp +++ b/libs/binder/RpcServer.cpp @@ -503,7 +503,7 @@ void RpcServer::establishConnection( auto status = binder::os::getRandomBytes(sessionId.data(), sessionId.size()); if (status != OK) { - ALOGE("Failed to read random session ID: %s", strerror(-status)); + ALOGE("Failed to read random session ID: %s", statusToString(status).c_str()); return; } } while (server->mSessions.end() != server->mSessions.find(sessionId)); diff --git a/libs/binder/RpcSession.cpp b/libs/binder/RpcSession.cpp index cd21a91d2c..16023ffa82 100644 --- a/libs/binder/RpcSession.cpp +++ b/libs/binder/RpcSession.cpp @@ -164,7 +164,7 @@ status_t RpcSession::setupUnixDomainSocketBootstrapClient(unique_fd bootstrapFd) status_t status = mBootstrapTransport->interruptableWriteFully(mShutdownTrigger.get(), &iov, 1, std::nullopt, &fds); if (status != OK) { - ALOGE("Failed to send fd over bootstrap transport: %s", strerror(-status)); + ALOGE("Failed to send fd over bootstrap transport: %s", statusToString(status).c_str()); return status; } 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/TEST_MAPPING b/libs/binder/TEST_MAPPING index 95a5da20ae..ab449572d6 100644 --- a/libs/binder/TEST_MAPPING +++ b/libs/binder/TEST_MAPPING @@ -94,6 +94,9 @@ }, { "name": "libbinder_rpc_unstable_bindgen_test" + }, + { + "name": "binderCacheUnitTest" } ], "presubmit-large": [ @@ -133,9 +136,6 @@ { "name": "binder_sdk_test", "host": true - }, - { - "name": "binderCacheUnitTest" } ], "imports": [ diff --git a/libs/binder/aidl/android/content/pm/ApexStagedEvent.aidl b/libs/binder/aidl/android/content/pm/ApexStagedEvent.aidl index 75f87530f9..9bac38641e 100644 --- a/libs/binder/aidl/android/content/pm/ApexStagedEvent.aidl +++ b/libs/binder/aidl/android/content/pm/ApexStagedEvent.aidl @@ -16,6 +16,8 @@ package android.content.pm; +import android.content.pm.StagedApexInfo; + /** * This event is designed for notification to native code listener about * any changes to set of apex packages staged for installation on next boot. @@ -23,5 +25,5 @@ package android.content.pm; * @hide */ parcelable ApexStagedEvent { - @utf8InCpp String[] stagedApexModuleNames; + StagedApexInfo[] stagedApexInfos; } diff --git a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl index 3ddfefa311..0f0be2f22b 100644 --- a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl +++ b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl @@ -135,13 +135,7 @@ interface IPackageManagerNative { void unregisterStagedApexObserver(in IStagedApexObserver observer); /** - * Get APEX module names of all APEX that are staged ready for installation + * Get information of staged APEXes. */ - @utf8InCpp String[] getStagedApexModuleNames(); - - /** - * Get information of APEX which is staged ready for installation. - * Returns null if no such APEX is found. - */ - @nullable StagedApexInfo getStagedApexInfo(in @utf8InCpp String moduleName); + StagedApexInfo[] getStagedApexInfos(); } diff --git a/libs/binder/aidl/android/content/pm/StagedApexInfo.aidl b/libs/binder/aidl/android/content/pm/StagedApexInfo.aidl index 949835b452..8f7ad30779 100644 --- a/libs/binder/aidl/android/content/pm/StagedApexInfo.aidl +++ b/libs/binder/aidl/android/content/pm/StagedApexInfo.aidl @@ -22,6 +22,7 @@ package android.content.pm; * * @hide */ +@JavaDerive(equals=true) parcelable StagedApexInfo { @utf8InCpp String moduleName; @utf8InCpp String diskImagePath; 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/SafeInterface.h b/libs/binder/include/binder/SafeInterface.h index c671eed039..0b4f196b8f 100644 --- a/libs/binder/include/binder/SafeInterface.h +++ b/libs/binder/include/binder/SafeInterface.h @@ -152,6 +152,14 @@ public: return callParcel("writeParcelableVector", [&]() { return parcel->writeParcelableVector(v); }); } + + status_t read(const Parcel& parcel, std::vector<bool>* v) const { + return callParcel("readBoolVector", [&]() { return parcel.readBoolVector(v); }); + } + status_t write(Parcel* parcel, const std::vector<bool>& v) const { + return callParcel("writeBoolVector", [&]() { return parcel->writeBoolVector(v); }); + } + status_t read(const Parcel& parcel, float* f) const { return callParcel("readFloat", [&]() { return parcel.readFloat(f); }); } 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/include_rpc_unstable/binder_rpc_unstable.hpp b/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp index 392ebb5b0a..48c0ea636b 100644 --- a/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp +++ b/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp @@ -37,8 +37,12 @@ enum class ARpcSession_FileDescriptorTransportMode { // Set `cid` to VMADDR_CID_LOCAL to only bind to the local vsock interface. // Returns an opaque handle to the running server instance, or null if the server // could not be started. +// Set |port| to VMADDR_PORT_ANY to pick an available ephemeral port. +// |assignedPort| will be set to the assigned port number if it is not null. +// This will be the provided |port|, or the chosen available ephemeral port when +// |port| is VMADDR_PORT_ANY. [[nodiscard]] ARpcServer* ARpcServer_newVsock(AIBinder* service, unsigned int cid, - unsigned int port); + unsigned int port, unsigned int* assignedPort); // Starts a Unix domain RPC server with an open raw socket file descriptor // and a given root IBinder object. diff --git a/libs/binder/libbinder_rpc_unstable.cpp b/libs/binder/libbinder_rpc_unstable.cpp index 21537fc50d..a84a0c6e0b 100644 --- a/libs/binder/libbinder_rpc_unstable.cpp +++ b/libs/binder/libbinder_rpc_unstable.cpp @@ -81,7 +81,8 @@ RpcSession::FileDescriptorTransportMode toTransportMode( extern "C" { #ifndef __TRUSTY__ -ARpcServer* ARpcServer_newVsock(AIBinder* service, unsigned int cid, unsigned int port) { +ARpcServer* ARpcServer_newVsock(AIBinder* service, unsigned int cid, unsigned int port, + unsigned int* assignedPort) { auto server = RpcServer::make(); unsigned int bindCid = VMADDR_CID_ANY; // bind to the remote interface @@ -90,7 +91,7 @@ ARpcServer* ARpcServer_newVsock(AIBinder* service, unsigned int cid, unsigned in cid = VMADDR_CID_ANY; // no need for a connection filter } - if (status_t status = server->setupVsockServer(bindCid, port); status != OK) { + if (status_t status = server->setupVsockServer(bindCid, port, assignedPort); status != OK) { ALOGE("Failed to set up vsock server with port %u error: %s", port, statusToString(status).c_str()); return nullptr; diff --git a/libs/binder/ndk/Android.bp b/libs/binder/ndk/Android.bp index 5f45cb2f07..5710bbfa9f 100644 --- a/libs/binder/ndk/Android.bp +++ b/libs/binder/ndk/Android.bp @@ -82,7 +82,6 @@ cc_library { llndk: { symbol_file: "libbinder_ndk.map.txt", - export_llndk_headers: ["libvendorsupport_llndk_headers"], }, cflags: [ @@ -95,6 +94,7 @@ cc_library { "persistable_bundle.cpp", "process.cpp", "service_manager.cpp", + "binder_rpc.cpp", ], static_libs: [ @@ -109,11 +109,9 @@ cc_library { ], header_libs: [ - "libvendorsupport_llndk_headers", "jni_headers", ], export_header_lib_headers: [ - "libvendorsupport_llndk_headers", "jni_headers", ], diff --git a/libs/binder/ndk/binder_rpc.cpp b/libs/binder/ndk/binder_rpc.cpp new file mode 100644 index 0000000000..53ab68e643 --- /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* const* const 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 STATUS_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 STATUS_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..c6518d816f 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,15 @@ #include <android/binder_auto_utils.h> #include <android/binder_ibinder.h> +#if defined(__BIONIC__) +#define API_LEVEL_AT_LEAST(sdk_api_level) __builtin_available(android sdk_api_level, *) +#elif defined(TRUSTY_USERSPACE) +// TODO(b/349936395): set to true for Trusty +#define API_LEVEL_AT_LEAST(sdk_api_level) (false) +#else +#define API_LEVEL_AT_LEAST(sdk_api_level) (true) +#endif // __BIONIC__ + #if __has_include(<android/binder_shell.h>) #include <android/binder_shell.h> #define HAS_BINDER_SHELL_COMMAND @@ -164,6 +173,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 +269,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 +294,18 @@ 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)) { + if (codeToFunction != 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..f3f3c3802a 100644 --- a/libs/binder/ndk/include_cpp/android/persistable_bundle_aidl.h +++ b/libs/binder/ndk/include_cpp/android/persistable_bundle_aidl.h @@ -22,17 +22,14 @@ #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 <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, *)) +#define API_LEVEL_AT_LEAST(sdk_api_level) __builtin_available(android sdk_api_level, *) +#elif defined(TRUSTY_USERSPACE) +// TODO(b/349936395): set to true for Trusty +#define API_LEVEL_AT_LEAST(sdk_api_level) (false) #else -#define API_LEVEL_AT_LEAST(sdk_api_level, vendor_api_level) (true) +#define API_LEVEL_AT_LEAST(sdk_api_level) (true) #endif // __BIONIC__ -#endif // __ANDROID_VENDOR__ namespace aidl::android::os { @@ -44,7 +41,7 @@ namespace aidl::android::os { class PersistableBundle { public: PersistableBundle() noexcept { - if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) { + if (API_LEVEL_AT_LEAST(__ANDROID_API_V__)) { mPBundle = APersistableBundle_new(); } } @@ -54,13 +51,13 @@ class PersistableBundle { PersistableBundle(PersistableBundle&& other) noexcept : mPBundle(other.release()) {} // duplicates, does not take ownership of the APersistableBundle* PersistableBundle(const PersistableBundle& other) { - if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) { + if (API_LEVEL_AT_LEAST(__ANDROID_API_V__)) { mPBundle = APersistableBundle_dup(other.mPBundle); } } // duplicates, does not take ownership of the APersistableBundle* PersistableBundle& operator=(const PersistableBundle& other) { - if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) { + if (API_LEVEL_AT_LEAST(__ANDROID_API_V__)) { mPBundle = APersistableBundle_dup(other.mPBundle); } return *this; @@ -70,7 +67,7 @@ class PersistableBundle { binder_status_t readFromParcel(const AParcel* _Nonnull parcel) { reset(); - if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) { + if (API_LEVEL_AT_LEAST(__ANDROID_API_V__)) { return APersistableBundle_readFromParcel(parcel, &mPBundle); } else { return STATUS_INVALID_OPERATION; @@ -81,7 +78,7 @@ class PersistableBundle { if (!mPBundle) { return STATUS_BAD_VALUE; } - if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) { + if (API_LEVEL_AT_LEAST(__ANDROID_API_V__)) { return APersistableBundle_writeToParcel(mPBundle, parcel); } else { return STATUS_INVALID_OPERATION; @@ -96,7 +93,7 @@ class PersistableBundle { */ void reset(APersistableBundle* _Nullable pBundle = nullptr) noexcept { if (mPBundle) { - if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) { + if (API_LEVEL_AT_LEAST(__ANDROID_API_V__)) { APersistableBundle_delete(mPBundle); } mPBundle = nullptr; @@ -109,7 +106,7 @@ class PersistableBundle { * what should be used to check for equality. */ bool deepEquals(const PersistableBundle& rhs) const { - if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) { + if (API_LEVEL_AT_LEAST(__ANDROID_API_V__)) { return APersistableBundle_isEqual(get(), rhs.get()); } else { return false; @@ -148,7 +145,7 @@ class PersistableBundle { inline std::string toString() const { if (!mPBundle) { return "<PersistableBundle: null>"; - } else if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) { + } else if (API_LEVEL_AT_LEAST(__ANDROID_API_V__)) { std::ostringstream os; os << "<PersistableBundle: "; os << "size: " << std::to_string(APersistableBundle_size(mPBundle)); @@ -159,7 +156,7 @@ class PersistableBundle { } int32_t size() const { - if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) { + if (API_LEVEL_AT_LEAST(__ANDROID_API_V__)) { return APersistableBundle_size(mPBundle); } else { return 0; @@ -167,7 +164,7 @@ class PersistableBundle { } int32_t erase(const std::string& key) { - if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) { + if (API_LEVEL_AT_LEAST(__ANDROID_API_V__)) { return APersistableBundle_erase(mPBundle, key.c_str()); } else { return 0; @@ -175,37 +172,37 @@ class PersistableBundle { } void putBoolean(const std::string& key, bool val) { - if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) { + if (API_LEVEL_AT_LEAST(__ANDROID_API_V__)) { APersistableBundle_putBoolean(mPBundle, key.c_str(), val); } } void putInt(const std::string& key, int32_t val) { - if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) { + if (API_LEVEL_AT_LEAST(__ANDROID_API_V__)) { APersistableBundle_putInt(mPBundle, key.c_str(), val); } } void putLong(const std::string& key, int64_t val) { - if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) { + if (API_LEVEL_AT_LEAST(__ANDROID_API_V__)) { APersistableBundle_putLong(mPBundle, key.c_str(), val); } } void putDouble(const std::string& key, double val) { - if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) { + if (API_LEVEL_AT_LEAST(__ANDROID_API_V__)) { APersistableBundle_putDouble(mPBundle, key.c_str(), val); } } void putString(const std::string& key, const std::string& val) { - if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) { + if (API_LEVEL_AT_LEAST(__ANDROID_API_V__)) { APersistableBundle_putString(mPBundle, key.c_str(), val.c_str()); } } void putBooleanVector(const std::string& key, const std::vector<bool>& vec) { - if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) { + if (API_LEVEL_AT_LEAST(__ANDROID_API_V__)) { // std::vector<bool> has no ::data(). int32_t num = vec.size(); if (num > 0) { @@ -222,7 +219,7 @@ class PersistableBundle { } void putIntVector(const std::string& key, const std::vector<int32_t>& vec) { - if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) { + if (API_LEVEL_AT_LEAST(__ANDROID_API_V__)) { int32_t num = vec.size(); if (num > 0) { APersistableBundle_putIntVector(mPBundle, key.c_str(), vec.data(), num); @@ -230,7 +227,7 @@ class PersistableBundle { } } void putLongVector(const std::string& key, const std::vector<int64_t>& vec) { - if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) { + if (API_LEVEL_AT_LEAST(__ANDROID_API_V__)) { int32_t num = vec.size(); if (num > 0) { APersistableBundle_putLongVector(mPBundle, key.c_str(), vec.data(), num); @@ -238,7 +235,7 @@ class PersistableBundle { } } void putDoubleVector(const std::string& key, const std::vector<double>& vec) { - if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) { + if (API_LEVEL_AT_LEAST(__ANDROID_API_V__)) { int32_t num = vec.size(); if (num > 0) { APersistableBundle_putDoubleVector(mPBundle, key.c_str(), vec.data(), num); @@ -246,7 +243,7 @@ class PersistableBundle { } } void putStringVector(const std::string& key, const std::vector<std::string>& vec) { - if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) { + if (API_LEVEL_AT_LEAST(__ANDROID_API_V__)) { int32_t num = vec.size(); if (num > 0) { char** inVec = (char**)malloc(num * sizeof(char*)); @@ -261,13 +258,13 @@ class PersistableBundle { } } void putPersistableBundle(const std::string& key, const PersistableBundle& pBundle) { - if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) { + if (API_LEVEL_AT_LEAST(__ANDROID_API_V__)) { APersistableBundle_putPersistableBundle(mPBundle, key.c_str(), pBundle.mPBundle); } } bool getBoolean(const std::string& key, bool* _Nonnull val) const { - if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) { + if (API_LEVEL_AT_LEAST(__ANDROID_API_V__)) { return APersistableBundle_getBoolean(mPBundle, key.c_str(), val); } else { return false; @@ -275,7 +272,7 @@ class PersistableBundle { } bool getInt(const std::string& key, int32_t* _Nonnull val) const { - if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) { + if (API_LEVEL_AT_LEAST(__ANDROID_API_V__)) { return APersistableBundle_getInt(mPBundle, key.c_str(), val); } else { return false; @@ -283,7 +280,7 @@ class PersistableBundle { } bool getLong(const std::string& key, int64_t* _Nonnull val) const { - if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) { + if (API_LEVEL_AT_LEAST(__ANDROID_API_V__)) { return APersistableBundle_getLong(mPBundle, key.c_str(), val); } else { return false; @@ -291,7 +288,7 @@ class PersistableBundle { } bool getDouble(const std::string& key, double* _Nonnull val) const { - if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) { + if (API_LEVEL_AT_LEAST(__ANDROID_API_V__)) { return APersistableBundle_getDouble(mPBundle, key.c_str(), val); } else { return false; @@ -303,7 +300,7 @@ class PersistableBundle { } bool getString(const std::string& key, std::string* _Nonnull val) const { - if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) { + if (API_LEVEL_AT_LEAST(__ANDROID_API_V__)) { char* outString = nullptr; bool ret = APersistableBundle_getString(mPBundle, key.c_str(), &outString, &stringAllocator, nullptr); @@ -321,7 +318,7 @@ class PersistableBundle { const char* _Nonnull, T* _Nullable, int32_t), const APersistableBundle* _Nonnull pBundle, const char* _Nonnull key, std::vector<T>* _Nonnull vec) const { - if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) { + if (API_LEVEL_AT_LEAST(__ANDROID_API_V__)) { int32_t bytes = 0; // call first with nullptr to get required size in bytes bytes = getVec(pBundle, key, nullptr, 0); @@ -343,28 +340,28 @@ class PersistableBundle { } bool getBooleanVector(const std::string& key, std::vector<bool>* _Nonnull vec) const { - if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) { + if (API_LEVEL_AT_LEAST(__ANDROID_API_V__)) { return getVecInternal<bool>(&APersistableBundle_getBooleanVector, mPBundle, key.c_str(), vec); } return false; } bool getIntVector(const std::string& key, std::vector<int32_t>* _Nonnull vec) const { - if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) { + if (API_LEVEL_AT_LEAST(__ANDROID_API_V__)) { return getVecInternal<int32_t>(&APersistableBundle_getIntVector, mPBundle, key.c_str(), vec); } return false; } bool getLongVector(const std::string& key, std::vector<int64_t>* _Nonnull vec) const { - if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) { + if (API_LEVEL_AT_LEAST(__ANDROID_API_V__)) { return getVecInternal<int64_t>(&APersistableBundle_getLongVector, mPBundle, key.c_str(), vec); } return false; } bool getDoubleVector(const std::string& key, std::vector<double>* _Nonnull vec) const { - if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) { + if (API_LEVEL_AT_LEAST(__ANDROID_API_V__)) { return getVecInternal<double>(&APersistableBundle_getDoubleVector, mPBundle, key.c_str(), vec); } @@ -389,7 +386,7 @@ class PersistableBundle { } bool getStringVector(const std::string& key, std::vector<std::string>* _Nonnull vec) const { - if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) { + if (API_LEVEL_AT_LEAST(__ANDROID_API_V__)) { int32_t bytes = APersistableBundle_getStringVector(mPBundle, key.c_str(), nullptr, 0, &stringAllocator, nullptr); if (bytes > 0) { @@ -406,7 +403,7 @@ class PersistableBundle { } bool getPersistableBundle(const std::string& key, PersistableBundle* _Nonnull val) const { - if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) { + if (API_LEVEL_AT_LEAST(__ANDROID_API_V__)) { APersistableBundle* bundle = nullptr; bool ret = APersistableBundle_getPersistableBundle(mPBundle, key.c_str(), &bundle); if (ret) { @@ -438,77 +435,77 @@ class PersistableBundle { } std::set<std::string> getBooleanKeys() const { - if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) { + if (API_LEVEL_AT_LEAST(__ANDROID_API_V__)) { return getKeys(&APersistableBundle_getBooleanKeys, mPBundle); } else { return {}; } } std::set<std::string> getIntKeys() const { - if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) { + if (API_LEVEL_AT_LEAST(__ANDROID_API_V__)) { return getKeys(&APersistableBundle_getIntKeys, mPBundle); } else { return {}; } } std::set<std::string> getLongKeys() const { - if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) { + if (API_LEVEL_AT_LEAST(__ANDROID_API_V__)) { return getKeys(&APersistableBundle_getLongKeys, mPBundle); } else { return {}; } } std::set<std::string> getDoubleKeys() const { - if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) { + if (API_LEVEL_AT_LEAST(__ANDROID_API_V__)) { return getKeys(&APersistableBundle_getDoubleKeys, mPBundle); } else { return {}; } } std::set<std::string> getStringKeys() const { - if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) { + if (API_LEVEL_AT_LEAST(__ANDROID_API_V__)) { return getKeys(&APersistableBundle_getStringKeys, mPBundle); } else { return {}; } } std::set<std::string> getBooleanVectorKeys() const { - if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) { + if (API_LEVEL_AT_LEAST(__ANDROID_API_V__)) { return getKeys(&APersistableBundle_getBooleanVectorKeys, mPBundle); } else { return {}; } } std::set<std::string> getIntVectorKeys() const { - if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) { + if (API_LEVEL_AT_LEAST(__ANDROID_API_V__)) { return getKeys(&APersistableBundle_getIntVectorKeys, mPBundle); } else { return {}; } } std::set<std::string> getLongVectorKeys() const { - if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) { + if (API_LEVEL_AT_LEAST(__ANDROID_API_V__)) { return getKeys(&APersistableBundle_getLongVectorKeys, mPBundle); } else { return {}; } } std::set<std::string> getDoubleVectorKeys() const { - if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) { + if (API_LEVEL_AT_LEAST(__ANDROID_API_V__)) { return getKeys(&APersistableBundle_getDoubleVectorKeys, mPBundle); } else { return {}; } } std::set<std::string> getStringVectorKeys() const { - if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) { + if (API_LEVEL_AT_LEAST(__ANDROID_API_V__)) { return getKeys(&APersistableBundle_getStringVectorKeys, mPBundle); } else { return {}; } } std::set<std::string> getPersistableBundleKeys() const { - if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) { + if (API_LEVEL_AT_LEAST(__ANDROID_API_V__)) { return getKeys(&APersistableBundle_getPersistableBundleKeys, mPBundle); } else { return {}; 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_platform/android/binder_rpc.h b/libs/binder/ndk/include_platform/android/binder_rpc.h new file mode 100644 index 0000000000..7d54e2dad9 --- /dev/null +++ b/libs/binder/ndk/include_platform/android/binder_rpc.h @@ -0,0 +1,326 @@ +/* + * 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 const* const _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. + * \return STATUS_OK on success. + * STATUS_UNEXPECTED_NULL if instance or binder arguments are null. + * STATUS_BAD_TYPE if the binder is not an IAccessor. + * STATUS_NAME_NOT_FOUND if the binder is an IAccessor, but not + * associated with the provided instance name. + */ +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 3cd2b9a891..e5a3da460e 100644 --- a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp +++ b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp @@ -1108,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..8404a48c26 100644 --- a/libs/binder/rust/Android.bp +++ b/libs/binder/rust/Android.bp @@ -15,6 +15,7 @@ rust_library { "libbinder_ndk_sys", "libdowncast_rs", "liblibc", + "liblog_rust", ], host_supported: true, vendor_available: true, @@ -79,6 +80,9 @@ rust_library { shared_libs: [ "libbinder_ndk", ], + rustlibs: [ + "liblibc", + ], host_supported: true, vendor_available: true, product_available: true, @@ -129,9 +133,21 @@ rust_bindgen { // rustified "libbinder_ndk_bindgen_flags.txt", ], + bindgen_flags: [ + "--blocklist-type", + "sockaddr", + "--raw-line", + "use libc::sockaddr;", + ], + cflags: [ + "-DANDROID_PLATFORM", + ], shared_libs: [ "libbinder_ndk", ], + rustlibs: [ + "liblibc", + ], host_supported: true, vendor_available: true, product_available: true, @@ -166,6 +182,9 @@ rust_bindgen { // rustified "libbinder_ndk_bindgen_flags.txt", ], + cflags: [ + "-DANDROID_PLATFORM", + ], shared_libs: [ "libbinder_ndk_on_trusty_mock", "libc++", @@ -185,6 +204,7 @@ rust_test { "libbinder_ndk_sys", "libdowncast_rs", "liblibc", + "liblog_rust", ], } @@ -196,4 +216,7 @@ rust_test { auto_gen_config: true, clippy_lints: "none", lints: "none", + rustlibs: [ + "liblibc", + ], } diff --git a/libs/binder/rust/Cargo.toml b/libs/binder/rust/Cargo.toml new file mode 100644 index 0000000000..e5738c574a --- /dev/null +++ b/libs/binder/rust/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "android-binder" +version = "0.1.0" +edition = "2021" +description = "Safe bindings to Android Binder, restricted to the NDK" +license = "Apache-2.0" + +[dependencies] +binder-ndk-sys = { package = "android-binder-ndk-sys", version = "0.1", path = "./sys" } +downcast-rs = "1.2.1" +libc = "0.2.159" + +[lints.rust.unexpected_cfgs] +level = "warn" +check-cfg = ["cfg(android_vendor)", "cfg(android_ndk)", "cfg(android_vndk)", "cfg(trusty)"] diff --git a/libs/binder/rust/build.rs b/libs/binder/rust/build.rs new file mode 100644 index 0000000000..f3e6b53778 --- /dev/null +++ b/libs/binder/rust/build.rs @@ -0,0 +1,4 @@ +fn main() { + // Anything with cargo is NDK only. If you want to access anything else, use Soong. + println!("cargo::rustc-cfg=android_ndk"); +} diff --git a/libs/binder/rust/rpcbinder/src/server/android.rs b/libs/binder/rust/rpcbinder/src/server/android.rs index 2ab34472a9..74ce315e30 100644 --- a/libs/binder/rust/rpcbinder/src/server/android.rs +++ b/libs/binder/rust/rpcbinder/src/server/android.rs @@ -18,7 +18,7 @@ use crate::session::FileDescriptorTransportMode; use binder::{unstable_api::AsNative, SpIBinder}; use binder_rpc_unstable_bindgen::ARpcServer; use foreign_types::{foreign_type, ForeignType, ForeignTypeRef}; -use std::ffi::CString; +use std::ffi::{c_uint, CString}; use std::io::{Error, ErrorKind}; use std::os::unix::io::{IntoRawFd, OwnedFd}; @@ -42,18 +42,29 @@ impl RpcServer { /// Creates a binder RPC server, serving the supplied binder service implementation on the given /// vsock port. Only connections from the given CID are accepted. /// - // Set `cid` to libc::VMADDR_CID_ANY to accept connections from any client. - // Set `cid` to libc::VMADDR_CID_LOCAL to only bind to the local vsock interface. - pub fn new_vsock(mut service: SpIBinder, cid: u32, port: u32) -> Result<RpcServer, Error> { + /// Set `cid` to [`libc::VMADDR_CID_ANY`] to accept connections from any client. + /// Set `cid` to [`libc::VMADDR_CID_LOCAL`] to only bind to the local vsock interface. + /// Set `port` to [`libc::VMADDR_PORT_ANY`] to pick an ephemeral port. + /// The assigned port is returned with RpcServer. + pub fn new_vsock( + mut service: SpIBinder, + cid: u32, + port: u32, + ) -> Result<(RpcServer, u32 /* assigned_port */), Error> { let service = service.as_native_mut(); + let mut assigned_port: c_uint = 0; // SAFETY: Service ownership is transferring to the server and won't be valid afterward. // Plus the binder objects are threadsafe. - unsafe { + let server = unsafe { Self::checked_from_ptr(binder_rpc_unstable_bindgen::ARpcServer_newVsock( - service, cid, port, - )) - } + service, + cid, + port, + &mut assigned_port, + ))? + }; + Ok((server, assigned_port as _)) } /// Creates a binder RPC server, serving the supplied binder service implementation on the given diff --git a/libs/binder/rust/src/binder.rs b/libs/binder/rust/src/binder.rs index 9a252b853b..8c0501ba2f 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 @@ -182,8 +207,10 @@ pub const LAST_CALL_TRANSACTION: TransactionCode = sys::LAST_CALL_TRANSACTION; /// Corresponds to TF_ONE_WAY -- an asynchronous call. pub const FLAG_ONEWAY: TransactionFlags = sys::FLAG_ONEWAY; /// Corresponds to TF_CLEAR_BUF -- clear transaction buffers after call is made. +#[cfg(not(android_ndk))] pub const FLAG_CLEAR_BUF: TransactionFlags = sys::FLAG_CLEAR_BUF; /// Set to the vendor flag if we are building for the VNDK, 0 otherwise +#[cfg(not(android_ndk))] pub const FLAG_PRIVATE_LOCAL: TransactionFlags = sys::FLAG_PRIVATE_LOCAL; /// Internal interface of binder local or remote objects for making @@ -196,7 +223,7 @@ pub trait IBinderInternal: IBinder { fn is_binder_alive(&self) -> bool; /// Indicate that the service intends to receive caller security contexts. - #[cfg(not(android_vndk))] + #[cfg(not(any(android_vndk, android_ndk)))] fn set_requesting_sid(&mut self, enable: bool); /// Dump this object to the given file handle @@ -321,7 +348,6 @@ impl InterfaceClass { panic!("Expected non-null class pointer from AIBinder_Class_define!"); } sys::AIBinder_Class_setOnDump(class, Some(I::on_dump)); - sys::AIBinder_Class_setHandleShellCommand(class, None); class }; InterfaceClass(ptr) @@ -689,7 +715,7 @@ unsafe impl<T, V: AsNative<T>> AsNative<T> for Option<V> { pub struct BinderFeatures { /// Indicates that the service intends to receive caller security contexts. This must be true /// for `ThreadState::with_calling_sid` to work. - #[cfg(not(android_vndk))] + #[cfg(not(any(android_vndk, android_ndk)))] pub set_requesting_sid: bool, // Ensure that clients include a ..BinderFeatures::default() to preserve backwards compatibility // when new fields are added. #[non_exhaustive] doesn't work because it prevents struct @@ -891,8 +917,12 @@ macro_rules! declare_binder_interface { impl $native { /// Create a new binder service. pub fn new_binder<T: $interface + Sync + Send + 'static>(inner: T, features: $crate::BinderFeatures) -> $crate::Strong<dyn $interface> { + #[cfg(not(android_ndk))] let mut binder = $crate::binder_impl::Binder::new_with_stability($native(Box::new(inner)), $stability); - #[cfg(not(android_vndk))] + #[cfg(android_ndk)] + let mut binder = $crate::binder_impl::Binder::new($native(Box::new(inner))); + + #[cfg(not(any(android_vndk, android_ndk)))] $crate::binder_impl::IBinderInternal::set_requesting_sid(&mut binder, features.set_requesting_sid); $crate::Strong::new(Box::new(binder)) } diff --git a/libs/binder/rust/src/lib.rs b/libs/binder/rust/src/lib.rs index e70f4f0232..14493db262 100644 --- a/libs/binder/rust/src/lib.rs +++ b/libs/binder/rust/src/lib.rs @@ -100,10 +100,12 @@ mod error; mod native; mod parcel; mod proxy; -#[cfg(not(trusty))] +#[cfg(not(any(trusty, android_ndk)))] mod service; -#[cfg(not(trusty))] +#[cfg(not(any(trusty, android_ndk)))] mod state; +#[cfg(not(any(android_vendor, android_ndk, android_vndk)))] +mod system_only; use binder_ndk_sys as sys; @@ -112,14 +114,19 @@ pub use binder::{BinderFeatures, FromIBinder, IBinder, Interface, Strong, Weak}; pub use error::{ExceptionCode, IntoBinderResult, Status, StatusCode}; pub use parcel::{ParcelFileDescriptor, Parcelable, ParcelableHolder}; pub use proxy::{DeathRecipient, SpIBinder, WpIBinder}; -#[cfg(not(trusty))] +#[cfg(not(any(trusty, android_ndk)))] pub use service::{ add_service, check_interface, check_service, force_lazy_services_persist, - get_declared_instances, get_interface, get_service, is_declared, is_handling_transaction, - register_lazy_service, wait_for_interface, wait_for_service, LazyServiceGuard, + get_declared_instances, is_declared, is_handling_transaction, register_lazy_service, + wait_for_interface, wait_for_service, LazyServiceGuard, }; -#[cfg(not(trusty))] +#[cfg(not(any(trusty, android_ndk)))] +#[allow(deprecated)] +pub use service::{get_interface, get_service}; +#[cfg(not(any(trusty, android_ndk)))] pub use state::{ProcessState, ThreadState}; +#[cfg(not(any(android_vendor, android_vndk, android_ndk)))] +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,10 +135,12 @@ 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_ONEWAY, LAST_CALL_TRANSACTION, }; + #[cfg(not(android_ndk))] + pub use crate::binder::{FLAG_CLEAR_BUF, FLAG_PRIVATE_LOCAL}; pub use crate::binder_async::BinderAsyncRuntime; pub use crate::error::status_t; pub use crate::native::Binder; diff --git a/libs/binder/rust/src/native.rs b/libs/binder/rust/src/native.rs index c87cc94973..9e1cfd6b8f 100644 --- a/libs/binder/rust/src/native.rs +++ b/libs/binder/rust/src/native.rs @@ -14,9 +14,9 @@ * limitations under the License. */ -use crate::binder::{ - AsNative, Interface, InterfaceClassMethods, Remotable, Stability, TransactionCode, -}; +#[cfg(not(android_ndk))] +use crate::binder::Stability; +use crate::binder::{AsNative, Interface, InterfaceClassMethods, Remotable, TransactionCode}; use crate::error::{status_result, status_t, Result, StatusCode}; use crate::parcel::{BorrowedParcel, Serialize}; use crate::proxy::SpIBinder; @@ -76,14 +76,32 @@ impl<T: Remotable> Binder<T> { /// This moves the `rust_object` into an owned [`Box`] and Binder will /// manage its lifetime. pub fn new(rust_object: T) -> Binder<T> { - Self::new_with_stability(rust_object, Stability::default()) + #[cfg(not(android_ndk))] + { + Self::new_with_stability(rust_object, Stability::default()) + } + #[cfg(android_ndk)] + { + Self::new_unmarked(rust_object) + } } /// Create a new Binder remotable object with the given stability /// /// This moves the `rust_object` into an owned [`Box`] and Binder will /// manage its lifetime. + #[cfg(not(android_ndk))] pub fn new_with_stability(rust_object: T, stability: Stability) -> Binder<T> { + let mut binder = Self::new_unmarked(rust_object); + binder.mark_stability(stability); + binder + } + + /// Creates a new Binder remotable object with unset stability + /// + /// This is internal because normally we want to set the stability explicitly, + /// however for the NDK variant we cannot mark the stability. + fn new_unmarked(rust_object: T) -> Binder<T> { let class = T::get_class(); let rust_object = Box::into_raw(Box::new(rust_object)); // Safety: `AIBinder_new` expects a valid class pointer (which we @@ -93,9 +111,7 @@ impl<T: Remotable> Binder<T> { // decremented via `AIBinder_decStrong` when the reference lifetime // ends. let ibinder = unsafe { sys::AIBinder_new(class.into(), rust_object as *mut c_void) }; - let mut binder = Binder { ibinder, rust_object }; - binder.mark_stability(stability); - binder + Binder { ibinder, rust_object } } /// Set the extension of a binder interface. This allows a downstream @@ -189,6 +205,7 @@ impl<T: Remotable> Binder<T> { } /// Mark this binder object with the given stability guarantee + #[cfg(not(android_ndk))] fn mark_stability(&mut self, stability: Stability) { match stability { Stability::Local => self.mark_local_stability(), @@ -215,7 +232,7 @@ impl<T: Remotable> Binder<T> { /// Mark this binder object with local stability, which is vendor if we are /// building for android_vendor and system otherwise. - #[cfg(not(android_vendor))] + #[cfg(not(any(android_vendor, android_ndk)))] fn mark_local_stability(&mut self) { // Safety: Self always contains a valid `AIBinder` pointer, so we can // always call this C API safely. diff --git a/libs/binder/rust/src/parcel.rs b/libs/binder/rust/src/parcel.rs index 3bfc425ee3..485b0bdb0d 100644 --- a/libs/binder/rust/src/parcel.rs +++ b/libs/binder/rust/src/parcel.rs @@ -197,6 +197,7 @@ unsafe impl<'a> AsNative<sys::AParcel> for BorrowedParcel<'a> { // Data serialization methods impl<'a> BorrowedParcel<'a> { /// Data written to parcelable is zero'd before being deleted or reallocated. + #[cfg(not(android_ndk))] pub fn mark_sensitive(&mut self) { // Safety: guaranteed to have a parcel object, and this method never fails unsafe { sys::AParcel_markSensitive(self.as_native()) } @@ -342,6 +343,7 @@ impl<'a> WritableSubParcel<'a> { impl Parcel { /// Data written to parcelable is zero'd before being deleted or reallocated. + #[cfg(not(android_ndk))] pub fn mark_sensitive(&mut self) { self.borrowed().mark_sensitive() } 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/proxy.rs b/libs/binder/rust/src/proxy.rs index 04f1517556..593d12c1e9 100644 --- a/libs/binder/rust/src/proxy.rs +++ b/libs/binder/rust/src/proxy.rs @@ -298,7 +298,7 @@ impl<T: AsNative<sys::AIBinder>> IBinderInternal for T { unsafe { sys::AIBinder_isAlive(self.as_native()) } } - #[cfg(not(android_vndk))] + #[cfg(not(any(android_vndk, android_ndk)))] fn set_requesting_sid(&mut self, enable: bool) { // Safety: `SpIBinder` guarantees that `self` always contains a valid // pointer to an `AIBinder`. diff --git a/libs/binder/rust/src/service.rs b/libs/binder/rust/src/service.rs index 29dd8e1f58..f4fdcf51c0 100644 --- a/libs/binder/rust/src/service.rs +++ b/libs/binder/rust/src/service.rs @@ -176,6 +176,7 @@ pub fn wait_for_service(name: &str) -> Option<SpIBinder> { /// seconds if it doesn't yet exist. #[deprecated = "this polls 5s, use wait_for_interface or check_interface"] pub fn get_interface<T: FromIBinder + ?Sized>(name: &str) -> Result<Strong<T>> { + #[allow(deprecated)] interface_cast(get_service(name)) } diff --git a/libs/binder/rust/src/system_only.rs b/libs/binder/rust/src/system_only.rs new file mode 100644 index 0000000000..9833cbe4e2 --- /dev/null +++ b/libs/binder/rust/src/system_only.rs @@ -0,0 +1,220 @@ +/* + * 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, sockaddr_un, sockaddr_vm, socklen_t}; +use std::sync::Arc; +use std::{fmt, mem, 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(sockaddr_vm), + /// For unix domain socket connection + Unix(sockaddr_un), +} + +/// 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 *const sockaddr_vm as *const sockaddr, + mem::size_of::<sockaddr_vm>() as socklen_t, + ) + } + } + 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 *const sockaddr_un as *const sockaddr, + mem::size_of::<sockaddr_un>() as socklen_t, + ) + } + } + } + } + + /// 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..557f0e895d 100644 --- a/libs/binder/rust/sys/BinderBindings.hpp +++ b/libs/binder/rust/sys/BinderBindings.hpp @@ -15,14 +15,19 @@ */ #include <android/binder_ibinder.h> +#include <android/binder_parcel.h> +#include <android/binder_status.h> + +/* Platform only */ +#if defined(ANDROID_PLATFORM) || defined(__ANDROID_VENDOR__) #include <android/binder_ibinder_platform.h> #include <android/binder_manager.h> -#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> +#endif namespace android { @@ -80,8 +85,10 @@ enum { enum { FLAG_ONEWAY = FLAG_ONEWAY, +#if defined(ANDROID_PLATFORM) || defined(__ANDROID_VENDOR__) FLAG_CLEAR_BUF = FLAG_CLEAR_BUF, FLAG_PRIVATE_LOCAL = FLAG_PRIVATE_LOCAL, +#endif }; } // namespace consts diff --git a/libs/binder/rust/sys/Cargo.toml b/libs/binder/rust/sys/Cargo.toml new file mode 100644 index 0000000000..ad8e9c26f5 --- /dev/null +++ b/libs/binder/rust/sys/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "android-binder-ndk-sys" +version = "0.1.0" +edition = "2021" +description = "Bindgen bindings to android binder, restricted to the NDK" +license = "Apache-2.0" + +[dependencies] + +[lib] +path = "lib.rs" + +[build-dependencies] +bindgen = "0.70.1" diff --git a/libs/binder/rust/sys/build.rs b/libs/binder/rust/sys/build.rs new file mode 100644 index 0000000000..cb9c65ba51 --- /dev/null +++ b/libs/binder/rust/sys/build.rs @@ -0,0 +1,59 @@ +/* + * 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 std::env; +use std::path::PathBuf; + +fn main() { + let ndk_home = PathBuf::from(env::var("ANDROID_NDK_HOME").unwrap()); + let toolchain = ndk_home.join("toolchains/llvm/prebuilt/linux-x86_64/"); + let sysroot = toolchain.join("sysroot"); + let bindings = bindgen::Builder::default() + .clang_arg(format!("--sysroot={}", sysroot.display())) + // TODO figure out what the "standard" #define is and use that instead + .header("BinderBindings.hpp") + .parse_callbacks(Box::new(bindgen::CargoCallbacks::new())) + // Keep in sync with libbinder_ndk_bindgen_flags.txt + .default_enum_style(bindgen::EnumVariation::Rust { non_exhaustive: true }) + .constified_enum("android::c_interface::consts::.*") + .allowlist_type("android::c_interface::.*") + .allowlist_type("AStatus") + .allowlist_type("AIBinder_Class") + .allowlist_type("AIBinder") + .allowlist_type("AIBinder_Weak") + .allowlist_type("AIBinder_DeathRecipient") + .allowlist_type("AParcel") + .allowlist_type("binder_status_t") + .blocklist_function("vprintf") + .blocklist_function("strtold") + .blocklist_function("_vtlog") + .blocklist_function("vscanf") + .blocklist_function("vfprintf_worker") + .blocklist_function("vsprintf") + .blocklist_function("vsnprintf") + .blocklist_function("vsnprintf_filtered") + .blocklist_function("vfscanf") + .blocklist_function("vsscanf") + .blocklist_function("vdprintf") + .blocklist_function("vasprintf") + .blocklist_function("strtold_l") + .allowlist_function(".*") + .generate() + .expect("Couldn't generate bindings"); + let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); + bindings.write_to_file(out_path.join("bindings.rs")).expect("Couldn't write bindings."); + println!("cargo::rustc-link-lib=binder_ndk"); +} diff --git a/libs/binder/rust/sys/lib.rs b/libs/binder/rust/sys/lib.rs index 5352473272..349e5a9cc8 100644 --- a/libs/binder/rust/sys/lib.rs +++ b/libs/binder/rust/sys/lib.rs @@ -20,6 +20,7 @@ use std::error::Error; use std::fmt; #[cfg(not(target_os = "trusty"))] +#[allow(bad_style)] mod bindings { include!(concat!(env!("OUT_DIR"), "/bindings.rs")); } 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..28a3f654b8 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 { @@ -728,6 +731,9 @@ cc_test { "liblog", "libutils", ], + static_libs: [ + "libgmock", + ], test_suites: [ "general-tests", "vts", diff --git a/libs/binder/tests/binderCacheUnitTest.cpp b/libs/binder/tests/binderCacheUnitTest.cpp index 482d197688..c5ad79391c 100644 --- a/libs/binder/tests/binderCacheUnitTest.cpp +++ b/libs/binder/tests/binderCacheUnitTest.cpp @@ -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/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp index bcab6decca..ec2f50ca16 100644 --- a/libs/binder/tests/binderLibTest.cpp +++ b/libs/binder/tests/binderLibTest.cpp @@ -2261,7 +2261,7 @@ public: if (ret != NO_ERROR) { return ret; } - auto event = frozenStateChangeCallback->events.popWithTimeout(10ms); + auto event = frozenStateChangeCallback->events.popWithTimeout(1000ms); if (!event.has_value()) { return NOT_ENOUGH_DATA; } diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp index 0ef200bcbe..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)); @@ -1204,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()); @@ -1251,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); @@ -1261,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"); @@ -1271,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()); @@ -1287,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 @@ -1552,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/binderSafeInterfaceTest.cpp b/libs/binder/tests/binderSafeInterfaceTest.cpp index 0aa678dd65..849dc7c4d5 100644 --- a/libs/binder/tests/binderSafeInterfaceTest.cpp +++ b/libs/binder/tests/binderSafeInterfaceTest.cpp @@ -40,6 +40,8 @@ #include <sys/eventfd.h> #include <sys/prctl.h> +#include <gmock/gmock.h> + using namespace std::chrono_literals; // NOLINT - google-build-using-namespace using android::binder::unique_fd; @@ -222,6 +224,7 @@ public: SetDeathToken = IBinder::FIRST_CALL_TRANSACTION, ReturnsNoMemory, LogicalNot, + LogicalNotVector, ModifyEnum, IncrementFlattenable, IncrementLightFlattenable, @@ -249,6 +252,7 @@ public: // These are ordered according to their corresponding methods in SafeInterface::ParcelHandler virtual status_t logicalNot(bool a, bool* notA) const = 0; + virtual status_t logicalNot(const std::vector<bool>& a, std::vector<bool>* notA) const = 0; virtual status_t modifyEnum(TestEnum a, TestEnum* b) const = 0; virtual status_t increment(const TestFlattenable& a, TestFlattenable* aPlusOne) const = 0; virtual status_t increment(const TestLightFlattenable& a, @@ -288,7 +292,14 @@ public: } status_t logicalNot(bool a, bool* notA) const override { ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__); - return callRemote<decltype(&ISafeInterfaceTest::logicalNot)>(Tag::LogicalNot, a, notA); + using Signature = status_t (ISafeInterfaceTest::*)(bool, bool*) const; + return callRemote<Signature>(Tag::LogicalNot, a, notA); + } + status_t logicalNot(const std::vector<bool>& a, std::vector<bool>* notA) const override { + ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__); + using Signature = status_t (ISafeInterfaceTest::*)(const std::vector<bool>&, + std::vector<bool>*) const; + return callRemote<Signature>(Tag::LogicalNotVector, a, notA); } status_t modifyEnum(TestEnum a, TestEnum* b) const override { ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__); @@ -406,6 +417,14 @@ public: *notA = !a; return NO_ERROR; } + status_t logicalNot(const std::vector<bool>& a, std::vector<bool>* notA) const override { + ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__); + notA->clear(); + for (bool value : a) { + notA->push_back(!value); + } + return NO_ERROR; + } status_t modifyEnum(TestEnum a, TestEnum* b) const override { ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__); *b = (a == TestEnum::INITIAL) ? TestEnum::FINAL : TestEnum::INVALID; @@ -513,7 +532,13 @@ public: return callLocal(data, reply, &ISafeInterfaceTest::returnsNoMemory); } case ISafeInterfaceTest::Tag::LogicalNot: { - return callLocal(data, reply, &ISafeInterfaceTest::logicalNot); + using Signature = status_t (ISafeInterfaceTest::*)(bool a, bool* notA) const; + return callLocal<Signature>(data, reply, &ISafeInterfaceTest::logicalNot); + } + case ISafeInterfaceTest::Tag::LogicalNotVector: { + using Signature = status_t (ISafeInterfaceTest::*)(const std::vector<bool>& a, + std::vector<bool>* notA) const; + return callLocal<Signature>(data, reply, &ISafeInterfaceTest::logicalNot); } case ISafeInterfaceTest::Tag::ModifyEnum: { return callLocal(data, reply, &ISafeInterfaceTest::modifyEnum); @@ -639,6 +664,15 @@ TEST_F(SafeInterfaceTest, TestLogicalNot) { ASSERT_EQ(!b, notB); } +TEST_F(SafeInterfaceTest, TestLogicalNotVector) { + const std::vector<bool> a = {true, false, true}; + std::vector<bool> notA; + status_t result = mSafeInterfaceTest->logicalNot(a, ¬A); + ASSERT_EQ(NO_ERROR, result); + std::vector<bool> expected = {false, true, false}; + ASSERT_THAT(notA, testing::ContainerEq(expected)); +} + TEST_F(SafeInterfaceTest, TestModifyEnum) { const TestEnum a = TestEnum::INITIAL; TestEnum b = TestEnum::INVALID; diff --git a/libs/binder/tests/binderUtilsHostTest.cpp b/libs/binder/tests/binderUtilsHostTest.cpp index 6301c74842..a62ad96be1 100644 --- a/libs/binder/tests/binderUtilsHostTest.cpp +++ b/libs/binder/tests/binderUtilsHostTest.cpp @@ -56,7 +56,7 @@ TEST(UtilsHost, ExecuteLongRunning) { }); auto elapsedMs = millisSince(start); EXPECT_GE(elapsedMs, 1000); - EXPECT_LT(elapsedMs, 2000); + EXPECT_LT(elapsedMs, 3000); // b/377571547: higher to reduce flake ASSERT_TRUE(result.has_value()); EXPECT_EQ(std::nullopt, result->exitCode); @@ -65,7 +65,7 @@ TEST(UtilsHost, ExecuteLongRunning) { // ~CommandResult() called, child process is killed. // Assert that the second sleep does not finish. - EXPECT_LT(millisSince(start), 2000); + EXPECT_LT(millisSince(start), 3000); } TEST(UtilsHost, ExecuteLongRunning2) { 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 deleted file mode 100644 index 3ae3d8f577..0000000000 --- a/libs/binder/trusty/ndk/include/android/llndk-versioning.h +++ /dev/null @@ -1,18 +0,0 @@ -/* - * 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 - -#define __INTRODUCED_IN_LLNDK(x) /* nothing on Trusty */ 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/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/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp index da74e9cde6..831b2ee4be 100644 --- a/libs/gui/BufferQueueProducer.cpp +++ b/libs/gui/BufferQueueProducer.cpp @@ -1508,7 +1508,6 @@ void BufferQueueProducer::allocateBuffers(uint32_t width, uint32_t height, const bool useDefaultSize = !width && !height; while (true) { - size_t newBufferCount = 0; uint32_t allocWidth = 0; uint32_t allocHeight = 0; PixelFormat allocFormat = PIXEL_FORMAT_UNKNOWN; @@ -1530,8 +1529,9 @@ void BufferQueueProducer::allocateBuffers(uint32_t width, uint32_t height, // Only allocate one buffer at a time to reduce risks of overlapping an allocation from // both allocateBuffers and dequeueBuffer. - newBufferCount = mCore->mFreeSlots.empty() ? 0 : 1; - if (newBufferCount == 0) { + if (mCore->mFreeSlots.empty()) { + BQ_LOGV("allocateBuffers: a slot was occupied while " + "allocating. Dropping allocated buffer."); return; } @@ -1573,27 +1573,23 @@ void BufferQueueProducer::allocateBuffers(uint32_t width, uint32_t height, }; #endif - Vector<sp<GraphicBuffer>> buffers; - for (size_t i = 0; i < newBufferCount; ++i) { #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_EXTENDEDALLOCATE) - sp<GraphicBuffer> graphicBuffer = new GraphicBuffer(allocRequest); + sp<GraphicBuffer> graphicBuffer = new GraphicBuffer(allocRequest); #else - sp<GraphicBuffer> graphicBuffer = new GraphicBuffer( - allocWidth, allocHeight, allocFormat, BQ_LAYER_COUNT, - allocUsage, allocName); + sp<GraphicBuffer> graphicBuffer = new GraphicBuffer( + allocWidth, allocHeight, allocFormat, BQ_LAYER_COUNT, + allocUsage, allocName); #endif - status_t result = graphicBuffer->initCheck(); + status_t result = graphicBuffer->initCheck(); - if (result != NO_ERROR) { - BQ_LOGE("allocateBuffers: failed to allocate buffer (%u x %u, format" - " %u, usage %#" PRIx64 ")", width, height, format, usage); - std::lock_guard<std::mutex> lock(mCore->mMutex); - mCore->mIsAllocating = false; - mCore->mIsAllocatingCondition.notify_all(); - return; - } - buffers.push_back(graphicBuffer); + if (result != NO_ERROR) { + BQ_LOGE("allocateBuffers: failed to allocate buffer (%u x %u, format" + " %u, usage %#" PRIx64 ")", width, height, format, usage); + std::lock_guard<std::mutex> lock(mCore->mMutex); + mCore->mIsAllocating = false; + mCore->mIsAllocatingCondition.notify_all(); + return; } { // Autolock scope @@ -1621,15 +1617,13 @@ void BufferQueueProducer::allocateBuffers(uint32_t width, uint32_t height, continue; } - for (size_t i = 0; i < newBufferCount; ++i) { - if (mCore->mFreeSlots.empty()) { - BQ_LOGV("allocateBuffers: a slot was occupied while " - "allocating. Dropping allocated buffer."); - continue; - } + if (mCore->mFreeSlots.empty()) { + BQ_LOGV("allocateBuffers: a slot was occupied while " + "allocating. Dropping allocated buffer."); + } else { auto slot = mCore->mFreeSlots.begin(); mCore->clearBufferSlotLocked(*slot); // Clean up the slot first - mSlots[*slot].mGraphicBuffer = buffers[i]; + mSlots[*slot].mGraphicBuffer = graphicBuffer; mSlots[*slot].mFence = Fence::NO_FENCE; #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_EXTENDEDALLOCATE) mSlots[*slot].mAdditionalOptionsGenerationId = allocOptionsGenId; diff --git a/libs/gui/include/gui/IGraphicBufferProducer.h b/libs/gui/include/gui/IGraphicBufferProducer.h index 3aac457a09..197e792367 100644 --- a/libs/gui/include/gui/IGraphicBufferProducer.h +++ b/libs/gui/include/gui/IGraphicBufferProducer.h @@ -403,7 +403,7 @@ public: uint64_t nextFrameNumber{0}; FrameEventHistoryDelta frameTimestamps; bool bufferReplaced{false}; - int maxBufferCount{0}; + int maxBufferCount{BufferQueueDefs::NUM_BUFFER_SLOTS}; status_t result{NO_ERROR}; }; diff --git a/libs/gui/tests/BufferItemConsumer_test.cpp b/libs/gui/tests/BufferItemConsumer_test.cpp index 845a1caf21..3b6a66efe9 100644 --- a/libs/gui/tests/BufferItemConsumer_test.cpp +++ b/libs/gui/tests/BufferItemConsumer_test.cpp @@ -30,6 +30,7 @@ static constexpr int kWidth = 100; static constexpr int kHeight = 100; static constexpr int kMaxLockedBuffers = 3; static constexpr int kFormat = HAL_PIXEL_FORMAT_RGBA_8888; +static constexpr int kUsage = GRALLOC_USAGE_SW_READ_RARELY; static constexpr int kFrameSleepUs = 30 * 1000; class BufferItemConsumerTest : public ::testing::Test { @@ -56,7 +57,7 @@ class BufferItemConsumerTest : public ::testing::Test { }; void SetUp() override { - mBIC = new BufferItemConsumer(kFormat, kMaxLockedBuffers, true); + mBIC = new BufferItemConsumer(kUsage, kMaxLockedBuffers, true); String8 name("BufferItemConsumer_Under_Test"); mBIC->setName(name); mBFL = new BufferFreedListener(this); diff --git a/libs/nativewindow/include/android/hardware_buffer.h b/libs/nativewindow/include/android/hardware_buffer.h index d05ff3457a..5a78a5c82c 100644 --- a/libs/nativewindow/include/android/hardware_buffer.h +++ b/libs/nativewindow/include/android/hardware_buffer.h @@ -175,6 +175,14 @@ enum AHardwareBuffer_Format { AHARDWAREBUFFER_FORMAT_YCbCr_P010 = 0x36, /** + * YUV P210 format. + * Must have an even width and height. Can be accessed in OpenGL + * shaders through an external sampler. Does not support mip-maps + * cube-maps or multi-layered textures. + */ + AHARDWAREBUFFER_FORMAT_YCbCr_P210 = 0x3c, + + /** * Corresponding formats: * Vulkan: VK_FORMAT_R8_UNORM * OpenGL ES: GR_GL_R8 diff --git a/libs/nativewindow/include/android/native_window.h b/libs/nativewindow/include/android/native_window.h index be6623ee75..6f816bf614 100644 --- a/libs/nativewindow/include/android/native_window.h +++ b/libs/nativewindow/include/android/native_window.h @@ -366,14 +366,13 @@ int32_t ANativeWindow_setFrameRateWithChangeStrategy(ANativeWindow* window, floa * * See ANativeWindow_setFrameRateWithChangeStrategy(). * - * Available since API level 34. + * Available since API level 31. * * \param window pointer to an ANativeWindow object. * * \return 0 for success, -EINVAL if the window value is invalid. */ -inline int32_t ANativeWindow_clearFrameRate(ANativeWindow* window) - __INTRODUCED_IN(__ANDROID_API_U__) { +inline int32_t ANativeWindow_clearFrameRate(ANativeWindow* window) __INTRODUCED_IN(31) { return ANativeWindow_setFrameRateWithChangeStrategy(window, 0, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS); diff --git a/libs/nativewindow/rust/Android.bp b/libs/nativewindow/rust/Android.bp index d68d6ba1af..faab48b1ce 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", @@ -109,7 +110,9 @@ rust_defaults { name: "libnativewindow_defaults", srcs: ["src/lib.rs"], rustlibs: [ + "android.hardware.common-V2-rust", "libbinder_rs", + "libbitflags", "libnativewindow_bindgen", ], } diff --git a/libs/nativewindow/rust/src/handle.rs b/libs/nativewindow/rust/src/handle.rs index c41ab8d1b8..2b08c1bcb9 100644 --- a/libs/nativewindow/rust/src/handle.rs +++ b/libs/nativewindow/rust/src/handle.rs @@ -12,6 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +use android_hardware_common::{ + aidl::android::hardware::common::NativeHandle::NativeHandle as AidlNativeHandle, + binder::ParcelFileDescriptor, +}; use std::{ ffi::c_int, mem::forget, @@ -81,6 +85,12 @@ impl NativeHandle { /// Destroys the `NativeHandle`, taking ownership of the file descriptors it contained. pub fn into_fds(self) -> Vec<OwnedFd> { + // Unset FDSan tag since this `native_handle_t` is no longer the owner of the file + // descriptors after this function. + // SAFETY: Our wrapped `native_handle_t` pointer is always valid. + unsafe { + ffi::native_handle_unset_fdsan_tag(self.as_ref()); + } let fds = self.data()[..self.fd_count()] .iter() .map(|fd| { @@ -190,6 +200,21 @@ impl Drop for NativeHandle { } } +impl From<AidlNativeHandle> for NativeHandle { + fn from(aidl_native_handle: AidlNativeHandle) -> Self { + let fds = aidl_native_handle.fds.into_iter().map(OwnedFd::from).collect(); + Self::new(fds, &aidl_native_handle.ints).unwrap() + } +} + +impl From<NativeHandle> for AidlNativeHandle { + fn from(native_handle: NativeHandle) -> Self { + let ints = native_handle.ints().to_owned(); + let fds = native_handle.into_fds().into_iter().map(ParcelFileDescriptor::new).collect(); + Self { ints, fds } + } +} + // SAFETY: `NativeHandle` owns the `native_handle_t`, which just contains some integers and file // descriptors, which aren't tied to any particular thread. unsafe impl Send for NativeHandle {} @@ -240,4 +265,43 @@ mod test { drop(cloned); } + + #[test] + fn to_fds() { + 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 fds = original.into_fds(); + assert_eq!(fds.len(), 1); + } + + #[test] + fn to_aidl() { + 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 aidl = AidlNativeHandle::from(original); + assert_eq!(&aidl.ints, &[42]); + assert_eq!(aidl.fds.len(), 1); + } + + #[test] + fn to_from_aidl() { + 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 aidl = AidlNativeHandle::from(original); + assert_eq!(&aidl.ints, &[42]); + assert_eq!(aidl.fds.len(), 1); + + let converted_back = NativeHandle::from(aidl); + assert_eq!(converted_back.ints(), &[42]); + assert_eq!(converted_back.fds().len(), 1); + } } diff --git a/libs/nativewindow/rust/src/lib.rs b/libs/nativewindow/rust/src/lib.rs index 931c311e65..014c912a67 100644 --- a/libs/nativewindow/rust/src/lib.rs +++ b/libs/nativewindow/rust/src/lib.rs @@ -19,10 +19,9 @@ extern crate nativewindow_bindgen as ffi; mod handle; mod surface; -pub use handle::NativeHandle; -pub use surface::Surface; - pub use ffi::{AHardwareBuffer_Format, AHardwareBuffer_UsageFlags}; +pub use handle::NativeHandle; +pub use surface::{buffer::Buffer, Surface}; use binder::{ binder_impl::{BorrowedParcel, UnstructuredParcelable}, @@ -204,8 +203,8 @@ impl HardwareBuffer { Self(buffer_ptr) } - /// Creates a new Rust HardwareBuffer to wrap the given AHardwareBuffer without taking ownership - /// of it. + /// Creates a new Rust HardwareBuffer to wrap the given `AHardwareBuffer` without taking + /// ownership of it. /// /// Unlike [`from_raw`](Self::from_raw) this method will increment the refcount on the buffer. /// This means that the caller can continue to use the raw buffer it passed in, and must call @@ -221,8 +220,20 @@ impl HardwareBuffer { Self(buffer) } - /// Get the internal |AHardwareBuffer| pointer without decrementing the refcount. This can - /// be used to provide a pointer to the AHB for a C/C++ API over the FFI. + /// Returns the internal `AHardwareBuffer` pointer. + /// + /// This is only valid as long as this `HardwareBuffer` exists, so shouldn't be stored. It can + /// be used to provide a pointer for a C/C++ API over FFI. + pub fn as_raw(&self) -> NonNull<AHardwareBuffer> { + self.0 + } + + /// Gets the internal `AHardwareBuffer` pointer without decrementing the refcount. This can + /// be used for a C/C++ API which takes ownership of the pointer. + /// + /// The caller is responsible for releasing the `AHardwareBuffer` pointer by calling + /// `AHardwareBuffer_release` when it is finished with it, or may convert it back to a Rust + /// `HardwareBuffer` by calling [`HardwareBuffer::from_raw`]. pub fn into_raw(self) -> NonNull<AHardwareBuffer> { let buffer = ManuallyDrop::new(self); buffer.0 diff --git a/libs/nativewindow/rust/src/surface.rs b/libs/nativewindow/rust/src/surface.rs index 25fea807b5..ed52471aa1 100644 --- a/libs/nativewindow/rust/src/surface.rs +++ b/libs/nativewindow/rust/src/surface.rs @@ -14,20 +14,27 @@ //! Rust wrapper for `ANativeWindow` and related types. +pub(crate) mod buffer; + use binder::{ binder_impl::{BorrowedParcel, UnstructuredParcelable}, impl_deserialize_for_unstructured_parcelable, impl_serialize_for_unstructured_parcelable, unstable_api::{status_result, AsNative}, StatusCode, }; +use bitflags::bitflags; +use buffer::Buffer; 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_lock, + ANativeWindow_readFromParcel, ANativeWindow_release, ANativeWindow_setBuffersDataSpace, + ANativeWindow_setBuffersGeometry, ANativeWindow_setBuffersTransform, + ANativeWindow_unlockAndPost, ANativeWindow_writeToParcel, ARect, }; use std::error::Error; use std::fmt::{self, Debug, Display, Formatter}; -use std::ptr::{null_mut, NonNull}; +use std::ptr::{self, null_mut, NonNull}; /// Wrapper around an opaque C `ANativeWindow`. #[derive(PartialEq, Eq)] @@ -60,6 +67,132 @@ 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)) + } + } + + /// Locks the window's next drawing surface for writing, and returns it. + pub fn lock(&mut self, bounds: Option<&mut ARect>) -> Result<Buffer, ErrorCode> { + let mut buffer = buffer::EMPTY; + // 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. The other pointers must be valid because the come from + // references, and aren't retained after the function returns. + let status = unsafe { + ANativeWindow_lock( + self.0.as_ptr(), + &mut buffer, + bounds.map(ptr::from_mut).unwrap_or(null_mut()), + ) + }; + if status != 0 { + return Err(ErrorCode(status)); + } + + Ok(Buffer::new(buffer, self)) + } + + /// Unlocks the window's drawing surface which was previously locked, posting the new buffer to + /// the display. + /// + /// This shouldn't be called directly but via the [`Buffer`], hence is not public here. + fn unlock_and_post(&mut self) -> 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_unlockAndPost(self.0.as_ptr()) }; + if status == 0 { + Ok(()) + } else { + Err(ErrorCode(status)) + } + } } impl Drop for Surface { @@ -141,3 +274,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/nativewindow/rust/src/surface/buffer.rs b/libs/nativewindow/rust/src/surface/buffer.rs new file mode 100644 index 0000000000..a2d74d4ed6 --- /dev/null +++ b/libs/nativewindow/rust/src/surface/buffer.rs @@ -0,0 +1,68 @@ +// 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 super::{ErrorCode, Surface}; +use nativewindow_bindgen::{AHardwareBuffer_Format, ANativeWindow_Buffer}; +use std::ptr::null_mut; + +/// An empty `ANativeWindow_Buffer`. +pub const EMPTY: ANativeWindow_Buffer = ANativeWindow_Buffer { + width: 0, + height: 0, + stride: 0, + format: 0, + bits: null_mut(), + reserved: [0; 6], +}; + +/// Rust wrapper for `ANativeWindow_Buffer`, representing a locked buffer from a [`Surface`]. +pub struct Buffer<'a> { + /// The wrapped `ANativeWindow_Buffer`. + pub buffer: ANativeWindow_Buffer, + surface: &'a mut Surface, +} + +impl<'a> Buffer<'a> { + pub(crate) fn new(buffer: ANativeWindow_Buffer, surface: &'a mut Surface) -> Self { + Self { buffer, surface } + } + + /// Unlocks the window's drawing surface which was previously locked to create this buffer, + /// posting the buffer to the display. + pub fn unlock_and_post(self) -> Result<(), ErrorCode> { + self.surface.unlock_and_post() + } + + /// The number of pixels that are shown horizontally. + pub fn width(&self) -> i32 { + self.buffer.width + } + + /// The number of pixels that are shown vertically. + pub fn height(&self) -> i32 { + self.buffer.height + } + + /// The number of pixels that a line in the buffer takes in memory. + /// + /// This may be greater than the width. + pub fn stride(&self) -> i32 { + self.buffer.stride + } + + /// The pixel format of the buffer. + pub fn format(&self) -> Result<AHardwareBuffer_Format::Type, ErrorCode> { + self.buffer.format.try_into().map_err(|_| ErrorCode(self.buffer.format)) + } +} 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/Gralloc5.cpp b/libs/ui/Gralloc5.cpp index c9ec036186..2143f79f11 100644 --- a/libs/ui/Gralloc5.cpp +++ b/libs/ui/Gralloc5.cpp @@ -23,7 +23,6 @@ #include <aidlcommonsupport/NativeHandle.h> #include <android/binder_manager.h> #include <android/hardware/graphics/mapper/utils/IMapperMetadataTypes.h> -#include <android/llndk-versioning.h> #include <binder/IPCThreadState.h> #include <dlfcn.h> #include <ui/FatVector.h> @@ -91,7 +90,7 @@ static void *loadIMapperLibrary() { } void* so = nullptr; - if API_LEVEL_AT_LEAST (__ANDROID_API_V__, 202404) { + if (__builtin_available(android __ANDROID_API_V__, *)) { so = AServiceManager_openDeclaredPassthroughHal("mapper", mapperSuffix.c_str(), RTLD_LOCAL | RTLD_NOW); } else { 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/Android.bp b/opengl/libs/Android.bp index 5159ffe86b..b19a862b6c 100644 --- a/opengl/libs/Android.bp +++ b/opengl/libs/Android.bp @@ -135,6 +135,9 @@ cc_library_static { "EGL/MultifileBlobCache.cpp", ], export_include_dirs: ["EGL"], + shared_libs: [ + "libz", + ], } cc_library_shared { @@ -169,6 +172,7 @@ cc_library_shared { "libutils", "libSurfaceFlingerProp", "libunwindstack", + "libz", ], static_libs: [ "libEGL_getProcAddress", @@ -199,6 +203,7 @@ cc_test { ], shared_libs: [ "libutils", + "libz", ], } diff --git a/opengl/libs/EGL/FileBlobCache.cpp b/opengl/libs/EGL/FileBlobCache.cpp index 4a0fac4ce5..573ca5411a 100644 --- a/opengl/libs/EGL/FileBlobCache.cpp +++ b/opengl/libs/EGL/FileBlobCache.cpp @@ -27,6 +27,7 @@ #include <log/log.h> #include <utils/Trace.h> +#include <zlib.h> // Cache file header static const char* cacheFileMagic = "EGL$"; @@ -34,20 +35,10 @@ static const size_t cacheFileHeaderSize = 8; namespace android { -uint32_t crc32c(const uint8_t* buf, size_t len) { - const uint32_t polyBits = 0x82F63B78; - uint32_t r = 0; - for (size_t i = 0; i < len; i++) { - r ^= buf[i]; - for (int j = 0; j < 8; j++) { - if (r & 1) { - r = (r >> 1) ^ polyBits; - } else { - r >>= 1; - } - } - } - return r; +uint32_t GenerateCRC32(const uint8_t *data, size_t size) +{ + const unsigned long initialValue = crc32_z(0u, nullptr, 0u); + return static_cast<uint32_t>(crc32_z(initialValue, data, size)); } FileBlobCache::FileBlobCache(size_t maxKeySize, size_t maxValueSize, size_t maxTotalSize, @@ -101,7 +92,7 @@ FileBlobCache::FileBlobCache(size_t maxKeySize, size_t maxValueSize, size_t maxT return; } uint32_t* crc = reinterpret_cast<uint32_t*>(buf + 4); - if (crc32c(buf + headerSize, cacheSize) != *crc) { + if (GenerateCRC32(buf + headerSize, cacheSize) != *crc) { ALOGE("cache file failed CRC check"); close(fd); return; @@ -175,7 +166,7 @@ void FileBlobCache::writeToFile() { // Write the file magic and CRC memcpy(buf, cacheFileMagic, 4); uint32_t* crc = reinterpret_cast<uint32_t*>(buf + 4); - *crc = crc32c(buf + headerSize, cacheSize); + *crc = GenerateCRC32(buf + headerSize, cacheSize); if (write(fd, buf, fileSize) == -1) { ALOGE("error writing cache file: %s (%d)", strerror(errno), diff --git a/opengl/libs/EGL/FileBlobCache.h b/opengl/libs/EGL/FileBlobCache.h index f083b0d6ca..224444da65 100644 --- a/opengl/libs/EGL/FileBlobCache.h +++ b/opengl/libs/EGL/FileBlobCache.h @@ -22,7 +22,7 @@ namespace android { -uint32_t crc32c(const uint8_t* buf, size_t len); +uint32_t GenerateCRC32(const uint8_t *data, size_t size); class FileBlobCache : public BlobCache { public: diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp index bf0e38e986..fed6afc8e0 100644 --- a/opengl/libs/EGL/Loader.cpp +++ b/opengl/libs/EGL/Loader.cpp @@ -548,6 +548,10 @@ static void* load_angle(const char* kind, android_namespace_t* ns) { .flags = ANDROID_DLEXT_USE_NAMESPACE, .library_namespace = ns, }; + auto prop = base::GetProperty("debug.angle.libs.suffix", ""); + if (!prop.empty()) { + name = std::string("lib") + kind + "_" + prop + ".so"; + } so = do_android_dlopen_ext(name.c_str(), RTLD_LOCAL | RTLD_NOW, &dlextinfo); } diff --git a/opengl/libs/EGL/MultifileBlobCache.cpp b/opengl/libs/EGL/MultifileBlobCache.cpp index 9905210014..f7e33b383f 100644 --- a/opengl/libs/EGL/MultifileBlobCache.cpp +++ b/opengl/libs/EGL/MultifileBlobCache.cpp @@ -214,9 +214,8 @@ MultifileBlobCache::MultifileBlobCache(size_t maxKeySize, size_t maxValueSize, s } // Ensure we have a good CRC - if (header.crc != - crc32c(mappedEntry + sizeof(MultifileHeader), - fileSize - sizeof(MultifileHeader))) { + if (header.crc != GenerateCRC32(mappedEntry + sizeof(MultifileHeader), + fileSize - sizeof(MultifileHeader))) { ALOGV("INIT: Entry %u failed CRC check! Removing.", entryHash); if (remove(fullPath.c_str()) != 0) { ALOGE("Error removing %s: %s", fullPath.c_str(), std::strerror(errno)); @@ -532,9 +531,9 @@ bool MultifileBlobCache::createStatus(const std::string& baseDir) { mBuildId.length() > PROP_VALUE_MAX ? PROP_VALUE_MAX : mBuildId.length()); // Finally update the crc, using cacheVersion and everything the follows - status.crc = - crc32c(reinterpret_cast<uint8_t*>(&status) + offsetof(MultifileStatus, cacheVersion), - sizeof(status) - offsetof(MultifileStatus, cacheVersion)); + status.crc = GenerateCRC32( + reinterpret_cast<uint8_t *>(&status) + offsetof(MultifileStatus, cacheVersion), + sizeof(status) - offsetof(MultifileStatus, cacheVersion)); // Create the status file std::string cacheStatus = baseDir + "/" + kMultifileBlobCacheStatusFile; @@ -599,9 +598,9 @@ bool MultifileBlobCache::checkStatus(const std::string& baseDir) { } // Ensure we have a good CRC - if (status.crc != - crc32c(reinterpret_cast<uint8_t*>(&status) + offsetof(MultifileStatus, cacheVersion), - sizeof(status) - offsetof(MultifileStatus, cacheVersion))) { + if (status.crc != GenerateCRC32(reinterpret_cast<uint8_t *>(&status) + + offsetof(MultifileStatus, cacheVersion), + sizeof(status) - offsetof(MultifileStatus, cacheVersion))) { ALOGE("STATUS(CHECK): Cache status failed CRC check!"); return false; } @@ -840,8 +839,8 @@ void MultifileBlobCache::processTask(DeferredTask& task) { // Add CRC check to the header (always do this last!) MultifileHeader* header = reinterpret_cast<MultifileHeader*>(buffer); - header->crc = - crc32c(buffer + sizeof(MultifileHeader), bufferSize - sizeof(MultifileHeader)); + header->crc = GenerateCRC32(buffer + sizeof(MultifileHeader), + bufferSize - sizeof(MultifileHeader)); ssize_t result = write(fd, buffer, bufferSize); if (result != bufferSize) { diff --git a/opengl/libs/EGL/MultifileBlobCache.h b/opengl/libs/EGL/MultifileBlobCache.h index 18566c2892..65aa2db344 100644 --- a/opengl/libs/EGL/MultifileBlobCache.h +++ b/opengl/libs/EGL/MultifileBlobCache.h @@ -34,7 +34,7 @@ namespace android { -constexpr uint32_t kMultifileBlobCacheVersion = 1; +constexpr uint32_t kMultifileBlobCacheVersion = 2; constexpr char kMultifileBlobCacheStatusFile[] = "cache.status"; struct MultifileHeader { diff --git a/opengl/libs/EGL/egl_platform_entries.cpp b/opengl/libs/EGL/egl_platform_entries.cpp index 6e35041662..6713a5c69d 100644 --- a/opengl/libs/EGL/egl_platform_entries.cpp +++ b/opengl/libs/EGL/egl_platform_entries.cpp @@ -2141,6 +2141,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; @@ -2405,7 +2409,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/opengl/libs/EGL/fuzzer/Android.bp b/opengl/libs/EGL/fuzzer/Android.bp index 022a2a3f06..4947e5ff6c 100644 --- a/opengl/libs/EGL/fuzzer/Android.bp +++ b/opengl/libs/EGL/fuzzer/Android.bp @@ -36,6 +36,10 @@ cc_fuzz { "libutils", ], + shared_libs: [ + "libz", + ], + srcs: [ "MultifileBlobCache_fuzzer.cpp", ], diff --git a/services/gpuservice/vts/Android.bp b/services/gpuservice/vts/Android.bp index a24822a7d1..6e0a9f7ace 100644 --- a/services/gpuservice/vts/Android.bp +++ b/services/gpuservice/vts/Android.bp @@ -13,6 +13,7 @@ // limitations under the License. package { + default_team: "trendy_team_android_gpu", default_applicable_licenses: ["frameworks_native_license"], } 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 05139cf09d..5db21fdfa5 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -2868,7 +2868,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; } @@ -5787,7 +5788,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/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index c5702e92d9..7b5c47b1ac 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -12927,6 +12927,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/stats/Android.bp b/services/stats/Android.bp index 6b99627f5a..f698515545 100644 --- a/services/stats/Android.bp +++ b/services/stats/Android.bp @@ -7,6 +7,11 @@ package { default_applicable_licenses: ["frameworks_native_license"], } +vintf_fragment { + name: "android.frameworks.stats-service.xml", + src: "android.frameworks.stats-service.xml", +} + cc_library_shared { name: "libstatshidl", srcs: [ @@ -38,7 +43,7 @@ cc_library_shared { local_include_dirs: [ "include/stats", ], - vintf_fragments: [ + vintf_fragment_modules: [ "android.frameworks.stats-service.xml", ], } diff --git a/services/surfaceflinger/CompositionEngine/Android.bp b/services/surfaceflinger/CompositionEngine/Android.bp index b4ac9ba741..141a228b13 100644 --- a/services/surfaceflinger/CompositionEngine/Android.bp +++ b/services/surfaceflinger/CompositionEngine/Android.bp @@ -49,9 +49,7 @@ cc_defaults { "libaidlcommonsupport", "libprocessgroup", "libprocessgroup_util", - "libcgrouprc", "libjsoncpp", - "libcgrouprc_format", ], header_libs: [ "android.hardware.graphics.composer@2.1-command-buffer", 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/tests/unittests/RefreshRateSelectorTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp index 9efe73d450..adbd868a28 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> { diff --git a/vulkan/vkjson/vkjson.cc b/vulkan/vkjson/vkjson.cc index 0284192cc4..bfb7bd6d6f 100644 --- a/vulkan/vkjson/vkjson.cc +++ b/vulkan/vkjson/vkjson.cc @@ -1169,7 +1169,7 @@ inline Json::Value ArrayToJsonValue(uint32_t count, const T* values) { return array; } -template <typename T, unsigned int N> +template <typename T, size_t N> inline Json::Value ToJsonValue(const T (&value)[N]) { return ArrayToJsonValue(N, value); } @@ -1293,7 +1293,7 @@ inline bool AsArray(Json::Value* json_value, uint32_t count, T* values) { return true; } -template <typename T, unsigned int N> +template <typename T, size_t N> inline bool AsValue(Json::Value* json_value, T (*value)[N]) { return AsArray(json_value, N, *value); } |