summaryrefslogtreecommitdiff
path: root/libs/binder/IServiceManager.cpp
diff options
context:
space:
mode:
author Devin Moore <devinmoore@google.com> 2024-08-08 21:01:24 +0000
committer Devin Moore <devinmoore@google.com> 2024-08-29 17:10:42 +0000
commit18f63759c833fe73c2323a5f2c5637b8c93ac8a3 (patch)
treea60afff59f119dc5913cbd738a3e096bb83999ff /libs/binder/IServiceManager.cpp
parent9d04fe2c66aff0fea66657f397827ed334ea3b7d (diff)
Add support for injecting RPC binder accessors to libbinder
This allows libbinder to set up client connections to binder RPC services underneath the libbinder service manager APIs. It requires callbacks to be added to the local process to get connection information that the client is responsible for obtaining. Once these callbacks are added to libbinder, any client elswhere in the process using the service manager APIs will be able to get and use a binder for the service in the same way they do for kernel binder services. Test: atest binderRpcTest vm_accessor_test Bug: 358427181 Change-Id: Iec27d30a669e0673bd66c99fded1edc335f7dff1
Diffstat (limited to 'libs/binder/IServiceManager.cpp')
-rw-r--r--libs/binder/IServiceManager.cpp210
1 files changed, 209 insertions, 1 deletions
diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
index 8b80aed630..61d32cf2f7 100644
--- a/libs/binder/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include <sys/socket.h>
#define LOG_TAG "ServiceManagerCppClient"
#include <binder/IServiceManager.h>
@@ -24,14 +25,19 @@
#include <chrono>
#include <condition_variable>
+#include <FdTrigger.h>
+#include <RpcSocketAddress.h>
#include <android-base/properties.h>
+#include <android/os/BnAccessor.h>
#include <android/os/BnServiceCallback.h>
+#include <android/os/BnServiceManager.h>
#include <android/os/IAccessor.h>
#include <android/os/IServiceManager.h>
#include <binder/IPCThreadState.h>
#include <binder/Parcel.h>
+#include <binder/RpcSession.h>
#include <utils/String8.h>
-
+#include <variant>
#ifndef __ANDROID_VNDK__
#include <binder/IPermissionController.h>
#endif
@@ -149,8 +155,141 @@ protected:
}
};
+class AccessorProvider {
+public:
+ AccessorProvider(RpcAccessorProvider&& provider) : mProvider(provider) {}
+ sp<IBinder> provide(const String16& name) { return mProvider(name); }
+
+private:
+ AccessorProvider() = delete;
+
+ RpcAccessorProvider mProvider;
+};
+
+class AccessorProviderEntry {
+public:
+ AccessorProviderEntry(std::shared_ptr<AccessorProvider>&& provider) : mProvider(provider) {}
+ std::shared_ptr<AccessorProvider> mProvider;
+
+private:
+ AccessorProviderEntry() = delete;
+};
+
[[clang::no_destroy]] static std::once_flag gSmOnce;
[[clang::no_destroy]] static sp<IServiceManager> gDefaultServiceManager;
+[[clang::no_destroy]] static std::mutex gAccessorProvidersMutex;
+[[clang::no_destroy]] static std::vector<AccessorProviderEntry> gAccessorProviders;
+
+class LocalAccessor : public android::os::BnAccessor {
+public:
+ LocalAccessor(const String16& instance, RpcSocketAddressProvider&& connectionInfoProvider)
+ : mInstance(instance), mConnectionInfoProvider(connectionInfoProvider) {
+ LOG_ALWAYS_FATAL_IF(!mConnectionInfoProvider,
+ "LocalAccessor object needs a valid connection info provider");
+ }
+
+ ~LocalAccessor() {
+ if (mOnDelete) mOnDelete();
+ }
+
+ ::android::binder::Status addConnection(::android::os::ParcelFileDescriptor* outFd) {
+ using android::os::IAccessor;
+ sockaddr_storage addrStorage;
+ std::unique_ptr<FdTrigger> trigger = FdTrigger::make();
+ RpcTransportFd fd;
+ status_t status =
+ mConnectionInfoProvider(mInstance, reinterpret_cast<sockaddr*>(&addrStorage),
+ sizeof(addrStorage));
+ if (status != OK) {
+ const std::string error = "The connection info provider was unable to provide "
+ "connection info for instance " +
+ std::string(String8(mInstance).c_str()) +
+ " with status: " + statusToString(status);
+ ALOGE("%s", error.c_str());
+ return Status::fromServiceSpecificError(IAccessor::ERROR_CONNECTION_INFO_NOT_FOUND,
+ error.c_str());
+ }
+ if (addrStorage.ss_family == AF_VSOCK) {
+ sockaddr_vm* addr = reinterpret_cast<sockaddr_vm*>(&addrStorage);
+ status = singleSocketConnection(VsockSocketAddress(addr->svm_cid, addr->svm_port),
+ trigger, &fd);
+ } else if (addrStorage.ss_family == AF_UNIX) {
+ sockaddr_un* addr = reinterpret_cast<sockaddr_un*>(&addrStorage);
+ status = singleSocketConnection(UnixSocketAddress(addr->sun_path), trigger, &fd);
+ } else if (addrStorage.ss_family == AF_INET) {
+ sockaddr_in* addr = reinterpret_cast<sockaddr_in*>(&addrStorage);
+ status = singleSocketConnection(InetSocketAddress(reinterpret_cast<sockaddr*>(addr),
+ sizeof(sockaddr_in),
+ inet_ntoa(addr->sin_addr),
+ ntohs(addr->sin_port)),
+ trigger, &fd);
+ } else {
+ const std::string error =
+ "Unsupported socket family type or the ConnectionInfoProvider failed to find a "
+ "valid address. Family type: " +
+ std::to_string(addrStorage.ss_family);
+ ALOGE("%s", error.c_str());
+ return Status::fromServiceSpecificError(IAccessor::ERROR_UNSUPPORTED_SOCKET_FAMILY,
+ error.c_str());
+ }
+ if (status != OK) {
+ const std::string error = "Failed to connect to socket for " +
+ std::string(String8(mInstance).c_str()) +
+ " with status: " + statusToString(status);
+ ALOGE("%s", error.c_str());
+ int err = 0;
+ if (status == -EACCES) {
+ err = IAccessor::ERROR_FAILED_TO_CONNECT_EACCES;
+ } else {
+ err = IAccessor::ERROR_FAILED_TO_CONNECT_TO_SOCKET;
+ }
+ return Status::fromServiceSpecificError(err, error.c_str());
+ }
+ *outFd = os::ParcelFileDescriptor(std::move(fd.fd));
+ return Status::ok();
+ }
+
+ ::android::binder::Status getInstanceName(String16* instance) {
+ *instance = mInstance;
+ return Status::ok();
+ }
+
+private:
+ LocalAccessor() = delete;
+ String16 mInstance;
+ RpcSocketAddressProvider mConnectionInfoProvider;
+ std::function<void()> mOnDelete;
+};
+
+android::binder::Status getInjectedAccessor(const std::string& name,
+ android::os::Service* service) {
+ std::vector<AccessorProviderEntry> copiedProviders;
+ {
+ std::lock_guard<std::mutex> lock(gAccessorProvidersMutex);
+ copiedProviders.insert(copiedProviders.begin(), gAccessorProviders.begin(),
+ gAccessorProviders.end());
+ }
+
+ // Unlocked to call the providers. This requires the providers to be
+ // threadsafe and not contain any references to objects that could be
+ // deleted.
+ for (const auto& provider : copiedProviders) {
+ sp<IBinder> binder = provider.mProvider->provide(String16(name.c_str()));
+ if (binder == nullptr) continue;
+ status_t status = validateAccessor(String16(name.c_str()), binder);
+ if (status != OK) {
+ ALOGE("A provider returned a binder that is not an IAccessor for instance %s. Status: "
+ "%s",
+ name.c_str(), statusToString(status).c_str());
+ return android::binder::Status::fromStatusT(android::INVALID_OPERATION);
+ }
+ *service = os::Service::make<os::Service::Tag::accessor>(binder);
+ return android::binder::Status::ok();
+ }
+
+ *service = os::Service::make<os::Service::Tag::accessor>(nullptr);
+ return android::binder::Status::ok();
+}
sp<IServiceManager> defaultServiceManager()
{
@@ -173,6 +312,75 @@ void setDefaultServiceManager(const sp<IServiceManager>& sm) {
}
}
+std::weak_ptr<AccessorProvider> addAccessorProvider(RpcAccessorProvider&& providerCallback) {
+ std::lock_guard<std::mutex> lock(gAccessorProvidersMutex);
+ std::shared_ptr<AccessorProvider> provider =
+ std::make_shared<AccessorProvider>(std::move(providerCallback));
+ gAccessorProviders.push_back(AccessorProviderEntry(std::move(provider)));
+
+ return provider;
+}
+
+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;
+ }
+ std::lock_guard<std::mutex> lock(gAccessorProvidersMutex);
+ size_t sizeBefore = gAccessorProviders.size();
+ gAccessorProviders.erase(std::remove_if(gAccessorProviders.begin(), gAccessorProviders.end(),
+ [&](AccessorProviderEntry entry) {
+ return entry.mProvider == provider;
+ }),
+ gAccessorProviders.end());
+ if (sizeBefore == gAccessorProviders.size()) {
+ ALOGE("Failed to find an AccessorProvider for removeAccessorProvider");
+ return NAME_NOT_FOUND;
+ }
+
+ return OK;
+}
+
+status_t validateAccessor(const String16& instance, const sp<IBinder>& binder) {
+ if (binder == nullptr) {
+ ALOGE("Binder is null");
+ return BAD_VALUE;
+ }
+ sp<IAccessor> accessor = interface_cast<IAccessor>(binder);
+ if (accessor == nullptr) {
+ ALOGE("This binder for %s is not an IAccessor binder", String8(instance).c_str());
+ return BAD_TYPE;
+ }
+ String16 reportedInstance;
+ Status status = accessor->getInstanceName(&reportedInstance);
+ if (!status.isOk()) {
+ ALOGE("Failed to validate the binder being used to create a new ARpc_Accessor for %s with "
+ "status: %s",
+ String8(instance).c_str(), status.toString8().c_str());
+ return NAME_NOT_FOUND;
+ }
+ if (reportedInstance != instance) {
+ ALOGE("Instance %s doesn't match the Accessor's instance of %s", String8(instance).c_str(),
+ String8(reportedInstance).c_str());
+ return NAME_NOT_FOUND;
+ }
+ return OK;
+}
+
+sp<IBinder> createAccessor(const String16& instance,
+ RpcSocketAddressProvider&& connectionInfoProvider) {
+ // Try to create a new accessor
+ if (!connectionInfoProvider) {
+ ALOGE("Could not find an Accessor for %s and no ConnectionInfoProvider provided to "
+ "create a new one",
+ String8(instance).c_str());
+ return nullptr;
+ }
+ sp<IBinder> binder = sp<LocalAccessor>::make(instance, std::move(connectionInfoProvider));
+ return binder;
+}
+
#if !defined(__ANDROID_VNDK__)
// IPermissionController is not accessible to vendors