Merge "Add support to exempt the battery usage with visible FGS notifications" into tm-dev
This commit is contained in:
@@ -5796,7 +5796,7 @@
|
|||||||
<!-- The types of state where we'll exempt its battery usage during that state.
|
<!-- 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.
|
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,
|
<!-- 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
|
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.annotation.NonNull;
|
||||||
import android.app.ActivityManagerInternal.ForegroundServiceStateListener;
|
import android.app.ActivityManagerInternal.ForegroundServiceStateListener;
|
||||||
import android.app.IProcessObserver;
|
import android.app.IProcessObserver;
|
||||||
|
import android.content.ComponentName;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.pm.ServiceInfo.ForegroundServiceType;
|
import android.content.pm.ServiceInfo.ForegroundServiceType;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Message;
|
import android.os.Message;
|
||||||
import android.os.PowerExemptionManager.ReasonCode;
|
import android.os.PowerExemptionManager.ReasonCode;
|
||||||
|
import android.os.RemoteException;
|
||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
import android.provider.DeviceConfig;
|
import android.provider.DeviceConfig;
|
||||||
|
import android.service.notification.NotificationListenerService;
|
||||||
|
import android.service.notification.StatusBarNotification;
|
||||||
import android.util.ArrayMap;
|
import android.util.ArrayMap;
|
||||||
import android.util.ArraySet;
|
|
||||||
import android.util.Slog;
|
import android.util.Slog;
|
||||||
import android.util.SparseArray;
|
import android.util.SparseArray;
|
||||||
|
import android.util.SparseBooleanArray;
|
||||||
import android.util.TimeUtils;
|
import android.util.TimeUtils;
|
||||||
|
|
||||||
import com.android.internal.annotations.GuardedBy;
|
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.BaseAppStateEventsTracker.BaseAppStateEventsPolicy;
|
||||||
import com.android.server.am.BaseAppStateTimeEvents.BaseTimeEvent;
|
import com.android.server.am.BaseAppStateTimeEvents.BaseTimeEvent;
|
||||||
import com.android.server.am.BaseAppStateTracker.Injector;
|
import com.android.server.am.BaseAppStateTracker.Injector;
|
||||||
import com.android.server.notification.NotificationManagerInternal;
|
|
||||||
|
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.lang.reflect.Constructor;
|
import java.lang.reflect.Constructor;
|
||||||
@@ -72,11 +75,14 @@ final class AppFGSTracker extends BaseAppStateDurationsTracker<AppFGSPolicy, Pac
|
|||||||
private final MyHandler mHandler;
|
private final MyHandler mHandler;
|
||||||
|
|
||||||
@GuardedBy("mLock")
|
@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.
|
// Unlocked since it's only accessed in single thread.
|
||||||
private final ArrayMap<PackageDurations, Long> mTmpPkgDurations = new ArrayMap<>();
|
private final ArrayMap<PackageDurations, Long> mTmpPkgDurations = new ArrayMap<>();
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
final NotificationListener mNotificationListener = new NotificationListener();
|
||||||
|
|
||||||
final IProcessObserver.Stub mProcessObserver = new IProcessObserver.Stub() {
|
final IProcessObserver.Stub mProcessObserver = new IProcessObserver.Stub() {
|
||||||
@Override
|
@Override
|
||||||
public void onForegroundActivitiesChanged(int pid, int uid, boolean fg) {
|
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_CHANGED = 2;
|
||||||
static final int MSG_FOREGROUND_SERVICES_NOTIFICATION_UPDATED = 3;
|
static final int MSG_FOREGROUND_SERVICES_NOTIFICATION_UPDATED = 3;
|
||||||
static final int MSG_CHECK_LONG_RUNNING_FGS = 4;
|
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;
|
private final AppFGSTracker mTracker;
|
||||||
|
|
||||||
@@ -146,6 +154,12 @@ final class AppFGSTracker extends BaseAppStateDurationsTracker<AppFGSPolicy, Pac
|
|||||||
case MSG_CHECK_LONG_RUNNING_FGS:
|
case MSG_CHECK_LONG_RUNNING_FGS:
|
||||||
mTracker.checkLongRunningFgs();
|
mTracker.checkLongRunningFgs();
|
||||||
break;
|
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,20 +237,37 @@ final class AppFGSTracker extends BaseAppStateDurationsTracker<AppFGSPolicy, Pac
|
|||||||
private void handleForegroundServiceNotificationUpdated(String packageName, int uid,
|
private void handleForegroundServiceNotificationUpdated(String packageName, int uid,
|
||||||
int notificationId) {
|
int notificationId) {
|
||||||
synchronized (mLock) {
|
synchronized (mLock) {
|
||||||
|
SparseBooleanArray notificationIDs = mFGSNotificationIDs.get(uid, packageName);
|
||||||
if (notificationId > 0) {
|
if (notificationId > 0) {
|
||||||
ArraySet<Integer> notificationIDs = mFGSNotificationIDs.get(uid, packageName);
|
|
||||||
if (notificationIDs == null) {
|
if (notificationIDs == null) {
|
||||||
notificationIDs = new ArraySet<>();
|
notificationIDs = new SparseBooleanArray();
|
||||||
mFGSNotificationIDs.put(uid, packageName, notificationIDs);
|
mFGSNotificationIDs.put(uid, packageName, notificationIDs);
|
||||||
}
|
}
|
||||||
notificationIDs.add(notificationId);
|
notificationIDs.put(notificationId, false);
|
||||||
} else if (notificationId < 0) {
|
} else if (notificationId < 0) {
|
||||||
final ArraySet<Integer> notificationIDs = mFGSNotificationIDs.get(uid, packageName);
|
|
||||||
if (notificationIDs != null) {
|
if (notificationIDs != null) {
|
||||||
notificationIDs.remove(-notificationId);
|
final int indexOfKey = notificationIDs.indexOfKey(-notificationId);
|
||||||
if (notificationIDs.isEmpty()) {
|
if (indexOfKey >= 0) {
|
||||||
|
final boolean wasVisible = notificationIDs.valueAt(indexOfKey);
|
||||||
|
notificationIDs.removeAt(indexOfKey);
|
||||||
|
if (notificationIDs.size() == 0) {
|
||||||
mFGSNotificationIDs.remove(uid, packageName);
|
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")
|
@GuardedBy("mLock")
|
||||||
private boolean hasForegroundServiceNotificationsLocked(String packageName, int uid) {
|
private boolean hasForegroundServiceNotificationsLocked(String packageName, int uid) {
|
||||||
final ArraySet<Integer> notificationIDs = mFGSNotificationIDs.get(uid, packageName);
|
final SparseBooleanArray notificationIDs = mFGSNotificationIDs.get(uid, packageName);
|
||||||
if (notificationIDs == null || notificationIDs.isEmpty()) {
|
if (notificationIDs == null || notificationIDs.size() == 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
final NotificationManagerInternal nm = mInjector.getNotificationManagerInternal();
|
|
||||||
final int userId = UserHandle.getUserId(uid);
|
|
||||||
for (int i = notificationIDs.size() - 1; i >= 0; i--) {
|
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 true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
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")
|
@GuardedBy("mLock")
|
||||||
private void scheduleDurationCheckLocked(long now) {
|
private void scheduleDurationCheckLocked(long now) {
|
||||||
// Look for the active FGS with longest running time till 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) {
|
synchronized (mLock) {
|
||||||
scheduleDurationCheckLocked(SystemClock.elapsedRealtime());
|
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 {
|
} else {
|
||||||
|
try {
|
||||||
|
mNotificationListener.unregisterAsSystemService();
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
// Intra-process call, should never happen.
|
||||||
|
}
|
||||||
mHandler.removeMessages(MyHandler.MSG_CHECK_LONG_RUNNING_FGS);
|
mHandler.removeMessages(MyHandler.MSG_CHECK_LONG_RUNNING_FGS);
|
||||||
synchronized (mLock) {
|
synchronized (mLock) {
|
||||||
mPkgEvents.clear();
|
mPkgEvents.clear();
|
||||||
@@ -436,9 +533,9 @@ final class AppFGSTracker extends BaseAppStateDurationsTracker<AppFGSPolicy, Pac
|
|||||||
|
|
||||||
boolean hasForegroundServiceNotifications(int uid) {
|
boolean hasForegroundServiceNotifications(int uid) {
|
||||||
synchronized (mLock) {
|
synchronized (mLock) {
|
||||||
final SparseArray<ArrayMap<String, ArraySet<Integer>>> map =
|
final SparseArray<ArrayMap<String, SparseBooleanArray>> map =
|
||||||
mFGSNotificationIDs.getMap();
|
mFGSNotificationIDs.getMap();
|
||||||
final ArrayMap<String, ArraySet<Integer>> pkgs = map.get(uid);
|
final ArrayMap<String, SparseBooleanArray> pkgs = map.get(uid);
|
||||||
if (pkgs != null) {
|
if (pkgs != null) {
|
||||||
for (int i = pkgs.size() - 1; i >= 0; i--) {
|
for (int i = pkgs.size() - 1; i >= 0; i--) {
|
||||||
if (hasForegroundServiceNotificationsLocked(pkgs.keyAt(i), uid)) {
|
if (hasForegroundServiceNotificationsLocked(pkgs.keyAt(i), uid)) {
|
||||||
@@ -463,7 +560,7 @@ final class AppFGSTracker extends BaseAppStateDurationsTracker<AppFGSPolicy, Pac
|
|||||||
pw.println("APPS WITH ACTIVE FOREGROUND SERVICES:");
|
pw.println("APPS WITH ACTIVE FOREGROUND SERVICES:");
|
||||||
prefix = " " + prefix;
|
prefix = " " + prefix;
|
||||||
synchronized (mLock) {
|
synchronized (mLock) {
|
||||||
final SparseArray<ArrayMap<String, ArraySet<Integer>>> map =
|
final SparseArray<ArrayMap<String, SparseBooleanArray>> map =
|
||||||
mFGSNotificationIDs.getMap();
|
mFGSNotificationIDs.getMap();
|
||||||
if (map.size() == 0) {
|
if (map.size() == 0) {
|
||||||
pw.print(prefix);
|
pw.print(prefix);
|
||||||
@@ -472,7 +569,7 @@ final class AppFGSTracker extends BaseAppStateDurationsTracker<AppFGSPolicy, Pac
|
|||||||
for (int i = 0, size = map.size(); i < size; i++) {
|
for (int i = 0, size = map.size(); i < size; i++) {
|
||||||
final int uid = map.keyAt(i);
|
final int uid = map.keyAt(i);
|
||||||
final String uidString = UserHandle.formatUid(uid);
|
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++) {
|
for (int j = 0, numOfPkgs = pkgs.size(); j < numOfPkgs; j++) {
|
||||||
final String pkgName = pkgs.keyAt(j);
|
final String pkgName = pkgs.keyAt(j);
|
||||||
pw.print(prefix);
|
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> {
|
static final class AppFGSPolicy extends BaseAppStateEventsPolicy<AppFGSTracker> {
|
||||||
/**
|
/**
|
||||||
* Whether or not we should enable the monitoring on abusive FGS.
|
* 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_MEDIA_SESSION = 1;
|
||||||
static final int STATE_TYPE_FGS_MEDIA_PLAYBACK = 1 << 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_FGS_LOCATION = 1 << 2;
|
||||||
static final int STATE_TYPE_PERMISSION = 1 << 3;
|
static final int STATE_TYPE_FGS_WITH_NOTIFICATION = 1 << 3;
|
||||||
static final int STATE_TYPE_NUM = 4;
|
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_MEDIA_SESSION = 0;
|
||||||
static final int STATE_TYPE_INDEX_FGS_MEDIA_PLAYBACK = 1;
|
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_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 AppRestrictionController mAppRestrictionController;
|
||||||
protected final Injector<T> mInjector;
|
protected final Injector<T> mInjector;
|
||||||
@@ -129,6 +131,9 @@ public abstract class BaseAppStateTracker<T extends BaseAppStatePolicy> {
|
|||||||
case STATE_TYPE_FGS_LOCATION:
|
case STATE_TYPE_FGS_LOCATION:
|
||||||
sb.append("FGS_LOCATION");
|
sb.append("FGS_LOCATION");
|
||||||
break;
|
break;
|
||||||
|
case STATE_TYPE_FGS_WITH_NOTIFICATION:
|
||||||
|
sb.append("FGS_NOTIFICATION");
|
||||||
|
break;
|
||||||
case STATE_TYPE_PERMISSION:
|
case STATE_TYPE_PERMISSION:
|
||||||
sb.append("PERMISSION");
|
sb.append("PERMISSION");
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -31,6 +31,7 @@
|
|||||||
<uses-permission android:name="android.permission.WAKE_LOCK"/>
|
<uses-permission android:name="android.permission.WAKE_LOCK"/>
|
||||||
<uses-permission
|
<uses-permission
|
||||||
android:name="android.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD"/>
|
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 -->
|
<!-- needed by MasterClearReceiverTest to display a system dialog -->
|
||||||
<uses-permission android:name="android.permission.INTERNAL_SYSTEM_WINDOW"/>
|
<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.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_LOCATION;
|
||||||
import static com.android.server.am.BaseAppStateTracker.STATE_TYPE_FGS_MEDIA_PLAYBACK;
|
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_MEDIA_SESSION;
|
||||||
import static com.android.server.am.BaseAppStateTracker.STATE_TYPE_PERMISSION;
|
import static com.android.server.am.BaseAppStateTracker.STATE_TYPE_PERMISSION;
|
||||||
|
|
||||||
@@ -113,6 +114,7 @@ import android.os.UidBatteryConsumer;
|
|||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
import android.permission.PermissionManager;
|
import android.permission.PermissionManager;
|
||||||
import android.provider.DeviceConfig;
|
import android.provider.DeviceConfig;
|
||||||
|
import android.service.notification.StatusBarNotification;
|
||||||
import android.telephony.TelephonyManager;
|
import android.telephony.TelephonyManager;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
@@ -566,6 +568,7 @@ public final class BackgroundRestrictionTest {
|
|||||||
DeviceConfigSession<Float> bgCurrentDrainBgRestrictedThreshold = null;
|
DeviceConfigSession<Float> bgCurrentDrainBgRestrictedThreshold = null;
|
||||||
DeviceConfigSession<Boolean> bgPromptFgsWithNotiToBgRestricted = null;
|
DeviceConfigSession<Boolean> bgPromptFgsWithNotiToBgRestricted = null;
|
||||||
DeviceConfigSession<Long> bgNotificationMinInterval = null;
|
DeviceConfigSession<Long> bgNotificationMinInterval = null;
|
||||||
|
DeviceConfigSession<Integer> bgBatteryExemptionTypes = null;
|
||||||
|
|
||||||
mBgRestrictionController.addAppBackgroundRestrictionListener(listener);
|
mBgRestrictionController.addAppBackgroundRestrictionListener(listener);
|
||||||
|
|
||||||
@@ -627,16 +630,25 @@ public final class BackgroundRestrictionTest {
|
|||||||
ConstantsObserver.DEFAULT_BG_ABUSIVE_NOTIFICATION_MINIMAL_INTERVAL_MS);
|
ConstantsObserver.DEFAULT_BG_ABUSIVE_NOTIFICATION_MINIMAL_INTERVAL_MS);
|
||||||
bgNotificationMinInterval.set(windowMs);
|
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;
|
mCurrentTimeMillis = 10_000L;
|
||||||
doReturn(mCurrentTimeMillis - windowMs).when(stats).getStatsStartTimestamp();
|
doReturn(mCurrentTimeMillis - windowMs).when(stats).getStatsStartTimestamp();
|
||||||
doReturn(mCurrentTimeMillis).when(stats).getStatsEndTimestamp();
|
doReturn(mCurrentTimeMillis).when(stats).getStatsEndTimestamp();
|
||||||
doReturn(statsList).when(mBatteryStatsInternal).getBatteryUsageStats(anyObject());
|
doReturn(statsList).when(mBatteryStatsInternal).getBatteryUsageStats(anyObject());
|
||||||
doReturn(true).when(mNotificationManagerInternal).isNotificationShown(
|
|
||||||
testPkgName, null, notificationId, testUser);
|
|
||||||
mAppFGSTracker.onForegroundServiceStateChanged(testPkgName, testUid,
|
mAppFGSTracker.onForegroundServiceStateChanged(testPkgName, testUid,
|
||||||
testPid, true);
|
testPid, true);
|
||||||
mAppFGSTracker.onForegroundServiceNotificationUpdated(
|
mAppFGSTracker.onForegroundServiceNotificationUpdated(
|
||||||
testPkgName, testUid, notificationId);
|
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,
|
runTestBgCurrentDrainMonitorOnce(listener, stats, uids,
|
||||||
new double[]{restrictBucketThresholdMah - 1, 0},
|
new double[]{restrictBucketThresholdMah - 1, 0},
|
||||||
@@ -915,6 +927,7 @@ public final class BackgroundRestrictionTest {
|
|||||||
closeIfNotNull(bgCurrentDrainBgRestrictedThreshold);
|
closeIfNotNull(bgCurrentDrainBgRestrictedThreshold);
|
||||||
closeIfNotNull(bgPromptFgsWithNotiToBgRestricted);
|
closeIfNotNull(bgPromptFgsWithNotiToBgRestricted);
|
||||||
closeIfNotNull(bgNotificationMinInterval);
|
closeIfNotNull(bgNotificationMinInterval);
|
||||||
|
closeIfNotNull(bgBatteryExemptionTypes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1250,14 +1263,15 @@ public final class BackgroundRestrictionTest {
|
|||||||
List<Pair<List<MediaController>, Long>> mediaControllers, List<Long> topStateChanges,
|
List<Pair<List<MediaController>, Long>> mediaControllers, List<Long> topStateChanges,
|
||||||
VerificationMode mode) throws Exception {
|
VerificationMode mode) throws Exception {
|
||||||
runExemptionTestOnce(
|
runExemptionTestOnce(
|
||||||
packageName, uid, pid, serviceType, sleepMs, true, perm, mediaControllers,
|
packageName, uid, pid, serviceType, sleepMs, true, false, perm, mediaControllers,
|
||||||
topStateChanges, true, true,
|
topStateChanges, true, true,
|
||||||
() -> checkNotificationShown(new String[] {packageName}, mode, false)
|
() -> checkNotificationShown(new String[] {packageName}, mode, false)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void runExemptionTestOnce(String packageName, int uid, int pid,
|
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<Pair<List<MediaController>, Long>> mediaControllers,
|
||||||
List<Long> topStateChanges, boolean resetFGSTracker, boolean resetController,
|
List<Long> topStateChanges, boolean resetFGSTracker, boolean resetController,
|
||||||
RunnableWithException r) throws Exception {
|
RunnableWithException r) throws Exception {
|
||||||
@@ -1302,7 +1316,20 @@ public final class BackgroundRestrictionTest {
|
|||||||
FOREGROUND_SERVICE_TYPE_NONE);
|
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) {
|
if (perm != null) {
|
||||||
doReturn(PERMISSION_GRANTED)
|
doReturn(PERMISSION_GRANTED)
|
||||||
.when(mPermissionManagerServiceInternal)
|
.when(mPermissionManagerServiceInternal)
|
||||||
@@ -1513,7 +1540,8 @@ public final class BackgroundRestrictionTest {
|
|||||||
mContext.getResources().getInteger(
|
mContext.getResources().getInteger(
|
||||||
R.integer.config_bg_current_drain_exempted_types));
|
R.integer.config_bg_current_drain_exempted_types));
|
||||||
bgBatteryExemptionTypes.set(STATE_TYPE_MEDIA_SESSION | STATE_TYPE_FGS_MEDIA_PLAYBACK
|
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<>(
|
bgPermissionMonitorEnabled = new DeviceConfigSession<>(
|
||||||
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
|
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
|
||||||
@@ -1546,7 +1574,7 @@ public final class BackgroundRestrictionTest {
|
|||||||
// Run with a media playback service which starts/stops immediately, we should
|
// Run with a media playback service which starts/stops immediately, we should
|
||||||
// goto the restricted bucket.
|
// goto the restricted bucket.
|
||||||
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
|
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,
|
null, null, null, listener, stats, uids,
|
||||||
new double[]{restrictBucketThresholdMah + 1, 0},
|
new double[]{restrictBucketThresholdMah + 1, 0},
|
||||||
new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
|
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.
|
// Run with a media playback service with extended time. We should be back to normal.
|
||||||
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
|
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
|
||||||
FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK, bgMediaPlaybackMinDuration * 2, false,
|
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[]{restrictBucketThresholdMah + 1, 0},
|
||||||
new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
|
new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
|
||||||
true, RESTRICTION_LEVEL_ADAPTIVE_BUCKET, timeout, false,
|
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.
|
// Run with a media playback service with extended time, with higher current drain.
|
||||||
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
|
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
|
||||||
FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK, bgMediaPlaybackMinDuration * 2, false,
|
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[]{restrictBucketHighThresholdMah - 1, 0},
|
||||||
new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
|
new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
|
||||||
true, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, true,
|
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.
|
// Run with a media playback service with extended time, with even higher current drain.
|
||||||
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
|
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
|
||||||
FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK, bgMediaPlaybackMinDuration * 2, false,
|
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[]{restrictBucketHighThresholdMah + 1, 0},
|
||||||
new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
|
new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
|
||||||
false, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, false,
|
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.
|
// Run with a media session with extended time, with higher current drain.
|
||||||
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
|
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
|
||||||
FOREGROUND_SERVICE_TYPE_NONE, bgMediaPlaybackMinDuration * 2, false, null,
|
FOREGROUND_SERVICE_TYPE_NONE, bgMediaPlaybackMinDuration * 2, false, false,
|
||||||
List.of(Pair.create(createMediaControllers(new String[] {testPkgName1},
|
null, List.of(Pair.create(createMediaControllers(new String[] {testPkgName1},
|
||||||
new int[] {testUid1}), bgMediaPlaybackMinDuration * 2)),
|
new int[] {testUid1}), bgMediaPlaybackMinDuration * 2)),
|
||||||
null, listener, stats, uids,
|
null, listener, stats, uids,
|
||||||
new double[]{restrictBucketHighThresholdMah - 1, 0},
|
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.
|
// Run with a media session with extended time, with even higher current drain.
|
||||||
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
|
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
|
||||||
FOREGROUND_SERVICE_TYPE_NONE, bgMediaPlaybackMinDuration * 2, false, null,
|
FOREGROUND_SERVICE_TYPE_NONE, bgMediaPlaybackMinDuration * 2, false, false,
|
||||||
List.of(Pair.create(createMediaControllers(new String[] {testPkgName1},
|
null, List.of(Pair.create(createMediaControllers(new String[] {testPkgName1},
|
||||||
new int[] {testUid1}), bgMediaPlaybackMinDuration * 2)),
|
new int[] {testUid1}), bgMediaPlaybackMinDuration * 2)),
|
||||||
null, listener, stats, uids,
|
null, listener, stats, uids,
|
||||||
new double[]{restrictBucketHighThresholdMah + 1, 0},
|
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,
|
// Run with a media session with extended time, with moderate current drain,
|
||||||
// but it ran on the top when the location service is active.
|
// but it ran on the top when the location service is active.
|
||||||
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
|
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
|
||||||
FOREGROUND_SERVICE_TYPE_NONE, bgMediaPlaybackMinDuration * 2, false, null,
|
FOREGROUND_SERVICE_TYPE_NONE, bgMediaPlaybackMinDuration * 2, false, false,
|
||||||
List.of(Pair.create(createMediaControllers(new String[] {testPkgName1},
|
null, List.of(Pair.create(createMediaControllers(new String[] {testPkgName1},
|
||||||
new int[] {testUid1}), bgMediaPlaybackMinDuration * 2)),
|
new int[] {testUid1}), bgMediaPlaybackMinDuration * 2)),
|
||||||
List.of(0L, timeout * 2), listener, stats, uids,
|
List.of(0L, timeout * 2), listener, stats, uids,
|
||||||
new double[]{restrictBucketThresholdMah + 1, 0},
|
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.
|
// Run with a location service with extended time, with higher current drain.
|
||||||
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
|
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,
|
null, null, null, listener, stats, uids,
|
||||||
new double[]{restrictBucketHighThresholdMah - 1, 0},
|
new double[]{restrictBucketHighThresholdMah - 1, 0},
|
||||||
new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
|
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.
|
// Run with a location service with extended time, with even higher current drain.
|
||||||
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
|
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,
|
null, null, null, listener, stats, uids,
|
||||||
new double[]{restrictBucketHighThresholdMah + 1, 0},
|
new double[]{restrictBucketHighThresholdMah + 1, 0},
|
||||||
new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
|
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,
|
// Run with a location service with extended time, with moderate current drain,
|
||||||
// but it ran on the top when the location service is active.
|
// but it ran on the top when the location service is active.
|
||||||
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
|
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,
|
null, null, List.of(0L, timeout * 2), listener, stats, uids,
|
||||||
new double[]{restrictBucketThresholdMah + 1, 0},
|
new double[]{restrictBucketThresholdMah + 1, 0},
|
||||||
new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
|
new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
|
||||||
@@ -1692,7 +1720,7 @@ public final class BackgroundRestrictionTest {
|
|||||||
|
|
||||||
// Run with bg location permission, with moderate current drain.
|
// Run with bg location permission, with moderate current drain.
|
||||||
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
|
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,
|
ACCESS_BACKGROUND_LOCATION, null, null, listener, stats, uids,
|
||||||
new double[]{restrictBucketThresholdMah - 1, 0},
|
new double[]{restrictBucketThresholdMah - 1, 0},
|
||||||
new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
|
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.
|
// Run with bg location permission, with a bit higher current drain.
|
||||||
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
|
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,
|
ACCESS_BACKGROUND_LOCATION, null, null, listener, stats, uids,
|
||||||
new double[]{restrictBucketThresholdMah + 1, 0},
|
new double[]{restrictBucketThresholdMah + 1, 0},
|
||||||
new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
|
new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
|
||||||
@@ -1718,7 +1746,7 @@ public final class BackgroundRestrictionTest {
|
|||||||
|
|
||||||
// Run with bg location permission, with higher current drain.
|
// Run with bg location permission, with higher current drain.
|
||||||
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
|
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,
|
ACCESS_BACKGROUND_LOCATION , null, null, listener, stats, uids,
|
||||||
new double[]{restrictBucketHighThresholdMah - 1, 0},
|
new double[]{restrictBucketHighThresholdMah - 1, 0},
|
||||||
new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
|
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.
|
// Run with bg location permission, with even higher current drain.
|
||||||
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
|
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,
|
ACCESS_BACKGROUND_LOCATION , null, null, listener, stats, uids,
|
||||||
new double[]{restrictBucketHighThresholdMah + 1, 0},
|
new double[]{restrictBucketHighThresholdMah + 1, 0},
|
||||||
new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
|
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
|
// Run with a media playback service which starts/stops immediately, we should
|
||||||
// goto the restricted bucket.
|
// goto the restricted bucket.
|
||||||
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
|
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,
|
null, null, null, listener, stats, uids,
|
||||||
new double[]{restrictBucketThresholdMah + 1, 0},
|
new double[]{restrictBucketThresholdMah + 1, 0},
|
||||||
new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
|
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.
|
// Run with a media playback service with extended time. We should be back to normal.
|
||||||
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
|
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
|
||||||
FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK, bgMediaPlaybackMinDuration * 2, false,
|
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[]{restrictBucketThresholdMah + 1, 0},
|
||||||
new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
|
new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
|
||||||
true, RESTRICTION_LEVEL_ADAPTIVE_BUCKET, timeout, false,
|
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.
|
// Run with a media playback service with extended time, with higher current drain.
|
||||||
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
|
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
|
||||||
FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK, bgMediaPlaybackMinDuration * 2, false,
|
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[]{restrictBucketHighThresholdMah - 1, 0},
|
||||||
new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
|
new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
|
||||||
true, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, true,
|
true, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, true,
|
||||||
@@ -1802,7 +1830,7 @@ public final class BackgroundRestrictionTest {
|
|||||||
// playback.
|
// playback.
|
||||||
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
|
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
|
||||||
FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK, bgMediaPlaybackMinDuration * 2, false,
|
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[]{restrictBucketHighThresholdMah + 100, 0},
|
||||||
new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
|
new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
|
||||||
true, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, false,
|
true, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, false,
|
||||||
@@ -1817,7 +1845,7 @@ public final class BackgroundRestrictionTest {
|
|||||||
|
|
||||||
// Run with coarse location permission, with high current drain.
|
// Run with coarse location permission, with high current drain.
|
||||||
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
|
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,
|
ACCESS_COARSE_LOCATION, null, null, listener, stats, uids,
|
||||||
new double[]{restrictBucketThresholdMah + 1, 0},
|
new double[]{restrictBucketThresholdMah + 1, 0},
|
||||||
new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
|
new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
|
||||||
@@ -1831,7 +1859,7 @@ public final class BackgroundRestrictionTest {
|
|||||||
|
|
||||||
// Run with fine location permission, with high current drain.
|
// Run with fine location permission, with high current drain.
|
||||||
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
|
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,
|
ACCESS_FINE_LOCATION, null, null, listener, stats, uids,
|
||||||
new double[]{restrictBucketThresholdMah + 1, 0},
|
new double[]{restrictBucketThresholdMah + 1, 0},
|
||||||
new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
|
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.
|
// Run with a media session with extended time, with higher current drain.
|
||||||
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
|
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
|
||||||
FOREGROUND_SERVICE_TYPE_NONE, bgMediaPlaybackMinDuration * 2, false, null,
|
FOREGROUND_SERVICE_TYPE_NONE, bgMediaPlaybackMinDuration * 2, false, false,
|
||||||
List.of(Pair.create(createMediaControllers(new String[] {testPkgName1},
|
null, List.of(Pair.create(createMediaControllers(new String[] {testPkgName1},
|
||||||
new int[] {testUid1}), bgMediaPlaybackMinDuration * 2)),
|
new int[] {testUid1}), bgMediaPlaybackMinDuration * 2)),
|
||||||
null, listener, stats, uids,
|
null, listener, stats, uids,
|
||||||
new double[]{restrictBucketHighThresholdMah - 1, 0},
|
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
|
// it still should stay in the current restriction level as we exempt the media
|
||||||
// session.
|
// session.
|
||||||
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
|
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
|
||||||
FOREGROUND_SERVICE_TYPE_NONE, bgMediaPlaybackMinDuration * 2, false, null,
|
FOREGROUND_SERVICE_TYPE_NONE, bgMediaPlaybackMinDuration * 2, false, false,
|
||||||
List.of(Pair.create(createMediaControllers(new String[] {testPkgName1},
|
null, List.of(Pair.create(createMediaControllers(new String[] {testPkgName1},
|
||||||
new int[] {testUid1}), bgMediaPlaybackMinDuration * 2)),
|
new int[] {testUid1}), bgMediaPlaybackMinDuration * 2)),
|
||||||
null, listener, stats, uids,
|
null, listener, stats, uids,
|
||||||
new double[]{restrictBucketHighThresholdMah + 100, 0},
|
new double[]{restrictBucketHighThresholdMah + 100, 0},
|
||||||
@@ -1867,9 +1895,51 @@ public final class BackgroundRestrictionTest {
|
|||||||
true, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, true,
|
true, RESTRICTION_LEVEL_RESTRICTED_BUCKET, timeout, true,
|
||||||
null, windowMs, initialBg, initialFgs, initialFg, initialCached);
|
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.
|
// Set the policy to exempt all.
|
||||||
bgBatteryExemptionTypes.set(STATE_TYPE_MEDIA_SESSION | STATE_TYPE_FGS_MEDIA_PLAYBACK
|
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.
|
// Start over.
|
||||||
resetBgRestrictionController();
|
resetBgRestrictionController();
|
||||||
@@ -1878,7 +1948,7 @@ public final class BackgroundRestrictionTest {
|
|||||||
|
|
||||||
// Run with a location service with extended time, with higher current drain.
|
// Run with a location service with extended time, with higher current drain.
|
||||||
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
|
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,
|
null, null, null, listener, stats, uids,
|
||||||
new double[]{restrictBucketHighThresholdMah - 1, 0},
|
new double[]{restrictBucketHighThresholdMah - 1, 0},
|
||||||
new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
|
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.
|
// 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.
|
// it still should stay in the current restriction level as we exempt the location.
|
||||||
runTestBgCurrentDrainExemptionOnce(testPkgName1, testUid1, testPid1,
|
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,
|
null, null, null, listener, stats, uids,
|
||||||
new double[]{restrictBucketHighThresholdMah + 100, 0},
|
new double[]{restrictBucketHighThresholdMah + 100, 0},
|
||||||
new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
|
new double[]{0, restrictBucketThresholdMah - 1}, zeros, zeros,
|
||||||
@@ -1913,8 +1983,8 @@ public final class BackgroundRestrictionTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void runTestBgCurrentDrainExemptionOnce(String packageName, int uid, int pid,
|
private void runTestBgCurrentDrainExemptionOnce(String packageName, int uid, int pid,
|
||||||
int serviceType, long sleepMs, boolean stopAfterSleep, String perm,
|
int serviceType, long sleepMs, boolean stopAfterSleep, boolean withNotification,
|
||||||
List<Pair<List<MediaController>, Long>> mediaControllers,
|
String perm, List<Pair<List<MediaController>, Long>> mediaControllers,
|
||||||
List<Long> topStateChanges, TestAppRestrictionLevelListener listener,
|
List<Long> topStateChanges, TestAppRestrictionLevelListener listener,
|
||||||
BatteryUsageStats stats, int[] uids, double[] bg, double[] fgs, double[] fg,
|
BatteryUsageStats stats, int[] uids, double[] bg, double[] fgs, double[] fg,
|
||||||
double[] cached, boolean expectingTimeout, int expectingLevel, long timeout,
|
double[] cached, boolean expectingTimeout, int expectingLevel, long timeout,
|
||||||
@@ -1941,7 +2011,7 @@ public final class BackgroundRestrictionTest {
|
|||||||
}
|
}
|
||||||
waitForIdleHandler(mBgRestrictionController.getBackgroundHandler());
|
waitForIdleHandler(mBgRestrictionController.getBackgroundHandler());
|
||||||
runExemptionTestOnce(
|
runExemptionTestOnce(
|
||||||
packageName, uid, pid, serviceType, sleepMs, stopAfterSleep,
|
packageName, uid, pid, serviceType, sleepMs, stopAfterSleep, withNotification,
|
||||||
perm, mediaControllers, topStateChanges, resetFGSTracker, false,
|
perm, mediaControllers, topStateChanges, resetFGSTracker, false,
|
||||||
() -> {
|
() -> {
|
||||||
clearInvocations(mInjector.getAppStandbyInternal());
|
clearInvocations(mInjector.getAppStandbyInternal());
|
||||||
|
|||||||
Reference in New Issue
Block a user