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