blob: 97639217a0c88368d563569849c04f65fc33bc65 [file] [log] [blame]
Chong Zhangacb33502020-04-20 11:04:48 -07001/*
2 * Copyright (C) 2020 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
Chong Zhang75222182020-04-29 14:43:42 -070017//#define LOG_NDEBUG 0
Chong Zhangacb33502020-04-20 11:04:48 -070018#define LOG_TAG "TranscodingUidPolicy"
19
Chong Zhang97d367b2020-09-16 12:53:14 -070020#include <aidl/android/media/BnResourceManagerClient.h>
21#include <aidl/android/media/IResourceManagerService.h>
22#include <android/binder_manager.h>
23#include <android/binder_process.h>
Chong Zhang0579c6f2020-10-05 12:03:34 -070024#include <android/content/pm/IPackageManagerNative.h>
Chong Zhangacb33502020-04-20 11:04:48 -070025#include <binder/ActivityManager.h>
Chong Zhang0579c6f2020-10-05 12:03:34 -070026#include <binder/IServiceManager.h>
Chong Zhangc37bdfe2020-10-06 13:54:09 -070027#include <binder/PermissionController.h>
Chong Zhangacb33502020-04-20 11:04:48 -070028#include <cutils/misc.h> // FIRST_APPLICATION_UID
Chong Zhangc37bdfe2020-10-06 13:54:09 -070029#include <cutils/multiuser.h>
Chong Zhangacb33502020-04-20 11:04:48 -070030#include <inttypes.h>
31#include <media/TranscodingUidPolicy.h>
32#include <utils/Log.h>
33
34#include <utility>
35
36namespace android {
37
38constexpr static uid_t OFFLINE_UID = -1;
39constexpr static const char* kTranscodingTag = "transcoding";
40
Chong Zhang97d367b2020-09-16 12:53:14 -070041/*
42 * The OOM score we're going to ask ResourceManager to use for our native transcoding
43 * service. ResourceManager issues reclaims based on these scores. It gets the scores
44 * from ActivityManagerService, which doesn't track native services. The values of the
45 * OOM scores are defined in:
46 * frameworks/base/services/core/java/com/android/server/am/ProcessList.java
47 * We use SERVICE_ADJ which is lower priority than an app possibly visible to the
48 * user, but higher priority than a cached app (which could be killed without disruption
49 * to the user).
50 */
51constexpr static int32_t SERVICE_ADJ = 500;
52
53using Status = ::ndk::ScopedAStatus;
54using aidl::android::media::BnResourceManagerClient;
55using aidl::android::media::IResourceManagerService;
56
57/*
58 * Placeholder ResourceManagerClient for registering process info override
59 * with the IResourceManagerService. This is only used as a token by the service
60 * to get notifications about binder death, not used for reclaiming resources.
61 */
62struct TranscodingUidPolicy::ResourceManagerClient : public BnResourceManagerClient {
63 explicit ResourceManagerClient() = default;
64
65 Status reclaimResource(bool* _aidl_return) override {
66 *_aidl_return = false;
67 return Status::ok();
68 }
69
70 Status getName(::std::string* _aidl_return) override {
71 _aidl_return->clear();
72 return Status::ok();
73 }
74
75 virtual ~ResourceManagerClient() = default;
76};
77
Chong Zhangacb33502020-04-20 11:04:48 -070078struct TranscodingUidPolicy::UidObserver : public BnUidObserver,
79 public virtual IBinder::DeathRecipient {
80 explicit UidObserver(TranscodingUidPolicy* owner) : mOwner(owner) {}
81
82 // IUidObserver
83 void onUidGone(uid_t uid, bool disabled) override;
84 void onUidActive(uid_t uid) override;
85 void onUidIdle(uid_t uid, bool disabled) override;
86 void onUidStateChanged(uid_t uid, int32_t procState, int64_t procStateSeq,
87 int32_t capability) override;
88
89 // IBinder::DeathRecipient implementation
90 void binderDied(const wp<IBinder>& who) override;
91
92 TranscodingUidPolicy* mOwner;
93};
94
95void TranscodingUidPolicy::UidObserver::onUidGone(uid_t uid __unused, bool disabled __unused) {}
96
97void TranscodingUidPolicy::UidObserver::onUidActive(uid_t uid __unused) {}
98
99void TranscodingUidPolicy::UidObserver::onUidIdle(uid_t uid __unused, bool disabled __unused) {}
100
101void TranscodingUidPolicy::UidObserver::onUidStateChanged(uid_t uid, int32_t procState,
102 int64_t procStateSeq __unused,
103 int32_t capability __unused) {
104 mOwner->onUidStateChanged(uid, procState);
105}
106
107void TranscodingUidPolicy::UidObserver::binderDied(const wp<IBinder>& /*who*/) {
108 ALOGW("TranscodingUidPolicy: ActivityManager has died");
109 // TODO(chz): this is a rare event (since if the AMS is dead, the system is
110 // probably dead as well). But we should try to reconnect.
111 mOwner->setUidObserverRegistered(false);
112}
113
114////////////////////////////////////////////////////////////////////////////
115
Chong Zhang0579c6f2020-10-05 12:03:34 -0700116//static
117bool TranscodingUidPolicy::getNamesForUids(const std::vector<int32_t>& uids,
118 std::vector<std::string>* names) {
119 names->clear();
120 sp<IServiceManager> sm(defaultServiceManager());
121 sp<IBinder> binder(sm->getService(String16("package_native")));
122 if (binder == nullptr) {
123 ALOGE("getService package_native failed");
124 return false;
125 }
126
127 sp<content::pm::IPackageManagerNative> packageMgr =
128 interface_cast<content::pm::IPackageManagerNative>(binder);
129 binder::Status status = packageMgr->getNamesForUids(uids, names);
130
131 if (!status.isOk() || names->size() != uids.size()) {
132 names->clear();
133 return false;
134 }
135 return true;
136}
137
Chong Zhangc37bdfe2020-10-06 13:54:09 -0700138//static
139status_t TranscodingUidPolicy::getUidForPackage(String16 packageName, /*inout*/ uid_t& uid) {
140 PermissionController pc;
141 uid = pc.getPackageUid(packageName, 0);
142 if (uid <= 0) {
143 ALOGE("Unknown package: '%s'", String8(packageName).string());
144 return BAD_VALUE;
145 }
146
147 uid = multiuser_get_uid(0 /*userId*/, uid);
148 return NO_ERROR;
149}
150
Chong Zhangacb33502020-04-20 11:04:48 -0700151TranscodingUidPolicy::TranscodingUidPolicy()
152 : mAm(std::make_shared<ActivityManager>()),
153 mUidObserver(new UidObserver(this)),
154 mRegistered(false),
155 mTopUidState(ActivityManager::PROCESS_STATE_UNKNOWN) {
156 registerSelf();
Chong Zhang97d367b2020-09-16 12:53:14 -0700157 setProcessInfoOverride();
Chong Zhangacb33502020-04-20 11:04:48 -0700158}
159
160TranscodingUidPolicy::~TranscodingUidPolicy() {
161 unregisterSelf();
162}
163
164void TranscodingUidPolicy::registerSelf() {
165 status_t res = mAm->linkToDeath(mUidObserver.get());
166 mAm->registerUidObserver(
167 mUidObserver.get(),
168 ActivityManager::UID_OBSERVER_GONE | ActivityManager::UID_OBSERVER_IDLE |
169 ActivityManager::UID_OBSERVER_ACTIVE | ActivityManager::UID_OBSERVER_PROCSTATE,
170 ActivityManager::PROCESS_STATE_UNKNOWN, String16(kTranscodingTag));
171
172 if (res == OK) {
173 Mutex::Autolock _l(mUidLock);
174
175 mRegistered = true;
176 ALOGI("TranscodingUidPolicy: Registered with ActivityManager");
177 } else {
178 mAm->unregisterUidObserver(mUidObserver.get());
179 }
180}
181
182void TranscodingUidPolicy::unregisterSelf() {
183 mAm->unregisterUidObserver(mUidObserver.get());
184 mAm->unlinkToDeath(mUidObserver.get());
185
186 Mutex::Autolock _l(mUidLock);
187
188 mRegistered = false;
189
190 ALOGI("TranscodingUidPolicy: Unregistered with ActivityManager");
191}
192
Chong Zhang97d367b2020-09-16 12:53:14 -0700193void TranscodingUidPolicy::setProcessInfoOverride() {
194 ::ndk::SpAIBinder binder(AServiceManager_getService("media.resource_manager"));
195 std::shared_ptr<IResourceManagerService> service = IResourceManagerService::fromBinder(binder);
196 if (service == nullptr) {
197 ALOGE("Failed to get IResourceManagerService");
198 return;
199 }
200
201 mProcInfoOverrideClient = ::ndk::SharedRefBase::make<ResourceManagerClient>();
202 Status status = service->overrideProcessInfo(
203 mProcInfoOverrideClient, getpid(), ActivityManager::PROCESS_STATE_SERVICE, SERVICE_ADJ);
204 if (!status.isOk()) {
205 ALOGW("Failed to setProcessInfoOverride.");
206 }
207}
208
Chong Zhangacb33502020-04-20 11:04:48 -0700209void TranscodingUidPolicy::setUidObserverRegistered(bool registered) {
210 Mutex::Autolock _l(mUidLock);
211
212 mRegistered = registered;
213}
214
215void TranscodingUidPolicy::setCallback(const std::shared_ptr<UidPolicyCallbackInterface>& cb) {
216 mUidPolicyCallback = cb;
217}
218
219void TranscodingUidPolicy::registerMonitorUid(uid_t uid) {
220 Mutex::Autolock _l(mUidLock);
221 if (uid == OFFLINE_UID) {
222 ALOGW("Ignoring the offline uid");
223 return;
224 }
225 if (mUidStateMap.find(uid) != mUidStateMap.end()) {
226 ALOGE("%s: Trying to register uid: %d which is already monitored!", __FUNCTION__, uid);
227 return;
228 }
229
230 int32_t state = ActivityManager::PROCESS_STATE_UNKNOWN;
Hui Yu799ba4f2020-05-05 17:04:15 -0700231 if (mRegistered && mAm->isUidActive(uid, String16(kTranscodingTag))) {
Chong Zhangacb33502020-04-20 11:04:48 -0700232 state = mAm->getUidProcessState(uid, String16(kTranscodingTag));
233 }
234
235 ALOGV("%s: inserting new uid: %u, procState %d", __FUNCTION__, uid, state);
236
237 mUidStateMap.emplace(std::pair<uid_t, int32_t>(uid, state));
238 mStateUidMap[state].insert(uid);
239
240 updateTopUid_l();
241}
242
243void TranscodingUidPolicy::unregisterMonitorUid(uid_t uid) {
244 Mutex::Autolock _l(mUidLock);
245
246 auto it = mUidStateMap.find(uid);
247 if (it == mUidStateMap.end()) {
248 ALOGE("%s: Trying to unregister uid: %d which is not monitored!", __FUNCTION__, uid);
249 return;
250 }
251
252 auto stateIt = mStateUidMap.find(it->second);
253 if (stateIt != mStateUidMap.end()) {
254 stateIt->second.erase(uid);
255 if (stateIt->second.empty()) {
256 mStateUidMap.erase(stateIt);
257 }
258 }
259 mUidStateMap.erase(it);
260
261 updateTopUid_l();
262}
263
264bool TranscodingUidPolicy::isUidOnTop(uid_t uid) {
265 Mutex::Autolock _l(mUidLock);
266
267 return mTopUidState != ActivityManager::PROCESS_STATE_UNKNOWN &&
268 mTopUidState == getProcState_l(uid);
269}
270
271std::unordered_set<uid_t> TranscodingUidPolicy::getTopUids() const {
272 Mutex::Autolock _l(mUidLock);
273
274 if (mTopUidState == ActivityManager::PROCESS_STATE_UNKNOWN) {
275 return std::unordered_set<uid_t>();
276 }
277
278 return mStateUidMap.at(mTopUidState);
279}
280
281void TranscodingUidPolicy::onUidStateChanged(uid_t uid, int32_t procState) {
282 ALOGV("onUidStateChanged: %u, procState %d", uid, procState);
283
284 bool topUidSetChanged = false;
285 std::unordered_set<uid_t> topUids;
286 {
287 Mutex::Autolock _l(mUidLock);
288 auto it = mUidStateMap.find(uid);
289 if (it != mUidStateMap.end() && it->second != procState) {
290 // Top set changed if 1) the uid is in the current top uid set, or 2) the
291 // new procState is at least the same priority as the current top uid state.
292 bool isUidCurrentTop = mTopUidState != ActivityManager::PROCESS_STATE_UNKNOWN &&
293 mStateUidMap[mTopUidState].count(uid) > 0;
294 bool isNewStateHigherThanTop = procState != ActivityManager::PROCESS_STATE_UNKNOWN &&
295 (procState <= mTopUidState ||
296 mTopUidState == ActivityManager::PROCESS_STATE_UNKNOWN);
297 topUidSetChanged = (isUidCurrentTop || isNewStateHigherThanTop);
298
299 // Move uid to the new procState.
300 mStateUidMap[it->second].erase(uid);
301 mStateUidMap[procState].insert(uid);
302 it->second = procState;
303
304 if (topUidSetChanged) {
305 updateTopUid_l();
306
307 // Make a copy of the uid set for callback.
308 topUids = mStateUidMap[mTopUidState];
309 }
310 }
311 }
312
313 ALOGV("topUidSetChanged: %d", topUidSetChanged);
314
315 if (topUidSetChanged) {
316 auto callback = mUidPolicyCallback.lock();
317 if (callback != nullptr) {
318 callback->onTopUidsChanged(topUids);
319 }
320 }
321}
322
323void TranscodingUidPolicy::updateTopUid_l() {
Chong Zhangacb33502020-04-20 11:04:48 -0700324 mTopUidState = ActivityManager::PROCESS_STATE_UNKNOWN;
Chong Zhang75222182020-04-29 14:43:42 -0700325
326 // Find the lowest uid state (ignoring PROCESS_STATE_UNKNOWN) with some monitored uids.
Chong Zhangacb33502020-04-20 11:04:48 -0700327 for (auto stateIt = mStateUidMap.begin(); stateIt != mStateUidMap.end(); stateIt++) {
328 if (stateIt->first != ActivityManager::PROCESS_STATE_UNKNOWN && !stateIt->second.empty()) {
329 mTopUidState = stateIt->first;
330 break;
331 }
332 }
333
334 ALOGV("%s: top uid state is %d", __FUNCTION__, mTopUidState);
335}
336
337int32_t TranscodingUidPolicy::getProcState_l(uid_t uid) {
338 auto it = mUidStateMap.find(uid);
339 if (it != mUidStateMap.end()) {
340 return it->second;
341 }
342 return ActivityManager::PROCESS_STATE_UNKNOWN;
343}
344
345} // namespace android