/* * 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 #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] : mNameToCallback) { 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; if (auto it = mNameToService.find(name); it != mNameToService.end()) { const Service& 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); } 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); } mNameToService[name] = Service { .binder = binder, .allowIsolated = allowIsolated, .dumpPriority = dumpPriority, }; auto it = mNameToCallback.find(name); if (it != mNameToCallback.end()) { for (const sp& cb : it->second) { // 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); } mNameToCallback[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 = mNameToCallback.find(name); if (it != mNameToCallback.end()) { removeCallback(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::removeCallback(const wp& who, CallbackMap::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 = mNameToCallback.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 = mNameToCallback.begin(); it != mNameToCallback.end();) { removeCallback(who, &it, nullptr /*found*/); } } 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(); } } // namespace android