/* * 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 using ::android::binder::Status; namespace android { ServiceManager::ServiceManager(std::unique_ptr&& access) : mAccess(std::move(access)) {} Status ServiceManager::getService(const std::string& name, sp* outBinder) { // Servicemanager is single-threaded and cannot block. This method exists for legacy reasons. return checkService(name, outBinder); } Status ServiceManager::checkService(const std::string& name, sp* outBinder) { auto ctx = mAccess->getCallingContext(name); auto it = mNameToService.find(name); if (it == mNameToService.end()) { *outBinder = nullptr; return Status::ok(); } 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) { *outBinder = nullptr; return Status::ok(); } } // TODO(b/136023468): move this check to be first if (!mAccess->canFind(ctx)) { // returns ok and null for legacy reasons *outBinder = nullptr; return Status::ok(); } *outBinder = service.binder; return Status::ok(); } Status ServiceManager::addService(const std::string& name, const sp& binder, bool allowIsolated, int32_t dumpPriority) { auto ctx = mAccess->getCallingContext(name); // apps cannot add services if (multiuser_get_app_id(ctx.uid) >= AID_APP) { return Status::fromExceptionCode(Status::EX_SECURITY); } if (!mAccess->canAdd(ctx)) { return Status::fromExceptionCode(Status::EX_SECURITY); } if (binder == nullptr) { return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT); } // match legacy rules if (name.size() == 0 || name.size() > 127) { return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT); } if (OK != binder->linkToDeath(this)) { LOG(ERROR) << "Could not linkToDeath when adding " << name; return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE); } auto it = mNameToService.find(name); if (it != mNameToService.end()) { if (OK != it->second.binder->unlinkToDeath(this)) { LOG(WARNING) << "Could not unlinkToDeath when adding " << name; } } mNameToService[name] = Service { .binder = binder, .allowIsolated = allowIsolated, .dumpPriority = dumpPriority, }; 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(); } 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; } } } } // namespace android