blob: 61d3833d31971c3699814a8e4409b06f646c7c6d [file] [log] [blame]
Makoto Onuki9be01402017-11-10 13:22:26 -08001/*
2 * Copyright (C) 2017 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 */
16package com.android.server;
17
18import android.annotation.NonNull;
Makoto Onuki9be01402017-11-10 13:22:26 -080019import android.app.ActivityManager;
20import android.app.AppOpsManager;
21import android.app.AppOpsManager.PackageOps;
Makoto Onuki2206af32017-11-21 16:25:35 -080022import android.app.IActivityManager;
Makoto Onuki9be01402017-11-10 13:22:26 -080023import android.app.IUidObserver;
Makoto Onuki2206af32017-11-21 16:25:35 -080024import android.content.BroadcastReceiver;
Makoto Onuki9be01402017-11-10 13:22:26 -080025import android.content.Context;
Makoto Onuki2206af32017-11-21 16:25:35 -080026import android.content.Intent;
27import android.content.IntentFilter;
Makoto Onuki9be01402017-11-10 13:22:26 -080028import android.os.Handler;
Makoto Onuki2206af32017-11-21 16:25:35 -080029import android.os.Looper;
30import android.os.Message;
Makoto Onuki9be01402017-11-10 13:22:26 -080031import android.os.PowerManager.ServiceType;
32import android.os.PowerManagerInternal;
33import android.os.RemoteException;
34import android.os.ServiceManager;
35import android.os.UserHandle;
36import android.util.ArraySet;
37import android.util.Pair;
Makoto Onuki9be01402017-11-10 13:22:26 -080038import android.util.SparseBooleanArray;
Makoto Onuki2206af32017-11-21 16:25:35 -080039import android.util.proto.ProtoOutputStream;
Makoto Onuki9be01402017-11-10 13:22:26 -080040
41import com.android.internal.annotations.GuardedBy;
Makoto Onuki2206af32017-11-21 16:25:35 -080042import com.android.internal.annotations.VisibleForTesting;
Makoto Onuki9be01402017-11-10 13:22:26 -080043import com.android.internal.app.IAppOpsCallback;
44import com.android.internal.app.IAppOpsService;
Makoto Onuki2206af32017-11-21 16:25:35 -080045import com.android.internal.util.ArrayUtils;
Makoto Onuki9be01402017-11-10 13:22:26 -080046import com.android.internal.util.Preconditions;
Makoto Onuki2206af32017-11-21 16:25:35 -080047import com.android.server.ForceAppStandbyTrackerProto.RunAnyInBackgroundRestrictedPackages;
Makoto Onuki9be01402017-11-10 13:22:26 -080048
Makoto Onuki2206af32017-11-21 16:25:35 -080049import java.io.PrintWriter;
50import java.util.Arrays;
Makoto Onuki9be01402017-11-10 13:22:26 -080051import java.util.List;
52
53/**
Makoto Onuki2206af32017-11-21 16:25:35 -080054 * Class to keep track of the information related to "force app standby", which includes:
55 * - OP_RUN_ANY_IN_BACKGROUND for each package
56 * - UID foreground state
57 * - User+system power save whitelist
58 * - Temporary power save whitelist
59 * - Global "force all apps standby" mode enforced by battery saver.
Makoto Onuki9be01402017-11-10 13:22:26 -080060 *
Makoto Onuki2206af32017-11-21 16:25:35 -080061 * TODO: In general, we can reduce the number of callbacks by checking all signals before sending
62 * each callback. For example, even when an UID comes into the foreground, if it wasn't
63 * originally restricted, then there's no need to send an event.
64 * Doing this would be error-prone, so we punt it for now, but we should revisit it later.
65 *
66 * Test:
67 atest $ANDROID_BUILD_TOP/frameworks/base/services/tests/servicestests/src/com/android/server/ForceAppStandbyTrackerTest.java
Makoto Onuki9be01402017-11-10 13:22:26 -080068 */
69public class ForceAppStandbyTracker {
70 private static final String TAG = "ForceAppStandbyTracker";
71
72 @GuardedBy("ForceAppStandbyTracker.class")
73 private static ForceAppStandbyTracker sInstance;
74
75 private final Object mLock = new Object();
76 private final Context mContext;
77
Makoto Onuki2206af32017-11-21 16:25:35 -080078 @VisibleForTesting
79 static final int TARGET_OP = AppOpsManager.OP_RUN_ANY_IN_BACKGROUND;
80
81 IActivityManager mIActivityManager;
Makoto Onuki9be01402017-11-10 13:22:26 -080082 AppOpsManager mAppOpsManager;
83 IAppOpsService mAppOpsService;
84 PowerManagerInternal mPowerManagerInternal;
85
Makoto Onuki2206af32017-11-21 16:25:35 -080086 private final MyHandler mHandler;
Makoto Onuki9be01402017-11-10 13:22:26 -080087
88 /**
89 * Pair of (uid (not user-id), packageName) with OP_RUN_ANY_IN_BACKGROUND *not* allowed.
90 */
91 @GuardedBy("mLock")
Makoto Onuki2206af32017-11-21 16:25:35 -080092 final ArraySet<Pair<Integer, String>> mRunAnyRestrictedPackages = new ArraySet<>();
Makoto Onuki9be01402017-11-10 13:22:26 -080093
94 @GuardedBy("mLock")
95 final SparseBooleanArray mForegroundUids = new SparseBooleanArray();
96
97 @GuardedBy("mLock")
Makoto Onuki2206af32017-11-21 16:25:35 -080098 private int[] mPowerWhitelistedAllAppIds = new int[0];
99
100 @GuardedBy("mLock")
101 private int[] mTempWhitelistedAppIds = mPowerWhitelistedAllAppIds;
102
103 @GuardedBy("mLock")
Makoto Onuki9be01402017-11-10 13:22:26 -0800104 final ArraySet<Listener> mListeners = new ArraySet<>();
105
106 @GuardedBy("mLock")
107 boolean mStarted;
108
109 @GuardedBy("mLock")
110 boolean mForceAllAppsStandby;
111
112 public static abstract class Listener {
Makoto Onuki2206af32017-11-21 16:25:35 -0800113 /**
114 * This is called when the OP_RUN_ANY_IN_BACKGROUND appops changed for a package.
115 */
116 private void onRunAnyAppOpsChanged(ForceAppStandbyTracker sender,
117 int uid, @NonNull String packageName) {
118 updateJobsForUidPackage(uid, packageName);
119
120 if (!sender.areAlarmsRestricted(uid, packageName)) {
121 unblockAlarmsForUidPackage(uid, packageName);
122 }
Makoto Onuki9be01402017-11-10 13:22:26 -0800123 }
124
Makoto Onuki2206af32017-11-21 16:25:35 -0800125 /**
126 * This is called when the foreground state changed for a UID.
127 */
128 private void onUidForegroundStateChanged(ForceAppStandbyTracker sender, int uid) {
129 updateJobsForUid(uid);
130
131 if (sender.isInForeground(uid)) {
132 unblockAlarmsForUid(uid);
133 }
134 }
135
136 /**
137 * This is called when an app-id(s) is removed from the power save whitelist.
138 */
139 private void onPowerSaveUnwhitelisted(ForceAppStandbyTracker sender) {
140 updateAllJobs();
141 unblockAllUnrestrictedAlarms();
142 }
143
144 /**
145 * This is called when the power save whitelist changes, excluding the
146 * {@link #onPowerSaveUnwhitelisted} case.
147 */
148 private void onPowerSaveWhitelistedChanged(ForceAppStandbyTracker sender) {
149 updateAllJobs();
150 }
151
152 /**
153 * This is called when the temp whitelist changes.
154 */
155 private void onTempPowerSaveWhitelistChanged(ForceAppStandbyTracker sender) {
156
157 // TODO This case happens rather frequently; consider optimizing and update jobs
158 // only for affected app-ids.
159
160 updateAllJobs();
161 }
162
163 /**
164 * This is called when the global "force all apps standby" flag changes.
165 */
166 private void onForceAllAppsStandbyChanged(ForceAppStandbyTracker sender) {
167 updateAllJobs();
168
169 if (!sender.isForceAllAppsStandbyEnabled()) {
170 unblockAllUnrestrictedAlarms();
171 }
172 }
173
174 /**
175 * Called when the job restrictions for multiple UIDs might have changed, so the job
176 * scheduler should re-evaluate all restrictions for all jobs.
177 */
178 public void updateAllJobs() {
179 }
180
181 /**
182 * Called when the job restrictions for a UID might have changed, so the job
183 * scheduler should re-evaluate all restrictions for all jobs.
184 */
185 public void updateJobsForUid(int uid) {
186 }
187
188 /**
189 * Called when the job restrictions for a UID - package might have changed, so the job
190 * scheduler should re-evaluate all restrictions for all jobs.
191 */
192 public void updateJobsForUidPackage(int uid, String packageName) {
193 }
194
195 /**
196 * Called when the job restrictions for multiple UIDs might have changed, so the alarm
197 * manager should re-evaluate all restrictions for all blocked jobs.
198 */
199 public void unblockAllUnrestrictedAlarms() {
200 }
201
202 /**
203 * Called when all jobs for a specific UID are unblocked.
204 */
205 public void unblockAlarmsForUid(int uid) {
206 }
207
208 /**
209 * Called when all alarms for a specific UID - package are unblocked.
210 */
211 public void unblockAlarmsForUidPackage(int uid, String packageName) {
Makoto Onuki9be01402017-11-10 13:22:26 -0800212 }
213 }
214
Makoto Onuki2206af32017-11-21 16:25:35 -0800215 @VisibleForTesting
216 ForceAppStandbyTracker(Context context, Looper looper) {
Makoto Onuki9be01402017-11-10 13:22:26 -0800217 mContext = context;
Makoto Onuki2206af32017-11-21 16:25:35 -0800218 mHandler = new MyHandler(looper);
219 }
220
221 private ForceAppStandbyTracker(Context context) {
222 this(context, FgThread.get().getLooper());
Makoto Onuki9be01402017-11-10 13:22:26 -0800223 }
224
225 /**
226 * Get the singleton instance.
227 */
228 public static synchronized ForceAppStandbyTracker getInstance(Context context) {
229 if (sInstance == null) {
230 sInstance = new ForceAppStandbyTracker(context);
231 }
232 return sInstance;
233 }
234
235 /**
236 * Call it when the system is ready.
237 */
238 public void start() {
239 synchronized (mLock) {
240 if (mStarted) {
241 return;
242 }
243 mStarted = true;
244
Makoto Onuki2206af32017-11-21 16:25:35 -0800245 mIActivityManager = Preconditions.checkNotNull(injectIActivityManager());
246 mAppOpsManager = Preconditions.checkNotNull(injectAppOpsManager());
247 mAppOpsService = Preconditions.checkNotNull(injectIAppOpsService());
248 mPowerManagerInternal = Preconditions.checkNotNull(injectPowerManagerInternal());
Makoto Onuki9be01402017-11-10 13:22:26 -0800249
250 try {
Makoto Onuki2206af32017-11-21 16:25:35 -0800251 mIActivityManager.registerUidObserver(new UidObserver(),
Makoto Onuki9be01402017-11-10 13:22:26 -0800252 ActivityManager.UID_OBSERVER_GONE | ActivityManager.UID_OBSERVER_IDLE
253 | ActivityManager.UID_OBSERVER_ACTIVE,
254 ActivityManager.PROCESS_STATE_UNKNOWN, null);
Makoto Onuki2206af32017-11-21 16:25:35 -0800255 mAppOpsService.startWatchingMode(TARGET_OP, null,
Makoto Onuki9be01402017-11-10 13:22:26 -0800256 new AppOpsWatcher());
257 } catch (RemoteException e) {
258 // shouldn't happen.
259 }
260
Makoto Onuki2206af32017-11-21 16:25:35 -0800261 IntentFilter filter = new IntentFilter();
262 filter.addAction(Intent.ACTION_USER_REMOVED);
263 mContext.registerReceiver(new MyReceiver(), filter);
Makoto Onuki9be01402017-11-10 13:22:26 -0800264
265 refreshForcedAppStandbyUidPackagesLocked();
Makoto Onuki2206af32017-11-21 16:25:35 -0800266
267 mPowerManagerInternal.registerLowPowerModeObserver(
268 ServiceType.FORCE_ALL_APPS_STANDBY,
269 (state) -> updateForceAllAppsStandby(state.batterySaverEnabled));
270
271 updateForceAllAppsStandby(mPowerManagerInternal.getLowPowerState(
272 ServiceType.FORCE_ALL_APPS_STANDBY).batterySaverEnabled);
Makoto Onuki9be01402017-11-10 13:22:26 -0800273 }
274 }
275
Makoto Onuki2206af32017-11-21 16:25:35 -0800276 @VisibleForTesting
277 AppOpsManager injectAppOpsManager() {
278 return mContext.getSystemService(AppOpsManager.class);
279 }
280
281 @VisibleForTesting
282 IAppOpsService injectIAppOpsService() {
283 return IAppOpsService.Stub.asInterface(
284 ServiceManager.getService(Context.APP_OPS_SERVICE));
285 }
286
287 @VisibleForTesting
288 IActivityManager injectIActivityManager() {
289 return ActivityManager.getService();
290 }
291
292 @VisibleForTesting
293 PowerManagerInternal injectPowerManagerInternal() {
294 return LocalServices.getService(PowerManagerInternal.class);
295 }
296
Makoto Onuki9be01402017-11-10 13:22:26 -0800297 /**
Makoto Onuki2206af32017-11-21 16:25:35 -0800298 * Update {@link #mRunAnyRestrictedPackages} with the current app ops state.
Makoto Onuki9be01402017-11-10 13:22:26 -0800299 */
300 private void refreshForcedAppStandbyUidPackagesLocked() {
Makoto Onuki2206af32017-11-21 16:25:35 -0800301 mRunAnyRestrictedPackages.clear();
302 final List<PackageOps> ops = mAppOpsManager.getPackagesForOps(
303 new int[] {TARGET_OP});
Makoto Onuki9be01402017-11-10 13:22:26 -0800304
305 if (ops == null) {
306 return;
307 }
308 final int size = ops.size();
309 for (int i = 0; i < size; i++) {
310 final AppOpsManager.PackageOps pkg = ops.get(i);
311 final List<AppOpsManager.OpEntry> entries = ops.get(i).getOps();
312
313 for (int j = 0; j < entries.size(); j++) {
314 AppOpsManager.OpEntry ent = entries.get(j);
Makoto Onuki2206af32017-11-21 16:25:35 -0800315 if (ent.getOp() != TARGET_OP) {
Makoto Onuki9be01402017-11-10 13:22:26 -0800316 continue;
317 }
318 if (ent.getMode() != AppOpsManager.MODE_ALLOWED) {
Makoto Onuki2206af32017-11-21 16:25:35 -0800319 mRunAnyRestrictedPackages.add(Pair.create(
Makoto Onuki9be01402017-11-10 13:22:26 -0800320 pkg.getUid(), pkg.getPackageName()));
321 }
322 }
323 }
324 }
325
Makoto Onuki2206af32017-11-21 16:25:35 -0800326 /**
327 * Update {@link #mForceAllAppsStandby} and notifies the listeners.
328 */
329 void updateForceAllAppsStandby(boolean enable) {
330 synchronized (mLock) {
331 if (enable == mForceAllAppsStandby) {
332 return;
333 }
334 mForceAllAppsStandby = enable;
335
336 mHandler.notifyForceAllAppsStandbyChanged();
Makoto Onuki9be01402017-11-10 13:22:26 -0800337 }
338 }
339
340 private int findForcedAppStandbyUidPackageIndexLocked(int uid, @NonNull String packageName) {
Makoto Onuki2206af32017-11-21 16:25:35 -0800341 final int size = mRunAnyRestrictedPackages.size();
342 if (size > 8) {
343 return mRunAnyRestrictedPackages.indexOf(Pair.create(uid, packageName));
344 }
Makoto Onuki9be01402017-11-10 13:22:26 -0800345 for (int i = 0; i < size; i++) {
Makoto Onuki2206af32017-11-21 16:25:35 -0800346 final Pair<Integer, String> pair = mRunAnyRestrictedPackages.valueAt(i);
Makoto Onuki9be01402017-11-10 13:22:26 -0800347
348 if ((pair.first == uid) && packageName.equals(pair.second)) {
349 return i;
350 }
351 }
352 return -1;
353 }
354
355 /**
Makoto Onuki2206af32017-11-21 16:25:35 -0800356 * @return whether a uid package-name pair is in mRunAnyRestrictedPackages.
Makoto Onuki9be01402017-11-10 13:22:26 -0800357 */
Makoto Onuki2206af32017-11-21 16:25:35 -0800358 boolean isRunAnyRestrictedLocked(int uid, @NonNull String packageName) {
Makoto Onuki9be01402017-11-10 13:22:26 -0800359 return findForcedAppStandbyUidPackageIndexLocked(uid, packageName) >= 0;
360 }
361
Makoto Onuki2206af32017-11-21 16:25:35 -0800362 /**
363 * Add to / remove from {@link #mRunAnyRestrictedPackages}.
364 */
365 boolean updateForcedAppStandbyUidPackageLocked(int uid, @NonNull String packageName,
Makoto Onuki9be01402017-11-10 13:22:26 -0800366 boolean restricted) {
367 final int index = findForcedAppStandbyUidPackageIndexLocked(uid, packageName);
368 final boolean wasRestricted = index >= 0;
369 if (wasRestricted == restricted) {
370 return false;
371 }
372 if (restricted) {
Makoto Onuki2206af32017-11-21 16:25:35 -0800373 mRunAnyRestrictedPackages.add(Pair.create(uid, packageName));
Makoto Onuki9be01402017-11-10 13:22:26 -0800374 } else {
Makoto Onuki2206af32017-11-21 16:25:35 -0800375 mRunAnyRestrictedPackages.removeAt(index);
Makoto Onuki9be01402017-11-10 13:22:26 -0800376 }
377 return true;
378 }
379
Makoto Onuki2206af32017-11-21 16:25:35 -0800380 /**
381 * Puts a UID to {@link #mForegroundUids}.
382 */
Makoto Onuki9be01402017-11-10 13:22:26 -0800383 void uidToForeground(int uid) {
384 synchronized (mLock) {
385 if (!UserHandle.isApp(uid)) {
386 return;
387 }
388 // TODO This can be optimized by calling indexOfKey and sharing the index for get and
389 // put.
390 if (mForegroundUids.get(uid)) {
391 return;
392 }
393 mForegroundUids.put(uid, true);
Makoto Onuki2206af32017-11-21 16:25:35 -0800394 mHandler.notifyUidForegroundStateChanged(uid);
Makoto Onuki9be01402017-11-10 13:22:26 -0800395 }
396 }
397
Makoto Onuki2206af32017-11-21 16:25:35 -0800398 /**
399 * Sets false for a UID {@link #mForegroundUids}, or remove it when {@code remove} is true.
400 */
Makoto Onuki9be01402017-11-10 13:22:26 -0800401 void uidToBackground(int uid, boolean remove) {
402 synchronized (mLock) {
403 if (!UserHandle.isApp(uid)) {
404 return;
405 }
406 // TODO This can be optimized by calling indexOfKey and sharing the index for get and
407 // put.
408 if (!mForegroundUids.get(uid)) {
409 return;
410 }
411 if (remove) {
412 mForegroundUids.delete(uid);
413 } else {
414 mForegroundUids.put(uid, false);
415 }
Makoto Onuki2206af32017-11-21 16:25:35 -0800416 mHandler.notifyUidForegroundStateChanged(uid);
Makoto Onuki9be01402017-11-10 13:22:26 -0800417 }
418 }
419
Makoto Onuki2206af32017-11-21 16:25:35 -0800420 private final class UidObserver extends IUidObserver.Stub {
Makoto Onuki9be01402017-11-10 13:22:26 -0800421 @Override public void onUidStateChanged(int uid, int procState, long procStateSeq) {
422 }
423
424 @Override public void onUidGone(int uid, boolean disabled) {
425 uidToBackground(uid, /*remove=*/ true);
426 }
427
428 @Override public void onUidActive(int uid) {
429 uidToForeground(uid);
430 }
431
432 @Override public void onUidIdle(int uid, boolean disabled) {
433 // Just to avoid excessive memcpy, don't remove from the array in this case.
434 uidToBackground(uid, /*remove=*/ false);
435 }
436
437 @Override public void onUidCachedChanged(int uid, boolean cached) {
438 }
439 };
440
441 private final class AppOpsWatcher extends IAppOpsCallback.Stub {
442 @Override
443 public void opChanged(int op, int uid, String packageName) throws RemoteException {
Makoto Onuki2206af32017-11-21 16:25:35 -0800444 boolean restricted = false;
445 try {
446 restricted = mAppOpsService.checkOperation(TARGET_OP,
447 uid, packageName) != AppOpsManager.MODE_ALLOWED;
448 } catch (RemoteException e) {
449 // Shouldn't happen
450 }
Makoto Onuki9be01402017-11-10 13:22:26 -0800451 synchronized (mLock) {
Makoto Onuki2206af32017-11-21 16:25:35 -0800452 if (updateForcedAppStandbyUidPackageLocked(uid, packageName, restricted)) {
453 mHandler.notifyRunAnyAppOpsChanged(uid, packageName);
454 }
455 }
456 }
457 }
Makoto Onuki9be01402017-11-10 13:22:26 -0800458
Makoto Onuki2206af32017-11-21 16:25:35 -0800459 private final class MyReceiver extends BroadcastReceiver {
460 @Override
461 public void onReceive(Context context, Intent intent) {
462 if (Intent.ACTION_USER_REMOVED.equals(intent.getAction())) {
463 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
464 if (userId > 0) {
465 mHandler.doUserRemoved(userId);
Makoto Onuki9be01402017-11-10 13:22:26 -0800466 }
467 }
468 }
469 }
470
471 private Listener[] cloneListeners() {
472 synchronized (mLock) {
473 return mListeners.toArray(new Listener[mListeners.size()]);
474 }
475 }
476
Makoto Onuki2206af32017-11-21 16:25:35 -0800477 private class MyHandler extends Handler {
478 private static final int MSG_UID_STATE_CHANGED = 1;
479 private static final int MSG_RUN_ANY_CHANGED = 2;
480 private static final int MSG_ALL_UNWHITELISTED = 3;
481 private static final int MSG_ALL_WHITELIST_CHANGED = 4;
482 private static final int MSG_TEMP_WHITELIST_CHANGED = 5;
483 private static final int MSG_FORCE_ALL_CHANGED = 6;
Makoto Onuki9be01402017-11-10 13:22:26 -0800484
Makoto Onuki2206af32017-11-21 16:25:35 -0800485 private static final int MSG_USER_REMOVED = 7;
Makoto Onuki9be01402017-11-10 13:22:26 -0800486
Makoto Onuki2206af32017-11-21 16:25:35 -0800487 public MyHandler(Looper looper) {
488 super(looper);
Makoto Onuki9be01402017-11-10 13:22:26 -0800489 }
Makoto Onuki2206af32017-11-21 16:25:35 -0800490
491 public void notifyUidForegroundStateChanged(int uid) {
492 obtainMessage(MSG_UID_STATE_CHANGED, uid, 0).sendToTarget();
493 }
494 public void notifyRunAnyAppOpsChanged(int uid, @NonNull String packageName) {
495 obtainMessage(MSG_RUN_ANY_CHANGED, uid, 0, packageName).sendToTarget();
496 }
497
498 public void notifyAllUnwhitelisted() {
499 obtainMessage(MSG_ALL_UNWHITELISTED).sendToTarget();
500 }
501
502 public void notifyAllWhitelistChanged() {
503 obtainMessage(MSG_ALL_WHITELIST_CHANGED).sendToTarget();
504 }
505
506 public void notifyTempWhitelistChanged() {
507 obtainMessage(MSG_TEMP_WHITELIST_CHANGED).sendToTarget();
508 }
509
510 public void notifyForceAllAppsStandbyChanged() {
511 obtainMessage(MSG_FORCE_ALL_CHANGED).sendToTarget();
512 }
513
514 public void doUserRemoved(int userId) {
515 obtainMessage(MSG_USER_REMOVED, userId, 0).sendToTarget();
516 }
517
518 @Override
519 public void dispatchMessage(Message msg) {
520 switch (msg.what) {
521 case MSG_USER_REMOVED:
522 handleUserRemoved(msg.arg1);
523 return;
524 }
525
526 // Only notify the listeners when started.
527 synchronized (mLock) {
528 if (!mStarted) {
529 return;
530 }
531 }
532 final ForceAppStandbyTracker sender = ForceAppStandbyTracker.this;
533
534 switch (msg.what) {
535 case MSG_UID_STATE_CHANGED:
536 for (Listener l : cloneListeners()) {
537 l.onUidForegroundStateChanged(sender, msg.arg1);
538 }
539 return;
540 case MSG_RUN_ANY_CHANGED:
541 for (Listener l : cloneListeners()) {
542 l.onRunAnyAppOpsChanged(sender, msg.arg1, (String) msg.obj);
543 }
544 return;
545 case MSG_ALL_UNWHITELISTED:
546 for (Listener l : cloneListeners()) {
547 l.onPowerSaveUnwhitelisted(sender);
548 }
549 return;
550 case MSG_ALL_WHITELIST_CHANGED:
551 for (Listener l : cloneListeners()) {
552 l.onPowerSaveWhitelistedChanged(sender);
553 }
554 return;
555 case MSG_TEMP_WHITELIST_CHANGED:
556 for (Listener l : cloneListeners()) {
557 l.onTempPowerSaveWhitelistChanged(sender);
558 }
559 return;
560 case MSG_FORCE_ALL_CHANGED:
561 for (Listener l : cloneListeners()) {
562 l.onForceAllAppsStandbyChanged(sender);
563 }
564 return;
565 case MSG_USER_REMOVED:
566 handleUserRemoved(msg.arg1);
567 return;
568 }
569 }
570 }
571
572 void handleUserRemoved(int removedUserId) {
573 synchronized (mLock) {
574 for (int i = mRunAnyRestrictedPackages.size() - 1; i >= 0; i--) {
575 final Pair<Integer, String> pair = mRunAnyRestrictedPackages.valueAt(i);
576 final int uid = pair.first;
577 final int userId = UserHandle.getUserId(uid);
578
579 if (userId == removedUserId) {
580 mRunAnyRestrictedPackages.removeAt(i);
581 }
582 }
583 for (int i = mForegroundUids.size() - 1; i >= 0; i--) {
584 final int uid = mForegroundUids.keyAt(i);
585 final int userId = UserHandle.getUserId(uid);
586
587 if (userId == removedUserId) {
588 mForegroundUids.removeAt(i);
589 }
590 }
591 }
592 }
593
594 /**
595 * Called by device idle controller to update the power save whitelists.
596 */
597 public void setPowerSaveWhitelistAppIds(
598 int[] powerSaveWhitelistAllAppIdArray, int[] tempWhitelistAppIdArray) {
599 synchronized (mLock) {
600 final int[] previousWhitelist = mPowerWhitelistedAllAppIds;
601 final int[] previousTempWhitelist = mTempWhitelistedAppIds;
602
603 mPowerWhitelistedAllAppIds = powerSaveWhitelistAllAppIdArray;
604 mTempWhitelistedAppIds = tempWhitelistAppIdArray;
605
606 if (isAnyAppIdUnwhitelisted(previousWhitelist, mPowerWhitelistedAllAppIds)) {
607 mHandler.notifyAllUnwhitelisted();
608 } else if (!Arrays.equals(previousWhitelist, mPowerWhitelistedAllAppIds)) {
609 mHandler.notifyAllWhitelistChanged();
610 }
611
612 if (!Arrays.equals(previousTempWhitelist, mTempWhitelistedAppIds)) {
613 mHandler.notifyTempWhitelistChanged();
614 }
615
616 }
617 }
618
619 /**
620 * @retunr true if a sorted app-id array {@code prevArray} has at least one element
621 * that's not in a sorted app-id array {@code newArray}.
622 */
623 @VisibleForTesting
624 static boolean isAnyAppIdUnwhitelisted(int[] prevArray, int[] newArray) {
625 int i1 = 0;
626 int i2 = 0;
627 boolean prevFinished;
628 boolean newFinished;
629
630 for (;;) {
631 prevFinished = i1 >= prevArray.length;
632 newFinished = i2 >= newArray.length;
633 if (prevFinished || newFinished) {
634 break;
635 }
636 int a1 = prevArray[i1];
637 int a2 = newArray[i2];
638
639 if (a1 == a2) {
640 i1++;
641 i2++;
642 continue;
643 }
644 if (a1 < a2) {
645 // prevArray has an element that's not in a2.
646 return true;
647 }
648 i2++;
649 }
650 if (prevFinished) {
651 return false;
652 }
653 return newFinished;
Makoto Onuki9be01402017-11-10 13:22:26 -0800654 }
655
656 // Public interface.
657
658 /**
659 * Register a new listener.
660 */
661 public void addListener(@NonNull Listener listener) {
662 synchronized (mLock) {
663 mListeners.add(listener);
664 }
665 }
666
667 /**
Makoto Onuki2206af32017-11-21 16:25:35 -0800668 * @return whether alarms should be restricted for a UID package-name.
Makoto Onuki9be01402017-11-10 13:22:26 -0800669 */
Makoto Onuki2206af32017-11-21 16:25:35 -0800670 public boolean areAlarmsRestricted(int uid, @NonNull String packageName) {
671 return isRestricted(uid, packageName, /*useTempWhitelistToo=*/ false);
672 }
673
674 /**
675 * @return whether jobs should be restricted for a UID package-name.
676 */
677 public boolean areJobsRestricted(int uid, @NonNull String packageName) {
678 return isRestricted(uid, packageName, /*useTempWhitelistToo=*/ true);
679 }
680
681 /**
682 * @return whether force-app-standby is effective for a UID package-name.
683 */
684 private boolean isRestricted(int uid, @NonNull String packageName,
685 boolean useTempWhitelistToo) {
Makoto Onuki9be01402017-11-10 13:22:26 -0800686 if (isInForeground(uid)) {
687 return false;
688 }
689 synchronized (mLock) {
Makoto Onuki2206af32017-11-21 16:25:35 -0800690 // Whitelisted?
691 final int appId = UserHandle.getAppId(uid);
692 if (ArrayUtils.contains(mPowerWhitelistedAllAppIds, appId)) {
693 return false;
694 }
695 if (useTempWhitelistToo &&
696 ArrayUtils.contains(mTempWhitelistedAppIds, appId)) {
697 return false;
698 }
699
Makoto Onuki9be01402017-11-10 13:22:26 -0800700 if (mForceAllAppsStandby) {
701 return true;
702 }
Makoto Onuki2206af32017-11-21 16:25:35 -0800703
704 return isRunAnyRestrictedLocked(uid, packageName);
Makoto Onuki9be01402017-11-10 13:22:26 -0800705 }
706 }
707
Makoto Onuki2206af32017-11-21 16:25:35 -0800708 /**
709 * @return whether a UID is in the foreground or not.
710 *
711 * Note clients normally shouldn't need to access it. It's only for dumpsys.
712 */
Makoto Onuki9be01402017-11-10 13:22:26 -0800713 public boolean isInForeground(int uid) {
714 if (!UserHandle.isApp(uid)) {
715 return true;
716 }
717 synchronized (mLock) {
718 return mForegroundUids.get(uid);
719 }
720 }
721
Makoto Onuki2206af32017-11-21 16:25:35 -0800722 /**
723 * @return whether force all apps standby is enabled or not.
724 *
725 * Note clients normally shouldn't need to access it.
726 */
727 boolean isForceAllAppsStandbyEnabled() {
Makoto Onuki9be01402017-11-10 13:22:26 -0800728 synchronized (mLock) {
729 return mForceAllAppsStandby;
730 }
731 }
732
Makoto Onuki2206af32017-11-21 16:25:35 -0800733 /**
734 * @return whether a UID/package has {@code OP_RUN_ANY_IN_BACKGROUND} allowed or not.
735 *
736 * Note clients normally shouldn't need to access it. It's only for dumpsys.
737 */
Makoto Onuki9be01402017-11-10 13:22:26 -0800738 public boolean isRunAnyInBackgroundAppOpsAllowed(int uid, @NonNull String packageName) {
739 synchronized (mLock) {
Makoto Onuki2206af32017-11-21 16:25:35 -0800740 return !isRunAnyRestrictedLocked(uid, packageName);
Makoto Onuki9be01402017-11-10 13:22:26 -0800741 }
742 }
743
Makoto Onuki2206af32017-11-21 16:25:35 -0800744 /**
745 * @return whether a UID is in the user / system defined power-save whitelist or not.
746 *
747 * Note clients normally shouldn't need to access it. It's only for dumpsys.
748 */
749 public boolean isUidPowerSaveWhitelisted(int uid) {
Makoto Onuki9be01402017-11-10 13:22:26 -0800750 synchronized (mLock) {
Makoto Onuki2206af32017-11-21 16:25:35 -0800751 return ArrayUtils.contains(mPowerWhitelistedAllAppIds, UserHandle.getAppId(uid));
Makoto Onuki9be01402017-11-10 13:22:26 -0800752 }
753 }
754
Makoto Onuki2206af32017-11-21 16:25:35 -0800755 /**
756 * @return whether a UID is in the temp power-save whitelist or not.
757 *
758 * Note clients normally shouldn't need to access it. It's only for dumpsys.
759 */
760 public boolean isUidTempPowerSaveWhitelisted(int uid) {
Makoto Onuki9be01402017-11-10 13:22:26 -0800761 synchronized (mLock) {
Makoto Onuki2206af32017-11-21 16:25:35 -0800762 return ArrayUtils.contains(mTempWhitelistedAppIds, UserHandle.getAppId(uid));
763 }
764 }
765
766 public void dump(PrintWriter pw, String indent) {
767 synchronized (mLock) {
768 pw.print(indent);
769 pw.print("Force all apps standby: ");
770 pw.println(isForceAllAppsStandbyEnabled());
771
772 pw.print(indent);
773 pw.print("Foreground uids: [");
774
775 String sep = "";
776 for (int i = 0; i < mForegroundUids.size(); i++) {
777 if (mForegroundUids.valueAt(i)) {
778 pw.print(sep);
779 pw.print(UserHandle.formatUid(mForegroundUids.keyAt(i)));
780 sep = " ";
781 }
782 }
783 pw.println("]");
784
785 pw.print(indent);
786 pw.print("Whitelist appids: ");
787 pw.println(Arrays.toString(mPowerWhitelistedAllAppIds));
788
789 pw.print(indent);
790 pw.print("Temp whitelist appids: ");
791 pw.println(Arrays.toString(mTempWhitelistedAppIds));
792
793 pw.print(indent);
794 pw.println("Restricted packages:");
795 for (Pair<Integer, String> uidAndPackage : mRunAnyRestrictedPackages) {
796 pw.print(indent);
797 pw.print(" ");
798 pw.print(UserHandle.formatUid(uidAndPackage.first));
799 pw.print(" ");
800 pw.print(uidAndPackage.second);
801 pw.println();
802 }
803 }
804 }
805
806 public void dumpProto(ProtoOutputStream proto, long fieldId) {
807 synchronized (mLock) {
808 final long token = proto.start(fieldId);
809
810 proto.write(ForceAppStandbyTrackerProto.FORCE_ALL_APPS_STANDBY, mForceAllAppsStandby);
811
812 for (int i = 0; i < mForegroundUids.size(); i++) {
813 if (mForegroundUids.valueAt(i)) {
814 proto.write(ForceAppStandbyTrackerProto.FOREGROUND_UIDS,
815 mForegroundUids.keyAt(i));
816 }
817 }
818
819 for (int appId : mPowerWhitelistedAllAppIds) {
820 proto.write(ForceAppStandbyTrackerProto.POWER_SAVE_WHITELIST_APP_IDS, appId);
821 }
822
823 for (int appId : mTempWhitelistedAppIds) {
824 proto.write(ForceAppStandbyTrackerProto.TEMP_POWER_SAVE_WHITELIST_APP_IDS, appId);
825 }
826
827 for (Pair<Integer, String> uidAndPackage : mRunAnyRestrictedPackages) {
828 final long token2 = proto.start(
829 ForceAppStandbyTrackerProto.RUN_ANY_IN_BACKGROUND_RESTRICTED_PACKAGES);
830 proto.write(RunAnyInBackgroundRestrictedPackages.UID, uidAndPackage.first);
831 proto.write(RunAnyInBackgroundRestrictedPackages.PACKAGE_NAME,
832 uidAndPackage.second);
833 proto.end(token2);
834 }
835 proto.end(token);
Makoto Onuki9be01402017-11-10 13:22:26 -0800836 }
837 }
838}