blob: b88b67d1386ceb29a3075b0788193b475691d6f2 [file] [log] [blame]
/*
* 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 <android-base/logging.h>
#include <cutils/android_filesystem_config.h>
#include <cutils/multiuser.h>
using ::android::binder::Status;
namespace android {
ServiceManager::ServiceManager(std::unique_ptr<Access>&& access) : mAccess(std::move(access)) {}
Status ServiceManager::getService(const std::string& name, sp<IBinder>* 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<IBinder>* 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<IBinder>& 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<std::string>* 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<IBinder>& who) {
for (auto it = mNameToService.begin(); it != mNameToService.end();) {
if (who == it->second.binder) {
it = mNameToService.erase(it);
} else {
++it;
}
}
}
} // namespace android