blob: b88b67d1386ceb29a3075b0788193b475691d6f2 [file] [log] [blame]
Steven Moreland80e1e6d2019-06-21 12:35:59 -07001/*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "ServiceManager.h"
18
19#include <android-base/logging.h>
20#include <cutils/android_filesystem_config.h>
21#include <cutils/multiuser.h>
22
23using ::android::binder::Status;
24
25namespace android {
26
27ServiceManager::ServiceManager(std::unique_ptr<Access>&& access) : mAccess(std::move(access)) {}
28
29Status ServiceManager::getService(const std::string& name, sp<IBinder>* outBinder) {
30 // Servicemanager is single-threaded and cannot block. This method exists for legacy reasons.
31 return checkService(name, outBinder);
32}
33
34Status ServiceManager::checkService(const std::string& name, sp<IBinder>* outBinder) {
35 auto ctx = mAccess->getCallingContext(name);
36
37 auto it = mNameToService.find(name);
38 if (it == mNameToService.end()) {
39 *outBinder = nullptr;
40 return Status::ok();
41 }
42
43 const Service& service = it->second;
44
45 if (!service.allowIsolated) {
46 uid_t appid = multiuser_get_app_id(ctx.uid);
47 bool isIsolated = appid >= AID_ISOLATED_START && appid <= AID_ISOLATED_END;
48
49 if (isIsolated) {
50 *outBinder = nullptr;
51 return Status::ok();
52 }
53 }
54
55 // TODO(b/136023468): move this check to be first
56 if (!mAccess->canFind(ctx)) {
57 // returns ok and null for legacy reasons
58 *outBinder = nullptr;
59 return Status::ok();
60 }
61
62 *outBinder = service.binder;
63 return Status::ok();
64}
65
66Status ServiceManager::addService(const std::string& name, const sp<IBinder>& binder, bool allowIsolated, int32_t dumpPriority) {
67 auto ctx = mAccess->getCallingContext(name);
68
69 // apps cannot add services
70 if (multiuser_get_app_id(ctx.uid) >= AID_APP) {
71 return Status::fromExceptionCode(Status::EX_SECURITY);
72 }
73
74 if (!mAccess->canAdd(ctx)) {
75 return Status::fromExceptionCode(Status::EX_SECURITY);
76 }
77
78 if (binder == nullptr) {
79 return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT);
80 }
81
82 // match legacy rules
83 if (name.size() == 0 || name.size() > 127) {
84 return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT);
85 }
86
87 if (OK != binder->linkToDeath(this)) {
88 LOG(ERROR) << "Could not linkToDeath when adding " << name;
89 return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE);
90 }
91
92 auto it = mNameToService.find(name);
93 if (it != mNameToService.end()) {
94 if (OK != it->second.binder->unlinkToDeath(this)) {
95 LOG(WARNING) << "Could not unlinkToDeath when adding " << name;
96 }
97 }
98
99 mNameToService[name] = Service {
100 .binder = binder,
101 .allowIsolated = allowIsolated,
102 .dumpPriority = dumpPriority,
103 };
104
105 return Status::ok();
106}
107
108Status ServiceManager::listServices(int32_t dumpPriority, std::vector<std::string>* outList) {
109 if (!mAccess->canList(mAccess->getCallingContext(""))) {
110 return Status::fromExceptionCode(Status::EX_SECURITY);
111 }
112
113 size_t toReserve = 0;
114 for (auto const& [name, service] : mNameToService) {
115 (void) name;
116
117 if (service.dumpPriority & dumpPriority) ++toReserve;
118 }
119
120 CHECK(outList->empty());
121
122 outList->reserve(toReserve);
123 for (auto const& [name, service] : mNameToService) {
124 (void) service;
125
126 if (service.dumpPriority & dumpPriority) {
127 outList->push_back(name);
128 }
129 }
130
131 return Status::ok();
132}
133
134void ServiceManager::binderDied(const wp<IBinder>& who) {
135 for (auto it = mNameToService.begin(); it != mNameToService.end();) {
136 if (who == it->second.binder) {
137 it = mNameToService.erase(it);
138 } else {
139 ++it;
140 }
141 }
142}
143
144} // namespace android