summaryrefslogtreecommitdiff
path: root/libs/binder/IServiceManager.cpp
diff options
context:
space:
mode:
author Devin Moore <devinmoore@google.com> 2024-09-04 17:16:10 +0000
committer Gerrit Code Review <noreply-gerritcodereview@google.com> 2024-09-04 17:16:10 +0000
commitd53d0744fcd1cf7354941ad231bb633fee308066 (patch)
treee4de00651c218a2c5742bb2854d490257fad034b /libs/binder/IServiceManager.cpp
parent1af8a3eef46e4dcef8c69e43e30291211c2964ce (diff)
parent18f63759c833fe73c2323a5f2c5637b8c93ac8a3 (diff)
Merge "Add support for injecting RPC binder accessors to libbinder" into main
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 c55dd9de1b..cba21b2094 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
@@ -148,8 +154,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()
{
@@ -172,6 +311,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