diff options
author | 2024-09-24 23:52:33 +0000 | |
---|---|---|
committer | 2024-09-24 23:52:33 +0000 | |
commit | 7cc4a37a30e566e01f66171ba5efb8788ef00d7c (patch) | |
tree | a2572c0e57f8fcc982cf84a9c1491e45ef03f4e3 | |
parent | e39a1b54e1b6f5f0ef9a13a4f842c6cd1c40bba5 (diff) | |
parent | c370db498194e22bf1499cb5d1c834a79e3ee776 (diff) |
Merge "Add libbinder_ndk systemapi support for injecting RPC binder accessors" into main
-rw-r--r-- | libs/binder/IServiceManager.cpp | 44 | ||||
-rw-r--r-- | libs/binder/include/binder/IServiceManager.h | 23 | ||||
-rw-r--r-- | libs/binder/ndk/Android.bp | 1 | ||||
-rw-r--r-- | libs/binder/ndk/binder_rpc.cpp | 352 | ||||
-rw-r--r-- | libs/binder/ndk/include_platform/android/binder_rpc.h | 261 | ||||
-rw-r--r-- | libs/binder/ndk/libbinder_ndk.map.txt | 12 | ||||
-rw-r--r-- | libs/binder/tests/Android.bp | 3 | ||||
-rw-r--r-- | libs/binder/tests/binderRpcTest.cpp | 358 |
8 files changed, 1017 insertions, 37 deletions
diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp index 88761d772f..77b80ef3de 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(); diff --git a/libs/binder/include/binder/IServiceManager.h b/libs/binder/include/binder/IServiceManager.h index 879f319c5e..2b23276d1c 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 diff --git a/libs/binder/ndk/Android.bp b/libs/binder/ndk/Android.bp index 5f45cb2f07..a7423b3d2a 100644 --- a/libs/binder/ndk/Android.bp +++ b/libs/binder/ndk/Android.bp @@ -95,6 +95,7 @@ cc_library { "persistable_bundle.cpp", "process.cpp", "service_manager.cpp", + "binder_rpc.cpp", ], static_libs: [ diff --git a/libs/binder/ndk/binder_rpc.cpp b/libs/binder/ndk/binder_rpc.cpp new file mode 100644 index 0000000000..2cc5f8117e --- /dev/null +++ b/libs/binder/ndk/binder_rpc.cpp @@ -0,0 +1,352 @@ +/* + * 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 copyable for std::function, but we will never copy it + OnDeleteProviderHolder(const OnDeleteProviderHolder&) { + LOG_ALWAYS_FATAL("This object can't be copied!"); + } + + private: + OnDeleteProviderHolder() = delete; +}; + +ABinderRpc_AccessorProvider* ABinderRpc_registerAccessorProvider( + ABinderRpc_AccessorProvider_getAccessorCallback provider, const char** instances, + size_t numInstances, void* data, + ABinderRpc_AccessorProviderUserData_deleteCallback onDelete) { + if (provider == nullptr) { + ALOGE("Null provider passed to ABinderRpc_registerAccessorProvider"); + return nullptr; + } + if (data && onDelete == nullptr) { + ALOGE("If a non-null data ptr is passed to ABinderRpc_registerAccessorProvider, then a " + "ABinderRpc_AccessorProviderUserData_deleteCallback must alse 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 copyable 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 alse be passed to " + "delete " + "the data object once the ABinderRpc_Accessor is deleted."); + return nullptr; + } + std::shared_ptr<OnDeleteConnectionInfoHolder> onDeleteHolder = + std::make_shared<OnDeleteConnectionInfoHolder>(data, onDelete); + if (provider == nullptr) { + ALOGE("Can't create a new ABinderRpc_Accessor without a ABinderRpc_ConnectionInfoProvider " + "and it is " + "null"); + return nullptr; + } + android::RpcSocketAddressProvider generate = [provider, onDeleteHolder]( + const String16& name, sockaddr* outAddr, + size_t addrLen) -> status_t { + std::unique_ptr<ABinderRpc_ConnectionInfo> info( + provider(String8(name).c_str(), onDeleteHolder->mData)); + if (info == nullptr) { + ALOGE("The supplied ABinderRpc_ConnectionInfoProvider returned nullptr"); + return android::NAME_NOT_FOUND; + } + if (auto addr = std::get_if<sockaddr_vm>(&info->addr)) { + LOG_ALWAYS_FATAL_IF(addr->svm_family != AF_VSOCK, + "ABinderRpc_ConnectionInfo invalid family"); + if (addrLen < sizeof(sockaddr_vm)) { + ALOGE("Provided outAddr is too small! Expecting %zu, got %zu", sizeof(sockaddr_vm), + addrLen); + return android::BAD_VALUE; + } + LOG_ACCESSOR_DEBUG( + "Connection info provider found AF_VSOCK. family %d, port %d, cid %d", + addr->svm_family, addr->svm_port, addr->svm_cid); + *reinterpret_cast<sockaddr_vm*>(outAddr) = *addr; + } else if (auto addr = std::get_if<sockaddr_un>(&info->addr)) { + LOG_ALWAYS_FATAL_IF(addr->sun_family != AF_UNIX, + "ABinderRpc_ConnectionInfo invalid family"); + if (addrLen < sizeof(sockaddr_un)) { + ALOGE("Provided outAddr is too small! Expecting %zu, got %zu", sizeof(sockaddr_un), + addrLen); + return android::BAD_VALUE; + } + *reinterpret_cast<sockaddr_un*>(outAddr) = *addr; + } else if (auto addr = std::get_if<sockaddr_in>(&info->addr)) { + LOG_ALWAYS_FATAL_IF(addr->sin_family != AF_INET, + "ABinderRpc_ConnectionInfo invalid family"); + if (addrLen < sizeof(sockaddr_in)) { + ALOGE("Provided outAddr is too small! Expecting %zu, got %zu", sizeof(sockaddr_in), + addrLen); + return android::BAD_VALUE; + } + *reinterpret_cast<sockaddr_in*>(outAddr) = *addr; + } else { + LOG_ALWAYS_FATAL( + "Unsupported address family type when trying to get ARpcConnection info. A " + "new variant was added to the ABinderRpc_ConnectionInfo and this needs to be " + "updated."); + } + return OK; + }; + sp<IBinder> accessorBinder = android::createAccessor(String16(instance), std::move(generate)); + if (accessorBinder == nullptr) { + ALOGE("service manager did not get us an accessor"); + return nullptr; + } + LOG_ACCESSOR_DEBUG("service manager found an accessor, so returning one now from _new"); + return ABinderRpc_Accessor::make(instance, accessorBinder); +} + +void ABinderRpc_Accessor_delete(ABinderRpc_Accessor* accessor) { + delete accessor; +} + +AIBinder* ABinderRpc_Accessor_asBinder(ABinderRpc_Accessor* accessor) { + if (!accessor) { + ALOGE("ABinderRpc_Accessor argument is null."); + return nullptr; + } + + sp<IBinder> binder = accessor->asBinder(); + sp<AIBinder> aBinder = ABpBinder::lookupOrCreateFromBinder(binder); + AIBinder* ptr = aBinder.get(); + if (ptr == nullptr) { + LOG_ALWAYS_FATAL("Failed to lookupOrCreateFromBinder"); + } + ptr->incStrong(nullptr); + return ptr; +} + +ABinderRpc_Accessor* ABinderRpc_Accessor_fromBinder(const char* instance, AIBinder* binder) { + if (!binder) { + ALOGE("binder argument is null"); + return nullptr; + } + sp<IBinder> accessorBinder = binder->getBinder(); + if (accessorBinder) { + return ABinderRpc_Accessor::make(instance, accessorBinder); + } else { + ALOGE("Attempting to get an ABinderRpc_Accessor for %s but AIBinder::getBinder returned " + "null", + instance); + return nullptr; + } +} + +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 Arpc_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("Arpc_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("Arpc_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("Arpc_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("ARpc APIs only support AF_VSOCK right now but the supplied sockadder::sa_family is: %hu", + addr->sa_family); + return nullptr; +} + +void ABinderRpc_ConnectionInfo_delete(ABinderRpc_ConnectionInfo* info) { + delete info; +} 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..4c5471ff70 --- /dev/null +++ b/libs/binder/ndk/include_platform/android/binder_rpc.h @@ -0,0 +1,261 @@ +/* + * 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 + +/** + * 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` + * \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. + * \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 throguh multiple calls to this function because the first + * one to be deleted will call the onDelete callback. + * \param onDelete callback used to delete the objects that `data` points to. + * This is called after ABinderRpc_AccessorProvider is guaranteed to never be + * called again. Before this callback is called, `data` must remain + * valid. + * \return nullptr on error if the data pointer is non-null and the onDelete + * callback is null or if an instance in the instances list was previously + * registered. In the error case of duplicate instances, if data was + * provided with a ABinderRpc_AccessorProviderUserData_deleteCallback, + * the callback will be called to delete the data. + * Otherwise returns a pointer to the ABinderRpc_AccessorProvider that + * can be used to remove with ABinderRpc_unregisterAccessorProvider. + */ +ABinderRpc_AccessorProvider* _Nullable ABinderRpc_registerAccessorProvider( + ABinderRpc_AccessorProvider_getAccessorCallback _Nonnull provider, + const char* _Nullable* _Nonnull instances, size_t numInstances, void* _Nullable data, + ABinderRpc_AccessorProviderUserData_deleteCallback _Nullable onDelete) __INTRODUCED_IN(36); + +/** + * Remove an ABinderRpc_AccessorProvider from libbinder. This will remove references + * from the ABinderRpc_AccessorProvider and will no longer call the + * ABinderRpc_AccessorProvider_getAccessorCallback. + * + * Note: The `data` object that was used when adding the accessor will be + * deleted by the ABinderRpc_AccessorProviderUserData_deleteCallback at some + * point after this call. Do not use the object and do not try to delete + * it through any other means. + * Note: This will abort when used incorrectly if this provider was never + * registered or if it were already unregistered. + * + * \param provider to be removed and deleted + * + */ +void ABinderRpc_unregisterAccessorProvider(ABinderRpc_AccessorProvider* _Nonnull provider) + __INTRODUCED_IN(36); + +/** + * Callback which returns the RPC connection information for libbinder to use to + * connect to a socket that a given service is listening on. This is needed to + * create an ABinderRpc_Accessor so it can connect to these services. + * + * \param instance name of the service to connect to + * \param data userdata 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 + * \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, and the AIBinder must a proxy binder for a + * remote service (ABpBinder). + * This can be used when receivng 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. + * \param accessorBinder proxy binder from another processes ABinderRpc_Accessor. + * \return ABinderRpc_Accessor representing the other processes ABinderRpc_Accessor + * implementation. This function does not take ownership of the + * ABinderRpc_Accessor (so the caller needs to delete with + * ABinderRpc_Accessor_delete), and it preserves the recount of the bidner + * object. + */ +ABinderRpc_Accessor* _Nullable ABinderRpc_Accessor_fromBinder(const char* _Nonnull instance, + AIBinder* _Nonnull accessorBinder) + __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..c9e669ed36 100644 --- a/libs/binder/ndk/libbinder_ndk.map.txt +++ b/libs/binder/ndk/libbinder_ndk.map.txt @@ -248,6 +248,18 @@ LIBBINDER_NDK35 { # introduced=VanillaIceCream AServiceManager_openDeclaredPassthroughHal; # systemapi llndk=202404 }; +LIBBINDER_NDK36 { # introduced=36 + global: + ABinderRpc_registerAccessorProvider; # systemapi + ABinderRpc_unregisterAccessorProvider; # systemapi + ABinderRpc_Accessor_new; # 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/tests/Android.bp b/libs/binder/tests/Android.bp index 0e653af707..8b0dda33dd 100644 --- a/libs/binder/tests/Android.bp +++ b/libs/binder/tests/Android.bp @@ -532,6 +532,9 @@ cc_test { static_libs: [ "libbinder_rpc_single_threaded", ], + shared_libs: [ + "libbinder_ndk", + ], } cc_test { diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp index 0ef200bcbe..11150bcd77 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; @@ -1204,27 +1211,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,9 +1260,31 @@ 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); + EXPECT_EQ(binder, nullptr); + + status_t status = removeAccessorProvider(receipt); + 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); @@ -1261,6 +1292,11 @@ TEST_P(BinderRpcAccessor, InjectNoAccessorProvided) { 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 +1307,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 +1326,269 @@ 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, ARpcDoubleRemoveProvider) { + ABinderRpc_AccessorProvider* provider = + ABinderRpc_registerAccessorProvider(getAccessor, kARpcSupportedServices, + kARpcNumSupportedServices, nullptr, nullptr); + ASSERT_NE(nullptr, provider); + ABinderRpc_unregisterAccessorProvider(provider); + EXPECT_DEATH(ABinderRpc_unregisterAccessorProvider(provider), " was already unregistered"); +} + +TEST_F(BinderARpcNdk, ARpcNullArgs_ConnectionInfo_new) { + sockaddr_storage addr; + EXPECT_EQ(nullptr, ABinderRpc_ConnectionInfo_new(reinterpret_cast<const sockaddr*>(&addr), 0)); +} + +TEST_P(BinderRpcAccessor, ARpcGetService) { + constexpr size_t kNumThreads = 10; + bool isDeleted = false; + + auto proc = createRpcTestSocketServerProcess({.numThreads = kNumThreads}); + EXPECT_EQ(OK, proc.rootBinder->pingBinder()); + + 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); +} + #endif // BINDER_WITH_KERNEL_IPC #ifdef BINDER_RPC_TO_TRUSTY_TEST |