blob: 084a871ee60bb0e6a98b685f9ec664d64d1f5f1e [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
Chong Zhangc37bdfe2020-10-06 13:54:09 -0700117status_t TranscodingUidPolicy::getUidForPackage(String16 packageName, /*inout*/ uid_t& uid) {
118 PermissionController pc;
119 uid = pc.getPackageUid(packageName, 0);
120 if (uid <= 0) {
121 ALOGE("Unknown package: '%s'", String8(packageName).string());
122 return BAD_VALUE;
123 }
124
125 uid = multiuser_get_uid(0 /*userId*/, uid);
126 return NO_ERROR;
127}
128
Chong Zhangacb33502020-04-20 11:04:48 -0700129TranscodingUidPolicy::TranscodingUidPolicy()
130 : mAm(std::make_shared<ActivityManager>()),
131 mUidObserver(new UidObserver(this)),
132 mRegistered(false),
133 mTopUidState(ActivityManager::PROCESS_STATE_UNKNOWN) {
134 registerSelf();
Chong Zhang97d367b2020-09-16 12:53:14 -0700135 setProcessInfoOverride();
Chong Zhangacb33502020-04-20 11:04:48 -0700136}
137
138TranscodingUidPolicy::~TranscodingUidPolicy() {
139 unregisterSelf();
140}
141
142void TranscodingUidPolicy::registerSelf() {
143 status_t res = mAm->linkToDeath(mUidObserver.get());
144 mAm->registerUidObserver(
145 mUidObserver.get(),
146 ActivityManager::UID_OBSERVER_GONE | ActivityManager::UID_OBSERVER_IDLE |
147 ActivityManager::UID_OBSERVER_ACTIVE | ActivityManager::UID_OBSERVER_PROCSTATE,
148 ActivityManager::PROCESS_STATE_UNKNOWN, String16(kTranscodingTag));
149
150 if (res == OK) {
151 Mutex::Autolock _l(mUidLock);
152
153 mRegistered = true;
154 ALOGI("TranscodingUidPolicy: Registered with ActivityManager");
155 } else {
156 mAm->unregisterUidObserver(mUidObserver.get());
157 }
158}
159
160void TranscodingUidPolicy::unregisterSelf() {
161 mAm->unregisterUidObserver(mUidObserver.get());
162 mAm->unlinkToDeath(mUidObserver.get());
163
164 Mutex::Autolock _l(mUidLock);
165
166 mRegistered = false;
167
168 ALOGI("TranscodingUidPolicy: Unregistered with ActivityManager");
169}
170
Chong Zhang97d367b2020-09-16 12:53:14 -0700171void TranscodingUidPolicy::setProcessInfoOverride() {
172 ::ndk::SpAIBinder binder(AServiceManager_getService("media.resource_manager"));
173 std::shared_ptr<IResourceManagerService> service = IResourceManagerService::fromBinder(binder);
174 if (service == nullptr) {
175 ALOGE("Failed to get IResourceManagerService");
176 return;
177 }
178
179 mProcInfoOverrideClient = ::ndk::SharedRefBase::make<ResourceManagerClient>();
180 Status status = service->overrideProcessInfo(
181 mProcInfoOverrideClient, getpid(), ActivityManager::PROCESS_STATE_SERVICE, SERVICE_ADJ);
182 if (!status.isOk()) {
183 ALOGW("Failed to setProcessInfoOverride.");
184 }
185}
186
Chong Zhangacb33502020-04-20 11:04:48 -0700187void TranscodingUidPolicy::setUidObserverRegistered(bool registered) {
188 Mutex::Autolock _l(mUidLock);
189
190 mRegistered = registered;
191}
192
193void TranscodingUidPolicy::setCallback(const std::shared_ptr<UidPolicyCallbackInterface>& cb) {
194 mUidPolicyCallback = cb;
195}
196
197void TranscodingUidPolicy::registerMonitorUid(uid_t uid) {
198 Mutex::Autolock _l(mUidLock);
199 if (uid == OFFLINE_UID) {
200 ALOGW("Ignoring the offline uid");
201 return;
202 }
203 if (mUidStateMap.find(uid) != mUidStateMap.end()) {
204 ALOGE("%s: Trying to register uid: %d which is already monitored!", __FUNCTION__, uid);
205 return;
206 }
207
208 int32_t state = ActivityManager::PROCESS_STATE_UNKNOWN;
Hui Yu799ba4f2020-05-05 17:04:15 -0700209 if (mRegistered && mAm->isUidActive(uid, String16(kTranscodingTag))) {
Chong Zhangacb33502020-04-20 11:04:48 -0700210 state = mAm->getUidProcessState(uid, String16(kTranscodingTag));
211 }
212
213 ALOGV("%s: inserting new uid: %u, procState %d", __FUNCTION__, uid, state);
214
215 mUidStateMap.emplace(std::pair<uid_t, int32_t>(uid, state));
216 mStateUidMap[state].insert(uid);
217
218 updateTopUid_l();
219}
220
221void TranscodingUidPolicy::unregisterMonitorUid(uid_t uid) {
222 Mutex::Autolock _l(mUidLock);
223
224 auto it = mUidStateMap.find(uid);
225 if (it == mUidStateMap.end()) {
226 ALOGE("%s: Trying to unregister uid: %d which is not monitored!", __FUNCTION__, uid);
227 return;
228 }
229
230 auto stateIt = mStateUidMap.find(it->second);
231 if (stateIt != mStateUidMap.end()) {
232 stateIt->second.erase(uid);
233 if (stateIt->second.empty()) {
234 mStateUidMap.erase(stateIt);
235 }
236 }
237 mUidStateMap.erase(it);
238
239 updateTopUid_l();
240}
241
242bool TranscodingUidPolicy::isUidOnTop(uid_t uid) {
243 Mutex::Autolock _l(mUidLock);
244
245 return mTopUidState != ActivityManager::PROCESS_STATE_UNKNOWN &&
246 mTopUidState == getProcState_l(uid);
247}
248
249std::unordered_set<uid_t> TranscodingUidPolicy::getTopUids() const {
250 Mutex::Autolock _l(mUidLock);
251
252 if (mTopUidState == ActivityManager::PROCESS_STATE_UNKNOWN) {
253 return std::unordered_set<uid_t>();
254 }
255
256 return mStateUidMap.at(mTopUidState);
257}
258
259void TranscodingUidPolicy::onUidStateChanged(uid_t uid, int32_t procState) {
260 ALOGV("onUidStateChanged: %u, procState %d", uid, procState);
261
262 bool topUidSetChanged = false;
263 std::unordered_set<uid_t> topUids;
264 {
265 Mutex::Autolock _l(mUidLock);
266 auto it = mUidStateMap.find(uid);
267 if (it != mUidStateMap.end() && it->second != procState) {
268 // Top set changed if 1) the uid is in the current top uid set, or 2) the
269 // new procState is at least the same priority as the current top uid state.
270 bool isUidCurrentTop = mTopUidState != ActivityManager::PROCESS_STATE_UNKNOWN &&
271 mStateUidMap[mTopUidState].count(uid) > 0;
272 bool isNewStateHigherThanTop = procState != ActivityManager::PROCESS_STATE_UNKNOWN &&
273 (procState <= mTopUidState ||
274 mTopUidState == ActivityManager::PROCESS_STATE_UNKNOWN);
275 topUidSetChanged = (isUidCurrentTop || isNewStateHigherThanTop);
276
277 // Move uid to the new procState.
278 mStateUidMap[it->second].erase(uid);
279 mStateUidMap[procState].insert(uid);
280 it->second = procState;
281
282 if (topUidSetChanged) {
283 updateTopUid_l();
284
285 // Make a copy of the uid set for callback.
286 topUids = mStateUidMap[mTopUidState];
287 }
288 }
289 }
290
291 ALOGV("topUidSetChanged: %d", topUidSetChanged);
292
293 if (topUidSetChanged) {
294 auto callback = mUidPolicyCallback.lock();
295 if (callback != nullptr) {
296 callback->onTopUidsChanged(topUids);
297 }
298 }
299}
300
301void TranscodingUidPolicy::updateTopUid_l() {
Chong Zhangacb33502020-04-20 11:04:48 -0700302 mTopUidState = ActivityManager::PROCESS_STATE_UNKNOWN;
Chong Zhang75222182020-04-29 14:43:42 -0700303
304 // Find the lowest uid state (ignoring PROCESS_STATE_UNKNOWN) with some monitored uids.
Chong Zhangacb33502020-04-20 11:04:48 -0700305 for (auto stateIt = mStateUidMap.begin(); stateIt != mStateUidMap.end(); stateIt++) {
306 if (stateIt->first != ActivityManager::PROCESS_STATE_UNKNOWN && !stateIt->second.empty()) {
307 mTopUidState = stateIt->first;
308 break;
309 }
310 }
311
312 ALOGV("%s: top uid state is %d", __FUNCTION__, mTopUidState);
313}
314
315int32_t TranscodingUidPolicy::getProcState_l(uid_t uid) {
316 auto it = mUidStateMap.find(uid);
317 if (it != mUidStateMap.end()) {
318 return it->second;
319 }
320 return ActivityManager::PROCESS_STATE_UNKNOWN;
321}
322
323} // namespace android