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