blob: a538bde7487e640ed3ccf476a74fab7465ded80b [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")
Makoto Onuki12391f22018-01-18 21:44:28 +0000117 boolean mForceAllAppsStandby; // True if device is in extreme battery saver mode
Suprabh Shukla4deb8522018-01-08 16:27:10 -0800118
119 @GuardedBy("mLock")
Makoto Onuki12391f22018-01-18 21:44:28 +0000120 boolean mForcedAppStandbyEnabled; // True if the forced app standby feature is enabled
Suprabh Shukla4deb8522018-01-08 16:27:10 -0800121
Makoto Onuki12391f22018-01-18 21:44:28 +0000122 private class FeatureFlagObserver extends ContentObserver {
123 FeatureFlagObserver() {
Suprabh Shukla4deb8522018-01-08 16:27:10 -0800124 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
Makoto Onuki12391f22018-01-18 21:44:28 +0000139 public void onChange(boolean selfChange) {
140 final boolean enabled = isForcedAppStandbyEnabled();
141 synchronized (mLock) {
142 if (mForcedAppStandbyEnabled == enabled) {
143 return;
Suprabh Shukla4deb8522018-01-08 16:27:10 -0800144 }
Makoto Onuki12391f22018-01-18 21:44:28 +0000145 mForcedAppStandbyEnabled = enabled;
146 if (DEBUG) {
147 Slog.d(TAG,
148 "Forced app standby feature flag changed: " + mForcedAppStandbyEnabled);
Suprabh Shukla4deb8522018-01-08 16:27:10 -0800149 }
150 }
Makoto Onuki12391f22018-01-18 21:44:28 +0000151 mHandler.notifyFeatureFlagChanged();
Suprabh Shukla4deb8522018-01-08 16:27:10 -0800152 }
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());
Makoto Onuki12391f22018-01-18 21:44:28 +0000292 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,
Makoto Onuki12391f22018-01-18 21:44:28 +0000315 (state) -> updateForceAllAppsStandby(state.batterySaverEnabled));
Makoto Onuki2206af32017-11-21 16:25:35 -0800316
Makoto Onuki12391f22018-01-18 21:44:28 +0000317 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 */
Makoto Onuki12391f22018-01-18 21:44:28 +0000375 void updateForceAllAppsStandby(boolean enable) {
376 synchronized (mLock) {
377 if (enable == mForceAllAppsStandby) {
378 return;
379 }
380 mForceAllAppsStandby = enable;
Nancy Zheng9a603822018-01-12 11:45:37 -0800381
Makoto Onuki12391f22018-01-18 21:44:28 +0000382 mHandler.notifyForceAllAppsStandbyChanged();
383 }
Makoto Onuki9be01402017-11-10 13:22:26 -0800384 }
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;
Makoto Onuki12391f22018-01-18 21:44:28 +0000536 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
Makoto Onuki12391f22018-01-18 21:44:28 +0000566 public void notifyFeatureFlagChanged() {
567 obtainMessage(MSG_FEATURE_FLAG_CHANGED).sendToTarget();
Suprabh Shukla4deb8522018-01-08 16:27:10 -0800568 }
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;
Makoto Onuki12391f22018-01-18 21:44:28 +0000621 case MSG_FEATURE_FLAG_CHANGED:
Suprabh Shukla4deb8522018-01-08 16:27:10 -0800622 // 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) {
Makoto Onukieb8cfd12018-01-19 15:43:16 -0800740 return isRestricted(uid, packageName, /*useTempWhitelistToo=*/ false,
741 /* exemptOnBatterySaver =*/ false);
Makoto Onuki2206af32017-11-21 16:25:35 -0800742 }
743
744 /**
745 * @return whether jobs should be restricted for a UID package-name.
746 */
747 public boolean areJobsRestricted(int uid, @NonNull String packageName) {
Makoto Onukieb8cfd12018-01-19 15:43:16 -0800748 return isRestricted(uid, packageName, /*useTempWhitelistToo=*/ true,
749 /* exemptOnBatterySaver =*/ false);
Makoto Onuki2206af32017-11-21 16:25:35 -0800750 }
751
752 /**
753 * @return whether force-app-standby is effective for a UID package-name.
754 */
755 private boolean isRestricted(int uid, @NonNull String packageName,
Makoto Onukieb8cfd12018-01-19 15:43:16 -0800756 boolean useTempWhitelistToo, boolean exemptOnBatterySaver) {
Makoto Onuki9be01402017-11-10 13:22:26 -0800757 if (isInForeground(uid)) {
758 return false;
759 }
760 synchronized (mLock) {
Makoto Onuki2206af32017-11-21 16:25:35 -0800761 // Whitelisted?
762 final int appId = UserHandle.getAppId(uid);
763 if (ArrayUtils.contains(mPowerWhitelistedAllAppIds, appId)) {
764 return false;
765 }
766 if (useTempWhitelistToo &&
767 ArrayUtils.contains(mTempWhitelistedAppIds, appId)) {
768 return false;
769 }
Makoto Onukieb8cfd12018-01-19 15:43:16 -0800770 if (mForcedAppStandbyEnabled && isRunAnyRestrictedLocked(uid, packageName)) {
Makoto Onuki9be01402017-11-10 13:22:26 -0800771 return true;
772 }
Makoto Onukieb8cfd12018-01-19 15:43:16 -0800773 if (exemptOnBatterySaver) {
774 return false;
775 }
776 return mForceAllAppsStandby;
Makoto Onuki9be01402017-11-10 13:22:26 -0800777 }
778 }
779
Makoto Onuki2206af32017-11-21 16:25:35 -0800780 /**
781 * @return whether a UID is in the foreground or not.
782 *
783 * Note clients normally shouldn't need to access it. It's only for dumpsys.
784 */
Makoto Onuki9be01402017-11-10 13:22:26 -0800785 public boolean isInForeground(int uid) {
786 if (!UserHandle.isApp(uid)) {
787 return true;
788 }
789 synchronized (mLock) {
790 return mForegroundUids.get(uid);
791 }
792 }
793
Makoto Onuki2206af32017-11-21 16:25:35 -0800794 /**
795 * @return whether force all apps standby is enabled or not.
796 *
797 * Note clients normally shouldn't need to access it.
798 */
799 boolean isForceAllAppsStandbyEnabled() {
Makoto Onuki9be01402017-11-10 13:22:26 -0800800 synchronized (mLock) {
801 return mForceAllAppsStandby;
802 }
803 }
804
Makoto Onuki2206af32017-11-21 16:25:35 -0800805 /**
806 * @return whether a UID/package has {@code OP_RUN_ANY_IN_BACKGROUND} allowed or not.
807 *
808 * Note clients normally shouldn't need to access it. It's only for dumpsys.
809 */
Makoto Onuki9be01402017-11-10 13:22:26 -0800810 public boolean isRunAnyInBackgroundAppOpsAllowed(int uid, @NonNull String packageName) {
811 synchronized (mLock) {
Makoto Onuki2206af32017-11-21 16:25:35 -0800812 return !isRunAnyRestrictedLocked(uid, packageName);
Makoto Onuki9be01402017-11-10 13:22:26 -0800813 }
814 }
815
Makoto Onuki2206af32017-11-21 16:25:35 -0800816 /**
817 * @return whether a UID is in the user / system defined power-save whitelist or not.
818 *
819 * Note clients normally shouldn't need to access it. It's only for dumpsys.
820 */
821 public boolean isUidPowerSaveWhitelisted(int uid) {
Makoto Onuki9be01402017-11-10 13:22:26 -0800822 synchronized (mLock) {
Makoto Onuki2206af32017-11-21 16:25:35 -0800823 return ArrayUtils.contains(mPowerWhitelistedAllAppIds, UserHandle.getAppId(uid));
Makoto Onuki9be01402017-11-10 13:22:26 -0800824 }
825 }
826
Makoto Onuki2206af32017-11-21 16:25:35 -0800827 /**
828 * @return whether a UID is in the temp power-save whitelist or not.
829 *
830 * Note clients normally shouldn't need to access it. It's only for dumpsys.
831 */
832 public boolean isUidTempPowerSaveWhitelisted(int uid) {
Makoto Onuki9be01402017-11-10 13:22:26 -0800833 synchronized (mLock) {
Makoto Onuki2206af32017-11-21 16:25:35 -0800834 return ArrayUtils.contains(mTempWhitelistedAppIds, UserHandle.getAppId(uid));
835 }
836 }
837
838 public void dump(PrintWriter pw, String indent) {
839 synchronized (mLock) {
840 pw.print(indent);
Suprabh Shukla4deb8522018-01-08 16:27:10 -0800841 pw.println("Forced App Standby Feature enabled: " + mForcedAppStandbyEnabled);
842
843 pw.print(indent);
Makoto Onuki2206af32017-11-21 16:25:35 -0800844 pw.print("Force all apps standby: ");
845 pw.println(isForceAllAppsStandbyEnabled());
846
847 pw.print(indent);
848 pw.print("Foreground uids: [");
849
850 String sep = "";
851 for (int i = 0; i < mForegroundUids.size(); i++) {
852 if (mForegroundUids.valueAt(i)) {
853 pw.print(sep);
854 pw.print(UserHandle.formatUid(mForegroundUids.keyAt(i)));
855 sep = " ";
856 }
857 }
858 pw.println("]");
859
860 pw.print(indent);
861 pw.print("Whitelist appids: ");
862 pw.println(Arrays.toString(mPowerWhitelistedAllAppIds));
863
864 pw.print(indent);
865 pw.print("Temp whitelist appids: ");
866 pw.println(Arrays.toString(mTempWhitelistedAppIds));
867
868 pw.print(indent);
869 pw.println("Restricted packages:");
870 for (Pair<Integer, String> uidAndPackage : mRunAnyRestrictedPackages) {
871 pw.print(indent);
872 pw.print(" ");
873 pw.print(UserHandle.formatUid(uidAndPackage.first));
874 pw.print(" ");
875 pw.print(uidAndPackage.second);
876 pw.println();
877 }
878 }
879 }
880
881 public void dumpProto(ProtoOutputStream proto, long fieldId) {
882 synchronized (mLock) {
883 final long token = proto.start(fieldId);
884
885 proto.write(ForceAppStandbyTrackerProto.FORCE_ALL_APPS_STANDBY, mForceAllAppsStandby);
886
887 for (int i = 0; i < mForegroundUids.size(); i++) {
888 if (mForegroundUids.valueAt(i)) {
889 proto.write(ForceAppStandbyTrackerProto.FOREGROUND_UIDS,
890 mForegroundUids.keyAt(i));
891 }
892 }
893
894 for (int appId : mPowerWhitelistedAllAppIds) {
895 proto.write(ForceAppStandbyTrackerProto.POWER_SAVE_WHITELIST_APP_IDS, appId);
896 }
897
898 for (int appId : mTempWhitelistedAppIds) {
899 proto.write(ForceAppStandbyTrackerProto.TEMP_POWER_SAVE_WHITELIST_APP_IDS, appId);
900 }
901
902 for (Pair<Integer, String> uidAndPackage : mRunAnyRestrictedPackages) {
903 final long token2 = proto.start(
904 ForceAppStandbyTrackerProto.RUN_ANY_IN_BACKGROUND_RESTRICTED_PACKAGES);
905 proto.write(RunAnyInBackgroundRestrictedPackages.UID, uidAndPackage.first);
906 proto.write(RunAnyInBackgroundRestrictedPackages.PACKAGE_NAME,
907 uidAndPackage.second);
908 proto.end(token2);
909 }
910 proto.end(token);
Makoto Onuki9be01402017-11-10 13:22:26 -0800911 }
912 }
913}