blob: a75a3675f7f9849112c2e684952abec86decb5ba [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;
Suprabh Shukla4deb8522018-01-08 16:27:10 -080028import android.database.ContentObserver;
Makoto Onuki9be01402017-11-10 13:22:26 -080029import android.os.Handler;
Makoto Onuki2206af32017-11-21 16:25:35 -080030import android.os.Looper;
31import android.os.Message;
Makoto Onuki9be01402017-11-10 13:22:26 -080032import android.os.PowerManager.ServiceType;
33import android.os.PowerManagerInternal;
34import android.os.RemoteException;
35import android.os.ServiceManager;
36import android.os.UserHandle;
Suprabh Shukla4deb8522018-01-08 16:27:10 -080037import android.provider.Settings;
Makoto Onuki9be01402017-11-10 13:22:26 -080038import android.util.ArraySet;
39import android.util.Pair;
Suprabh Shukla4deb8522018-01-08 16:27:10 -080040import android.util.Slog;
Makoto Onuki9be01402017-11-10 13:22:26 -080041import android.util.SparseBooleanArray;
Makoto Onuki2206af32017-11-21 16:25:35 -080042import android.util.proto.ProtoOutputStream;
Makoto Onuki9be01402017-11-10 13:22:26 -080043
44import com.android.internal.annotations.GuardedBy;
Makoto Onuki2206af32017-11-21 16:25:35 -080045import com.android.internal.annotations.VisibleForTesting;
Makoto Onuki9be01402017-11-10 13:22:26 -080046import com.android.internal.app.IAppOpsCallback;
47import com.android.internal.app.IAppOpsService;
Makoto Onuki2206af32017-11-21 16:25:35 -080048import com.android.internal.util.ArrayUtils;
Makoto Onuki9be01402017-11-10 13:22:26 -080049import com.android.internal.util.Preconditions;
Makoto Onuki2206af32017-11-21 16:25:35 -080050import com.android.server.ForceAppStandbyTrackerProto.RunAnyInBackgroundRestrictedPackages;
Makoto Onuki9be01402017-11-10 13:22:26 -080051
Makoto Onuki2206af32017-11-21 16:25:35 -080052import java.io.PrintWriter;
53import java.util.Arrays;
Makoto Onuki9be01402017-11-10 13:22:26 -080054import java.util.List;
55
56/**
Makoto Onuki2206af32017-11-21 16:25:35 -080057 * Class to keep track of the information related to "force app standby", which includes:
58 * - OP_RUN_ANY_IN_BACKGROUND for each package
59 * - UID foreground state
60 * - User+system power save whitelist
61 * - Temporary power save whitelist
62 * - Global "force all apps standby" mode enforced by battery saver.
Makoto Onuki9be01402017-11-10 13:22:26 -080063 *
Makoto Onuki2206af32017-11-21 16:25:35 -080064 * TODO: In general, we can reduce the number of callbacks by checking all signals before sending
Suprabh Shukla4deb8522018-01-08 16:27:10 -080065 * each callback. For example, even when an UID comes into the foreground, if it wasn't
66 * originally restricted, then there's no need to send an event.
67 * Doing this would be error-prone, so we punt it for now, but we should revisit it later.
Makoto Onuki2206af32017-11-21 16:25:35 -080068 *
69 * Test:
Suprabh Shukla4deb8522018-01-08 16:27:10 -080070 * atest $ANDROID_BUILD_TOP/frameworks/base/services/tests/servicestests/src/com/android/server/ForceAppStandbyTrackerTest.java
Makoto Onuki9be01402017-11-10 13:22:26 -080071 */
72public class ForceAppStandbyTracker {
73 private static final String TAG = "ForceAppStandbyTracker";
Suprabh Shukla4deb8522018-01-08 16:27:10 -080074 private static final boolean DEBUG = false;
Makoto Onuki9be01402017-11-10 13:22:26 -080075
76 @GuardedBy("ForceAppStandbyTracker.class")
77 private static ForceAppStandbyTracker sInstance;
78
79 private final Object mLock = new Object();
80 private final Context mContext;
81
Makoto Onuki2206af32017-11-21 16:25:35 -080082 @VisibleForTesting
83 static final int TARGET_OP = AppOpsManager.OP_RUN_ANY_IN_BACKGROUND;
84
85 IActivityManager mIActivityManager;
Makoto Onuki9be01402017-11-10 13:22:26 -080086 AppOpsManager mAppOpsManager;
87 IAppOpsService mAppOpsService;
88 PowerManagerInternal mPowerManagerInternal;
89
Makoto Onuki2206af32017-11-21 16:25:35 -080090 private final MyHandler mHandler;
Makoto Onuki9be01402017-11-10 13:22:26 -080091
92 /**
93 * Pair of (uid (not user-id), packageName) with OP_RUN_ANY_IN_BACKGROUND *not* allowed.
94 */
95 @GuardedBy("mLock")
Makoto Onuki2206af32017-11-21 16:25:35 -080096 final ArraySet<Pair<Integer, String>> mRunAnyRestrictedPackages = new ArraySet<>();
Makoto Onuki9be01402017-11-10 13:22:26 -080097
98 @GuardedBy("mLock")
99 final SparseBooleanArray mForegroundUids = new SparseBooleanArray();
100
Makoto Onuki71755c92018-01-16 14:15:44 -0800101 /**
102 * System except-idle + user whitelist in the device idle controller.
103 */
Makoto Onuki9be01402017-11-10 13:22:26 -0800104 @GuardedBy("mLock")
Makoto Onuki2206af32017-11-21 16:25:35 -0800105 private int[] mPowerWhitelistedAllAppIds = new int[0];
106
107 @GuardedBy("mLock")
108 private int[] mTempWhitelistedAppIds = mPowerWhitelistedAllAppIds;
109
110 @GuardedBy("mLock")
Makoto Onuki9be01402017-11-10 13:22:26 -0800111 final ArraySet<Listener> mListeners = new ArraySet<>();
112
113 @GuardedBy("mLock")
114 boolean mStarted;
115
116 @GuardedBy("mLock")
Suprabh Shukla4deb8522018-01-08 16:27:10 -0800117 boolean mForceAllAppsStandby; // True if device is in extreme battery saver mode
118
119 @GuardedBy("mLock")
120 boolean mForcedAppStandbyEnabled; // True if the forced app standby feature is enabled
121
122 private class FeatureFlagObserver extends ContentObserver {
123 FeatureFlagObserver() {
124 super(null);
125 }
126
127 void register() {
128 mContext.getContentResolver().registerContentObserver(
129 Settings.Global.getUriFor(Settings.Global.FORCED_APP_STANDBY_ENABLED),
130 false, this);
131 }
132
133 boolean isForcedAppStandbyEnabled() {
134 return Settings.Global.getInt(mContext.getContentResolver(),
135 Settings.Global.FORCED_APP_STANDBY_ENABLED, 1) == 1;
136 }
137
138 @Override
139 public void onChange(boolean selfChange) {
140 final boolean enabled = isForcedAppStandbyEnabled();
141 synchronized (mLock) {
142 if (mForcedAppStandbyEnabled == enabled) {
143 return;
144 }
145 mForcedAppStandbyEnabled = enabled;
146 if (DEBUG) {
147 Slog.d(TAG,
148 "Forced app standby feature flag changed: " + mForcedAppStandbyEnabled);
149 }
150 }
151 mHandler.notifyFeatureFlagChanged();
152 }
153 }
Makoto Onuki9be01402017-11-10 13:22:26 -0800154
155 public static abstract class Listener {
Makoto Onuki2206af32017-11-21 16:25:35 -0800156 /**
157 * This is called when the OP_RUN_ANY_IN_BACKGROUND appops changed for a package.
158 */
159 private void onRunAnyAppOpsChanged(ForceAppStandbyTracker sender,
160 int uid, @NonNull String packageName) {
161 updateJobsForUidPackage(uid, packageName);
162
163 if (!sender.areAlarmsRestricted(uid, packageName)) {
164 unblockAlarmsForUidPackage(uid, packageName);
165 }
Makoto Onuki9be01402017-11-10 13:22:26 -0800166 }
167
Makoto Onuki2206af32017-11-21 16:25:35 -0800168 /**
169 * This is called when the foreground state changed for a UID.
170 */
171 private void onUidForegroundStateChanged(ForceAppStandbyTracker sender, int uid) {
172 updateJobsForUid(uid);
173
174 if (sender.isInForeground(uid)) {
175 unblockAlarmsForUid(uid);
176 }
177 }
178
179 /**
180 * This is called when an app-id(s) is removed from the power save whitelist.
181 */
182 private void onPowerSaveUnwhitelisted(ForceAppStandbyTracker sender) {
183 updateAllJobs();
184 unblockAllUnrestrictedAlarms();
185 }
186
187 /**
188 * This is called when the power save whitelist changes, excluding the
189 * {@link #onPowerSaveUnwhitelisted} case.
190 */
191 private void onPowerSaveWhitelistedChanged(ForceAppStandbyTracker sender) {
192 updateAllJobs();
193 }
194
195 /**
196 * This is called when the temp whitelist changes.
197 */
198 private void onTempPowerSaveWhitelistChanged(ForceAppStandbyTracker sender) {
199
200 // TODO This case happens rather frequently; consider optimizing and update jobs
201 // only for affected app-ids.
202
203 updateAllJobs();
204 }
205
206 /**
207 * This is called when the global "force all apps standby" flag changes.
208 */
209 private void onForceAllAppsStandbyChanged(ForceAppStandbyTracker sender) {
210 updateAllJobs();
211
212 if (!sender.isForceAllAppsStandbyEnabled()) {
213 unblockAllUnrestrictedAlarms();
214 }
215 }
216
217 /**
218 * Called when the job restrictions for multiple UIDs might have changed, so the job
219 * scheduler should re-evaluate all restrictions for all jobs.
220 */
221 public void updateAllJobs() {
222 }
223
224 /**
225 * Called when the job restrictions for a UID might have changed, so the job
226 * scheduler should re-evaluate all restrictions for all jobs.
227 */
228 public void updateJobsForUid(int uid) {
229 }
230
231 /**
232 * Called when the job restrictions for a UID - package might have changed, so the job
233 * scheduler should re-evaluate all restrictions for all jobs.
234 */
235 public void updateJobsForUidPackage(int uid, String packageName) {
236 }
237
238 /**
239 * Called when the job restrictions for multiple UIDs might have changed, so the alarm
240 * manager should re-evaluate all restrictions for all blocked jobs.
241 */
242 public void unblockAllUnrestrictedAlarms() {
243 }
244
245 /**
246 * Called when all jobs for a specific UID are unblocked.
247 */
248 public void unblockAlarmsForUid(int uid) {
249 }
250
251 /**
252 * Called when all alarms for a specific UID - package are unblocked.
253 */
254 public void unblockAlarmsForUidPackage(int uid, String packageName) {
Makoto Onuki9be01402017-11-10 13:22:26 -0800255 }
256 }
257
Makoto Onuki2206af32017-11-21 16:25:35 -0800258 @VisibleForTesting
259 ForceAppStandbyTracker(Context context, Looper looper) {
Makoto Onuki9be01402017-11-10 13:22:26 -0800260 mContext = context;
Makoto Onuki2206af32017-11-21 16:25:35 -0800261 mHandler = new MyHandler(looper);
262 }
263
264 private ForceAppStandbyTracker(Context context) {
265 this(context, FgThread.get().getLooper());
Makoto Onuki9be01402017-11-10 13:22:26 -0800266 }
267
268 /**
269 * Get the singleton instance.
270 */
271 public static synchronized ForceAppStandbyTracker getInstance(Context context) {
272 if (sInstance == null) {
273 sInstance = new ForceAppStandbyTracker(context);
274 }
275 return sInstance;
276 }
277
278 /**
279 * Call it when the system is ready.
280 */
281 public void start() {
282 synchronized (mLock) {
283 if (mStarted) {
284 return;
285 }
286 mStarted = true;
287
Makoto Onuki2206af32017-11-21 16:25:35 -0800288 mIActivityManager = Preconditions.checkNotNull(injectIActivityManager());
289 mAppOpsManager = Preconditions.checkNotNull(injectAppOpsManager());
290 mAppOpsService = Preconditions.checkNotNull(injectIAppOpsService());
291 mPowerManagerInternal = Preconditions.checkNotNull(injectPowerManagerInternal());
Suprabh Shukla4deb8522018-01-08 16:27:10 -0800292 final FeatureFlagObserver flagObserver = new FeatureFlagObserver();
293 flagObserver.register();
294 mForcedAppStandbyEnabled = flagObserver.isForcedAppStandbyEnabled();
Makoto Onuki9be01402017-11-10 13:22:26 -0800295
296 try {
Makoto Onuki2206af32017-11-21 16:25:35 -0800297 mIActivityManager.registerUidObserver(new UidObserver(),
Makoto Onuki9be01402017-11-10 13:22:26 -0800298 ActivityManager.UID_OBSERVER_GONE | ActivityManager.UID_OBSERVER_IDLE
299 | ActivityManager.UID_OBSERVER_ACTIVE,
300 ActivityManager.PROCESS_STATE_UNKNOWN, null);
Makoto Onuki2206af32017-11-21 16:25:35 -0800301 mAppOpsService.startWatchingMode(TARGET_OP, null,
Makoto Onuki9be01402017-11-10 13:22:26 -0800302 new AppOpsWatcher());
303 } catch (RemoteException e) {
304 // shouldn't happen.
305 }
306
Makoto Onuki2206af32017-11-21 16:25:35 -0800307 IntentFilter filter = new IntentFilter();
308 filter.addAction(Intent.ACTION_USER_REMOVED);
309 mContext.registerReceiver(new MyReceiver(), filter);
Makoto Onuki9be01402017-11-10 13:22:26 -0800310
311 refreshForcedAppStandbyUidPackagesLocked();
Makoto Onuki2206af32017-11-21 16:25:35 -0800312
313 mPowerManagerInternal.registerLowPowerModeObserver(
314 ServiceType.FORCE_ALL_APPS_STANDBY,
315 (state) -> updateForceAllAppsStandby(state.batterySaverEnabled));
316
317 updateForceAllAppsStandby(mPowerManagerInternal.getLowPowerState(
318 ServiceType.FORCE_ALL_APPS_STANDBY).batterySaverEnabled);
Makoto Onuki9be01402017-11-10 13:22:26 -0800319 }
320 }
321
Makoto Onuki2206af32017-11-21 16:25:35 -0800322 @VisibleForTesting
323 AppOpsManager injectAppOpsManager() {
324 return mContext.getSystemService(AppOpsManager.class);
325 }
326
327 @VisibleForTesting
328 IAppOpsService injectIAppOpsService() {
329 return IAppOpsService.Stub.asInterface(
330 ServiceManager.getService(Context.APP_OPS_SERVICE));
331 }
332
333 @VisibleForTesting
334 IActivityManager injectIActivityManager() {
335 return ActivityManager.getService();
336 }
337
338 @VisibleForTesting
339 PowerManagerInternal injectPowerManagerInternal() {
340 return LocalServices.getService(PowerManagerInternal.class);
341 }
342
Makoto Onuki9be01402017-11-10 13:22:26 -0800343 /**
Makoto Onuki2206af32017-11-21 16:25:35 -0800344 * Update {@link #mRunAnyRestrictedPackages} with the current app ops state.
Makoto Onuki9be01402017-11-10 13:22:26 -0800345 */
346 private void refreshForcedAppStandbyUidPackagesLocked() {
Makoto Onuki2206af32017-11-21 16:25:35 -0800347 mRunAnyRestrictedPackages.clear();
348 final List<PackageOps> ops = mAppOpsManager.getPackagesForOps(
349 new int[] {TARGET_OP});
Makoto Onuki9be01402017-11-10 13:22:26 -0800350
351 if (ops == null) {
352 return;
353 }
354 final int size = ops.size();
355 for (int i = 0; i < size; i++) {
356 final AppOpsManager.PackageOps pkg = ops.get(i);
357 final List<AppOpsManager.OpEntry> entries = ops.get(i).getOps();
358
359 for (int j = 0; j < entries.size(); j++) {
360 AppOpsManager.OpEntry ent = entries.get(j);
Makoto Onuki2206af32017-11-21 16:25:35 -0800361 if (ent.getOp() != TARGET_OP) {
Makoto Onuki9be01402017-11-10 13:22:26 -0800362 continue;
363 }
364 if (ent.getMode() != AppOpsManager.MODE_ALLOWED) {
Makoto Onuki2206af32017-11-21 16:25:35 -0800365 mRunAnyRestrictedPackages.add(Pair.create(
Makoto Onuki9be01402017-11-10 13:22:26 -0800366 pkg.getUid(), pkg.getPackageName()));
367 }
368 }
369 }
370 }
371
Makoto Onuki2206af32017-11-21 16:25:35 -0800372 /**
373 * Update {@link #mForceAllAppsStandby} and notifies the listeners.
374 */
375 void updateForceAllAppsStandby(boolean enable) {
376 synchronized (mLock) {
377 if (enable == mForceAllAppsStandby) {
378 return;
379 }
380 mForceAllAppsStandby = enable;
381
382 mHandler.notifyForceAllAppsStandbyChanged();
Makoto Onuki9be01402017-11-10 13:22:26 -0800383 }
384 }
385
386 private int findForcedAppStandbyUidPackageIndexLocked(int uid, @NonNull String packageName) {
Makoto Onuki2206af32017-11-21 16:25:35 -0800387 final int size = mRunAnyRestrictedPackages.size();
388 if (size > 8) {
389 return mRunAnyRestrictedPackages.indexOf(Pair.create(uid, packageName));
390 }
Makoto Onuki9be01402017-11-10 13:22:26 -0800391 for (int i = 0; i < size; i++) {
Makoto Onuki2206af32017-11-21 16:25:35 -0800392 final Pair<Integer, String> pair = mRunAnyRestrictedPackages.valueAt(i);
Makoto Onuki9be01402017-11-10 13:22:26 -0800393
394 if ((pair.first == uid) && packageName.equals(pair.second)) {
395 return i;
396 }
397 }
398 return -1;
399 }
400
401 /**
Makoto Onuki2206af32017-11-21 16:25:35 -0800402 * @return whether a uid package-name pair is in mRunAnyRestrictedPackages.
Makoto Onuki9be01402017-11-10 13:22:26 -0800403 */
Makoto Onuki2206af32017-11-21 16:25:35 -0800404 boolean isRunAnyRestrictedLocked(int uid, @NonNull String packageName) {
Makoto Onuki9be01402017-11-10 13:22:26 -0800405 return findForcedAppStandbyUidPackageIndexLocked(uid, packageName) >= 0;
406 }
407
Makoto Onuki2206af32017-11-21 16:25:35 -0800408 /**
409 * Add to / remove from {@link #mRunAnyRestrictedPackages}.
410 */
411 boolean updateForcedAppStandbyUidPackageLocked(int uid, @NonNull String packageName,
Makoto Onuki9be01402017-11-10 13:22:26 -0800412 boolean restricted) {
Suprabh Shukla4deb8522018-01-08 16:27:10 -0800413 final int index = findForcedAppStandbyUidPackageIndexLocked(uid, packageName);
Makoto Onuki9be01402017-11-10 13:22:26 -0800414 final boolean wasRestricted = index >= 0;
415 if (wasRestricted == restricted) {
416 return false;
417 }
418 if (restricted) {
Makoto Onuki2206af32017-11-21 16:25:35 -0800419 mRunAnyRestrictedPackages.add(Pair.create(uid, packageName));
Makoto Onuki9be01402017-11-10 13:22:26 -0800420 } else {
Makoto Onuki2206af32017-11-21 16:25:35 -0800421 mRunAnyRestrictedPackages.removeAt(index);
Makoto Onuki9be01402017-11-10 13:22:26 -0800422 }
423 return true;
424 }
425
Makoto Onuki2206af32017-11-21 16:25:35 -0800426 /**
427 * Puts a UID to {@link #mForegroundUids}.
428 */
Makoto Onuki9be01402017-11-10 13:22:26 -0800429 void uidToForeground(int uid) {
430 synchronized (mLock) {
431 if (!UserHandle.isApp(uid)) {
432 return;
433 }
434 // TODO This can be optimized by calling indexOfKey and sharing the index for get and
435 // put.
436 if (mForegroundUids.get(uid)) {
437 return;
438 }
439 mForegroundUids.put(uid, true);
Makoto Onuki2206af32017-11-21 16:25:35 -0800440 mHandler.notifyUidForegroundStateChanged(uid);
Makoto Onuki9be01402017-11-10 13:22:26 -0800441 }
442 }
443
Makoto Onuki2206af32017-11-21 16:25:35 -0800444 /**
445 * Sets false for a UID {@link #mForegroundUids}, or remove it when {@code remove} is true.
446 */
Makoto Onuki9be01402017-11-10 13:22:26 -0800447 void uidToBackground(int uid, boolean remove) {
448 synchronized (mLock) {
449 if (!UserHandle.isApp(uid)) {
450 return;
451 }
452 // TODO This can be optimized by calling indexOfKey and sharing the index for get and
453 // put.
454 if (!mForegroundUids.get(uid)) {
455 return;
456 }
457 if (remove) {
458 mForegroundUids.delete(uid);
459 } else {
460 mForegroundUids.put(uid, false);
461 }
Makoto Onuki2206af32017-11-21 16:25:35 -0800462 mHandler.notifyUidForegroundStateChanged(uid);
Makoto Onuki9be01402017-11-10 13:22:26 -0800463 }
464 }
465
Makoto Onuki2206af32017-11-21 16:25:35 -0800466 private final class UidObserver extends IUidObserver.Stub {
Suprabh Shukla4deb8522018-01-08 16:27:10 -0800467 @Override
468 public void onUidStateChanged(int uid, int procState, long procStateSeq) {
Makoto Onuki9be01402017-11-10 13:22:26 -0800469 }
470
Suprabh Shukla4deb8522018-01-08 16:27:10 -0800471 @Override
472 public void onUidGone(int uid, boolean disabled) {
Makoto Onuki9be01402017-11-10 13:22:26 -0800473 uidToBackground(uid, /*remove=*/ true);
474 }
475
Suprabh Shukla4deb8522018-01-08 16:27:10 -0800476 @Override
477 public void onUidActive(int uid) {
Makoto Onuki9be01402017-11-10 13:22:26 -0800478 uidToForeground(uid);
479 }
480
Suprabh Shukla4deb8522018-01-08 16:27:10 -0800481 @Override
482 public void onUidIdle(int uid, boolean disabled) {
Makoto Onuki9be01402017-11-10 13:22:26 -0800483 // Just to avoid excessive memcpy, don't remove from the array in this case.
484 uidToBackground(uid, /*remove=*/ false);
485 }
486
Suprabh Shukla4deb8522018-01-08 16:27:10 -0800487 @Override
488 public void onUidCachedChanged(int uid, boolean cached) {
Makoto Onuki9be01402017-11-10 13:22:26 -0800489 }
Suprabh Shukla4deb8522018-01-08 16:27:10 -0800490 }
Makoto Onuki9be01402017-11-10 13:22:26 -0800491
492 private final class AppOpsWatcher extends IAppOpsCallback.Stub {
493 @Override
494 public void opChanged(int op, int uid, String packageName) throws RemoteException {
Makoto Onuki2206af32017-11-21 16:25:35 -0800495 boolean restricted = false;
496 try {
497 restricted = mAppOpsService.checkOperation(TARGET_OP,
498 uid, packageName) != AppOpsManager.MODE_ALLOWED;
499 } catch (RemoteException e) {
500 // Shouldn't happen
501 }
Makoto Onuki9be01402017-11-10 13:22:26 -0800502 synchronized (mLock) {
Makoto Onuki2206af32017-11-21 16:25:35 -0800503 if (updateForcedAppStandbyUidPackageLocked(uid, packageName, restricted)) {
504 mHandler.notifyRunAnyAppOpsChanged(uid, packageName);
505 }
506 }
507 }
508 }
Makoto Onuki9be01402017-11-10 13:22:26 -0800509
Makoto Onuki2206af32017-11-21 16:25:35 -0800510 private final class MyReceiver extends BroadcastReceiver {
511 @Override
512 public void onReceive(Context context, Intent intent) {
513 if (Intent.ACTION_USER_REMOVED.equals(intent.getAction())) {
514 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
515 if (userId > 0) {
516 mHandler.doUserRemoved(userId);
Makoto Onuki9be01402017-11-10 13:22:26 -0800517 }
518 }
519 }
520 }
521
522 private Listener[] cloneListeners() {
523 synchronized (mLock) {
524 return mListeners.toArray(new Listener[mListeners.size()]);
525 }
526 }
527
Makoto Onuki2206af32017-11-21 16:25:35 -0800528 private class MyHandler extends Handler {
529 private static final int MSG_UID_STATE_CHANGED = 1;
530 private static final int MSG_RUN_ANY_CHANGED = 2;
531 private static final int MSG_ALL_UNWHITELISTED = 3;
532 private static final int MSG_ALL_WHITELIST_CHANGED = 4;
533 private static final int MSG_TEMP_WHITELIST_CHANGED = 5;
534 private static final int MSG_FORCE_ALL_CHANGED = 6;
Makoto Onuki2206af32017-11-21 16:25:35 -0800535 private static final int MSG_USER_REMOVED = 7;
Suprabh Shukla4deb8522018-01-08 16:27:10 -0800536 private static final int MSG_FEATURE_FLAG_CHANGED = 8;
Makoto Onuki9be01402017-11-10 13:22:26 -0800537
Makoto Onuki2206af32017-11-21 16:25:35 -0800538 public MyHandler(Looper looper) {
539 super(looper);
Makoto Onuki9be01402017-11-10 13:22:26 -0800540 }
Makoto Onuki2206af32017-11-21 16:25:35 -0800541
542 public void notifyUidForegroundStateChanged(int uid) {
543 obtainMessage(MSG_UID_STATE_CHANGED, uid, 0).sendToTarget();
544 }
Suprabh Shukla4deb8522018-01-08 16:27:10 -0800545
Makoto Onuki2206af32017-11-21 16:25:35 -0800546 public void notifyRunAnyAppOpsChanged(int uid, @NonNull String packageName) {
547 obtainMessage(MSG_RUN_ANY_CHANGED, uid, 0, packageName).sendToTarget();
548 }
549
550 public void notifyAllUnwhitelisted() {
551 obtainMessage(MSG_ALL_UNWHITELISTED).sendToTarget();
552 }
553
554 public void notifyAllWhitelistChanged() {
555 obtainMessage(MSG_ALL_WHITELIST_CHANGED).sendToTarget();
556 }
557
558 public void notifyTempWhitelistChanged() {
559 obtainMessage(MSG_TEMP_WHITELIST_CHANGED).sendToTarget();
560 }
561
562 public void notifyForceAllAppsStandbyChanged() {
563 obtainMessage(MSG_FORCE_ALL_CHANGED).sendToTarget();
564 }
565
Suprabh Shukla4deb8522018-01-08 16:27:10 -0800566 public void notifyFeatureFlagChanged() {
567 obtainMessage(MSG_FEATURE_FLAG_CHANGED).sendToTarget();
568 }
569
Makoto Onuki2206af32017-11-21 16:25:35 -0800570 public void doUserRemoved(int userId) {
571 obtainMessage(MSG_USER_REMOVED, userId, 0).sendToTarget();
572 }
573
574 @Override
Suprabh Shukla4deb8522018-01-08 16:27:10 -0800575 public void handleMessage(Message msg) {
Makoto Onuki2206af32017-11-21 16:25:35 -0800576 switch (msg.what) {
577 case MSG_USER_REMOVED:
578 handleUserRemoved(msg.arg1);
579 return;
580 }
581
582 // Only notify the listeners when started.
583 synchronized (mLock) {
584 if (!mStarted) {
585 return;
586 }
587 }
588 final ForceAppStandbyTracker sender = ForceAppStandbyTracker.this;
589
590 switch (msg.what) {
591 case MSG_UID_STATE_CHANGED:
592 for (Listener l : cloneListeners()) {
593 l.onUidForegroundStateChanged(sender, msg.arg1);
594 }
595 return;
596 case MSG_RUN_ANY_CHANGED:
597 for (Listener l : cloneListeners()) {
598 l.onRunAnyAppOpsChanged(sender, msg.arg1, (String) msg.obj);
599 }
600 return;
601 case MSG_ALL_UNWHITELISTED:
602 for (Listener l : cloneListeners()) {
603 l.onPowerSaveUnwhitelisted(sender);
604 }
605 return;
606 case MSG_ALL_WHITELIST_CHANGED:
607 for (Listener l : cloneListeners()) {
608 l.onPowerSaveWhitelistedChanged(sender);
609 }
610 return;
611 case MSG_TEMP_WHITELIST_CHANGED:
612 for (Listener l : cloneListeners()) {
613 l.onTempPowerSaveWhitelistChanged(sender);
614 }
615 return;
616 case MSG_FORCE_ALL_CHANGED:
617 for (Listener l : cloneListeners()) {
618 l.onForceAllAppsStandbyChanged(sender);
619 }
620 return;
Suprabh Shukla4deb8522018-01-08 16:27:10 -0800621 case MSG_FEATURE_FLAG_CHANGED:
622 // Feature flag for forced app standby changed.
623 final boolean unblockAlarms;
624 synchronized (mLock) {
625 unblockAlarms = !mForcedAppStandbyEnabled && !mForceAllAppsStandby;
626 }
627 for (Listener l: cloneListeners()) {
628 l.updateAllJobs();
629 if (unblockAlarms) {
630 l.unblockAllUnrestrictedAlarms();
631 }
632 }
633 return;
Makoto Onuki2206af32017-11-21 16:25:35 -0800634 case MSG_USER_REMOVED:
635 handleUserRemoved(msg.arg1);
636 return;
637 }
638 }
639 }
640
641 void handleUserRemoved(int removedUserId) {
642 synchronized (mLock) {
643 for (int i = mRunAnyRestrictedPackages.size() - 1; i >= 0; i--) {
644 final Pair<Integer, String> pair = mRunAnyRestrictedPackages.valueAt(i);
645 final int uid = pair.first;
646 final int userId = UserHandle.getUserId(uid);
647
648 if (userId == removedUserId) {
649 mRunAnyRestrictedPackages.removeAt(i);
650 }
651 }
652 for (int i = mForegroundUids.size() - 1; i >= 0; i--) {
653 final int uid = mForegroundUids.keyAt(i);
654 final int userId = UserHandle.getUserId(uid);
655
656 if (userId == removedUserId) {
657 mForegroundUids.removeAt(i);
658 }
659 }
660 }
661 }
662
663 /**
664 * Called by device idle controller to update the power save whitelists.
665 */
666 public void setPowerSaveWhitelistAppIds(
667 int[] powerSaveWhitelistAllAppIdArray, int[] tempWhitelistAppIdArray) {
668 synchronized (mLock) {
669 final int[] previousWhitelist = mPowerWhitelistedAllAppIds;
670 final int[] previousTempWhitelist = mTempWhitelistedAppIds;
671
672 mPowerWhitelistedAllAppIds = powerSaveWhitelistAllAppIdArray;
673 mTempWhitelistedAppIds = tempWhitelistAppIdArray;
674
675 if (isAnyAppIdUnwhitelisted(previousWhitelist, mPowerWhitelistedAllAppIds)) {
676 mHandler.notifyAllUnwhitelisted();
677 } else if (!Arrays.equals(previousWhitelist, mPowerWhitelistedAllAppIds)) {
678 mHandler.notifyAllWhitelistChanged();
679 }
680
681 if (!Arrays.equals(previousTempWhitelist, mTempWhitelistedAppIds)) {
682 mHandler.notifyTempWhitelistChanged();
683 }
684
685 }
686 }
687
688 /**
689 * @retunr true if a sorted app-id array {@code prevArray} has at least one element
690 * that's not in a sorted app-id array {@code newArray}.
691 */
692 @VisibleForTesting
693 static boolean isAnyAppIdUnwhitelisted(int[] prevArray, int[] newArray) {
694 int i1 = 0;
695 int i2 = 0;
696 boolean prevFinished;
697 boolean newFinished;
698
699 for (;;) {
700 prevFinished = i1 >= prevArray.length;
701 newFinished = i2 >= newArray.length;
702 if (prevFinished || newFinished) {
703 break;
704 }
705 int a1 = prevArray[i1];
706 int a2 = newArray[i2];
707
708 if (a1 == a2) {
709 i1++;
710 i2++;
711 continue;
712 }
713 if (a1 < a2) {
714 // prevArray has an element that's not in a2.
715 return true;
716 }
717 i2++;
718 }
719 if (prevFinished) {
720 return false;
721 }
722 return newFinished;
Makoto Onuki9be01402017-11-10 13:22:26 -0800723 }
724
725 // Public interface.
726
727 /**
728 * Register a new listener.
729 */
730 public void addListener(@NonNull Listener listener) {
731 synchronized (mLock) {
732 mListeners.add(listener);
733 }
734 }
735
736 /**
Makoto Onuki2206af32017-11-21 16:25:35 -0800737 * @return whether alarms should be restricted for a UID package-name.
Makoto Onuki9be01402017-11-10 13:22:26 -0800738 */
Makoto Onuki2206af32017-11-21 16:25:35 -0800739 public boolean areAlarmsRestricted(int uid, @NonNull String packageName) {
740 return isRestricted(uid, packageName, /*useTempWhitelistToo=*/ false);
741 }
742
743 /**
744 * @return whether jobs should be restricted for a UID package-name.
745 */
746 public boolean areJobsRestricted(int uid, @NonNull String packageName) {
747 return isRestricted(uid, packageName, /*useTempWhitelistToo=*/ true);
748 }
749
750 /**
751 * @return whether force-app-standby is effective for a UID package-name.
752 */
753 private boolean isRestricted(int uid, @NonNull String packageName,
754 boolean useTempWhitelistToo) {
Makoto Onuki9be01402017-11-10 13:22:26 -0800755 if (isInForeground(uid)) {
756 return false;
757 }
758 synchronized (mLock) {
Makoto Onuki2206af32017-11-21 16:25:35 -0800759 // Whitelisted?
760 final int appId = UserHandle.getAppId(uid);
761 if (ArrayUtils.contains(mPowerWhitelistedAllAppIds, appId)) {
762 return false;
763 }
764 if (useTempWhitelistToo &&
765 ArrayUtils.contains(mTempWhitelistedAppIds, appId)) {
766 return false;
767 }
768
Makoto Onuki9be01402017-11-10 13:22:26 -0800769 if (mForceAllAppsStandby) {
770 return true;
771 }
Makoto Onuki2206af32017-11-21 16:25:35 -0800772
Suprabh Shukla4deb8522018-01-08 16:27:10 -0800773 return mForcedAppStandbyEnabled && isRunAnyRestrictedLocked(uid, packageName);
Makoto Onuki9be01402017-11-10 13:22:26 -0800774 }
775 }
776
Makoto Onuki2206af32017-11-21 16:25:35 -0800777 /**
778 * @return whether a UID is in the foreground or not.
779 *
780 * Note clients normally shouldn't need to access it. It's only for dumpsys.
781 */
Makoto Onuki9be01402017-11-10 13:22:26 -0800782 public boolean isInForeground(int uid) {
783 if (!UserHandle.isApp(uid)) {
784 return true;
785 }
786 synchronized (mLock) {
787 return mForegroundUids.get(uid);
788 }
789 }
790
Makoto Onuki2206af32017-11-21 16:25:35 -0800791 /**
792 * @return whether force all apps standby is enabled or not.
793 *
794 * Note clients normally shouldn't need to access it.
795 */
796 boolean isForceAllAppsStandbyEnabled() {
Makoto Onuki9be01402017-11-10 13:22:26 -0800797 synchronized (mLock) {
798 return mForceAllAppsStandby;
799 }
800 }
801
Makoto Onuki2206af32017-11-21 16:25:35 -0800802 /**
803 * @return whether a UID/package has {@code OP_RUN_ANY_IN_BACKGROUND} allowed or not.
804 *
805 * Note clients normally shouldn't need to access it. It's only for dumpsys.
806 */
Makoto Onuki9be01402017-11-10 13:22:26 -0800807 public boolean isRunAnyInBackgroundAppOpsAllowed(int uid, @NonNull String packageName) {
808 synchronized (mLock) {
Makoto Onuki2206af32017-11-21 16:25:35 -0800809 return !isRunAnyRestrictedLocked(uid, packageName);
Makoto Onuki9be01402017-11-10 13:22:26 -0800810 }
811 }
812
Makoto Onuki2206af32017-11-21 16:25:35 -0800813 /**
814 * @return whether a UID is in the user / system defined power-save whitelist or not.
815 *
816 * Note clients normally shouldn't need to access it. It's only for dumpsys.
817 */
818 public boolean isUidPowerSaveWhitelisted(int uid) {
Makoto Onuki9be01402017-11-10 13:22:26 -0800819 synchronized (mLock) {
Makoto Onuki2206af32017-11-21 16:25:35 -0800820 return ArrayUtils.contains(mPowerWhitelistedAllAppIds, UserHandle.getAppId(uid));
Makoto Onuki9be01402017-11-10 13:22:26 -0800821 }
822 }
823
Makoto Onuki2206af32017-11-21 16:25:35 -0800824 /**
825 * @return whether a UID is in the temp power-save whitelist or not.
826 *
827 * Note clients normally shouldn't need to access it. It's only for dumpsys.
828 */
829 public boolean isUidTempPowerSaveWhitelisted(int uid) {
Makoto Onuki9be01402017-11-10 13:22:26 -0800830 synchronized (mLock) {
Makoto Onuki2206af32017-11-21 16:25:35 -0800831 return ArrayUtils.contains(mTempWhitelistedAppIds, UserHandle.getAppId(uid));
832 }
833 }
834
835 public void dump(PrintWriter pw, String indent) {
836 synchronized (mLock) {
837 pw.print(indent);
Suprabh Shukla4deb8522018-01-08 16:27:10 -0800838 pw.println("Forced App Standby Feature enabled: " + mForcedAppStandbyEnabled);
839
840 pw.print(indent);
Makoto Onuki2206af32017-11-21 16:25:35 -0800841 pw.print("Force all apps standby: ");
842 pw.println(isForceAllAppsStandbyEnabled());
843
844 pw.print(indent);
845 pw.print("Foreground uids: [");
846
847 String sep = "";
848 for (int i = 0; i < mForegroundUids.size(); i++) {
849 if (mForegroundUids.valueAt(i)) {
850 pw.print(sep);
851 pw.print(UserHandle.formatUid(mForegroundUids.keyAt(i)));
852 sep = " ";
853 }
854 }
855 pw.println("]");
856
857 pw.print(indent);
858 pw.print("Whitelist appids: ");
859 pw.println(Arrays.toString(mPowerWhitelistedAllAppIds));
860
861 pw.print(indent);
862 pw.print("Temp whitelist appids: ");
863 pw.println(Arrays.toString(mTempWhitelistedAppIds));
864
865 pw.print(indent);
866 pw.println("Restricted packages:");
867 for (Pair<Integer, String> uidAndPackage : mRunAnyRestrictedPackages) {
868 pw.print(indent);
869 pw.print(" ");
870 pw.print(UserHandle.formatUid(uidAndPackage.first));
871 pw.print(" ");
872 pw.print(uidAndPackage.second);
873 pw.println();
874 }
875 }
876 }
877
878 public void dumpProto(ProtoOutputStream proto, long fieldId) {
879 synchronized (mLock) {
880 final long token = proto.start(fieldId);
881
882 proto.write(ForceAppStandbyTrackerProto.FORCE_ALL_APPS_STANDBY, mForceAllAppsStandby);
883
884 for (int i = 0; i < mForegroundUids.size(); i++) {
885 if (mForegroundUids.valueAt(i)) {
886 proto.write(ForceAppStandbyTrackerProto.FOREGROUND_UIDS,
887 mForegroundUids.keyAt(i));
888 }
889 }
890
891 for (int appId : mPowerWhitelistedAllAppIds) {
892 proto.write(ForceAppStandbyTrackerProto.POWER_SAVE_WHITELIST_APP_IDS, appId);
893 }
894
895 for (int appId : mTempWhitelistedAppIds) {
896 proto.write(ForceAppStandbyTrackerProto.TEMP_POWER_SAVE_WHITELIST_APP_IDS, appId);
897 }
898
899 for (Pair<Integer, String> uidAndPackage : mRunAnyRestrictedPackages) {
900 final long token2 = proto.start(
901 ForceAppStandbyTrackerProto.RUN_ANY_IN_BACKGROUND_RESTRICTED_PACKAGES);
902 proto.write(RunAnyInBackgroundRestrictedPackages.UID, uidAndPackage.first);
903 proto.write(RunAnyInBackgroundRestrictedPackages.PACKAGE_NAME,
904 uidAndPackage.second);
905 proto.end(token2);
906 }
907 proto.end(token);
Makoto Onuki9be01402017-11-10 13:22:26 -0800908 }
909 }
910}