Merge "Add support to exempt the battery usage with visible FGS notifications" into tm-dev am: 9aeeb35e8d
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/17216368 Change-Id: I117c10a3992397cf7374e6b8d1fade8a981bf290
This commit is contained in:
@@ -5796,7 +5796,7 @@
|
||||
<!-- The types of state where we'll exempt its battery usage during that state.
|
||||
The state here must be one or a combination of STATE_TYPE_* in BaseAppStateTracker.
|
||||
-->
|
||||
<integer name="config_bg_current_drain_exempted_types">9</integer>
|
||||
<integer name="config_bg_current_drain_exempted_types">25</integer>
|
||||
|
||||
<!-- The behavior when an app has the permission ACCESS_BACKGROUND_LOCATION granted,
|
||||
whether or not the system will use a higher threshold towards its background battery usage
|
||||
|
||||
@@ -32,18 +32,22 @@ import static com.android.server.am.BaseAppStateTracker.ONE_HOUR;
|
||||
import android.annotation.NonNull;
|
||||
import android.app.ActivityManagerInternal.ForegroundServiceStateListener;
|
||||
import android.app.IProcessObserver;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ServiceInfo.ForegroundServiceType;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.os.PowerExemptionManager.ReasonCode;
|
||||
import android.os.RemoteException;
|
||||
import android.os.SystemClock;
|
||||
import android.os.UserHandle;
|
||||
import android.provider.DeviceConfig;
|
||||
import android.service.notification.NotificationListenerService;
|
||||
import android.service.notification.StatusBarNotification;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.ArraySet;
|
||||
import android.util.Slog;
|
||||
import android.util.SparseArray;
|
||||
import android.util.SparseBooleanArray;
|
||||
import android.util.TimeUtils;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
@@ -53,7 +57,6 @@ import com.android.server.am.AppFGSTracker.PackageDurations;
|
||||
import com.android.server.am.BaseAppStateEventsTracker.BaseAppStateEventsPolicy;
|
||||
import com.android.server.am.BaseAppStateTimeEvents.BaseTimeEvent;
|
||||
import com.android.server.am.BaseAppStateTracker.Injector;
|
||||
import com.android.server.notification.NotificationManagerInternal;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.lang.reflect.Constructor;
|
||||
@@ -72,11 +75,14 @@ final class AppFGSTracker extends BaseAppStateDurationsTracker<AppFGSPolicy, Pac
|
||||
private final MyHandler mHandler;
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private final UidProcessMap<ArraySet<Integer>> mFGSNotificationIDs = new UidProcessMap<>();
|
||||
private final UidProcessMap<SparseBooleanArray> mFGSNotificationIDs = new UidProcessMap<>();
|
||||
|
||||
// Unlocked since it's only accessed in single thread.
|
||||
private final ArrayMap<PackageDurations, Long> mTmpPkgDurations = new ArrayMap<>();
|
||||
|
||||
@VisibleForTesting
|
||||
final NotificationListener mNotificationListener = new NotificationListener();
|
||||
|
||||
final IProcessObserver.Stub mProcessObserver = new IProcessObserver.Stub() {
|
||||
@Override
|
||||
public void onForegroundActivitiesChanged(int pid, int uid, boolean fg) {
|
||||
@@ -116,6 +122,8 @@ final class AppFGSTracker extends BaseAppStateDurationsTracker<AppFGSPolicy, Pac
|
||||
static final int MSG_FOREGROUND_SERVICES_CHANGED = 2;
|
||||
static final int MSG_FOREGROUND_SERVICES_NOTIFICATION_UPDATED = 3;
|
||||
static final int MSG_CHECK_LONG_RUNNING_FGS = 4;
|
||||
static final int MSG_NOTIFICATION_POSTED = 5;
|
||||
static final int MSG_NOTIFICATION_REMOVED = 6;
|
||||
|
||||
private final AppFGSTracker mTracker;
|
||||
|
||||
@@ -146,6 +154,12 @@ final class AppFGSTracker extends BaseAppStateDurationsTracker<AppFGSPolicy, Pac
|
||||
case MSG_CHECK_LONG_RUNNING_FGS:
|
||||
mTracker.checkLongRunningFgs();
|
||||
break;
|
||||
case MSG_NOTIFICATION_POSTED:
|
||||
mTracker.handleNotificationPosted((String) msg.obj, msg.arg1, msg.arg2);
|
||||
break;
|
||||
case MSG_NOTIFICATION_REMOVED:
|
||||
mTracker.handleNotificationRemoved((String) msg.obj, msg.arg1, msg.arg2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -223,19 +237,36 @@ final class AppFGSTracker extends BaseAppStateDurationsTracker<AppFGSPolicy, Pac
|
||||
private void handleForegroundServiceNotificationUpdated(String packageName, int uid,
|
||||
int notificationId) {
|
||||
synchronized (mLock) {
|
||||
SparseBooleanArray notificationIDs = mFGSNotificationIDs.get(uid, packageName);
|
||||
if (notificationId > 0) {
|
||||
ArraySet<Integer> notificationIDs = mFGSNotificationIDs.get(uid, packageName);
|
||||
if (notificationIDs == null) {
|
||||
notificationIDs = new ArraySet<>();
|
||||
notificationIDs = new SparseBooleanArray();
|
||||
mFGSNotificationIDs.put(uid, packageName, notificationIDs);
|
||||
}
|
||||
notificationIDs.add(notificationId);
|
||||
notificationIDs.put(notificationId, false);
|
||||
} else if (notificationId < 0) {
|
||||
final ArraySet<Integer> notificationIDs = mFGSNotificationIDs.get(uid, packageName);
|
||||
if (notificationIDs != null) {
|
||||
notificationIDs.remove(-notificationId);
|
||||
if (notificationIDs.isEmpty()) {
|
||||
mFGSNotificationIDs.remove(uid, packageName);
|
||||
final int indexOfKey = notificationIDs.indexOfKey(-notificationId);
|
||||
if (indexOfKey >= 0) {
|
||||
final boolean wasVisible = notificationIDs.valueAt(indexOfKey);
|
||||
notificationIDs.removeAt(indexOfKey);
|
||||
if (notificationIDs.size() == 0) {
|
||||
mFGSNotificationIDs.remove(uid, packageName);
|
||||
}
|
||||
// Walk through the list of FGS notification IDs and see if there are any
|
||||
// visible ones.
|
||||
for (int i = notificationIDs.size() - 1; i >= 0; i--) {
|
||||
if (notificationIDs.valueAt(i)) {
|
||||
// Still visible, nothing to do.
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (wasVisible) {
|
||||
// That was the last visible notification, notify the listeners.
|
||||
notifyListenersOnStateChange(uid, packageName, false,
|
||||
SystemClock.elapsedRealtime(),
|
||||
STATE_TYPE_FGS_WITH_NOTIFICATION);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -244,20 +275,74 @@ final class AppFGSTracker extends BaseAppStateDurationsTracker<AppFGSPolicy, Pac
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private boolean hasForegroundServiceNotificationsLocked(String packageName, int uid) {
|
||||
final ArraySet<Integer> notificationIDs = mFGSNotificationIDs.get(uid, packageName);
|
||||
if (notificationIDs == null || notificationIDs.isEmpty()) {
|
||||
final SparseBooleanArray notificationIDs = mFGSNotificationIDs.get(uid, packageName);
|
||||
if (notificationIDs == null || notificationIDs.size() == 0) {
|
||||
return false;
|
||||
}
|
||||
final NotificationManagerInternal nm = mInjector.getNotificationManagerInternal();
|
||||
final int userId = UserHandle.getUserId(uid);
|
||||
for (int i = notificationIDs.size() - 1; i >= 0; i--) {
|
||||
if (nm.isNotificationShown(packageName, null, notificationIDs.valueAt(i), userId)) {
|
||||
if (notificationIDs.valueAt(i)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void handleNotificationPosted(String pkgName, int uid, int notificationId) {
|
||||
synchronized (mLock) {
|
||||
final SparseBooleanArray notificationIDs = mFGSNotificationIDs.get(uid, pkgName);
|
||||
final int indexOfKey;
|
||||
if (notificationIDs == null
|
||||
|| (indexOfKey = notificationIDs.indexOfKey(notificationId)) < 0) {
|
||||
return;
|
||||
}
|
||||
if (notificationIDs.valueAt(indexOfKey)) {
|
||||
// It's already visible.
|
||||
return;
|
||||
}
|
||||
boolean anyVisible = false;
|
||||
// Walk through the list of FGS notification IDs and see if there are any visible ones.
|
||||
for (int i = notificationIDs.size() - 1; i >= 0; i--) {
|
||||
if (notificationIDs.valueAt(i)) {
|
||||
anyVisible = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
notificationIDs.setValueAt(indexOfKey, true);
|
||||
if (!anyVisible) {
|
||||
// We didn't have any visible FGS notifications but now we have one,
|
||||
// let the listeners know.
|
||||
notifyListenersOnStateChange(uid, pkgName, true, SystemClock.elapsedRealtime(),
|
||||
STATE_TYPE_FGS_WITH_NOTIFICATION);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void handleNotificationRemoved(String pkgName, int uid, int notificationId) {
|
||||
synchronized (mLock) {
|
||||
final SparseBooleanArray notificationIDs = mFGSNotificationIDs.get(uid, pkgName);
|
||||
final int indexOfKey;
|
||||
if (notificationIDs == null
|
||||
|| (indexOfKey = notificationIDs.indexOfKey(notificationId)) < 0) {
|
||||
return;
|
||||
}
|
||||
if (!notificationIDs.valueAt(indexOfKey)) {
|
||||
// It's already invisible.
|
||||
return;
|
||||
}
|
||||
notificationIDs.setValueAt(indexOfKey, false);
|
||||
// Walk through the list of FGS notification IDs and see if there are any visible ones.
|
||||
for (int i = notificationIDs.size() - 1; i >= 0; i--) {
|
||||
if (notificationIDs.valueAt(i)) {
|
||||
// Still visible, nothing to do.
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Nothing is visible now, let the listeners know.
|
||||
notifyListenersOnStateChange(uid, pkgName, false, SystemClock.elapsedRealtime(),
|
||||
STATE_TYPE_FGS_WITH_NOTIFICATION);
|
||||
}
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private void scheduleDurationCheckLocked(long now) {
|
||||
// Look for the active FGS with longest running time till now.
|
||||
@@ -374,7 +459,19 @@ final class AppFGSTracker extends BaseAppStateDurationsTracker<AppFGSPolicy, Pac
|
||||
synchronized (mLock) {
|
||||
scheduleDurationCheckLocked(SystemClock.elapsedRealtime());
|
||||
}
|
||||
try {
|
||||
mNotificationListener.registerAsSystemService(mContext,
|
||||
new ComponentName(mContext, NotificationListener.class),
|
||||
UserHandle.USER_ALL);
|
||||
} catch (RemoteException e) {
|
||||
// Intra-process call, should never happen.
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
mNotificationListener.unregisterAsSystemService();
|
||||
} catch (RemoteException e) {
|
||||
// Intra-process call, should never happen.
|
||||
}
|
||||
mHandler.removeMessages(MyHandler.MSG_CHECK_LONG_RUNNING_FGS);
|
||||
synchronized (mLock) {
|
||||
mPkgEvents.clear();
|
||||
@@ -436,9 +533,9 @@ final class AppFGSTracker extends BaseAppStateDurationsTracker<AppFGSPolicy, Pac
|
||||
|
||||
boolean hasForegroundServiceNotifications(int uid) {
|
||||
synchronized (mLock) {
|
||||
final SparseArray<ArrayMap<String, ArraySet<Integer>>> map =
|
||||
final SparseArray<ArrayMap<String, SparseBooleanArray>> map =
|
||||
mFGSNotificationIDs.getMap();
|
||||
final ArrayMap<String, ArraySet<Integer>> pkgs = map.get(uid);
|
||||
final ArrayMap<String, SparseBooleanArray> pkgs = map.get(uid);
|
||||
if (pkgs != null) {
|
||||
for (int i = pkgs.size() - 1; i >= 0; i--) {
|
||||
if (hasForegroundServiceNotificationsLocked(pkgs.keyAt(i), uid)) {
|
||||
@@ -463,7 +560,7 @@ final class AppFGSTracker extends BaseAppStateDurationsTracker<AppFGSPolicy, Pac
|
||||
pw.println("APPS WITH ACTIVE FOREGROUND SERVICES:");
|
||||
prefix = " " + prefix;
|
||||
synchronized (mLock) {
|
||||
final SparseArray<ArrayMap<String, ArraySet<Integer>>> map =
|
||||
final SparseArray<ArrayMap<String, SparseBooleanArray>> map =
|
||||
mFGSNotificationIDs.getMap();
|
||||
if (map.size() == 0) {
|
||||
pw.print(prefix);
|
||||
@@ -472,7 +569,7 @@ final class AppFGSTracker extends BaseAppStateDurationsTracker<AppFGSPolicy, Pac
|
||||
for (int i = 0, size = map.size(); i < size; i++) {
|
||||
final int uid = map.keyAt(i);
|
||||
final String uidString = UserHandle.formatUid(uid);
|
||||
final ArrayMap<String, ArraySet<Integer>> pkgs = map.valueAt(i);
|
||||
final ArrayMap<String, SparseBooleanArray> pkgs = map.valueAt(i);
|
||||
for (int j = 0, numOfPkgs = pkgs.size(); j < numOfPkgs; j++) {
|
||||
final String pkgName = pkgs.keyAt(j);
|
||||
pw.print(prefix);
|
||||
@@ -622,6 +719,28 @@ final class AppFGSTracker extends BaseAppStateDurationsTracker<AppFGSPolicy, Pac
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
class NotificationListener extends NotificationListenerService {
|
||||
@Override
|
||||
public void onNotificationPosted(StatusBarNotification sbn, RankingMap map) {
|
||||
if (DEBUG_BACKGROUND_FGS_TRACKER) {
|
||||
Slog.i(TAG, "Notification posted: " + sbn);
|
||||
}
|
||||
mHandler.obtainMessage(MyHandler.MSG_NOTIFICATION_POSTED,
|
||||
sbn.getUid(), sbn.getId(), sbn.getPackageName()).sendToTarget();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNotificationRemoved(StatusBarNotification sbn, RankingMap rankingMap,
|
||||
int reason) {
|
||||
if (DEBUG_BACKGROUND_FGS_TRACKER) {
|
||||
Slog.i(TAG, "Notification removed: " + sbn);
|
||||
}
|
||||
mHandler.obtainMessage(MyHandler.MSG_NOTIFICATION_REMOVED,
|
||||
sbn.getUid(), sbn.getId(), sbn.getPackageName()).sendToTarget();
|
||||
}
|
||||
}
|
||||
|
||||
static final class AppFGSPolicy extends BaseAppStateEventsPolicy<AppFGSTracker> {
|
||||
/**
|
||||
* Whether or not we should enable the monitoring on abusive FGS.
|
||||
|
||||
@@ -64,13 +64,15 @@ public abstract class BaseAppStateTracker<T extends BaseAppStatePolicy> {
|
||||
static final int STATE_TYPE_MEDIA_SESSION = 1;
|
||||
static final int STATE_TYPE_FGS_MEDIA_PLAYBACK = 1 << 1;
|
||||
static final int STATE_TYPE_FGS_LOCATION = 1 << 2;
|
||||
static final int STATE_TYPE_PERMISSION = 1 << 3;
|
||||
static final int STATE_TYPE_NUM = 4;
|
||||
static final int STATE_TYPE_FGS_WITH_NOTIFICATION = 1 << 3;
|
||||
static final int STATE_TYPE_PERMISSION = 1 << 4;
|
||||
static final int STATE_TYPE_NUM = 5;
|
||||
|
||||
static final int STATE_TYPE_INDEX_MEDIA_SESSION = 0;
|
||||
static final int STATE_TYPE_INDEX_FGS_MEDIA_PLAYBACK = 1;
|
||||
static final int STATE_TYPE_INDEX_FGS_LOCATION = 2;
|
||||
static final int STATE_TYPE_INDEX_PERMISSION = 3;
|
||||
static final int STATE_TYPE_INDEX_FGS_WITH_NOTIFICATION = 3;
|
||||
static final int STATE_TYPE_INDEX_PERMISSION = 4;
|
||||
|
||||
protected final AppRestrictionController mAppRestrictionController;
|
||||
protected final Injector<T> mInjector;
|
||||
@@ -129,6 +131,9 @@ public abstract class BaseAppStateTracker<T extends BaseAppStatePolicy> {
|
||||
case STATE_TYPE_FGS_LOCATION:
|
||||
sb.append("FGS_LOCATION");
|
||||
break;
|
||||
case STATE_TYPE_FGS_WITH_NOTIFICATION:
|
||||
sb.append("FGS_NOTIFICATION");
|
||||
break;
|
||||
case STATE_TYPE_PERMISSION:
|
||||
sb.append("PERMISSION");
|
||||
break;
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK"/>
|
||||
<uses-permission
|
||||
android:name="android.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD"/>
|
||||
<uses-permission android:name="android.permission.STATUS_BAR_SERVICE" />
|
||||
|
||||
<!-- needed by MasterClearReceiverTest to display a system dialog -->
|
||||
<uses-permission android:name="android.permission.INTERNAL_SYSTEM_WINDOW"/>
|
||||
|
||||
@@ -59,6 +59,7 @@ import static com.android.server.am.AppPermissionTracker.AppPermissionPolicy;
|
||||
import static com.android.server.am.AppRestrictionController.STOCK_PM_FLAGS;
|
||||
import static com.android.server.am.BaseAppStateTracker.STATE_TYPE_FGS_LOCATION;
|
||||
import static com.android.server.am.BaseAppStateTracker.STATE_TYPE_FGS_MEDIA_PLAYBACK;
|
||||
import static com.android.server.am.BaseAppStateTracker.STATE_TYPE_FGS_WITH_NOTIFICATION;
|
||||
import static com.android.server.am.BaseAppStateTracker.STATE_TYPE_MEDIA_SESSION;
|
||||
import static com.android.server.am.BaseAppStateTracker.STATE_TYPE_PERMISSION;
|
||||
|
||||
@@ -113,6 +114,7 @@ import android.os.UidBatteryConsumer;
|
||||
import android.os.UserHandle;
|
||||
import android.permission.PermissionManager;
|
||||
import android.provider.DeviceConfig;
|
||||
import android.service.notification.StatusBarNotification;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
@@ -566,6 +568,7 @@ public final class BackgroundRestrictionTest {
|
||||
DeviceConfigSession<Float> bgCurrentDrainBgRestrictedThreshold = null;
|
||||
DeviceConfigSession<Boolean> bgPromptFgsWithNotiToBgRestricted = null;
|
||||
DeviceConfigSession<Long> bgNotificationMinInterval = null;
|
||||
DeviceConfigSession<Integer> bgBatteryExemptionTypes = null;
|
||||
|
||||
mBgRestrictionController.addAppBackgroundRestrictionListener(listener);
|
||||
|
||||
@@ -627,16 +630,25 @@ public final class BackgroundRestrictionTest {
|
||||
ConstantsObserver.DEFAULT_BG_ABUSIVE_NOTIFICATION_MINIMAL_INTERVAL_MS);
|
||||
bgNotificationMinInterval.set(windowMs);
|
||||
|
||||
bgBatteryExemptionTypes = new DeviceConfigSession<>(
|
||||
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
|
||||
AppBatteryPolicy.KEY_BG_CURRENT_DRAIN_EXEMPTED_TYPES,
|
||||
DeviceConfig::getInt,
|
||||
mContext.getResources().getInteger(
|
||||
R.integer.config_bg_current_drain_exempted_types));
|
||||
bgBatteryExemptionTypes.set(0);
|
||||
|
||||
mCurrentTimeMillis = 10_000L;
|
||||
doReturn(mCurrentTimeMillis - windowMs).when(stats).getStatsStartTimestamp();
|
||||
doReturn(mCurrentTimeMillis).when(stats).getStatsEndTimestamp();
|
||||
doReturn(statsList).when(mBatteryStatsInternal).getBatteryUsageStats(anyObject());
|
||||
doReturn(true).when(mNotificationManagerInternal).isNotificationShown(
|
||||
testPkgName, null, notificationId, testUser);
|
||||
mAppFGSTracker.onForegroundServiceStateChanged(testPkgName, testUid,
|
||||
testPid, true);
|
||||
mAppFGSTracker.onForegroundServiceNotificationUpdated(
|
||||
testPkgName, testUid, notificationId);
|
||||
mAppFGSTracker.mNotificationListener.onNotificationPosted(new StatusBarNotification(
|
||||
testPkgName, null, notificationId, null, testUid, testPid,
|
||||
new Notification(), UserHandle.of(testUser), null, mCurrentTimeMillis), null);
|
||||
|
||||
runTestBgCurrentDrainMonitorOnce(listener, stats, uids,
|
||||
new double[]{restrictBucketThresholdMah - 1, 0},
|
||||
@@ -915,6 +927,7 @@ public final class BackgroundRestrictionTest {
|
||||
closeIfNotNull(bgCurrentDrainBgRestrictedThreshold);
|
||||
closeIfNotNull(bgPromptFgsWithNotiToBgRestricted);
|
||||
closeIfNotNull(bgNotificationMinInterval);
|
||||
closeIfNotNull(bgBatteryExemptionTypes);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1250,14 +1263,15 @@ public final class BackgroundRestrictionTest {
|
||||
List<Pair<List<MediaController>, Long>> mediaControllers, List<Long> topStateChanges,
|
||||
VerificationMode mode) throws Exception {
|
||||
runExemptionTestOnce(
|
||||
packageName, uid, pid, serviceType, sleepMs, true, perm, mediaControllers,
|
||||
packageName, uid, pid, serviceType, sleepMs, true, false, perm, mediaControllers,
|
||||
topStateChanges, true, true,
|
||||
() -> checkNotificationShown(new String[] {packageName}, mode, false)
|
||||
);
|
||||
}
|
||||
|
||||
private void runExemptionTestOnce(String packageName, int uid, int pid,
|
||||
int serviceType, long sleepMs, boolean stopAfterSleep, String perm,
|
||||
int serviceType, long sleepMs, boolean stopAfterSleep,
|
||||
boolean withNotification, String perm,
|
||||
List<Pair<List<MediaController>, Long>> mediaControllers,
|
||||
List<Long> topStateChanges, boolean resetFGSTracker, boolean resetController,
|
||||
RunnableWithException r) throws Exception {
|
||||
@@ -1302,7 +1316,20 @@ public final class BackgroundRestrictionTest {
|
||||
FOREGROUND_SERVICE_TYPE_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
if (withNotification) {
|
||||
final int notificationId = 1000;
|
||||
mAppFGSTracker.onForegroundServiceNotificationUpdated(
|
||||
packageName, uid, notificationId);
|
||||
final StatusBarNotification noti = new StatusBarNotification(
|
||||
packageName, null, notificationId, null, uid, pid,
|
||||
new Notification(), UserHandle.of(UserHandle.getUserId(uid)),
|
||||
null, mCurrentTimeMillis);
|
||||
mAppFGSTracker.mNotificationListener.onNotificationPosted(noti, null);
|
||||
Thread.sleep(sleepMs);
|
||||
if (stopAfterSleep) {
|
||||
mAppFGSTracker.mNotificationListener.onNotificationRemoved(noti, null, 0);
|
||||
}
|
||||
}
|
||||
if (perm != null) {
|
||||
doReturn(PERMISSION_GRANTED)
|
||||
.when(mPermissionManagerServiceInternal)
|
||||
@@ -1513,7 +1540,8 @@ public final class BackgroundRestrictionTest {
|
||||
mContext.getResources().getInteger(
|
||||
R.integer.config_bg_current_drain_exempted_types));
|
||||
bgBatteryExemptionTypes.set(STATE_TYPE_MEDIA_SESSION | STATE_TYPE_FGS_MEDIA_PLAYBACK
|
||||
| STATE_TYPE_FGS_LOCATION | STATE_TYPE_PERMISSION);
|
||||
| STATE_TYPE_FGS_LOCATION | STATE_TYPE_PERMISSION
|
||||
| STATE_TYPE_FGS_WITH_NOTIFICATION);
|
||||
|
||||
bgPermissionMonitorEnabled = new DeviceConfigSession<>(
|
||||
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
|
||||
@@ -1546,7 +1574,7 @@ public final class BackgroundRestrictionTest {
|
||||
// Run with a media playback service which starts/stops immediately, we should
|
||||
// goto the restricted bucket.
|
||||
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
|
||||
FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK, 0, true,
|
||||
FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK, 0, true, false,
|
||||
null, null, null, listener, stats, uids,
|
||||
new double[]{restrictBucketThresholdMah + 1, 0},
|
||||
new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
|
||||
@@ -1556,7 +1584,7 @@ public final class BackgroundRestrictionTest {
|
||||
// Run with a media playback service with extended time. We should be back to normal.
|
||||
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
|
||||
FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK, bgMediaPlaybackMinDuration * 2, false,
|
||||
null, null, null, listener, stats, uids,
|
||||
false, null, null, null, listener, stats, uids,
|
||||
new double[]{restrictBucketThresholdMah + 1, 0},
|
||||
new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
|
||||
true, RESTRICTION_LEVEL_ADAPTIVE_BUCKET, timeout, false,
|
||||
@@ -1585,7 +1613,7 @@ public final class BackgroundRestrictionTest {
|
||||
// Run with a media playback service with extended time, with higher current drain.
|
||||
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
|
||||
FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK, bgMediaPlaybackMinDuration * 2, false,
|
||||
null, null, null, listener, stats, uids,
|
||||
false, null, null, null, listener, stats, uids,
|
||||
new double[]{restrictBucketHighThresholdMah - 1, 0},
|
||||
new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
|
||||
true, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, true,
|
||||
@@ -1594,7 +1622,7 @@ public final class BackgroundRestrictionTest {
|
||||
// Run with a media playback service with extended time, with even higher current drain.
|
||||
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
|
||||
FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK, bgMediaPlaybackMinDuration * 2, false,
|
||||
null, null, null, listener, stats, uids,
|
||||
false, null, null, null, listener, stats, uids,
|
||||
new double[]{restrictBucketHighThresholdMah + 1, 0},
|
||||
new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
|
||||
false, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, false,
|
||||
@@ -1607,8 +1635,8 @@ public final class BackgroundRestrictionTest {
|
||||
|
||||
// Run with a media session with extended time, with higher current drain.
|
||||
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
|
||||
FOREGROUND_SERVICE_TYPE_NONE, bgMediaPlaybackMinDuration * 2, false, null,
|
||||
List.of(Pair.create(createMediaControllers(new String[] {testPkgName1},
|
||||
FOREGROUND_SERVICE_TYPE_NONE, bgMediaPlaybackMinDuration * 2, false, false,
|
||||
null, List.of(Pair.create(createMediaControllers(new String[] {testPkgName1},
|
||||
new int[] {testUid1}), bgMediaPlaybackMinDuration * 2)),
|
||||
null, listener, stats, uids,
|
||||
new double[]{restrictBucketHighThresholdMah - 1, 0},
|
||||
@@ -1618,8 +1646,8 @@ public final class BackgroundRestrictionTest {
|
||||
|
||||
// Run with a media session with extended time, with even higher current drain.
|
||||
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
|
||||
FOREGROUND_SERVICE_TYPE_NONE, bgMediaPlaybackMinDuration * 2, false, null,
|
||||
List.of(Pair.create(createMediaControllers(new String[] {testPkgName1},
|
||||
FOREGROUND_SERVICE_TYPE_NONE, bgMediaPlaybackMinDuration * 2, false, false,
|
||||
null, List.of(Pair.create(createMediaControllers(new String[] {testPkgName1},
|
||||
new int[] {testUid1}), bgMediaPlaybackMinDuration * 2)),
|
||||
null, listener, stats, uids,
|
||||
new double[]{restrictBucketHighThresholdMah + 1, 0},
|
||||
@@ -1635,8 +1663,8 @@ public final class BackgroundRestrictionTest {
|
||||
// Run with a media session with extended time, with moderate current drain,
|
||||
// but it ran on the top when the location service is active.
|
||||
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
|
||||
FOREGROUND_SERVICE_TYPE_NONE, bgMediaPlaybackMinDuration * 2, false, null,
|
||||
List.of(Pair.create(createMediaControllers(new String[] {testPkgName1},
|
||||
FOREGROUND_SERVICE_TYPE_NONE, bgMediaPlaybackMinDuration * 2, false, false,
|
||||
null, List.of(Pair.create(createMediaControllers(new String[] {testPkgName1},
|
||||
new int[] {testUid1}), bgMediaPlaybackMinDuration * 2)),
|
||||
List.of(0L, timeout * 2), listener, stats, uids,
|
||||
new double[]{restrictBucketThresholdMah + 1, 0},
|
||||
@@ -1651,7 +1679,7 @@ public final class BackgroundRestrictionTest {
|
||||
|
||||
// Run with a location service with extended time, with higher current drain.
|
||||
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
|
||||
FOREGROUND_SERVICE_TYPE_LOCATION, bgMediaPlaybackMinDuration * 2, false,
|
||||
FOREGROUND_SERVICE_TYPE_LOCATION, bgMediaPlaybackMinDuration * 2, false, false,
|
||||
null, null, null, listener, stats, uids,
|
||||
new double[]{restrictBucketHighThresholdMah - 1, 0},
|
||||
new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
|
||||
@@ -1660,7 +1688,7 @@ public final class BackgroundRestrictionTest {
|
||||
|
||||
// Run with a location service with extended time, with even higher current drain.
|
||||
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
|
||||
FOREGROUND_SERVICE_TYPE_LOCATION, bgMediaPlaybackMinDuration * 2, false,
|
||||
FOREGROUND_SERVICE_TYPE_LOCATION, bgMediaPlaybackMinDuration * 2, false, false,
|
||||
null, null, null, listener, stats, uids,
|
||||
new double[]{restrictBucketHighThresholdMah + 1, 0},
|
||||
new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
|
||||
@@ -1675,7 +1703,7 @@ public final class BackgroundRestrictionTest {
|
||||
// Run with a location service with extended time, with moderate current drain,
|
||||
// but it ran on the top when the location service is active.
|
||||
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
|
||||
FOREGROUND_SERVICE_TYPE_LOCATION, bgMediaPlaybackMinDuration * 2, false,
|
||||
FOREGROUND_SERVICE_TYPE_LOCATION, bgMediaPlaybackMinDuration * 2, false, false,
|
||||
null, null, List.of(0L, timeout * 2), listener, stats, uids,
|
||||
new double[]{restrictBucketThresholdMah + 1, 0},
|
||||
new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
|
||||
@@ -1692,7 +1720,7 @@ public final class BackgroundRestrictionTest {
|
||||
|
||||
// Run with bg location permission, with moderate current drain.
|
||||
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
|
||||
FOREGROUND_SERVICE_TYPE_NONE, 0, false,
|
||||
FOREGROUND_SERVICE_TYPE_NONE, 0, false, false,
|
||||
ACCESS_BACKGROUND_LOCATION, null, null, listener, stats, uids,
|
||||
new double[]{restrictBucketThresholdMah - 1, 0},
|
||||
new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
|
||||
@@ -1701,7 +1729,7 @@ public final class BackgroundRestrictionTest {
|
||||
|
||||
// Run with bg location permission, with a bit higher current drain.
|
||||
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
|
||||
FOREGROUND_SERVICE_TYPE_NONE, 0, false,
|
||||
FOREGROUND_SERVICE_TYPE_NONE, 0, false, false,
|
||||
ACCESS_BACKGROUND_LOCATION, null, null, listener, stats, uids,
|
||||
new double[]{restrictBucketThresholdMah + 1, 0},
|
||||
new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
|
||||
@@ -1718,7 +1746,7 @@ public final class BackgroundRestrictionTest {
|
||||
|
||||
// Run with bg location permission, with higher current drain.
|
||||
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
|
||||
FOREGROUND_SERVICE_TYPE_NONE, 0, false,
|
||||
FOREGROUND_SERVICE_TYPE_NONE, 0, false, false,
|
||||
ACCESS_BACKGROUND_LOCATION , null, null, listener, stats, uids,
|
||||
new double[]{restrictBucketHighThresholdMah - 1, 0},
|
||||
new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
|
||||
@@ -1727,7 +1755,7 @@ public final class BackgroundRestrictionTest {
|
||||
|
||||
// Run with bg location permission, with even higher current drain.
|
||||
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
|
||||
FOREGROUND_SERVICE_TYPE_NONE, 0, false,
|
||||
FOREGROUND_SERVICE_TYPE_NONE, 0, false, false,
|
||||
ACCESS_BACKGROUND_LOCATION , null, null, listener, stats, uids,
|
||||
new double[]{restrictBucketHighThresholdMah + 1, 0},
|
||||
new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
|
||||
@@ -1749,7 +1777,7 @@ public final class BackgroundRestrictionTest {
|
||||
// Run with a media playback service which starts/stops immediately, we should
|
||||
// goto the restricted bucket.
|
||||
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
|
||||
FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK, 0, true,
|
||||
FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK, 0, true, false,
|
||||
null, null, null, listener, stats, uids,
|
||||
new double[]{restrictBucketThresholdMah + 1, 0},
|
||||
new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
|
||||
@@ -1759,7 +1787,7 @@ public final class BackgroundRestrictionTest {
|
||||
// Run with a media playback service with extended time. We should be back to normal.
|
||||
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
|
||||
FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK, bgMediaPlaybackMinDuration * 2, false,
|
||||
null, null, null, listener, stats, uids,
|
||||
false, null, null, null, listener, stats, uids,
|
||||
new double[]{restrictBucketThresholdMah + 1, 0},
|
||||
new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
|
||||
true, RESTRICTION_LEVEL_ADAPTIVE_BUCKET, timeout, false,
|
||||
@@ -1791,7 +1819,7 @@ public final class BackgroundRestrictionTest {
|
||||
// Run with a media playback service with extended time, with higher current drain.
|
||||
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
|
||||
FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK, bgMediaPlaybackMinDuration * 2, false,
|
||||
null, null, null, listener, stats, uids,
|
||||
false, null, null, null, listener, stats, uids,
|
||||
new double[]{restrictBucketHighThresholdMah - 1, 0},
|
||||
new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
|
||||
true, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, true,
|
||||
@@ -1802,7 +1830,7 @@ public final class BackgroundRestrictionTest {
|
||||
// playback.
|
||||
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
|
||||
FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK, bgMediaPlaybackMinDuration * 2, false,
|
||||
null, null, null, listener, stats, uids,
|
||||
false, null, null, null, listener, stats, uids,
|
||||
new double[]{restrictBucketHighThresholdMah + 100, 0},
|
||||
new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
|
||||
true, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, false,
|
||||
@@ -1817,7 +1845,7 @@ public final class BackgroundRestrictionTest {
|
||||
|
||||
// Run with coarse location permission, with high current drain.
|
||||
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
|
||||
FOREGROUND_SERVICE_TYPE_NONE, 0, false,
|
||||
FOREGROUND_SERVICE_TYPE_NONE, 0, false, false,
|
||||
ACCESS_COARSE_LOCATION, null, null, listener, stats, uids,
|
||||
new double[]{restrictBucketThresholdMah + 1, 0},
|
||||
new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
|
||||
@@ -1831,7 +1859,7 @@ public final class BackgroundRestrictionTest {
|
||||
|
||||
// Run with fine location permission, with high current drain.
|
||||
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
|
||||
FOREGROUND_SERVICE_TYPE_NONE, 0, false,
|
||||
FOREGROUND_SERVICE_TYPE_NONE, 0, false, false,
|
||||
ACCESS_FINE_LOCATION, null, null, listener, stats, uids,
|
||||
new double[]{restrictBucketThresholdMah + 1, 0},
|
||||
new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
|
||||
@@ -1845,8 +1873,8 @@ public final class BackgroundRestrictionTest {
|
||||
|
||||
// Run with a media session with extended time, with higher current drain.
|
||||
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
|
||||
FOREGROUND_SERVICE_TYPE_NONE, bgMediaPlaybackMinDuration * 2, false, null,
|
||||
List.of(Pair.create(createMediaControllers(new String[] {testPkgName1},
|
||||
FOREGROUND_SERVICE_TYPE_NONE, bgMediaPlaybackMinDuration * 2, false, false,
|
||||
null, List.of(Pair.create(createMediaControllers(new String[] {testPkgName1},
|
||||
new int[] {testUid1}), bgMediaPlaybackMinDuration * 2)),
|
||||
null, listener, stats, uids,
|
||||
new double[]{restrictBucketHighThresholdMah - 1, 0},
|
||||
@@ -1858,8 +1886,8 @@ public final class BackgroundRestrictionTest {
|
||||
// it still should stay in the current restriction level as we exempt the media
|
||||
// session.
|
||||
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
|
||||
FOREGROUND_SERVICE_TYPE_NONE, bgMediaPlaybackMinDuration * 2, false, null,
|
||||
List.of(Pair.create(createMediaControllers(new String[] {testPkgName1},
|
||||
FOREGROUND_SERVICE_TYPE_NONE, bgMediaPlaybackMinDuration * 2, false, false,
|
||||
null, List.of(Pair.create(createMediaControllers(new String[] {testPkgName1},
|
||||
new int[] {testUid1}), bgMediaPlaybackMinDuration * 2)),
|
||||
null, listener, stats, uids,
|
||||
new double[]{restrictBucketHighThresholdMah + 100, 0},
|
||||
@@ -1867,9 +1895,51 @@ public final class BackgroundRestrictionTest {
|
||||
true, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, true,
|
||||
null, windowMs, initialBg, initialFgs, initialFg, initialCached);
|
||||
|
||||
// Set the policy to exempt fgs with notifications.
|
||||
bgBatteryExemptionTypes.set(STATE_TYPE_FGS_WITH_NOTIFICATION);
|
||||
// Start over.
|
||||
resetBgRestrictionController();
|
||||
setUidBatteryConsumptions(stats, uids, zeros, zeros, zeros);
|
||||
mAppBatteryPolicy.reset();
|
||||
|
||||
// Run with a FGS with notification posted/removed immediately, we should
|
||||
// goto the restricted bucket.
|
||||
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
|
||||
FOREGROUND_SERVICE_TYPE_NONE, 0, true, true,
|
||||
null, null, null, listener, stats, uids,
|
||||
new double[]{restrictBucketThresholdMah + 1, 0},
|
||||
new double[]{0, restrictBucketThresholdMah - 1}, zeros,
|
||||
false, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, true,
|
||||
null, windowMs, null, null, null);
|
||||
|
||||
// Run with a service with notification for extended time. We should be back to normal.
|
||||
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
|
||||
FOREGROUND_SERVICE_TYPE_NONE, bgMediaPlaybackMinDuration * 2, false,
|
||||
true, null, null, null, listener, stats, uids,
|
||||
new double[]{restrictBucketThresholdMah + 1, 0},
|
||||
new double[]{0, restrictBucketThresholdMah - 1}, zeros,
|
||||
true, RESTRICTION_LEVEL_ADAPTIVE_BUCKET, timeout, false,
|
||||
() -> {
|
||||
// A user interaction will bring it back to normal.
|
||||
mIdleStateListener.onUserInteractionStarted(testPkgName1,
|
||||
UserHandle.getUserId(testUid1));
|
||||
waitForIdleHandler(mBgRestrictionController.getBackgroundHandler());
|
||||
// It should have been back to normal.
|
||||
listener.verify(timeout, testUid1, testPkgName1,
|
||||
RESTRICTION_LEVEL_ADAPTIVE_BUCKET);
|
||||
verify(mInjector.getAppStandbyInternal(), times(1)).maybeUnrestrictApp(
|
||||
eq(testPkgName1),
|
||||
eq(UserHandle.getUserId(testUid1)),
|
||||
eq(REASON_MAIN_FORCED_BY_SYSTEM),
|
||||
eq(REASON_SUB_FORCED_SYSTEM_FLAG_ABUSE),
|
||||
eq(REASON_MAIN_USAGE),
|
||||
eq(REASON_SUB_USAGE_USER_INTERACTION));
|
||||
}, windowMs, null, null, null);
|
||||
|
||||
// Set the policy to exempt all.
|
||||
bgBatteryExemptionTypes.set(STATE_TYPE_MEDIA_SESSION | STATE_TYPE_FGS_MEDIA_PLAYBACK
|
||||
| STATE_TYPE_FGS_LOCATION | STATE_TYPE_PERMISSION);
|
||||
| STATE_TYPE_FGS_LOCATION | STATE_TYPE_PERMISSION
|
||||
| STATE_TYPE_FGS_WITH_NOTIFICATION);
|
||||
|
||||
// Start over.
|
||||
resetBgRestrictionController();
|
||||
@@ -1878,7 +1948,7 @@ public final class BackgroundRestrictionTest {
|
||||
|
||||
// Run with a location service with extended time, with higher current drain.
|
||||
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
|
||||
FOREGROUND_SERVICE_TYPE_LOCATION, bgMediaPlaybackMinDuration * 2, false,
|
||||
FOREGROUND_SERVICE_TYPE_LOCATION, bgMediaPlaybackMinDuration * 2, false, false,
|
||||
null, null, null, listener, stats, uids,
|
||||
new double[]{restrictBucketHighThresholdMah - 1, 0},
|
||||
new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
|
||||
@@ -1888,7 +1958,7 @@ public final class BackgroundRestrictionTest {
|
||||
// Run with a location service with extended time, with even higher current drain.
|
||||
// it still should stay in the current restriction level as we exempt the location.
|
||||
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
|
||||
FOREGROUND_SERVICE_TYPE_LOCATION, bgMediaPlaybackMinDuration * 2, false,
|
||||
FOREGROUND_SERVICE_TYPE_LOCATION, bgMediaPlaybackMinDuration * 2, false, false,
|
||||
null, null, null, listener, stats, uids,
|
||||
new double[]{restrictBucketHighThresholdMah + 100, 0},
|
||||
new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
|
||||
@@ -1913,8 +1983,8 @@ public final class BackgroundRestrictionTest {
|
||||
}
|
||||
|
||||
private void runTestBgCurrentDrainExemptionOnce(String packageName, int uid, int pid,
|
||||
int serviceType, long sleepMs, boolean stopAfterSleep, String perm,
|
||||
List<Pair<List<MediaController>, Long>> mediaControllers,
|
||||
int serviceType, long sleepMs, boolean stopAfterSleep, boolean withNotification,
|
||||
String perm, List<Pair<List<MediaController>, Long>> mediaControllers,
|
||||
List<Long> topStateChanges, TestAppRestrictionLevelListener listener,
|
||||
BatteryUsageStats stats, int[] uids, double[] bg, double[] fgs, double[] fg,
|
||||
double[] cached, boolean expectingTimeout, int expectingLevel, long timeout,
|
||||
@@ -1941,7 +2011,7 @@ public final class BackgroundRestrictionTest {
|
||||
}
|
||||
waitForIdleHandler(mBgRestrictionController.getBackgroundHandler());
|
||||
runExemptionTestOnce(
|
||||
packageName, uid, pid, serviceType, sleepMs, stopAfterSleep,
|
||||
packageName, uid, pid, serviceType, sleepMs, stopAfterSleep, withNotification,
|
||||
perm, mediaControllers, topStateChanges, resetFGSTracker, false,
|
||||
() -> {
|
||||
clearInvocations(mInjector.getAppStandbyInternal());
|
||||
|
||||
Reference in New Issue
Block a user