diff options
| author | 2021-06-18 01:25:10 +0000 | |
|---|---|---|
| committer | 2021-06-18 01:25:10 +0000 | |
| commit | 86ab5cc302d24d7d6ba76f17eef46e8847d0118a (patch) | |
| tree | e5643803192a129eb34ae5a2cfd3e5fda10868b2 | |
| parent | 52e8e9d0ca7035bdb449b197ca1fe5acc6fbbd20 (diff) | |
| parent | 08ade0ad0ee6a614336de158d3711b19ed40ceca (diff) | |
Merge changes I53da0d94,I0fe853df,I69ef50cc am: 08ade0ad0e
Original change: https://android-review.googlesource.com/c/platform/frameworks/native/+/1736924
Change-Id: Iadcdac95a563867fc809017b6af5ff2c91f749a0
| -rw-r--r-- | libs/binder/servicedispatcher.cpp | 141 |
1 files changed, 134 insertions, 7 deletions
diff --git a/libs/binder/servicedispatcher.cpp b/libs/binder/servicedispatcher.cpp index af7912616e..62df9b7f2f 100644 --- a/libs/binder/servicedispatcher.cpp +++ b/libs/binder/servicedispatcher.cpp @@ -23,6 +23,8 @@ #include <android-base/logging.h> #include <android-base/properties.h> #include <android-base/stringprintf.h> +#include <android/os/BnServiceManager.h> +#include <android/os/IServiceManager.h> #include <binder/IServiceManager.h> #include <binder/RpcServer.h> @@ -41,25 +43,38 @@ using android::base::LogId; using android::base::LogSeverity; using android::base::StdioLogger; using android::base::StringPrintf; +using std::string_view_literals::operator""sv; namespace { + +using ServiceRetriever = decltype(&android::IServiceManager::checkService); + int Usage(const char* program) { + auto basename = Basename(program); auto format = R"(dispatch calls to RPC service. Usage: - %s <service_name> + %s [-g] <service_name> <service_name>: the service to connect to. + %s [-g] manager + Runs an RPC-friendly service that redirects calls to servicemanager. + + -g: use getService() instead of checkService(). + + If successful, writes port number and a new line character to stdout, and + blocks until killed. + Otherwise, writes error message to stderr and exits with non-zero code. )"; - LOG(ERROR) << StringPrintf(format, Basename(program).c_str()); + LOG(ERROR) << StringPrintf(format, basename.c_str(), basename.c_str()); return EX_USAGE; } -int Dispatch(const char* name) { +int Dispatch(const char* name, const ServiceRetriever& serviceRetriever) { auto sm = defaultServiceManager(); if (nullptr == sm) { LOG(ERROR) << "No servicemanager"; return EX_SOFTWARE; } - auto binder = sm->checkService(String16(name)); + auto binder = std::invoke(serviceRetriever, defaultServiceManager(), String16(name)); if (nullptr == binder) { LOG(ERROR) << "No service \"" << name << "\""; return EX_SOFTWARE; @@ -82,7 +97,7 @@ int Dispatch(const char* name) { LOG(ERROR) << "setRpcClientDebug failed with " << statusToString(status); return EX_SOFTWARE; } - LOG(INFO) << "Finish setting up RPC on service " << name << " on port" << port; + LOG(INFO) << "Finish setting up RPC on service " << name << " on port " << port; std::cout << port << std::endl; @@ -92,6 +107,110 @@ int Dispatch(const char* name) { __builtin_unreachable(); } +// Wrapper that wraps a BpServiceManager as a BnServiceManager. +class ServiceManagerProxyToNative : public android::os::BnServiceManager { +public: + ServiceManagerProxyToNative(const sp<android::os::IServiceManager>& impl) : mImpl(impl) {} + android::binder::Status getService(const std::string&, + android::sp<android::IBinder>*) override { + // We can't send BpBinder for regular binder over RPC. + return android::binder::Status::fromStatusT(android::INVALID_OPERATION); + } + android::binder::Status checkService(const std::string&, + android::sp<android::IBinder>*) override { + // We can't send BpBinder for regular binder over RPC. + return android::binder::Status::fromStatusT(android::INVALID_OPERATION); + } + android::binder::Status addService(const std::string&, const android::sp<android::IBinder>&, + bool, int32_t) override { + // We can't send BpBinder for RPC over regular binder. + return android::binder::Status::fromStatusT(android::INVALID_OPERATION); + } + android::binder::Status listServices(int32_t dumpPriority, + std::vector<std::string>* _aidl_return) override { + return mImpl->listServices(dumpPriority, _aidl_return); + } + android::binder::Status registerForNotifications( + const std::string&, const android::sp<android::os::IServiceCallback>&) override { + // We can't send BpBinder for RPC over regular binder. + return android::binder::Status::fromStatusT(android::INVALID_OPERATION); + } + android::binder::Status unregisterForNotifications( + const std::string&, const android::sp<android::os::IServiceCallback>&) override { + // We can't send BpBinder for RPC over regular binder. + return android::binder::Status::fromStatusT(android::INVALID_OPERATION); + } + android::binder::Status isDeclared(const std::string& name, bool* _aidl_return) override { + return mImpl->isDeclared(name, _aidl_return); + } + android::binder::Status getDeclaredInstances(const std::string& iface, + std::vector<std::string>* _aidl_return) override { + return mImpl->getDeclaredInstances(iface, _aidl_return); + } + android::binder::Status updatableViaApex(const std::string& name, + std::optional<std::string>* _aidl_return) override { + return mImpl->updatableViaApex(name, _aidl_return); + } + android::binder::Status registerClientCallback( + const std::string&, const android::sp<android::IBinder>&, + const android::sp<android::os::IClientCallback>&) override { + // We can't send BpBinder for RPC over regular binder. + return android::binder::Status::fromStatusT(android::INVALID_OPERATION); + } + android::binder::Status tryUnregisterService(const std::string&, + const android::sp<android::IBinder>&) override { + // We can't send BpBinder for RPC over regular binder. + return android::binder::Status::fromStatusT(android::INVALID_OPERATION); + } + android::binder::Status getServiceDebugInfo( + std::vector<android::os::ServiceDebugInfo>* _aidl_return) override { + return mImpl->getServiceDebugInfo(_aidl_return); + } + +private: + sp<android::os::IServiceManager> mImpl; +}; + +// Workaround for b/191059588. +// TODO(b/191059588): Once we can run RpcServer on single-threaded services, +// `servicedispatcher manager` should call Dispatch("manager") directly. +int wrapServiceManager(const ServiceRetriever& serviceRetriever) { + auto sm = defaultServiceManager(); + if (nullptr == sm) { + LOG(ERROR) << "No servicemanager"; + return EX_SOFTWARE; + } + auto service = std::invoke(serviceRetriever, defaultServiceManager(), String16("manager")); + if (nullptr == service) { + LOG(ERROR) << "No service called `manager`"; + return EX_SOFTWARE; + } + auto interface = android::os::IServiceManager::asInterface(service); + if (nullptr == interface) { + LOG(ERROR) << "Cannot cast service called `manager` to IServiceManager"; + return EX_SOFTWARE; + } + + // Work around restriction that doesn't allow us to send proxy over RPC. + interface = sp<ServiceManagerProxyToNative>::make(interface); + service = ServiceManagerProxyToNative::asBinder(interface); + + auto rpcServer = RpcServer::make(); + rpcServer->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction(); + rpcServer->setRootObject(service); + unsigned int port; + if (!rpcServer->setupInetServer(0, &port)) { + LOG(ERROR) << "Unable to set up inet server"; + return EX_SOFTWARE; + } + LOG(INFO) << "Finish wrapping servicemanager with RPC on port " << port; + std::cout << port << std::endl; + rpcServer->join(); + + LOG(FATAL) << "Wrapped servicemanager exits; this should not happen!"; + __builtin_unreachable(); +} + // Log to logd. For warning and more severe messages, also log to stderr. class ServiceDispatcherLogger { public: @@ -120,15 +239,23 @@ int main(int argc, char* argv[]) { LOG(WARNING) << "WARNING: servicedispatcher is debug only. Use with caution."; int opt; - while (-1 != (opt = getopt(argc, argv, ""))) { + ServiceRetriever serviceRetriever = &android::IServiceManager::checkService; + while (-1 != (opt = getopt(argc, argv, "g"))) { switch (opt) { + case 'g': { + serviceRetriever = &android::IServiceManager::getService; + } break; default: { return Usage(argv[0]); } } } + if (optind + 1 != argc) return Usage(argv[0]); auto name = argv[optind]; - return Dispatch(name); + if (name == "manager"sv) { + return wrapServiceManager(serviceRetriever); + } + return Dispatch(name, serviceRetriever); } |