Merge changes Ib1c28c94,Id3485a2a,If5ad5acf,Idc9054bd,Ie4e7e25d
* changes:
libbinder_ndk: eradicate global lock
libbinder: add IBinder::withLock
libbinder_ndk: remove global lock on proxy delete
libbinder: attachObject APIs work with threads
rename binderParcelTest binderUnitTest
diff --git a/cmds/lshal/Lshal.cpp b/cmds/lshal/Lshal.cpp
index bc99f4d..a5f98c2 100644
--- a/cmds/lshal/Lshal.cpp
+++ b/cmds/lshal/Lshal.cpp
@@ -142,12 +142,10 @@
}
}
- PipeRelay relay(out, err, interfaceName, instanceName);
-
- if (relay.initCheck() != OK) {
- std::string msg = "PipeRelay::initCheck() FAILED w/ " + std::to_string(relay.initCheck());
- err << msg << std::endl;
- LOG(ERROR) << msg;
+ auto relay = PipeRelay::create(out, err, interfaceName + "/" + instanceName);
+ if (!relay.ok()) {
+ err << "Unable to create PipeRelay: " << relay.error() << std::endl;
+ LOG(ERROR) << "Unable to create PipeRelay: " << relay.error();
return IO_ERROR;
}
@@ -155,7 +153,7 @@
native_handle_create(1 /* numFds */, 0 /* numInts */),
native_handle_delete);
- fdHandle->data[0] = relay.fd();
+ fdHandle->data[0] = relay.value()->fd().get();
hardware::Return<void> ret = base->debug(fdHandle.get(), convert(options));
diff --git a/cmds/lshal/PipeRelay.cpp b/cmds/lshal/PipeRelay.cpp
index 4e97636..0c3fb96 100644
--- a/cmds/lshal/PipeRelay.cpp
+++ b/cmds/lshal/PipeRelay.cpp
@@ -16,143 +16,93 @@
#include "PipeRelay.h"
-#include <sys/select.h>
-#include <sys/time.h>
+#include <sys/poll.h>
#include <sys/types.h>
#include <unistd.h>
-#include <atomic>
+#include <chrono>
+#include <optional>
-#include <utils/Thread.h>
+#include <android-base/unique_fd.h>
+
+using android::base::borrowed_fd;
+using android::base::Result;
+using android::base::unique_fd;
+using std::chrono_literals::operator""ms;
namespace android {
namespace lshal {
-
-static constexpr struct timeval READ_TIMEOUT { .tv_sec = 1, .tv_usec = 0 };
-
-static std::string getThreadName(std::string interfaceName, const std::string &instanceName) {
- auto dot = interfaceName.rfind(".");
- if (dot != std::string::npos) interfaceName = interfaceName.substr(dot + 1);
- return "RelayThread_" + interfaceName + "_" + instanceName;
+Result<std::unique_ptr<PipeRelay>> PipeRelay::create(std::ostream& os,
+ const NullableOStream<std::ostream>& err,
+ const std::string& fqName) {
+ auto pipeRelay = std::unique_ptr<PipeRelay>(new PipeRelay());
+ unique_fd rfd;
+ if (!android::base::Pipe(&rfd, &pipeRelay->mWrite)) {
+ return android::base::ErrnoError() << "pipe()";
+ }
+ // Workaround for b/111997867: need a separate FD trigger because rfd can't receive POLLHUP
+ // when the write end is closed after the write end was sent through hwbinder.
+ unique_fd rfdTrigger;
+ if (!android::base::Pipe(&rfdTrigger, &pipeRelay->mWriteTrigger)) {
+ return android::base::ErrnoError() << "pipe() for trigger";
+ }
+ pipeRelay->mThread =
+ std::make_unique<std::thread>(&PipeRelay::thread, std::move(rfd), std::move(rfdTrigger),
+ &os, &err, fqName);
+ return pipeRelay;
}
-struct PipeRelay::RelayThread : public Thread {
- explicit RelayThread(int fd, std::ostream &os, const NullableOStream<std::ostream> &err,
- const std::string &fqName);
+void PipeRelay::thread(unique_fd rfd, unique_fd rfdTrigger, std::ostream* out,
+ const NullableOStream<std::ostream>* err, std::string fqName) {
+ while (true) {
+ pollfd pfd[2];
+ pfd[0] = {.fd = rfd.get(), .events = POLLIN};
+ pfd[1] = {.fd = rfdTrigger.get(), .events = 0};
- bool threadLoop() override;
- void setFinished();
-
-private:
- int mFd;
- std::ostream &mOutStream;
- NullableOStream<std::ostream> mErrStream;
-
- // If we were to use requestExit() and exitPending() instead, threadLoop()
- // may not run at all by the time ~PipeRelay is called (i.e. debug() has
- // returned from HAL). By using our own flag, we ensure that select() and
- // read() are executed until data are drained.
- std::atomic_bool mFinished;
-
- std::string mFqName;
-
- DISALLOW_COPY_AND_ASSIGN(RelayThread);
-};
-
-////////////////////////////////////////////////////////////////////////////////
-
-PipeRelay::RelayThread::RelayThread(int fd, std::ostream &os,
- const NullableOStream<std::ostream> &err,
- const std::string &fqName)
- : mFd(fd), mOutStream(os), mErrStream(err), mFinished(false), mFqName(fqName) {}
-
-bool PipeRelay::RelayThread::threadLoop() {
- char buffer[1024];
-
- fd_set set;
- FD_ZERO(&set);
- FD_SET(mFd, &set);
-
- struct timeval timeout = READ_TIMEOUT;
-
- int res = TEMP_FAILURE_RETRY(select(mFd + 1, &set, nullptr, nullptr, &timeout));
- if (res < 0) {
- mErrStream << "debug " << mFqName << ": select() failed";
- return false;
- }
-
- if (res == 0 || !FD_ISSET(mFd, &set)) {
- if (mFinished) {
- mErrStream << "debug " << mFqName
- << ": timeout reading from pipe, output may be truncated.";
- return false;
+ int pollRes = poll(pfd, arraysize(pfd), -1 /* infinite timeout */);
+ if (pollRes < 0) {
+ int savedErrno = errno;
+ (*err) << "debug " << fqName << ": poll() failed: " << strerror(savedErrno)
+ << std::endl;
+ break;
}
- // timeout, but debug() has not returned, so wait for HAL to finish.
- return true;
- }
- // FD_ISSET(mFd, &set) == true. Data available, start reading
- ssize_t n = TEMP_FAILURE_RETRY(read(mFd, buffer, sizeof(buffer)));
-
- if (n < 0) {
- mErrStream << "debug " << mFqName << ": read() failed";
- }
-
- if (n <= 0) {
- return false;
- }
-
- mOutStream.write(buffer, n);
-
- return true;
-}
-
-void PipeRelay::RelayThread::setFinished() {
- mFinished = true;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-PipeRelay::PipeRelay(std::ostream &os, const NullableOStream<std::ostream> &err,
- const std::string &interfaceName, const std::string &instanceName)
- : mInitCheck(NO_INIT) {
- int res = pipe(mFds);
-
- if (res < 0) {
- mInitCheck = -errno;
- return;
- }
-
- mThread = new RelayThread(mFds[0], os, err, interfaceName + "/" + instanceName);
- mInitCheck = mThread->run(getThreadName(interfaceName, instanceName).c_str());
-}
-
-void PipeRelay::CloseFd(int *fd) {
- if (*fd >= 0) {
- close(*fd);
- *fd = -1;
+ if (pfd[0].revents & POLLIN) {
+ char buffer[1024];
+ ssize_t n = TEMP_FAILURE_RETRY(read(rfd.get(), buffer, sizeof(buffer)));
+ if (n < 0) {
+ int savedErrno = errno;
+ (*err) << "debug " << fqName << ": read() failed: " << strerror(savedErrno)
+ << std::endl;
+ break;
+ }
+ if (n == 0) {
+ (*err) << "Warning: debug " << fqName << ": poll() indicates POLLIN but no data"
+ << std::endl;
+ continue;
+ }
+ out->write(buffer, n);
+ }
+ if (pfd[0].revents & POLLHUP) {
+ break;
+ }
+ if (pfd[1].revents & POLLHUP) {
+ // ~PipeRelay is called on the main thread. |mWrite| has been flushed and closed.
+ // Ensure that our read end of the pipe doesn't have pending data, then exit.
+ if ((pfd[0].revents & POLLIN) == 0) {
+ break;
+ }
+ }
}
}
PipeRelay::~PipeRelay() {
- CloseFd(&mFds[1]);
-
- if (mThread != nullptr) {
- mThread->setFinished();
+ mWrite.reset();
+ mWriteTrigger.reset();
+ if (mThread != nullptr && mThread->joinable()) {
mThread->join();
- mThread.clear();
}
-
- CloseFd(&mFds[0]);
}
-status_t PipeRelay::initCheck() const {
- return mInitCheck;
-}
-
-int PipeRelay::fd() const {
- return mFds[1];
-}
-
-} // namespace lshal
-} // namespace android
+} // namespace lshal
+} // namespace android
diff --git a/cmds/lshal/PipeRelay.h b/cmds/lshal/PipeRelay.h
index bd994b4..45ba982 100644
--- a/cmds/lshal/PipeRelay.h
+++ b/cmds/lshal/PipeRelay.h
@@ -16,42 +16,43 @@
#pragma once
+#include <thread>
+
#include <android-base/macros.h>
-#include <ostream>
+#include <android-base/result.h>
+#include <android-base/unique_fd.h>
#include <utils/Errors.h>
#include <utils/RefBase.h>
+#include <ostream>
#include "NullableOStream.h"
namespace android {
namespace lshal {
-/* Creates an AF_UNIX socketpair and spawns a thread that relays any data
+/**
+ * Creates a pipe and spawns a thread that relays any data
* written to the "write"-end of the pair to the specified output stream "os".
*/
struct PipeRelay {
- explicit PipeRelay(std::ostream& os,
- const NullableOStream<std::ostream>& err,
- const std::string& interfaceName,
- const std::string& instanceName);
+ static android::base::Result<std::unique_ptr<PipeRelay>> create(
+ std::ostream& os, const NullableOStream<std::ostream>& err, const std::string& fqName);
~PipeRelay();
- status_t initCheck() const;
-
// Returns the file descriptor corresponding to the "write"-end of the
// connection.
- int fd() const;
+ android::base::borrowed_fd fd() const { return mWrite; }
private:
- struct RelayThread;
-
- status_t mInitCheck;
- int mFds[2];
- sp<RelayThread> mThread;
-
- static void CloseFd(int *fd);
-
+ PipeRelay() = default;
DISALLOW_COPY_AND_ASSIGN(PipeRelay);
+ static void thread(android::base::unique_fd rfd, android::base::unique_fd rfdTrigger,
+ std::ostream* out, const NullableOStream<std::ostream>* err,
+ std::string fqName);
+
+ android::base::unique_fd mWrite;
+ android::base::unique_fd mWriteTrigger;
+ std::unique_ptr<std::thread> mThread;
};
} // namespace lshal
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index d8f8e55..da570f3 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -151,6 +151,7 @@
"libbase",
],
srcs: [
+ "ServiceManagerHost.cpp",
"UtilsHost.cpp",
],
},
diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
index d421060..2175fd4 100644
--- a/libs/binder/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -35,6 +35,8 @@
#ifdef __ANDROID__
#include <cutils/properties.h>
+#else
+#include "ServiceManagerHost.h"
#endif
#include "Static.h"
@@ -84,8 +86,19 @@
IBinder* onAsBinder() override {
return IInterface::asBinder(mTheRealServiceManager).get();
}
-private:
+
+protected:
sp<AidlServiceManager> mTheRealServiceManager;
+
+ // Directly get the service in a way that, for lazy services, requests the service to be started
+ // if it is not currently started. This way, calls directly to ServiceManagerShim::getService
+ // will still have the 5s delay that is expected by a large amount of Android code.
+ //
+ // When implementing ServiceManagerShim, use realGetService instead of
+ // mTheRealServiceManager->getService so that it can be overridden in ServiceManagerHostShim.
+ virtual Status realGetService(const std::string& name, sp<IBinder>* _aidl_return) {
+ return mTheRealServiceManager->getService(name, _aidl_return);
+ }
};
[[clang::no_destroy]] static std::once_flag gSmOnce;
@@ -319,7 +332,7 @@
const std::string name = String8(name16).c_str();
sp<IBinder> out;
- if (Status status = mTheRealServiceManager->getService(name, &out); !status.isOk()) {
+ if (Status status = realGetService(name, &out); !status.isOk()) {
ALOGW("Failed to getService in waitForService for %s: %s", name.c_str(),
status.toString8().c_str());
return nullptr;
@@ -363,7 +376,7 @@
// - init gets death signal, but doesn't know it needs to restart
// the service
// - we need to request service again to get it to start
- if (Status status = mTheRealServiceManager->getService(name, &out); !status.isOk()) {
+ if (Status status = realGetService(name, &out); !status.isOk()) {
ALOGW("Failed to getService in waitForService on later try for %s: %s", name.c_str(),
status.toString8().c_str());
return nullptr;
@@ -412,4 +425,38 @@
return declared ? std::optional<String16>(String16(declared.value().c_str())) : std::nullopt;
}
+#ifndef __ANDROID__
+// ServiceManagerShim for host. Implements the old libbinder android::IServiceManager API.
+// The internal implementation of the AIDL interface android::os::IServiceManager calls into
+// on-device service manager.
+class ServiceManagerHostShim : public ServiceManagerShim {
+public:
+ using ServiceManagerShim::ServiceManagerShim;
+ // ServiceManagerShim::getService is based on checkService, so no need to override it.
+ sp<IBinder> checkService(const String16& name) const override {
+ return getDeviceService({String8(name).c_str()});
+ }
+
+protected:
+ // Override realGetService for ServiceManagerShim::waitForService.
+ Status realGetService(const std::string& name, sp<IBinder>* _aidl_return) {
+ *_aidl_return = getDeviceService({"-g", name});
+ return Status::ok();
+ }
+};
+sp<IServiceManager> createRpcDelegateServiceManager() {
+ auto binder = getDeviceService({"manager"});
+ if (binder == nullptr) {
+ ALOGE("getDeviceService(\"manager\") returns null");
+ return nullptr;
+ }
+ auto interface = AidlServiceManager::asInterface(binder);
+ if (interface == nullptr) {
+ ALOGE("getDeviceService(\"manager\") returns non service manager");
+ return nullptr;
+ }
+ return sp<ServiceManagerHostShim>::make(interface);
+}
+#endif
+
} // namespace android
diff --git a/libs/binder/LazyServiceRegistrar.cpp b/libs/binder/LazyServiceRegistrar.cpp
index 6165911..f66993f 100644
--- a/libs/binder/LazyServiceRegistrar.cpp
+++ b/libs/binder/LazyServiceRegistrar.cpp
@@ -40,9 +40,9 @@
void setActiveServicesCallback(const std::function<bool(bool)>& activeServicesCallback);
- bool tryUnregister();
+ bool tryUnregisterLocked();
- void reRegister();
+ void reRegisterLocked();
protected:
Status onClients(const sp<IBinder>& service, bool clients) override;
@@ -59,6 +59,9 @@
bool registered = true;
};
+ bool registerServiceLocked(const sp<IBinder>& service, const std::string& name,
+ bool allowIsolated, int dumpFlags);
+
/**
* Looks up a service guaranteed to be registered (service from onClients).
*/
@@ -68,7 +71,7 @@
* Unregisters all services that we can. If we can't unregister all, re-register other
* services.
*/
- void tryShutdown();
+ void tryShutdownLocked();
/**
* Try to shutdown the process, unless:
@@ -76,7 +79,10 @@
* - The active services count callback returns 'true', or
* - Some services have clients.
*/
- void maybeTryShutdown();
+ void maybeTryShutdownLocked();
+
+ // for below
+ std::mutex mMutex;
// count of services with clients
size_t mNumConnectedServices;
@@ -117,6 +123,13 @@
bool ClientCounterCallbackImpl::registerService(const sp<IBinder>& service, const std::string& name,
bool allowIsolated, int dumpFlags) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ return registerServiceLocked(service, name, allowIsolated, dumpFlags);
+}
+
+bool ClientCounterCallbackImpl::registerServiceLocked(const sp<IBinder>& service,
+ const std::string& name, bool allowIsolated,
+ int dumpFlags) {
auto manager = interface_cast<AidlServiceManager>(asBinder(defaultServiceManager()));
bool reRegister = mRegisteredServices.count(name) > 0;
@@ -164,14 +177,15 @@
}
void ClientCounterCallbackImpl::forcePersist(bool persist) {
+ std::lock_guard<std::mutex> lock(mMutex);
mForcePersist = persist;
if (!mForcePersist) {
// Attempt a shutdown in case the number of clients hit 0 while the flag was on
- maybeTryShutdown();
+ maybeTryShutdownLocked();
}
}
-bool ClientCounterCallbackImpl::tryUnregister() {
+bool ClientCounterCallbackImpl::tryUnregisterLocked() {
auto manager = interface_cast<AidlServiceManager>(asBinder(defaultServiceManager()));
for (auto& [name, entry] : mRegisteredServices) {
@@ -187,15 +201,14 @@
return true;
}
-void ClientCounterCallbackImpl::reRegister() {
+void ClientCounterCallbackImpl::reRegisterLocked() {
for (auto& [name, entry] : mRegisteredServices) {
// re-register entry if not already registered
if (entry.registered) {
continue;
}
- if (!registerService(entry.service, name, entry.allowIsolated,
- entry.dumpFlags)) {
+ if (!registerServiceLocked(entry.service, name, entry.allowIsolated, entry.dumpFlags)) {
// Must restart. Otherwise, clients will never be able to get a hold of this service.
LOG_ALWAYS_FATAL("Bad state: could not re-register services");
}
@@ -204,7 +217,7 @@
}
}
-void ClientCounterCallbackImpl::maybeTryShutdown() {
+void ClientCounterCallbackImpl::maybeTryShutdownLocked() {
if (mForcePersist) {
ALOGI("Shutdown prevented by forcePersist override flag.");
return;
@@ -223,15 +236,12 @@
// client count change event, try to shutdown the process if its services
// have no clients.
if (!handledInCallback && mNumConnectedServices == 0) {
- tryShutdown();
+ tryShutdownLocked();
}
}
-/**
- * onClients is oneway, so no need to worry about multi-threading. Note that this means multiple
- * invocations could occur on different threads however.
- */
Status ClientCounterCallbackImpl::onClients(const sp<IBinder>& service, bool clients) {
+ std::lock_guard<std::mutex> lock(mMutex);
auto & [name, registered] = *assertRegisteredService(service);
if (registered.clients == clients) {
LOG_ALWAYS_FATAL("Process already thought %s had clients: %d but servicemanager has "
@@ -252,23 +262,24 @@
ALOGI("Process has %zu (of %zu available) client(s) in use after notification %s has clients: %d",
mNumConnectedServices, mRegisteredServices.size(), name.c_str(), clients);
- maybeTryShutdown();
+ maybeTryShutdownLocked();
return Status::ok();
}
- void ClientCounterCallbackImpl::tryShutdown() {
- ALOGI("Trying to shut down the service. No clients in use for any service in process.");
+void ClientCounterCallbackImpl::tryShutdownLocked() {
+ ALOGI("Trying to shut down the service. No clients in use for any service in process.");
- if (tryUnregister()) {
- ALOGI("Unregistered all clients and exiting");
- exit(EXIT_SUCCESS);
- }
+ if (tryUnregisterLocked()) {
+ ALOGI("Unregistered all clients and exiting");
+ exit(EXIT_SUCCESS);
+ }
- reRegister();
+ reRegisterLocked();
}
void ClientCounterCallbackImpl::setActiveServicesCallback(const std::function<bool(bool)>&
activeServicesCallback) {
+ std::lock_guard<std::mutex> lock(mMutex);
mActiveServicesCallback = activeServicesCallback;
}
@@ -291,11 +302,15 @@
}
bool ClientCounterCallback::tryUnregister() {
- return mImpl->tryUnregister();
+ // see comments in header, this should only be called from the active
+ // services callback, see also b/191781736
+ return mImpl->tryUnregisterLocked();
}
void ClientCounterCallback::reRegister() {
- mImpl->reRegister();
+ // see comments in header, this should only be called from the active
+ // services callback, see also b/191781736
+ mImpl->reRegisterLocked();
}
} // namespace internal
diff --git a/libs/binder/RpcServer.cpp b/libs/binder/RpcServer.cpp
index a8f3fa8..2a87ae4 100644
--- a/libs/binder/RpcServer.cpp
+++ b/libs/binder/RpcServer.cpp
@@ -278,7 +278,7 @@
return;
}
- RpcAddress sessionId = RpcAddress::zero();
+ sessionId = RpcAddress::zero();
size_t tries = 0;
do {
// don't block if there is some entropy issue
diff --git a/libs/binder/RpcSession.cpp b/libs/binder/RpcSession.cpp
index 4f55eef..ee5e8bb 100644
--- a/libs/binder/RpcSession.cpp
+++ b/libs/binder/RpcSession.cpp
@@ -198,6 +198,8 @@
uint8_t* buffer = reinterpret_cast<uint8_t*>(data);
uint8_t* end = buffer + size;
+ MAYBE_WAIT_IN_FLAKE_MODE;
+
status_t status;
while ((status = triggerablePollRead(fd)) == OK) {
ssize_t readSize = TEMP_FAILURE_RETRY(recv(fd.get(), buffer, end - buffer, MSG_NOSIGNAL));
diff --git a/libs/binder/RpcState.cpp b/libs/binder/RpcState.cpp
index fd2eff6..b5eaaa3 100644
--- a/libs/binder/RpcState.cpp
+++ b/libs/binder/RpcState.cpp
@@ -26,12 +26,28 @@
#include "Debug.h"
#include "RpcWireFormat.h"
+#include <random>
+
#include <inttypes.h>
namespace android {
using base::ScopeGuard;
+#ifdef RPC_FLAKE_PRONE
+void rpcMaybeWaitToFlake() {
+ static std::random_device r;
+ static std::mutex m;
+
+ unsigned num;
+ {
+ std::lock_guard<std::mutex> lock(m);
+ num = r();
+ }
+ if (num % 10 == 0) usleep(num % 1000);
+}
+#endif
+
RpcState::RpcState() {}
RpcState::~RpcState() {}
@@ -260,6 +276,8 @@
LOG_RPC_DETAIL("Sending %s on fd %d: %s", what, connection->fd.get(),
hexString(data, size).c_str());
+ MAYBE_WAIT_IN_FLAKE_MODE;
+
if (size > std::numeric_limits<ssize_t>::max()) {
ALOGE("Cannot send %s at size %zu (too big)", what, size);
(void)session->shutdownAndWait(false);
@@ -483,7 +501,7 @@
delete[] const_cast<uint8_t*>(data - offsetof(RpcWireReply, data));
(void)dataSize;
LOG_ALWAYS_FATAL_IF(objects != nullptr);
- LOG_ALWAYS_FATAL_IF(objectsCount, 0);
+ LOG_ALWAYS_FATAL_IF(objectsCount != 0, "%zu objects remaining", objectsCount);
}
status_t RpcState::waitForReply(const sp<RpcSession::RpcConnection>& connection,
diff --git a/libs/binder/RpcState.h b/libs/binder/RpcState.h
index 529dee5..8201eba 100644
--- a/libs/binder/RpcState.h
+++ b/libs/binder/RpcState.h
@@ -42,6 +42,15 @@
#define LOG_RPC_DETAIL(...) ALOGV(__VA_ARGS__) // for type checking
#endif
+#define RPC_FLAKE_PRONE false
+
+#ifdef RPC_FLAKE_PRONE
+void rpcMaybeWaitToFlake();
+#define MAYBE_WAIT_IN_FLAKE_MODE rpcMaybeWaitToFlake()
+#else
+#define MAYBE_WAIT_IN_FLAKE_MODE do {} while (false)
+#endif
+
/**
* Abstracts away management of ref counts and the wire format from
* RpcSession
diff --git a/libs/binder/ServiceManagerHost.cpp b/libs/binder/ServiceManagerHost.cpp
new file mode 100644
index 0000000..07f5778
--- /dev/null
+++ b/libs/binder/ServiceManagerHost.cpp
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2021 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 "ServiceManagerHost.h"
+
+#include <android-base/parseint.h>
+#include <android-base/strings.h>
+#include <binder/IServiceManager.h>
+#include <binder/RpcSession.h>
+
+#include "UtilsHost.h"
+
+namespace android {
+
+namespace {
+
+const void* kDeviceServiceExtraId = "DeviceServiceExtra";
+
+// Parse stdout of program execution to string. If any error, return 0.
+unsigned int parsePortNumber(const std::string& out, const std::string& what) {
+ auto trimmed = android::base::Trim(out);
+ unsigned int port = 0;
+ if (!android::base::ParseUint(trimmed, &port)) {
+ int savedErrno = errno;
+ ALOGE("%s is not a valid %s: %s", trimmed.c_str(), what.c_str(), strerror(savedErrno));
+ return 0;
+ }
+ if (port == 0) {
+ ALOGE("0 is not a valid %s", what.c_str());
+ return 0; // explicitly
+ }
+ return port;
+}
+
+// RAII object for adb forwarding
+class AdbForwarder {
+public:
+ AdbForwarder() = default;
+ static std::optional<AdbForwarder> forward(unsigned int devicePort);
+ AdbForwarder(AdbForwarder&& other) noexcept { (*this) = std::move(other); }
+ AdbForwarder& operator=(AdbForwarder&&) noexcept;
+ ~AdbForwarder();
+ [[nodiscard]] const std::optional<unsigned int>& hostPort() const { return mPort; }
+
+private:
+ DISALLOW_COPY_AND_ASSIGN(AdbForwarder);
+ explicit AdbForwarder(unsigned int port) : mPort(port) {}
+ std::optional<unsigned int> mPort;
+};
+std::optional<AdbForwarder> AdbForwarder::forward(unsigned int devicePort) {
+ auto result =
+ execute({"adb", "forward", "tcp:0", "tcp:" + std::to_string(devicePort)}, nullptr);
+ if (!result.ok()) {
+ ALOGE("Unable to run `adb forward tcp:0 tcp:%d`: %s", devicePort,
+ result.error().message().c_str());
+ return std::nullopt;
+ }
+ // Must end with exit code 0 (`has_value() && value() == 0`)
+ if (result->exitCode.value_or(1) != 0) {
+ ALOGE("Unable to run `adb forward tcp:0 tcp:%d`, command exits with %s", devicePort,
+ result->toString().c_str());
+ return std::nullopt;
+ }
+ if (!result->stderr.empty()) {
+ LOG_HOST("`adb forward tcp:0 tcp:%d` writes to stderr: %s", devicePort,
+ result->stderr.c_str());
+ }
+
+ unsigned int hostPort = parsePortNumber(result->stdout, "host port");
+ if (hostPort == 0) return std::nullopt;
+
+ return AdbForwarder(hostPort);
+}
+
+AdbForwarder& AdbForwarder::operator=(AdbForwarder&& other) noexcept {
+ std::swap(mPort, other.mPort);
+ return *this;
+}
+
+AdbForwarder::~AdbForwarder() {
+ if (!mPort.has_value()) return;
+
+ auto result = execute({"adb", "forward", "--remove", "tcp:" + std::to_string(*mPort)}, nullptr);
+ if (!result.ok()) {
+ ALOGE("Unable to run `adb forward --remove tcp:%d`: %s", *mPort,
+ result.error().message().c_str());
+ return;
+ }
+ // Must end with exit code 0 (`has_value() && value() == 0`)
+ if (result->exitCode.value_or(1) != 0) {
+ ALOGE("Unable to run `adb forward --remove tcp:%d`, command exits with %s", *mPort,
+ result->toString().c_str());
+ return;
+ }
+ if (!result->stderr.empty()) {
+ LOG_HOST("`adb forward --remove tcp:%d` writes to stderr: %s", *mPort,
+ result->stderr.c_str());
+ }
+
+ LOG_HOST("Successfully run `adb forward --remove tcp:%d`", *mPort);
+}
+
+void cleanupCommandResult(const void* id, void* obj, void* /* cookie */) {
+ LOG_ALWAYS_FATAL_IF(id != kDeviceServiceExtraId,
+ "cleanupCommandResult invoked with mismatched ID %p, "
+ "expected %p",
+ id, kDeviceServiceExtraId);
+ auto ptr = static_cast<CommandResult*>(obj);
+ delete ptr;
+}
+
+} // namespace
+
+sp<IBinder> getDeviceService(std::vector<std::string>&& serviceDispatcherArgs) {
+ std::vector<std::string> prefix{"adb", "shell", "servicedispatcher"};
+ serviceDispatcherArgs.insert(serviceDispatcherArgs.begin(), prefix.begin(), prefix.end());
+
+ auto result = execute(std::move(serviceDispatcherArgs), &CommandResult::stdoutEndsWithNewLine);
+ if (!result.ok()) {
+ ALOGE("%s", result.error().message().c_str());
+ return nullptr;
+ }
+
+ // `servicedispatcher` process must be alive to keep the port open.
+ if (result->exitCode.has_value()) {
+ ALOGE("Command exits with: %s", result->toString().c_str());
+ return nullptr;
+ }
+ if (!result->stderr.empty()) {
+ LOG_HOST("servicedispatcher writes to stderr: %s", result->stderr.c_str());
+ }
+
+ if (!result->stdoutEndsWithNewLine()) {
+ ALOGE("Unexpected command result: %s", result->toString().c_str());
+ return nullptr;
+ }
+
+ unsigned int devicePort = parsePortNumber(result->stdout, "device port");
+ if (devicePort == 0) return nullptr;
+
+ auto forwardResult = AdbForwarder::forward(devicePort);
+ if (!forwardResult.has_value()) {
+ return nullptr;
+ }
+ LOG_ALWAYS_FATAL_IF(!forwardResult->hostPort().has_value());
+
+ auto rpcSession = RpcSession::make();
+ if (!rpcSession->setupInetClient("127.0.0.1", *forwardResult->hostPort())) {
+ ALOGE("Unable to set up inet client on host port %u", *forwardResult->hostPort());
+ return nullptr;
+ }
+ auto binder = rpcSession->getRootObject();
+ if (binder == nullptr) {
+ ALOGE("RpcSession::getRootObject returns nullptr");
+ return nullptr;
+ }
+ binder->attachObject(kDeviceServiceExtraId,
+ static_cast<void*>(new CommandResult(std::move(*result))), nullptr,
+ &cleanupCommandResult);
+ return binder;
+}
+
+} // namespace android
diff --git a/libs/binder/ServiceManagerHost.h b/libs/binder/ServiceManagerHost.h
new file mode 100644
index 0000000..e59724c
--- /dev/null
+++ b/libs/binder/ServiceManagerHost.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2021 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-base/macros.h>
+#include <android/os/IServiceManager.h>
+
+namespace android {
+
+// Get a service on device by running servicedispatcher with the given args, e.g.
+// getDeviceService({"foo"});
+// Return nullptr on any error.
+// When the returned binder object is destroyed, remove adb forwarding and kills
+// the long-running servicedispatcher process.
+sp<IBinder> getDeviceService(std::vector<std::string>&& serviceDispatcherArgs);
+
+} // namespace android
diff --git a/libs/binder/TEST_MAPPING b/libs/binder/TEST_MAPPING
index fbbfcdc..748fa72 100644
--- a/libs/binder/TEST_MAPPING
+++ b/libs/binder/TEST_MAPPING
@@ -31,7 +31,7 @@
"name": "binderStabilityTest"
},
{
- "name": "binderUtilsTest"
+ "name": "binderUtilsHostTest"
},
{
"name": "libbinder_ndk_unit_test"
diff --git a/libs/binder/include/binder/IServiceManager.h b/libs/binder/include/binder/IServiceManager.h
index 3dbe2c4..8e46147 100644
--- a/libs/binder/include/binder/IServiceManager.h
+++ b/libs/binder/include/binder/IServiceManager.h
@@ -169,4 +169,17 @@
int32_t* outPid, int32_t* outUid);
bool checkPermission(const String16& permission, pid_t pid, uid_t uid);
+#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
+// defaultServiceManager() returns it:
+// int main() {
+// setDefaultServiceManager(createRpcDelegateServiceManager());
+// auto sm = defaultServiceManager();
+// // ...
+// }
+// Resources are cleaned up when the object is destroyed.
+sp<IServiceManager> createRpcDelegateServiceManager();
+#endif
+
} // namespace android
diff --git a/libs/binder/include/binder/LazyServiceRegistrar.h b/libs/binder/include/binder/LazyServiceRegistrar.h
index f3ba830..2e22b84 100644
--- a/libs/binder/include/binder/LazyServiceRegistrar.h
+++ b/libs/binder/include/binder/LazyServiceRegistrar.h
@@ -79,9 +79,10 @@
*/
void setActiveServicesCallback(const std::function<bool(bool)>& activeServicesCallback);
- /**
+ /**
* Try to unregister all services previously registered with 'registerService'.
- * Returns 'true' if successful.
+ * Returns 'true' if successful. This should only be called within the callback registered by
+ * setActiveServicesCallback.
*/
bool tryUnregister();