/* * Copyright (C) 2019 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 "ServiceManager.h" #include #include #include #include #include #include #include #include #include #ifndef VENDORSERVICEMANAGER #include #include #endif // !VENDORSERVICEMANAGER using ::android::binder::Status; using ::android::internal::Stability; namespace android { #ifndef VENDORSERVICEMANAGER static bool isVintfDeclared(const std::string& name) { size_t firstSlash = name.find('/'); size_t lastDot = name.rfind('.', firstSlash); if (firstSlash == std::string::npos || lastDot == std::string::npos) { LOG(ERROR) << "VINTF HALs require names in the format type/instance (e.g. " << "some.package.foo.IFoo/default) but got: " << name; return false; } const std::string package = name.substr(0, lastDot); const std::string iface = name.substr(lastDot+1, firstSlash-lastDot-1); const std::string instance = name.substr(firstSlash+1); for (const auto& manifest : { vintf::VintfObject::GetDeviceHalManifest(), vintf::VintfObject::GetFrameworkHalManifest() }) { if (manifest != nullptr && manifest->hasAidlInstance(package, iface, instance)) { return true; } } LOG(ERROR) << "Could not find " << package << "." << iface << "/" << instance << " in the VINTF manifest."; return false; } static bool meetsDeclarationRequirements(const sp& binder, const std::string& name) { if (!Stability::requiresVintfDeclaration(binder)) { return true; } return isVintfDeclared(name); } #endif // !VENDORSERVICEMANAGER ServiceManager::ServiceManager(std::unique_ptr&& access) : mAccess(std::move(access)) { #ifndef VENDORSERVICEMANAGER // can process these at any times, don't want to delay first VINTF client std::thread([] { vintf::VintfObject::GetDeviceHalManifest(); vintf::VintfObject::GetFrameworkHalManifest(); }).detach(); #endif // !VENDORSERVICEMANAGER } ServiceManager::~ServiceManager() { // this should only happen in tests for (const auto& [name, callbacks] : mNameToRegistrationCallback) { CHECK(!callbacks.empty()) << name; for (const auto& callback : callbacks) { CHECK(callback != nullptr) << name; } } for (const auto& [name, service] : mNameToService) { CHECK(service.binder != nullptr) << name; } } Status ServiceManager::getService(const std::string& name, sp* outBinder) { *outBinder = tryGetService(name, true); // returns ok regardless of result for legacy reasons return Status::ok(); } Status ServiceManager::checkService(const std::string& name, sp* outBinder) { *outBinder = tryGetService(name, false); // returns ok regardless of result for legacy reasons return Status::ok(); } sp ServiceManager::tryGetService(const std::string& name, bool startIfNotFound) { auto ctx = mAccess->getCallingContext(); sp out; Service* service = nullptr; if (auto it = mNameToService.find(name); it != mNameToService.end()) { service = &(it->second); if (!service->allowIsolated) { uid_t appid = multiuser_get_app_id(ctx.uid); bool isIsolated = appid >= AID_ISOLATED_START && appid <= AID_ISOLATED_END; if (isIsolated) { return nullptr; } } out = service->binder; } if (!mAccess->canFind(ctx, name)) { return nullptr; } if (!out && startIfNotFound) { 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; } bool isValidServiceName(const std::string& name) { if (name.size() == 0) return false; if (name.size() > 127) return false; for (char c : name) { if (c == '_' || c == '-' || c == '.' || c == '/') continue; if (c >= 'a' && c <= 'z') continue; if (c >= 'A' && c <= 'Z') continue; if (c >= '0' && c <= '9') continue; return false; } return true; } Status ServiceManager::addService(const std::string& name, const sp& binder, bool allowIsolated, int32_t dumpPriority) { auto ctx = mAccess->getCallingContext(); // apps cannot add services if (multiuser_get_app_id(ctx.uid) >= AID_APP) { return Status::fromExceptionCode(Status::EX_SECURITY); } if (!mAccess->canAdd(ctx, name)) { return Status::fromExceptionCode(Status::EX_SECURITY); } if (binder == nullptr) { return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT); } if (!isValidServiceName(name)) { LOG(ERROR) << "Invalid service name: " << name; return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT); } #ifndef VENDORSERVICEMANAGER if (!meetsDeclarationRequirements(binder, name)) { // already logged return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT); } #endif // !VENDORSERVICEMANAGER // implicitly unlinked when the binder is removed if (binder->remoteBinder() != nullptr && binder->linkToDeath(this) != OK) { LOG(ERROR) << "Could not linkToDeath when adding " << name; return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE); } auto entry = mNameToService.emplace(name, Service { .binder = binder, .allowIsolated = allowIsolated, .dumpPriority = dumpPriority, .debugPid = ctx.debugPid, }); auto it = mNameToRegistrationCallback.find(name); if (it != mNameToRegistrationCallback.end()) { for (const sp& cb : it->second) { entry.first->second.guaranteeClient = true; // permission checked in registerForNotifications cb->onRegistration(name, binder); } } return Status::ok(); } Status ServiceManager::listServices(int32_t dumpPriority, std::vector* outList) { if (!mAccess->canList(mAccess->getCallingContext())) { return Status::fromExceptionCode(Status::EX_SECURITY); } size_t toReserve = 0; for (auto const& [name, service] : mNameToService) { (void) name; if (service.dumpPriority & dumpPriority) ++toReserve; } CHECK(outList->empty()); outList->reserve(toReserve); for (auto const& [name, service] : mNameToService) { (void) service; if (service.dumpPriority & dumpPriority) { outList->push_back(name); } } return Status::ok(); } Status ServiceManager::registerForNotifications( const std::string& name, const sp& callback) { auto ctx = mAccess->getCallingContext(); if (!mAccess->canFind(ctx, name)) { return Status::fromExceptionCode(Status::EX_SECURITY); } if (!isValidServiceName(name)) { LOG(ERROR) << "Invalid service name: " << name; return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT); } if (callback == nullptr) { return Status::fromExceptionCode(Status::EX_NULL_POINTER); } if (OK != IInterface::asBinder(callback)->linkToDeath(this)) { LOG(ERROR) << "Could not linkToDeath when adding " << name; return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE); } mNameToRegistrationCallback[name].push_back(callback); if (auto it = mNameToService.find(name); it != mNameToService.end()) { const sp& binder = it->second.binder; // never null if an entry exists CHECK(binder != nullptr) << name; callback->onRegistration(name, binder); } return Status::ok(); } Status ServiceManager::unregisterForNotifications( const std::string& name, const sp& callback) { auto ctx = mAccess->getCallingContext(); if (!mAccess->canFind(ctx, name)) { return Status::fromExceptionCode(Status::EX_SECURITY); } bool found = false; auto it = mNameToRegistrationCallback.find(name); if (it != mNameToRegistrationCallback.end()) { removeRegistrationCallback(IInterface::asBinder(callback), &it, &found); } if (!found) { LOG(ERROR) << "Trying to unregister callback, but none exists " << name; return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE); } return Status::ok(); } Status ServiceManager::isDeclared(const std::string& name, bool* outReturn) { auto ctx = mAccess->getCallingContext(); if (!mAccess->canFind(ctx, name)) { return Status::fromExceptionCode(Status::EX_SECURITY); } *outReturn = false; #ifndef VENDORSERVICEMANAGER *outReturn = isVintfDeclared(name); #endif return Status::ok(); } void ServiceManager::removeRegistrationCallback(const wp& who, ServiceCallbackMap::iterator* it, bool* found) { std::vector>& listeners = (*it)->second; for (auto lit = listeners.begin(); lit != listeners.end();) { if (IInterface::asBinder(*lit) == who) { if(found) *found = true; lit = listeners.erase(lit); } else { ++lit; } } if (listeners.empty()) { *it = mNameToRegistrationCallback.erase(*it); } else { (*it)++; } } void ServiceManager::binderDied(const wp& who) { for (auto it = mNameToService.begin(); it != mNameToService.end();) { if (who == it->second.binder) { it = mNameToService.erase(it); } else { ++it; } } for (auto it = mNameToRegistrationCallback.begin(); it != mNameToRegistrationCallback.end();) { removeRegistrationCallback(who, &it, nullptr /*found*/); } for (auto it = mNameToClientCallback.begin(); it != mNameToClientCallback.end();) { removeClientCallback(who, &it); } } void ServiceManager::tryStartService(const std::string& name) { ALOGI("Since '%s' could not be found, trying to start it as a lazy AIDL service", name.c_str()); std::thread([=] { (void)base::SetProperty("ctl.interface_start", "aidl/" + name); }).detach(); } Status ServiceManager::registerClientCallback(const std::string& name, const sp& service, const sp& 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& who, ClientCallbackMap::iterator* it) { std::vector>& 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 = binder->remoteBinder(); if (bpBinder == nullptr) return -1; return ProcessState::self()->getStrongRefCountForNodeByHandle(bpBinder->handle()); } void ServiceManager::handleClientCallbacks() { for (const auto& [name, service] : mNameToService) { handleServiceClientCallback(name, true); } } ssize_t ServiceManager::handleServiceClientCallback(const std::string& serviceName, bool isCalledOnInterval) { 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; } // only send notifications if this was called via the interval checking workflow if (isCalledOnInterval) { 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& 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 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, false); // 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