diff options
-rw-r--r-- | libs/binder/BackendUnifiedServiceManager.cpp | 46 | ||||
-rw-r--r-- | libs/binder/BackendUnifiedServiceManager.h | 7 | ||||
-rw-r--r-- | libs/binder/IServiceManager.cpp | 210 | ||||
-rw-r--r-- | libs/binder/RpcSession.cpp | 20 | ||||
-rw-r--r-- | libs/binder/RpcSocketAddress.h | 7 | ||||
-rw-r--r-- | libs/binder/aidl/android/os/IAccessor.aidl | 43 | ||||
-rw-r--r-- | libs/binder/include/binder/IServiceManager.h | 66 | ||||
-rw-r--r-- | libs/binder/tests/binderRpcTest.cpp | 189 | ||||
-rw-r--r-- | libs/binder/tests/binderRpcTestFixture.h | 6 |
9 files changed, 567 insertions, 27 deletions
diff --git a/libs/binder/BackendUnifiedServiceManager.cpp b/libs/binder/BackendUnifiedServiceManager.cpp index 54f687b280..fee36da911 100644 --- a/libs/binder/BackendUnifiedServiceManager.cpp +++ b/libs/binder/BackendUnifiedServiceManager.cpp @@ -46,7 +46,9 @@ binder::Status BackendUnifiedServiceManager::getService2(const ::std::string& na os::Service* _out) { os::Service service; binder::Status status = mTheRealServiceManager->getService2(name, &service); - toBinderService(service, _out); + if (status.isOk()) { + return toBinderService(name, service, _out); + } return status; } @@ -54,15 +56,38 @@ binder::Status BackendUnifiedServiceManager::checkService(const ::std::string& n os::Service* _out) { os::Service service; binder::Status status = mTheRealServiceManager->checkService(name, &service); - toBinderService(service, _out); + if (status.isOk()) { + return toBinderService(name, service, _out); + } return status; } -void BackendUnifiedServiceManager::toBinderService(const os::Service& in, os::Service* _out) { +binder::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); + if (!status.isOk()) { + *_out = os::Service::make<os::Service::Tag::binder>(nullptr); + return status; + } + if (accessor.getTag() == os::Service::Tag::accessor && + accessor.get<os::Service::Tag::accessor>() != nullptr) { + ALOGI("Found local injected service for %s, will attempt to create connection", + name.c_str()); + // Call this again using the accessor Service to get the real + // service's binder into _out + return toBinderService(name, accessor, _out); + } + } + *_out = in; - break; + return binder::Status::ok(); } case os::Service::Tag::accessor: { sp<IBinder> accessorBinder = in.get<os::Service::Tag::accessor>(); @@ -70,7 +95,7 @@ void BackendUnifiedServiceManager::toBinderService(const os::Service& in, os::Se if (accessor == nullptr) { ALOGE("Service#accessor doesn't have accessor. VM is maybe starting..."); *_out = os::Service::make<os::Service::Tag::binder>(nullptr); - break; + return binder::Status::ok(); } auto request = [=] { os::ParcelFileDescriptor fd; @@ -83,10 +108,15 @@ void BackendUnifiedServiceManager::toBinderService(const os::Service& in, os::Se } }; auto session = RpcSession::make(); - session->setupPreconnectedClient(base::unique_fd{}, request); + status_t status = session->setupPreconnectedClient(base::unique_fd{}, request); + if (status != OK) { + ALOGE("Failed to set up preconnected binder RPC client: %s", + statusToString(status).c_str()); + return binder::Status::fromStatusT(status); + } session->setSessionSpecificRoot(accessorBinder); *_out = os::Service::make<os::Service::Tag::binder>(session->getRootObject()); - break; + return binder::Status::ok(); } default: { LOG_ALWAYS_FATAL("Unknown service type: %d", in.getTag()); @@ -177,4 +207,4 @@ sp<BackendUnifiedServiceManager> getBackendUnifiedServiceManager() { return gUnifiedServiceManager; } -} // namespace android
\ No newline at end of file +} // namespace android diff --git a/libs/binder/BackendUnifiedServiceManager.h b/libs/binder/BackendUnifiedServiceManager.h index 8f3839fcb2..387eb35346 100644 --- a/libs/binder/BackendUnifiedServiceManager.h +++ b/libs/binder/BackendUnifiedServiceManager.h @@ -59,9 +59,12 @@ public: private: sp<os::IServiceManager> mTheRealServiceManager; - void toBinderService(const os::Service& in, os::Service* _out); + binder::Status toBinderService(const ::std::string& name, const os::Service& in, + os::Service* _out); }; sp<BackendUnifiedServiceManager> getBackendUnifiedServiceManager(); -} // namespace android
\ No newline at end of file +android::binder::Status getInjectedAccessor(const std::string& name, android::os::Service* service); + +} // namespace android 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 diff --git a/libs/binder/RpcSession.cpp b/libs/binder/RpcSession.cpp index 49def82b5d..cd21a91d2c 100644 --- a/libs/binder/RpcSession.cpp +++ b/libs/binder/RpcSession.cpp @@ -589,6 +589,21 @@ status_t RpcSession::setupSocketClient(const RpcSocketAddress& addr) { status_t RpcSession::setupOneSocketConnection(const RpcSocketAddress& addr, const std::vector<uint8_t>& sessionId, bool incoming) { + RpcTransportFd transportFd; + status_t status = singleSocketConnection(addr, mShutdownTrigger, &transportFd); + if (status != OK) return status; + + return initAndAddConnection(std::move(transportFd), sessionId, incoming); +} + +status_t singleSocketConnection(const RpcSocketAddress& addr, + const std::unique_ptr<FdTrigger>& shutdownTrigger, + RpcTransportFd* outFd) { + LOG_ALWAYS_FATAL_IF(outFd == nullptr, + "There is no reason to call this function without an outFd"); + LOG_ALWAYS_FATAL_IF(shutdownTrigger == nullptr, + "FdTrigger argument is required so we don't get stuck in the connect call " + "if the server process shuts down."); for (size_t tries = 0; tries < 5; tries++) { if (tries > 0) usleep(10000); @@ -620,7 +635,7 @@ status_t RpcSession::setupOneSocketConnection(const RpcSocketAddress& addr, if (connErrno == EAGAIN || connErrno == EINPROGRESS) { // For non-blocking sockets, connect() may return EAGAIN (for unix domain socket) or // EINPROGRESS (for others). Call poll() and getsockopt() to get the error. - status_t pollStatus = mShutdownTrigger->triggerablePoll(transportFd, POLLOUT); + status_t pollStatus = shutdownTrigger->triggerablePoll(transportFd, POLLOUT); if (pollStatus != OK) { ALOGE("Could not POLLOUT after connect() on non-blocking socket: %s", statusToString(pollStatus).c_str()); @@ -654,7 +669,8 @@ status_t RpcSession::setupOneSocketConnection(const RpcSocketAddress& addr, LOG_RPC_DETAIL("Socket at %s client with fd %d", addr.toString().c_str(), transportFd.fd.get()); - return initAndAddConnection(std::move(transportFd), sessionId, incoming); + *outFd = std::move(transportFd); + return OK; } ALOGE("Ran out of retries to connect to %s", addr.toString().c_str()); diff --git a/libs/binder/RpcSocketAddress.h b/libs/binder/RpcSocketAddress.h index c7ba5d96a7..ee7d448c43 100644 --- a/libs/binder/RpcSocketAddress.h +++ b/libs/binder/RpcSocketAddress.h @@ -113,4 +113,11 @@ private: unsigned int mPort; }; +/** + * Connects to a single socket and produces a RpcTransportFd. + */ +status_t singleSocketConnection(const RpcSocketAddress& address, + const std::unique_ptr<FdTrigger>& shutdownTrigger, + RpcTransportFd* outFd); + } // namespace android diff --git a/libs/binder/aidl/android/os/IAccessor.aidl b/libs/binder/aidl/android/os/IAccessor.aidl index a3134a3f7c..c06e05c444 100644 --- a/libs/binder/aidl/android/os/IAccessor.aidl +++ b/libs/binder/aidl/android/os/IAccessor.aidl @@ -25,15 +25,56 @@ import android.os.ParcelFileDescriptor; */ interface IAccessor { /** + * The connection info was not available for this service. + * This happens when the user-supplied callback fails to produce + * valid connection info. + * Depending on the implementation of the callback, it might be helpful + * to retry. + */ + const int ERROR_CONNECTION_INFO_NOT_FOUND = 0; + /** + * Failed to create the socket. Often happens when the process trying to create + * the socket lacks the permissions to do so. + * This may be a temporary issue, so retrying the operation is OK. + */ + const int ERROR_FAILED_TO_CREATE_SOCKET = 1; + /** + * Failed to connect to the socket. This can happen for many reasons, so be sure + * log the error message and check it. + * This may be a temporary issue, so retrying the operation is OK. + */ + const int ERROR_FAILED_TO_CONNECT_TO_SOCKET = 2; + /** + * Failed to connect to the socket with EACCES because this process does not + * have perimssions to connect. + * There is no need to retry the connection as this access will not be granted + * upon retry. + */ + const int ERROR_FAILED_TO_CONNECT_EACCES = 3; + /** + * Unsupported socket family type returned. + * There is no need to retry the connection as this socket family is not + * supported. + */ + const int ERROR_UNSUPPORTED_SOCKET_FAMILY = 4; + + /** * Adds a connection to the RPC server of the service managed by the IAccessor. * * This method can be called multiple times to establish multiple distinct * connections to the same RPC server. * + * @throws ServiceSpecificError with message and one of the IAccessor::ERROR_ values. + * * @return A file descriptor connected to the RPC session of the service managed * by IAccessor. */ ParcelFileDescriptor addConnection(); - // TODO(b/350941051): Add API for debugging. + /** + * Get the instance name for the service this accessor is responsible for. + * + * This is used to verify the proxy binder is associated with the expected instance name. + */ + String getInstanceName(); } diff --git a/libs/binder/include/binder/IServiceManager.h b/libs/binder/include/binder/IServiceManager.h index 5fb73079cb..879f319c5e 100644 --- a/libs/binder/include/binder/IServiceManager.h +++ b/libs/binder/include/binder/IServiceManager.h @@ -17,14 +17,16 @@ #pragma once #include <binder/Common.h> #include <binder/IInterface.h> -#include <utils/Vector.h> +// Trusty has its own definition of socket APIs from trusty_ipc.h +#ifndef __TRUSTY__ +#include <sys/socket.h> +#endif // __TRUSTY__ #include <utils/String16.h> +#include <utils/Vector.h> #include <optional> namespace android { -// ---------------------------------------------------------------------- - /** * Service manager for C++ services. * @@ -216,6 +218,64 @@ LIBBINDER_EXPORTED bool checkCallingPermission(const String16& permission, int32 LIBBINDER_EXPORTED bool checkPermission(const String16& permission, pid_t pid, uid_t uid, bool logPermissionFailure = true); +// ---------------------------------------------------------------------- +// Trusty's definition of the socket APIs does not include sockaddr types +#ifndef __TRUSTY__ +typedef std::function<status_t(const String16& name, sockaddr* outAddr, socklen_t addrSize)> + RpcSocketAddressProvider; + +typedef std::function<sp<IBinder>(const String16& name)> RpcAccessorProvider; + +class AccessorProvider; + +/** + * Register an accessor provider for the service manager APIs. + * + * \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); + +/** + * Remove an accessor provider using the pointer provided by addAccessorProvider + * along with the cookie pointer that was used. + * + * \param provider cookie that was returned by addAccessorProvider to keep track + * of this instance. + */ +[[nodiscard]] LIBBINDER_EXPORTED status_t +removeAccessorProvider(std::weak_ptr<AccessorProvider> provider); + +/** + * Create an Accessor associated with a service that can create a socket connection based + * on the connection info from the supplied RpcSocketAddressProvider. + * + * \param instance name of the service that this Accessor is associated with + * \param connectionInfoProvider a callback that returns connection info for + * connecting to the service. + * \return the binder of the IAccessor implementation from libbinder + */ +LIBBINDER_EXPORTED sp<IBinder> createAccessor(const String16& instance, + RpcSocketAddressProvider&& connectionInfoProvider); + +/** + * Check to make sure this binder is the expected binder that is an IAccessor + * associated with a specific instance. + * + * This helper function exists to avoid adding the IAccessor type to + * libbinder_ndk. + * + * \param instance name of the service that this Accessor should be associated with + * \param binder to validate + * + * \return OK if the binder is an IAccessor for `instance` + */ +LIBBINDER_EXPORTED status_t validateAccessor(const String16& instance, const sp<IBinder>& binder); +#endif // __TRUSTY__ + #ifndef __ANDROID__ // Create an IServiceManager that delegates the service manager on the device via adb. // This is can be set as the default service manager at program start, so that diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp index 3038de9a41..fbca35e81f 100644 --- a/libs/binder/tests/binderRpcTest.cpp +++ b/libs/binder/tests/binderRpcTest.cpp @@ -365,26 +365,57 @@ std::unique_ptr<ProcessSession> BinderRpc::createRpcTestSocketServerProcessEtc( session->setMaxOutgoingConnections(options.numOutgoingConnections); session->setFileDescriptorTransportMode(options.clientFileDescriptorTransportMode); + sockaddr_storage addr{}; + socklen_t addrLen = 0; + switch (socketType) { - case SocketType::PRECONNECTED: + case SocketType::PRECONNECTED: { + sockaddr_un addr_un{}; + addr_un.sun_family = AF_UNIX; + strcpy(addr_un.sun_path, serverConfig.addr.c_str()); + addr = *reinterpret_cast<sockaddr_storage*>(&addr_un); + addrLen = sizeof(sockaddr_un); + status = session->setupPreconnectedClient({}, [=]() { return connectTo(UnixSocketAddress(serverConfig.addr.c_str())); }); - break; + } break; case SocketType::UNIX_RAW: - case SocketType::UNIX: + case SocketType::UNIX: { + sockaddr_un addr_un{}; + addr_un.sun_family = AF_UNIX; + strcpy(addr_un.sun_path, serverConfig.addr.c_str()); + addr = *reinterpret_cast<sockaddr_storage*>(&addr_un); + addrLen = sizeof(sockaddr_un); + status = session->setupUnixDomainClient(serverConfig.addr.c_str()); - break; + } break; case SocketType::UNIX_BOOTSTRAP: status = session->setupUnixDomainSocketBootstrapClient( unique_fd(dup(bootstrapClientFd.get()))); break; - case SocketType::VSOCK: + case SocketType::VSOCK: { + sockaddr_vm addr_vm{ + .svm_family = AF_VSOCK, + .svm_port = static_cast<unsigned int>(serverInfo.port), + .svm_cid = VMADDR_CID_LOCAL, + }; + addr = *reinterpret_cast<sockaddr_storage*>(&addr_vm); + addrLen = sizeof(sockaddr_vm); + status = session->setupVsockClient(VMADDR_CID_LOCAL, serverInfo.port); - break; - case SocketType::INET: - status = session->setupInetClient("127.0.0.1", serverInfo.port); - break; + } break; + case SocketType::INET: { + const std::string ip_addr = "127.0.0.1"; + sockaddr_in addr_in{}; + addr_in.sin_family = AF_INET; + addr_in.sin_port = htons(serverInfo.port); + inet_aton(ip_addr.c_str(), &addr_in.sin_addr); + addr = *reinterpret_cast<sockaddr_storage*>(&addr_in); + addrLen = sizeof(sockaddr_in); + + status = session->setupInetClient(ip_addr.c_str(), serverInfo.port); + } break; case SocketType::TIPC: status = session->setupPreconnectedClient({}, [=]() { #ifdef BINDER_RPC_TO_TRUSTY_TEST @@ -413,7 +444,7 @@ std::unique_ptr<ProcessSession> BinderRpc::createRpcTestSocketServerProcessEtc( break; } LOG_ALWAYS_FATAL_IF(status != OK, "Could not connect: %s", statusToString(status).c_str()); - ret->sessions.push_back({session, session->getRootObject()}); + ret->sessions.push_back({session, session->getRootObject(), addr, addrLen}); } return ret; } @@ -1127,6 +1158,139 @@ TEST_P(BinderRpc, Fds) { ASSERT_EQ(beforeFds, countFds()) << (system("ls -l /proc/self/fd/"), "fd leak?"); } +// TODO need to add IServiceManager.cpp/.h to libbinder_no_kernel +#ifdef BINDER_WITH_KERNEL_IPC + +class BinderRpcAccessor : public BinderRpc { + void SetUp() override { + if (serverSingleThreaded()) { + // This blocks on android::FdTrigger::triggerablePoll when attempting to set + // up the client RpcSession + GTEST_SKIP() << "Accessors are not supported for single threaded libbinder"; + } + if (rpcSecurity() == RpcSecurity::TLS) { + GTEST_SKIP() << "Accessors are not supported with TLS"; + // ... for now + } + + if (socketType() == SocketType::UNIX_BOOTSTRAP) { + GTEST_SKIP() << "Accessors do not support UNIX_BOOTSTRAP because no connection " + "information is known"; + } + if (socketType() == SocketType::TIPC) { + GTEST_SKIP() << "Accessors do not support TIPC because the socket transport is not " + "known in libbinder"; + } + BinderRpc::SetUp(); + } +}; + +inline void waitForExtraSessionCleanup(const BinderRpcTestProcessSession& proc) { + // Need to give the server some time to delete its RpcSession after our last + // reference is dropped, closing the connection. Check for up to 1 second, + // every 10 ms. + for (size_t i = 0; i < 100; i++) { + std::vector<int32_t> remoteCounts; + EXPECT_OK(proc.rootIface->countBinders(&remoteCounts)); + // We exect the original binder to still be alive, we just want to wait + // for this extra session to be cleaned up. + if (remoteCounts.size() == proc.proc->sessions.size()) break; + usleep(10000); + } +} + +TEST_P(BinderRpcAccessor, InjectAndGetServiceHappyPath) { + constexpr size_t kNumThreads = 10; + const String16 kInstanceName("super.cool.service/better_than_default"); + + 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; + }); + }); + + EXPECT_FALSE(receipt.expired()); + + sp<IBinder> binder = defaultServiceManager()->checkService(kInstanceName); + sp<IBinderRpcTest> service = checked_interface_cast<IBinderRpcTest>(binder); + EXPECT_NE(service, nullptr); + + sp<IBinder> out; + EXPECT_OK(service->repeatBinder(binder, &out)); + EXPECT_EQ(binder, out); + + out.clear(); + binder.clear(); + service.clear(); + + status_t status = removeAccessorProvider(receipt); + EXPECT_EQ(status, OK); + + waitForExtraSessionCleanup(proc); +} + +TEST_P(BinderRpcAccessor, InjectNoAccessorProvided) { + const String16 kInstanceName("doesnt_matter_nothing_checks"); + + bool isProviderDeleted = false; + + auto receipt = addAccessorProvider([&](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, InjectNoSockaddrProvided) { + constexpr size_t kNumThreads = 10; + const String16 kInstanceName("super.cool.service/better_than_default"); + + auto proc = createRpcTestSocketServerProcess({.numThreads = kNumThreads}); + EXPECT_EQ(OK, proc.rootBinder->pingBinder()); + + 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; + }); + }); + + EXPECT_FALSE(receipt.expired()); + + sp<IBinder> binder = defaultServiceManager()->checkService(kInstanceName); + EXPECT_EQ(binder, nullptr); + + status_t status = removeAccessorProvider(receipt); + EXPECT_EQ(status, OK); +} + +#endif // BINDER_WITH_KERNEL_IPC + #ifdef BINDER_RPC_TO_TRUSTY_TEST static std::vector<BinderRpc::ParamType> getTrustyBinderRpcParams() { @@ -1315,6 +1479,11 @@ static std::vector<BinderRpc::ParamType> getBinderRpcParams() { INSTANTIATE_TEST_SUITE_P(PerSocket, BinderRpc, ::testing::ValuesIn(getBinderRpcParams()), BinderRpc::PrintParamInfo); +#ifdef BINDER_WITH_KERNEL_IPC +INSTANTIATE_TEST_SUITE_P(PerSocket, BinderRpcAccessor, ::testing::ValuesIn(getBinderRpcParams()), + BinderRpc::PrintParamInfo); +#endif // BINDER_WITH_KERNEL_IPC + class BinderRpcServerRootObject : public ::testing::TestWithParam<std::tuple<bool, bool, RpcSecurity>> {}; diff --git a/libs/binder/tests/binderRpcTestFixture.h b/libs/binder/tests/binderRpcTestFixture.h index 2c9646b30e..c8a8acc0a0 100644 --- a/libs/binder/tests/binderRpcTestFixture.h +++ b/libs/binder/tests/binderRpcTestFixture.h @@ -35,6 +35,12 @@ public: struct SessionInfo { sp<RpcSession> session; sp<IBinder> root; +// Trusty defines its own socket APIs in trusty_ipc.h but doesn't include +// sockaddr types. +#ifndef __TRUSTY__ + sockaddr_storage addr; + socklen_t addrLen; +#endif }; // client session objects associated with other process |