Loading cmds/servicemanager/ServiceManager.cpp +201 −6 Original line number Diff line number Diff line Loading @@ -18,6 +18,9 @@ #include <android-base/logging.h> #include <android-base/properties.h> #include <binder/BpBinder.h> #include <binder/IPCThreadState.h> #include <binder/ProcessState.h> #include <binder/Stability.h> #include <cutils/android_filesystem_config.h> #include <cutils/multiuser.h> Loading Loading @@ -108,10 +111,11 @@ sp<IBinder> ServiceManager::tryGetService(const std::string& name, bool startIfN auto ctx = mAccess->getCallingContext(); sp<IBinder> out; Service* service = nullptr; if (auto it = mNameToService.find(name); it != mNameToService.end()) { const Service& service = it->second; service = &(it->second); if (!service.allowIsolated) { if (!service->allowIsolated) { uid_t appid = multiuser_get_app_id(ctx.uid); bool isIsolated = appid >= AID_ISOLATED_START && appid <= AID_ISOLATED_END; Loading @@ -119,7 +123,7 @@ sp<IBinder> ServiceManager::tryGetService(const std::string& name, bool startIfN return nullptr; } } out = service.binder; out = service->binder; } if (!mAccess->canFind(ctx, name)) { Loading @@ -130,6 +134,12 @@ sp<IBinder> ServiceManager::tryGetService(const std::string& name, bool startIfN tryStartService(name); } if (out) { // Setting this guarantee each time we hand out a binder ensures that the client-checking // loop knows about the event even if the client immediately drops the service service->guaranteeClient = true; } return out; } Loading Loading @@ -182,15 +192,17 @@ Status ServiceManager::addService(const std::string& name, const sp<IBinder>& bi return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE); } mNameToService[name] = Service { auto entry = mNameToService.emplace(name, Service { .binder = binder, .allowIsolated = allowIsolated, .dumpPriority = dumpPriority, }; .debugPid = ctx.debugPid, }); auto it = mNameToCallback.find(name); if (it != mNameToCallback.end()) { for (const sp<IServiceCallback>& cb : it->second) { entry.first->second.guaranteeClient = true; // permission checked in registerForNotifications cb->onRegistration(name, binder); } Loading Loading @@ -330,6 +342,10 @@ void ServiceManager::binderDied(const wp<IBinder>& who) { for (auto it = mNameToCallback.begin(); it != mNameToCallback.end();) { removeCallback(who, &it, nullptr /*found*/); } for (auto it = mNameToClientCallback.begin(); it != mNameToClientCallback.end();) { removeClientCallback(who, &it); } } void ServiceManager::tryStartService(const std::string& name) { Loading @@ -341,4 +357,183 @@ void ServiceManager::tryStartService(const std::string& name) { }).detach(); } Status ServiceManager::registerClientCallback(const std::string& name, const sp<IBinder>& service, const sp<IClientCallback>& cb) { if (cb == nullptr) { return Status::fromExceptionCode(Status::EX_NULL_POINTER); } auto ctx = mAccess->getCallingContext(); if (!mAccess->canAdd(ctx, name)) { return Status::fromExceptionCode(Status::EX_SECURITY); } auto serviceIt = mNameToService.find(name); if (serviceIt == mNameToService.end()) { LOG(ERROR) << "Could not add callback for nonexistent service: " << name; return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT); } if (serviceIt->second.debugPid != IPCThreadState::self()->getCallingPid()) { LOG(WARNING) << "Only a server can register for client callbacks (for " << name << ")"; return Status::fromExceptionCode(Status::EX_UNSUPPORTED_OPERATION); } if (serviceIt->second.binder != service) { LOG(WARNING) << "Tried to register client callback for " << name << " but a different service is registered under this name."; return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT); } if (OK != IInterface::asBinder(cb)->linkToDeath(this)) { LOG(ERROR) << "Could not linkToDeath when adding client callback for " << name; return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE); } mNameToClientCallback[name].push_back(cb); return Status::ok(); } void ServiceManager::removeClientCallback(const wp<IBinder>& who, ClientCallbackMap::iterator* it) { std::vector<sp<IClientCallback>>& listeners = (*it)->second; for (auto lit = listeners.begin(); lit != listeners.end();) { if (IInterface::asBinder(*lit) == who) { lit = listeners.erase(lit); } else { ++lit; } } if (listeners.empty()) { *it = mNameToClientCallback.erase(*it); } else { (*it)++; } } ssize_t ServiceManager::Service::getNodeStrongRefCount() { sp<BpBinder> bpBinder = binder->remoteBinder(); if (bpBinder == nullptr) return -1; return ProcessState::self()->getStrongRefCountForNodeByHandle(bpBinder->handle()); } void ServiceManager::handleClientCallbacks() { for (const auto& [name, service] : mNameToService) { handleServiceClientCallback(name); } } ssize_t ServiceManager::handleServiceClientCallback(const std::string& serviceName) { auto serviceIt = mNameToService.find(serviceName); if (serviceIt == mNameToService.end() || mNameToClientCallback.count(serviceName) < 1) { return -1; } Service& service = serviceIt->second; ssize_t count = service.getNodeStrongRefCount(); // binder driver doesn't support this feature if (count == -1) return count; bool hasClients = count > 1; // this process holds a strong count if (service.guaranteeClient) { // we have no record of this client if (!service.hasClients && !hasClients) { sendClientCallbackNotifications(serviceName, true); } // guarantee is temporary service.guaranteeClient = false; } if (hasClients && !service.hasClients) { // client was retrieved in some other way sendClientCallbackNotifications(serviceName, true); } // there are no more clients, but the callback has not been called yet if (!hasClients && service.hasClients) { sendClientCallbackNotifications(serviceName, false); } return count; } void ServiceManager::sendClientCallbackNotifications(const std::string& serviceName, bool hasClients) { auto serviceIt = mNameToService.find(serviceName); if (serviceIt == mNameToService.end()) { LOG(WARNING) << "sendClientCallbackNotifications could not find service " << serviceName; return; } Service& service = serviceIt->second; CHECK(hasClients != service.hasClients) << "Record shows: " << service.hasClients << " so we can't tell clients again that we have client: " << hasClients; LOG(INFO) << "Notifying " << serviceName << " they have clients: " << hasClients; auto ccIt = mNameToClientCallback.find(serviceName); CHECK(ccIt != mNameToClientCallback.end()) << "sendClientCallbackNotifications could not find callbacks for service "; for (const auto& callback : ccIt->second) { callback->onClients(service.binder, hasClients); } service.hasClients = hasClients; } Status ServiceManager::tryUnregisterService(const std::string& name, const sp<IBinder>& binder) { if (binder == nullptr) { return Status::fromExceptionCode(Status::EX_NULL_POINTER); } auto ctx = mAccess->getCallingContext(); if (!mAccess->canAdd(ctx, name)) { return Status::fromExceptionCode(Status::EX_SECURITY); } auto serviceIt = mNameToService.find(name); if (serviceIt == mNameToService.end()) { LOG(WARNING) << "Tried to unregister " << name << ", but that service wasn't registered to begin with."; return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE); } if (serviceIt->second.debugPid != IPCThreadState::self()->getCallingPid()) { LOG(WARNING) << "Only a server can unregister itself (for " << name << ")"; return Status::fromExceptionCode(Status::EX_UNSUPPORTED_OPERATION); } sp<IBinder> storedBinder = serviceIt->second.binder; if (binder != storedBinder) { LOG(WARNING) << "Tried to unregister " << name << ", but a different service is registered under this name."; return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE); } int clients = handleServiceClientCallback(name); // clients < 0: feature not implemented or other error. Assume clients. // Otherwise: // - kernel driver will hold onto one refcount (during this transaction) // - servicemanager has a refcount (guaranteed by this transaction) // So, if clients > 2, then at least one other service on the system must hold a refcount. if (clients < 0 || clients > 2) { // client callbacks are either disabled or there are other clients LOG(INFO) << "Tried to unregister " << name << " but there are clients: " << clients; return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE); } mNameToService.erase(name); return Status::ok(); } } // namespace android No newline at end of file cmds/servicemanager/ServiceManager.h +22 −1 Original line number Diff line number Diff line Loading @@ -17,12 +17,14 @@ #pragma once #include <android/os/BnServiceManager.h> #include <android/os/IClientCallback.h> #include <android/os/IServiceCallback.h> #include "Access.h" namespace android { using os::IClientCallback; using os::IServiceCallback; class ServiceManager : public os::BnServiceManager, public IBinder::DeathRecipient { Loading @@ -40,9 +42,13 @@ public: const sp<IServiceCallback>& callback) override; binder::Status unregisterForNotifications(const std::string& name, const sp<IServiceCallback>& callback) override; binder::Status isDeclared(const std::string& name, bool* outReturn) override; binder::Status isDeclared(const std::string& name, bool* outReturn) override; binder::Status registerClientCallback(const std::string& name, const sp<IBinder>& service, const sp<IClientCallback>& cb) override; binder::Status tryUnregisterService(const std::string& name, const sp<IBinder>& binder) override; void binderDied(const wp<IBinder>& who) override; void handleClientCallbacks(); protected: virtual void tryStartService(const std::string& name); Loading @@ -52,9 +58,16 @@ private: sp<IBinder> binder; // not null bool allowIsolated; int32_t dumpPriority; bool hasClients = false; // notifications sent on true -> false. bool guaranteeClient = false; // forces the client check to true pid_t debugPid = 0; // the process in which this service runs // the number of clients of the service, including servicemanager itself ssize_t getNodeStrongRefCount(); }; using CallbackMap = std::map<std::string, std::vector<sp<IServiceCallback>>>; using ClientCallbackMap = std::map<std::string, std::vector<sp<IClientCallback>>>; using ServiceMap = std::map<std::string, Service>; // removes a callback from mNameToCallback, removing it if the vector is empty Loading @@ -62,10 +75,18 @@ private: void removeCallback(const wp<IBinder>& who, CallbackMap::iterator* it, bool* found); ssize_t handleServiceClientCallback(const std::string& serviceName); // Also updates mHasClients (of what the last callback was) void sendClientCallbackNotifications(const std::string& serviceName, bool hasClients); // removes a callback from mNameToClientCallback, deleting the entry if the vector is empty // this updates the iterator to the next location void removeClientCallback(const wp<IBinder>& who, ClientCallbackMap::iterator* it); sp<IBinder> tryGetService(const std::string& name, bool startIfNotFound); CallbackMap mNameToCallback; ServiceMap mNameToService; ClientCallbackMap mNameToClientCallback; std::unique_ptr<Access> mAccess; }; Loading cmds/servicemanager/main.cpp +91 −1 Original line number Diff line number Diff line Loading @@ -18,18 +18,101 @@ #include <binder/IPCThreadState.h> #include <binder/ProcessState.h> #include <binder/Status.h> #include <sys/timerfd.h> #include <utils/Looper.h> #include <utils/StrongPointer.h> #include "Access.h" #include "ServiceManager.h" using ::android::Access; using ::android::sp; using ::android::Looper; using ::android::LooperCallback; using ::android::ProcessState; using ::android::IPCThreadState; using ::android::ProcessState; using ::android::ServiceManager; using ::android::os::IServiceManager; using ::android::sp; class BinderCallback : public LooperCallback { public: static sp<BinderCallback> setupTo(const sp<Looper>& looper) { sp<BinderCallback> cb = new BinderCallback; int binder_fd = -1; IPCThreadState::self()->setupPolling(&binder_fd); LOG_ALWAYS_FATAL_IF(binder_fd < 0, "Failed to setupPolling: %d", binder_fd); // Flush after setupPolling(), to make sure the binder driver // knows about this thread handling commands. IPCThreadState::self()->flushCommands(); int ret = looper->addFd(binder_fd, Looper::POLL_CALLBACK, Looper::EVENT_INPUT, cb, nullptr /*data*/); LOG_ALWAYS_FATAL_IF(ret != 1, "Failed to add binder FD to Looper"); return cb; } int handleEvent(int /* fd */, int /* events */, void* /* data */) override { IPCThreadState::self()->handlePolledCommands(); return 1; // Continue receiving callbacks. } }; // LooperCallback for IClientCallback class ClientCallbackCallback : public LooperCallback { public: static sp<ClientCallbackCallback> setupTo(const sp<Looper>& looper, const sp<ServiceManager>& manager) { sp<ClientCallbackCallback> cb = new ClientCallbackCallback(manager); int fdTimer = timerfd_create(CLOCK_MONOTONIC, 0 /*flags*/); LOG_ALWAYS_FATAL_IF(fdTimer < 0, "Failed to timerfd_create: fd: %d err: %d", fdTimer, errno); itimerspec timespec { .it_interval = { .tv_sec = 5, .tv_nsec = 0, }, .it_value = { .tv_sec = 5, .tv_nsec = 0, }, }; int timeRes = timerfd_settime(fdTimer, 0 /*flags*/, ×pec, nullptr); LOG_ALWAYS_FATAL_IF(timeRes < 0, "Failed to timerfd_settime: res: %d err: %d", timeRes, errno); int addRes = looper->addFd(fdTimer, Looper::POLL_CALLBACK, Looper::EVENT_INPUT, cb, nullptr); LOG_ALWAYS_FATAL_IF(addRes != 1, "Failed to add client callback FD to Looper"); return cb; } int handleEvent(int fd, int /*events*/, void* /*data*/) override { uint64_t expirations; int ret = read(fd, &expirations, sizeof(expirations)); if (ret != sizeof(expirations)) { ALOGE("Read failed to callback FD: ret: %d err: %d", ret, errno); } mManager->handleClientCallbacks(); return 1; // Continue receiving callbacks. } private: ClientCallbackCallback(const sp<ServiceManager>& manager) : mManager(manager) {} sp<ServiceManager> mManager; }; int main(int argc, char** argv) { if (argc > 2) { LOG(FATAL) << "usage: " << argv[0] << " [binder driver]"; Loading @@ -49,7 +132,14 @@ int main(int argc, char** argv) { IPCThreadState::self()->setTheContextObject(manager); ps->becomeContextManager(nullptr, nullptr); IPCThreadState::self()->joinThreadPool(); sp<Looper> looper = Looper::prepare(false /*allowNonCallbacks*/); BinderCallback::setupTo(looper); ClientCallbackCallback::setupTo(looper, manager); while(true) { looper->pollAll(-1); } // should not be reached return EXIT_FAILURE; Loading libs/binder/Android.bp +2 −0 Original line number Diff line number Diff line Loading @@ -90,6 +90,7 @@ cc_library { "IResultReceiver.cpp", "IServiceManager.cpp", "IShellCallback.cpp", "LazyServiceRegistrar.cpp", "MemoryBase.cpp", "MemoryDealer.cpp", "MemoryHeapBase.cpp", Loading Loading @@ -160,6 +161,7 @@ filegroup { name: "libbinder_aidl", srcs: [ "aidl/android/content/pm/IPackageManagerNative.aidl", "aidl/android/os/IClientCallback.aidl", "aidl/android/os/IServiceCallback.aidl", "aidl/android/os/IServiceManager.aidl", ], Loading libs/binder/IServiceManager.cpp +2 −0 Original line number Diff line number Diff line Loading @@ -271,6 +271,8 @@ sp<IBinder> ServiceManagerShim::waitForService(const String16& name16) std::unique_lock<std::mutex> lock(mMutex); mBinder = binder; lock.unlock(); // Flushing here helps ensure the service's ref count remains accurate IPCThreadState::self()->flushCommands(); mCv.notify_one(); return Status::ok(); } Loading Loading
cmds/servicemanager/ServiceManager.cpp +201 −6 Original line number Diff line number Diff line Loading @@ -18,6 +18,9 @@ #include <android-base/logging.h> #include <android-base/properties.h> #include <binder/BpBinder.h> #include <binder/IPCThreadState.h> #include <binder/ProcessState.h> #include <binder/Stability.h> #include <cutils/android_filesystem_config.h> #include <cutils/multiuser.h> Loading Loading @@ -108,10 +111,11 @@ sp<IBinder> ServiceManager::tryGetService(const std::string& name, bool startIfN auto ctx = mAccess->getCallingContext(); sp<IBinder> out; Service* service = nullptr; if (auto it = mNameToService.find(name); it != mNameToService.end()) { const Service& service = it->second; service = &(it->second); if (!service.allowIsolated) { if (!service->allowIsolated) { uid_t appid = multiuser_get_app_id(ctx.uid); bool isIsolated = appid >= AID_ISOLATED_START && appid <= AID_ISOLATED_END; Loading @@ -119,7 +123,7 @@ sp<IBinder> ServiceManager::tryGetService(const std::string& name, bool startIfN return nullptr; } } out = service.binder; out = service->binder; } if (!mAccess->canFind(ctx, name)) { Loading @@ -130,6 +134,12 @@ sp<IBinder> ServiceManager::tryGetService(const std::string& name, bool startIfN tryStartService(name); } if (out) { // Setting this guarantee each time we hand out a binder ensures that the client-checking // loop knows about the event even if the client immediately drops the service service->guaranteeClient = true; } return out; } Loading Loading @@ -182,15 +192,17 @@ Status ServiceManager::addService(const std::string& name, const sp<IBinder>& bi return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE); } mNameToService[name] = Service { auto entry = mNameToService.emplace(name, Service { .binder = binder, .allowIsolated = allowIsolated, .dumpPriority = dumpPriority, }; .debugPid = ctx.debugPid, }); auto it = mNameToCallback.find(name); if (it != mNameToCallback.end()) { for (const sp<IServiceCallback>& cb : it->second) { entry.first->second.guaranteeClient = true; // permission checked in registerForNotifications cb->onRegistration(name, binder); } Loading Loading @@ -330,6 +342,10 @@ void ServiceManager::binderDied(const wp<IBinder>& who) { for (auto it = mNameToCallback.begin(); it != mNameToCallback.end();) { removeCallback(who, &it, nullptr /*found*/); } for (auto it = mNameToClientCallback.begin(); it != mNameToClientCallback.end();) { removeClientCallback(who, &it); } } void ServiceManager::tryStartService(const std::string& name) { Loading @@ -341,4 +357,183 @@ void ServiceManager::tryStartService(const std::string& name) { }).detach(); } Status ServiceManager::registerClientCallback(const std::string& name, const sp<IBinder>& service, const sp<IClientCallback>& cb) { if (cb == nullptr) { return Status::fromExceptionCode(Status::EX_NULL_POINTER); } auto ctx = mAccess->getCallingContext(); if (!mAccess->canAdd(ctx, name)) { return Status::fromExceptionCode(Status::EX_SECURITY); } auto serviceIt = mNameToService.find(name); if (serviceIt == mNameToService.end()) { LOG(ERROR) << "Could not add callback for nonexistent service: " << name; return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT); } if (serviceIt->second.debugPid != IPCThreadState::self()->getCallingPid()) { LOG(WARNING) << "Only a server can register for client callbacks (for " << name << ")"; return Status::fromExceptionCode(Status::EX_UNSUPPORTED_OPERATION); } if (serviceIt->second.binder != service) { LOG(WARNING) << "Tried to register client callback for " << name << " but a different service is registered under this name."; return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT); } if (OK != IInterface::asBinder(cb)->linkToDeath(this)) { LOG(ERROR) << "Could not linkToDeath when adding client callback for " << name; return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE); } mNameToClientCallback[name].push_back(cb); return Status::ok(); } void ServiceManager::removeClientCallback(const wp<IBinder>& who, ClientCallbackMap::iterator* it) { std::vector<sp<IClientCallback>>& listeners = (*it)->second; for (auto lit = listeners.begin(); lit != listeners.end();) { if (IInterface::asBinder(*lit) == who) { lit = listeners.erase(lit); } else { ++lit; } } if (listeners.empty()) { *it = mNameToClientCallback.erase(*it); } else { (*it)++; } } ssize_t ServiceManager::Service::getNodeStrongRefCount() { sp<BpBinder> bpBinder = binder->remoteBinder(); if (bpBinder == nullptr) return -1; return ProcessState::self()->getStrongRefCountForNodeByHandle(bpBinder->handle()); } void ServiceManager::handleClientCallbacks() { for (const auto& [name, service] : mNameToService) { handleServiceClientCallback(name); } } ssize_t ServiceManager::handleServiceClientCallback(const std::string& serviceName) { auto serviceIt = mNameToService.find(serviceName); if (serviceIt == mNameToService.end() || mNameToClientCallback.count(serviceName) < 1) { return -1; } Service& service = serviceIt->second; ssize_t count = service.getNodeStrongRefCount(); // binder driver doesn't support this feature if (count == -1) return count; bool hasClients = count > 1; // this process holds a strong count if (service.guaranteeClient) { // we have no record of this client if (!service.hasClients && !hasClients) { sendClientCallbackNotifications(serviceName, true); } // guarantee is temporary service.guaranteeClient = false; } if (hasClients && !service.hasClients) { // client was retrieved in some other way sendClientCallbackNotifications(serviceName, true); } // there are no more clients, but the callback has not been called yet if (!hasClients && service.hasClients) { sendClientCallbackNotifications(serviceName, false); } return count; } void ServiceManager::sendClientCallbackNotifications(const std::string& serviceName, bool hasClients) { auto serviceIt = mNameToService.find(serviceName); if (serviceIt == mNameToService.end()) { LOG(WARNING) << "sendClientCallbackNotifications could not find service " << serviceName; return; } Service& service = serviceIt->second; CHECK(hasClients != service.hasClients) << "Record shows: " << service.hasClients << " so we can't tell clients again that we have client: " << hasClients; LOG(INFO) << "Notifying " << serviceName << " they have clients: " << hasClients; auto ccIt = mNameToClientCallback.find(serviceName); CHECK(ccIt != mNameToClientCallback.end()) << "sendClientCallbackNotifications could not find callbacks for service "; for (const auto& callback : ccIt->second) { callback->onClients(service.binder, hasClients); } service.hasClients = hasClients; } Status ServiceManager::tryUnregisterService(const std::string& name, const sp<IBinder>& binder) { if (binder == nullptr) { return Status::fromExceptionCode(Status::EX_NULL_POINTER); } auto ctx = mAccess->getCallingContext(); if (!mAccess->canAdd(ctx, name)) { return Status::fromExceptionCode(Status::EX_SECURITY); } auto serviceIt = mNameToService.find(name); if (serviceIt == mNameToService.end()) { LOG(WARNING) << "Tried to unregister " << name << ", but that service wasn't registered to begin with."; return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE); } if (serviceIt->second.debugPid != IPCThreadState::self()->getCallingPid()) { LOG(WARNING) << "Only a server can unregister itself (for " << name << ")"; return Status::fromExceptionCode(Status::EX_UNSUPPORTED_OPERATION); } sp<IBinder> storedBinder = serviceIt->second.binder; if (binder != storedBinder) { LOG(WARNING) << "Tried to unregister " << name << ", but a different service is registered under this name."; return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE); } int clients = handleServiceClientCallback(name); // clients < 0: feature not implemented or other error. Assume clients. // Otherwise: // - kernel driver will hold onto one refcount (during this transaction) // - servicemanager has a refcount (guaranteed by this transaction) // So, if clients > 2, then at least one other service on the system must hold a refcount. if (clients < 0 || clients > 2) { // client callbacks are either disabled or there are other clients LOG(INFO) << "Tried to unregister " << name << " but there are clients: " << clients; return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE); } mNameToService.erase(name); return Status::ok(); } } // namespace android No newline at end of file
cmds/servicemanager/ServiceManager.h +22 −1 Original line number Diff line number Diff line Loading @@ -17,12 +17,14 @@ #pragma once #include <android/os/BnServiceManager.h> #include <android/os/IClientCallback.h> #include <android/os/IServiceCallback.h> #include "Access.h" namespace android { using os::IClientCallback; using os::IServiceCallback; class ServiceManager : public os::BnServiceManager, public IBinder::DeathRecipient { Loading @@ -40,9 +42,13 @@ public: const sp<IServiceCallback>& callback) override; binder::Status unregisterForNotifications(const std::string& name, const sp<IServiceCallback>& callback) override; binder::Status isDeclared(const std::string& name, bool* outReturn) override; binder::Status isDeclared(const std::string& name, bool* outReturn) override; binder::Status registerClientCallback(const std::string& name, const sp<IBinder>& service, const sp<IClientCallback>& cb) override; binder::Status tryUnregisterService(const std::string& name, const sp<IBinder>& binder) override; void binderDied(const wp<IBinder>& who) override; void handleClientCallbacks(); protected: virtual void tryStartService(const std::string& name); Loading @@ -52,9 +58,16 @@ private: sp<IBinder> binder; // not null bool allowIsolated; int32_t dumpPriority; bool hasClients = false; // notifications sent on true -> false. bool guaranteeClient = false; // forces the client check to true pid_t debugPid = 0; // the process in which this service runs // the number of clients of the service, including servicemanager itself ssize_t getNodeStrongRefCount(); }; using CallbackMap = std::map<std::string, std::vector<sp<IServiceCallback>>>; using ClientCallbackMap = std::map<std::string, std::vector<sp<IClientCallback>>>; using ServiceMap = std::map<std::string, Service>; // removes a callback from mNameToCallback, removing it if the vector is empty Loading @@ -62,10 +75,18 @@ private: void removeCallback(const wp<IBinder>& who, CallbackMap::iterator* it, bool* found); ssize_t handleServiceClientCallback(const std::string& serviceName); // Also updates mHasClients (of what the last callback was) void sendClientCallbackNotifications(const std::string& serviceName, bool hasClients); // removes a callback from mNameToClientCallback, deleting the entry if the vector is empty // this updates the iterator to the next location void removeClientCallback(const wp<IBinder>& who, ClientCallbackMap::iterator* it); sp<IBinder> tryGetService(const std::string& name, bool startIfNotFound); CallbackMap mNameToCallback; ServiceMap mNameToService; ClientCallbackMap mNameToClientCallback; std::unique_ptr<Access> mAccess; }; Loading
cmds/servicemanager/main.cpp +91 −1 Original line number Diff line number Diff line Loading @@ -18,18 +18,101 @@ #include <binder/IPCThreadState.h> #include <binder/ProcessState.h> #include <binder/Status.h> #include <sys/timerfd.h> #include <utils/Looper.h> #include <utils/StrongPointer.h> #include "Access.h" #include "ServiceManager.h" using ::android::Access; using ::android::sp; using ::android::Looper; using ::android::LooperCallback; using ::android::ProcessState; using ::android::IPCThreadState; using ::android::ProcessState; using ::android::ServiceManager; using ::android::os::IServiceManager; using ::android::sp; class BinderCallback : public LooperCallback { public: static sp<BinderCallback> setupTo(const sp<Looper>& looper) { sp<BinderCallback> cb = new BinderCallback; int binder_fd = -1; IPCThreadState::self()->setupPolling(&binder_fd); LOG_ALWAYS_FATAL_IF(binder_fd < 0, "Failed to setupPolling: %d", binder_fd); // Flush after setupPolling(), to make sure the binder driver // knows about this thread handling commands. IPCThreadState::self()->flushCommands(); int ret = looper->addFd(binder_fd, Looper::POLL_CALLBACK, Looper::EVENT_INPUT, cb, nullptr /*data*/); LOG_ALWAYS_FATAL_IF(ret != 1, "Failed to add binder FD to Looper"); return cb; } int handleEvent(int /* fd */, int /* events */, void* /* data */) override { IPCThreadState::self()->handlePolledCommands(); return 1; // Continue receiving callbacks. } }; // LooperCallback for IClientCallback class ClientCallbackCallback : public LooperCallback { public: static sp<ClientCallbackCallback> setupTo(const sp<Looper>& looper, const sp<ServiceManager>& manager) { sp<ClientCallbackCallback> cb = new ClientCallbackCallback(manager); int fdTimer = timerfd_create(CLOCK_MONOTONIC, 0 /*flags*/); LOG_ALWAYS_FATAL_IF(fdTimer < 0, "Failed to timerfd_create: fd: %d err: %d", fdTimer, errno); itimerspec timespec { .it_interval = { .tv_sec = 5, .tv_nsec = 0, }, .it_value = { .tv_sec = 5, .tv_nsec = 0, }, }; int timeRes = timerfd_settime(fdTimer, 0 /*flags*/, ×pec, nullptr); LOG_ALWAYS_FATAL_IF(timeRes < 0, "Failed to timerfd_settime: res: %d err: %d", timeRes, errno); int addRes = looper->addFd(fdTimer, Looper::POLL_CALLBACK, Looper::EVENT_INPUT, cb, nullptr); LOG_ALWAYS_FATAL_IF(addRes != 1, "Failed to add client callback FD to Looper"); return cb; } int handleEvent(int fd, int /*events*/, void* /*data*/) override { uint64_t expirations; int ret = read(fd, &expirations, sizeof(expirations)); if (ret != sizeof(expirations)) { ALOGE("Read failed to callback FD: ret: %d err: %d", ret, errno); } mManager->handleClientCallbacks(); return 1; // Continue receiving callbacks. } private: ClientCallbackCallback(const sp<ServiceManager>& manager) : mManager(manager) {} sp<ServiceManager> mManager; }; int main(int argc, char** argv) { if (argc > 2) { LOG(FATAL) << "usage: " << argv[0] << " [binder driver]"; Loading @@ -49,7 +132,14 @@ int main(int argc, char** argv) { IPCThreadState::self()->setTheContextObject(manager); ps->becomeContextManager(nullptr, nullptr); IPCThreadState::self()->joinThreadPool(); sp<Looper> looper = Looper::prepare(false /*allowNonCallbacks*/); BinderCallback::setupTo(looper); ClientCallbackCallback::setupTo(looper, manager); while(true) { looper->pollAll(-1); } // should not be reached return EXIT_FAILURE; Loading
libs/binder/Android.bp +2 −0 Original line number Diff line number Diff line Loading @@ -90,6 +90,7 @@ cc_library { "IResultReceiver.cpp", "IServiceManager.cpp", "IShellCallback.cpp", "LazyServiceRegistrar.cpp", "MemoryBase.cpp", "MemoryDealer.cpp", "MemoryHeapBase.cpp", Loading Loading @@ -160,6 +161,7 @@ filegroup { name: "libbinder_aidl", srcs: [ "aidl/android/content/pm/IPackageManagerNative.aidl", "aidl/android/os/IClientCallback.aidl", "aidl/android/os/IServiceCallback.aidl", "aidl/android/os/IServiceManager.aidl", ], Loading
libs/binder/IServiceManager.cpp +2 −0 Original line number Diff line number Diff line Loading @@ -271,6 +271,8 @@ sp<IBinder> ServiceManagerShim::waitForService(const String16& name16) std::unique_lock<std::mutex> lock(mMutex); mBinder = binder; lock.unlock(); // Flushing here helps ensure the service's ref count remains accurate IPCThreadState::self()->flushCommands(); mCv.notify_one(); return Status::ok(); } Loading