Merge "More changes for the exact alarm permission" into sc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
026ecf618a
@@ -23,6 +23,7 @@ import android.annotation.RequiresPermission;
|
|||||||
import android.annotation.SdkConstant;
|
import android.annotation.SdkConstant;
|
||||||
import android.annotation.SystemApi;
|
import android.annotation.SystemApi;
|
||||||
import android.annotation.SystemService;
|
import android.annotation.SystemService;
|
||||||
|
import android.annotation.TestApi;
|
||||||
import android.compat.annotation.ChangeId;
|
import android.compat.annotation.ChangeId;
|
||||||
import android.compat.annotation.EnabledSince;
|
import android.compat.annotation.EnabledSince;
|
||||||
import android.compat.annotation.UnsupportedAppUsage;
|
import android.compat.annotation.UnsupportedAppUsage;
|
||||||
@@ -1132,12 +1133,31 @@ public class AlarmManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called to check if the caller has permission to use alarms set via {@link }
|
* Called to check if the caller has the permission
|
||||||
* @return
|
* {@link Manifest.permission#SCHEDULE_EXACT_ALARM}.
|
||||||
|
*
|
||||||
|
* Apps can start {@link android.provider.Settings#ACTION_REQUEST_SCHEDULE_EXACT_ALARM} to
|
||||||
|
* request this from the user.
|
||||||
|
*
|
||||||
|
* @return {@code true} if the caller has the permission, {@code false} otherwise.
|
||||||
|
* @see android.provider.Settings#ACTION_REQUEST_SCHEDULE_EXACT_ALARM
|
||||||
*/
|
*/
|
||||||
public boolean canScheduleExactAlarms() {
|
public boolean canScheduleExactAlarms() {
|
||||||
|
return hasScheduleExactAlarm(mContext.getOpPackageName(), mContext.getUserId());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called to check if the given package in the given user has the permission
|
||||||
|
* {@link Manifest.permission#SCHEDULE_EXACT_ALARM}.
|
||||||
|
*
|
||||||
|
* <p><em>Note: This is only for use by system components.</em>
|
||||||
|
*
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
@TestApi
|
||||||
|
public boolean hasScheduleExactAlarm(@NonNull String packageName, int userId) {
|
||||||
try {
|
try {
|
||||||
return mService.canScheduleExactAlarms();
|
return mService.hasScheduleExactAlarm(packageName, userId);
|
||||||
} catch (RemoteException re) {
|
} catch (RemoteException re) {
|
||||||
throw re.rethrowFromSystemServer();
|
throw re.rethrowFromSystemServer();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,6 +41,6 @@ interface IAlarmManager {
|
|||||||
@UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
|
@UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
|
||||||
AlarmManager.AlarmClockInfo getNextAlarmClock(int userId);
|
AlarmManager.AlarmClockInfo getNextAlarmClock(int userId);
|
||||||
long currentNetworkTimeMillis();
|
long currentNetworkTimeMillis();
|
||||||
boolean canScheduleExactAlarms();
|
boolean hasScheduleExactAlarm(String packageName, int userId);
|
||||||
int getConfigVersion();
|
int getConfigVersion();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -126,6 +126,8 @@ import com.android.server.SystemServiceManager;
|
|||||||
import com.android.server.usage.AppStandbyInternal;
|
import com.android.server.usage.AppStandbyInternal;
|
||||||
import com.android.server.usage.AppStandbyInternal.AppIdleStateChangeListener;
|
import com.android.server.usage.AppStandbyInternal.AppIdleStateChangeListener;
|
||||||
|
|
||||||
|
import libcore.util.EmptyArray;
|
||||||
|
|
||||||
import java.io.FileDescriptor;
|
import java.io.FileDescriptor;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
@@ -139,6 +141,7 @@ import java.util.Date;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
import java.util.TreeSet;
|
import java.util.TreeSet;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
@@ -194,6 +197,7 @@ public class AlarmManagerService extends SystemService {
|
|||||||
DeviceIdleInternal mLocalDeviceIdleController;
|
DeviceIdleInternal mLocalDeviceIdleController;
|
||||||
private UsageStatsManagerInternal mUsageStatsManagerInternal;
|
private UsageStatsManagerInternal mUsageStatsManagerInternal;
|
||||||
private ActivityManagerInternal mActivityManagerInternal;
|
private ActivityManagerInternal mActivityManagerInternal;
|
||||||
|
private PackageManagerInternal mPackageManagerInternal;
|
||||||
|
|
||||||
final Object mLock = new Object();
|
final Object mLock = new Object();
|
||||||
|
|
||||||
@@ -262,10 +266,12 @@ public class AlarmManagerService extends SystemService {
|
|||||||
|
|
||||||
interface Stats {
|
interface Stats {
|
||||||
int REORDER_ALARMS_FOR_STANDBY = 0;
|
int REORDER_ALARMS_FOR_STANDBY = 0;
|
||||||
|
int HAS_SCHEDULE_EXACT_ALARM = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
private final StatLogger mStatLogger = new StatLogger("Alarm manager stats", new String[]{
|
private final StatLogger mStatLogger = new StatLogger("Alarm manager stats", new String[]{
|
||||||
"REORDER_ALARMS_FOR_STANDBY",
|
"REORDER_ALARMS_FOR_STANDBY",
|
||||||
|
"HAS_SCHEDULE_EXACT_ALARM",
|
||||||
});
|
});
|
||||||
|
|
||||||
BroadcastOptions mOptsWithFgs = BroadcastOptions.makeBasic();
|
BroadcastOptions mOptsWithFgs = BroadcastOptions.makeBasic();
|
||||||
@@ -383,6 +389,9 @@ public class AlarmManagerService extends SystemService {
|
|||||||
*/
|
*/
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
final class Constants implements DeviceConfig.OnPropertiesChangedListener {
|
final class Constants implements DeviceConfig.OnPropertiesChangedListener {
|
||||||
|
@VisibleForTesting
|
||||||
|
static final int MAX_EXACT_ALARM_DENY_LIST_SIZE = 250;
|
||||||
|
|
||||||
// Key names stored in the settings value.
|
// Key names stored in the settings value.
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
static final String KEY_MIN_FUTURITY = "min_futurity";
|
static final String KEY_MIN_FUTURITY = "min_futurity";
|
||||||
@@ -437,6 +446,8 @@ public class AlarmManagerService extends SystemService {
|
|||||||
static final String KEY_CRASH_NON_CLOCK_APPS = "crash_non_clock_apps";
|
static final String KEY_CRASH_NON_CLOCK_APPS = "crash_non_clock_apps";
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
static final String KEY_PRIORITY_ALARM_DELAY = "priority_alarm_delay";
|
static final String KEY_PRIORITY_ALARM_DELAY = "priority_alarm_delay";
|
||||||
|
@VisibleForTesting
|
||||||
|
static final String KEY_EXACT_ALARM_DENY_LIST = "exact_alarm_deny_list";
|
||||||
|
|
||||||
private static final long DEFAULT_MIN_FUTURITY = 5 * 1000;
|
private static final long DEFAULT_MIN_FUTURITY = 5 * 1000;
|
||||||
private static final long DEFAULT_MIN_INTERVAL = 60 * 1000;
|
private static final long DEFAULT_MIN_INTERVAL = 60 * 1000;
|
||||||
@@ -537,6 +548,12 @@ public class AlarmManagerService extends SystemService {
|
|||||||
*/
|
*/
|
||||||
public long PRIORITY_ALARM_DELAY = DEFAULT_PRIORITY_ALARM_DELAY;
|
public long PRIORITY_ALARM_DELAY = DEFAULT_PRIORITY_ALARM_DELAY;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set of apps that won't get SCHEDULE_EXACT_ALARM when the app-op mode for
|
||||||
|
* OP_SCHEDULE_EXACT_ALARM is MODE_DEFAULT.
|
||||||
|
*/
|
||||||
|
public Set<String> EXACT_ALARM_DENY_LIST = Collections.emptySet();
|
||||||
|
|
||||||
private long mLastAllowWhileIdleWhitelistDuration = -1;
|
private long mLastAllowWhileIdleWhitelistDuration = -1;
|
||||||
private int mVersion = 0;
|
private int mVersion = 0;
|
||||||
|
|
||||||
@@ -686,6 +703,21 @@ public class AlarmManagerService extends SystemService {
|
|||||||
PRIORITY_ALARM_DELAY = properties.getLong(KEY_PRIORITY_ALARM_DELAY,
|
PRIORITY_ALARM_DELAY = properties.getLong(KEY_PRIORITY_ALARM_DELAY,
|
||||||
DEFAULT_PRIORITY_ALARM_DELAY);
|
DEFAULT_PRIORITY_ALARM_DELAY);
|
||||||
break;
|
break;
|
||||||
|
case KEY_EXACT_ALARM_DENY_LIST:
|
||||||
|
final String rawValue = properties.getString(KEY_EXACT_ALARM_DENY_LIST,
|
||||||
|
"");
|
||||||
|
final String[] values = rawValue.isEmpty()
|
||||||
|
? EmptyArray.STRING
|
||||||
|
: rawValue.split(",", MAX_EXACT_ALARM_DENY_LIST_SIZE + 1);
|
||||||
|
if (values.length > MAX_EXACT_ALARM_DENY_LIST_SIZE) {
|
||||||
|
Slog.w(TAG, "Deny list too long, truncating to "
|
||||||
|
+ MAX_EXACT_ALARM_DENY_LIST_SIZE + " elements.");
|
||||||
|
updateExactAlarmDenyList(
|
||||||
|
Arrays.copyOf(values, MAX_EXACT_ALARM_DENY_LIST_SIZE));
|
||||||
|
} else {
|
||||||
|
updateExactAlarmDenyList(values);
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
if (name.startsWith(KEY_PREFIX_STANDBY_QUOTA) && !standbyQuotaUpdated) {
|
if (name.startsWith(KEY_PREFIX_STANDBY_QUOTA) && !standbyQuotaUpdated) {
|
||||||
// The quotas need to be updated in order, so we can't just rely
|
// The quotas need to be updated in order, so we can't just rely
|
||||||
@@ -699,6 +731,21 @@ public class AlarmManagerService extends SystemService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateExactAlarmDenyList(String[] newDenyList) {
|
||||||
|
if (newDenyList.length == 0) {
|
||||||
|
EXACT_ALARM_DENY_LIST = Collections.emptySet();
|
||||||
|
} else {
|
||||||
|
final Set<String> oldSet = EXACT_ALARM_DENY_LIST;
|
||||||
|
final Set<String> newlyAdded = new ArraySet<>(newDenyList);
|
||||||
|
EXACT_ALARM_DENY_LIST = Collections.unmodifiableSet(new ArraySet<>(newlyAdded));
|
||||||
|
newlyAdded.removeAll(oldSet);
|
||||||
|
if (newlyAdded.size() > 0) {
|
||||||
|
mHandler.obtainMessage(AlarmHandler.EXACT_ALARM_DENY_LIST_CHANGED, newlyAdded)
|
||||||
|
.sendToTarget();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void migrateAlarmsToNewStoreLocked() {
|
private void migrateAlarmsToNewStoreLocked() {
|
||||||
final AlarmStore newStore = LAZY_BATCHING ? new LazyAlarmStore()
|
final AlarmStore newStore = LAZY_BATCHING ? new LazyAlarmStore()
|
||||||
: new BatchingAlarmStore();
|
: new BatchingAlarmStore();
|
||||||
@@ -841,6 +888,9 @@ public class AlarmManagerService extends SystemService {
|
|||||||
TimeUtils.formatDuration(PRIORITY_ALARM_DELAY, pw);
|
TimeUtils.formatDuration(PRIORITY_ALARM_DELAY, pw);
|
||||||
pw.println();
|
pw.println();
|
||||||
|
|
||||||
|
pw.print(KEY_EXACT_ALARM_DENY_LIST, EXACT_ALARM_DENY_LIST);
|
||||||
|
pw.println();
|
||||||
|
|
||||||
pw.decreaseIndent();
|
pw.decreaseIndent();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1428,8 +1478,9 @@ public class AlarmManagerService extends SystemService {
|
|||||||
mInjector.setKernelTime(systemBuildTime);
|
mInjector.setKernelTime(systemBuildTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
|
||||||
// Determine SysUI's uid
|
// Determine SysUI's uid
|
||||||
mSystemUiUid = mInjector.getSystemUiUid();
|
mSystemUiUid = mInjector.getSystemUiUid(mPackageManagerInternal);
|
||||||
if (mSystemUiUid <= 0) {
|
if (mSystemUiUid <= 0) {
|
||||||
Slog.wtf(TAG, "SysUI package not found!");
|
Slog.wtf(TAG, "SysUI package not found!");
|
||||||
}
|
}
|
||||||
@@ -1504,10 +1555,7 @@ public class AlarmManagerService extends SystemService {
|
|||||||
if (op != AppOpsManager.OP_SCHEDULE_EXACT_ALARM) {
|
if (op != AppOpsManager.OP_SCHEDULE_EXACT_ALARM) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final int mode = mAppOpsService.checkOperation(op, uid,
|
if (!hasScheduleExactAlarmInternal(packageName, uid)) {
|
||||||
packageName);
|
|
||||||
if (mode != AppOpsManager.MODE_ALLOWED
|
|
||||||
&& mode != AppOpsManager.MODE_DEFAULT) {
|
|
||||||
mHandler.obtainMessage(AlarmHandler.REMOVE_EXACT_ALARMS,
|
mHandler.obtainMessage(AlarmHandler.REMOVE_EXACT_ALARMS,
|
||||||
uid, 0, packageName).sendToTarget();
|
uid, 0, packageName).sendToTarget();
|
||||||
}
|
}
|
||||||
@@ -2028,6 +2076,11 @@ public class AlarmManagerService extends SystemService {
|
|||||||
mHandler.obtainMessage(AlarmHandler.REMOVE_FOR_CANCELED, pi).sendToTarget();
|
mHandler.obtainMessage(AlarmHandler.REMOVE_FOR_CANCELED, pi).sendToTarget();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasScheduleExactAlarm(String packageName, int uid) {
|
||||||
|
return hasScheduleExactAlarmInternal(packageName, uid);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void registerInFlightListener(InFlightListener callback) {
|
public void registerInFlightListener(InFlightListener callback) {
|
||||||
synchronized (mLock) {
|
synchronized (mLock) {
|
||||||
@@ -2036,6 +2089,21 @@ public class AlarmManagerService extends SystemService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean hasScheduleExactAlarmInternal(String packageName, int uid) {
|
||||||
|
final long start = mStatLogger.getTime();
|
||||||
|
// No locking needed as EXACT_ALARM_DENY_LIST is immutable.
|
||||||
|
final boolean isOnDenyList = mConstants.EXACT_ALARM_DENY_LIST.contains(packageName);
|
||||||
|
if (isOnDenyList && mAppOps.checkOpNoThrow(AppOpsManager.OP_SCHEDULE_EXACT_ALARM, uid,
|
||||||
|
packageName) != AppOpsManager.MODE_ALLOWED) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
final boolean has = PermissionChecker.checkPermissionForPreflight(getContext(),
|
||||||
|
Manifest.permission.SCHEDULE_EXACT_ALARM, -1, uid, packageName)
|
||||||
|
== PermissionChecker.PERMISSION_GRANTED;
|
||||||
|
mStatLogger.logDurationStat(Stats.HAS_SCHEDULE_EXACT_ALARM, start);
|
||||||
|
return has;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the given uid does not require SCHEDULE_EXACT_ALARM to set exact,
|
* Returns true if the given uid does not require SCHEDULE_EXACT_ALARM to set exact,
|
||||||
* allow-while-idle alarms.
|
* allow-while-idle alarms.
|
||||||
@@ -2056,11 +2124,16 @@ public class AlarmManagerService extends SystemService {
|
|||||||
int type, long triggerAtTime, long windowLength, long interval, int flags,
|
int type, long triggerAtTime, long windowLength, long interval, int flags,
|
||||||
PendingIntent operation, IAlarmListener directReceiver, String listenerTag,
|
PendingIntent operation, IAlarmListener directReceiver, String listenerTag,
|
||||||
WorkSource workSource, AlarmManager.AlarmClockInfo alarmClock) {
|
WorkSource workSource, AlarmManager.AlarmClockInfo alarmClock) {
|
||||||
final int callingUid = Binder.getCallingUid();
|
final int callingUid = mInjector.getCallingUid();
|
||||||
|
final int callingUserId = UserHandle.getUserId(callingUid);
|
||||||
|
|
||||||
// make sure the caller is not lying about which package should be blamed for
|
// make sure the caller is not lying about which package should be blamed for
|
||||||
// wakelock time spent in alarm delivery
|
// wakelock time spent in alarm delivery
|
||||||
mAppOps.checkPackage(callingUid, callingPackage);
|
if (callingUid != mPackageManagerInternal.getPackageUid(callingPackage, 0,
|
||||||
|
callingUserId)) {
|
||||||
|
throw new SecurityException("Package " + callingPackage
|
||||||
|
+ " does not belong to the calling uid " + callingUid);
|
||||||
|
}
|
||||||
|
|
||||||
final boolean allowWhileIdle = (flags & FLAG_ALLOW_WHILE_IDLE) != 0;
|
final boolean allowWhileIdle = (flags & FLAG_ALLOW_WHILE_IDLE) != 0;
|
||||||
final boolean exact = (windowLength == AlarmManager.WINDOW_EXACT);
|
final boolean exact = (windowLength == AlarmManager.WINDOW_EXACT);
|
||||||
@@ -2077,7 +2150,7 @@ public class AlarmManagerService extends SystemService {
|
|||||||
final boolean needsPermission;
|
final boolean needsPermission;
|
||||||
boolean lowerQuota;
|
boolean lowerQuota;
|
||||||
if (CompatChanges.isChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION,
|
if (CompatChanges.isChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION,
|
||||||
callingPackage, UserHandle.getUserHandleForUid(callingUid))) {
|
callingPackage, UserHandle.of(callingUserId))) {
|
||||||
needsPermission = exact;
|
needsPermission = exact;
|
||||||
lowerQuota = !exact;
|
lowerQuota = !exact;
|
||||||
idleOptions = exact ? mOptsWithFgs.toBundle() : mOptsWithoutFgs.toBundle();
|
idleOptions = exact ? mOptsWithFgs.toBundle() : mOptsWithoutFgs.toBundle();
|
||||||
@@ -2086,7 +2159,7 @@ public class AlarmManagerService extends SystemService {
|
|||||||
lowerQuota = allowWhileIdle;
|
lowerQuota = allowWhileIdle;
|
||||||
idleOptions = allowWhileIdle ? mOptsWithFgs.toBundle() : null;
|
idleOptions = allowWhileIdle ? mOptsWithFgs.toBundle() : null;
|
||||||
}
|
}
|
||||||
if (needsPermission && !canScheduleExactAlarms()) {
|
if (needsPermission && !hasScheduleExactAlarmInternal(callingPackage, callingUid)) {
|
||||||
if (alarmClock != null || !isExemptFromExactAlarmPermission(callingUid)) {
|
if (alarmClock != null || !isExemptFromExactAlarmPermission(callingUid)) {
|
||||||
final String errorMessage = "Caller " + callingPackage + " needs to hold "
|
final String errorMessage = "Caller " + callingPackage + " needs to hold "
|
||||||
+ Manifest.permission.SCHEDULE_EXACT_ALARM + " to set "
|
+ Manifest.permission.SCHEDULE_EXACT_ALARM + " to set "
|
||||||
@@ -2165,10 +2238,18 @@ public class AlarmManagerService extends SystemService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean canScheduleExactAlarms() {
|
public boolean hasScheduleExactAlarm(String packageName, int userId) {
|
||||||
return PermissionChecker.checkCallingOrSelfPermissionForPreflight(getContext(),
|
final int callingUid = mInjector.getCallingUid();
|
||||||
Manifest.permission.SCHEDULE_EXACT_ALARM)
|
if (UserHandle.getUserId(callingUid) != userId) {
|
||||||
== PermissionChecker.PERMISSION_GRANTED;
|
getContext().enforceCallingOrSelfPermission(
|
||||||
|
Manifest.permission.INTERACT_ACROSS_USERS_FULL, "hasScheduleExactAlarm");
|
||||||
|
}
|
||||||
|
final int uid = mPackageManagerInternal.getPackageUid(packageName, 0, userId);
|
||||||
|
if (callingUid != uid && !UserHandle.isCore(callingUid)) {
|
||||||
|
throw new SecurityException("Uid " + callingUid
|
||||||
|
+ " cannot query hasScheduleExactAlarm for uid " + uid);
|
||||||
|
}
|
||||||
|
return (uid > 0) ? hasScheduleExactAlarmInternal(packageName, uid) : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -3071,28 +3152,64 @@ public class AlarmManagerService extends SystemService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when some packages are added to the {@link Constants#EXACT_ALARM_DENY_LIST}, as this
|
||||||
|
* may cause some of them to lose their permission.
|
||||||
|
*
|
||||||
|
* Note that these packages don't need to be installed on the device, but if they do have an
|
||||||
|
* exact alarm scheduled and they lose the permission, this alarm will be canceled.
|
||||||
|
*
|
||||||
|
* This is not expected to get called frequently.
|
||||||
|
*/
|
||||||
|
void handlePackagesAddedToExactAlarmsDenyListLocked(ArraySet<String> packageNames) {
|
||||||
|
Slog.w(TAG, "Packages " + packageNames + " added to the exact alarm deny list.");
|
||||||
|
final Predicate<Alarm> whichAlarms = a -> {
|
||||||
|
if (!packageNames.contains(a.packageName) || a.windowLength != 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!CompatChanges.isChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION,
|
||||||
|
a.packageName, UserHandle.getUserHandleForUid(a.uid))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (a.alarmClock == null && isExemptFromExactAlarmPermission(a.uid)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return !hasScheduleExactAlarmInternal(a.packageName, a.uid);
|
||||||
|
};
|
||||||
|
removeAlarmsInternalLocked(whichAlarms);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when an app loses {@link Manifest.permission#SCHEDULE_EXACT_ALARM} to remove alarms
|
* Called when an app loses {@link Manifest.permission#SCHEDULE_EXACT_ALARM} to remove alarms
|
||||||
* that the app is no longer eligible to use.
|
* that the app is no longer eligible to use.
|
||||||
|
*
|
||||||
|
* This is not expected to get called frequently.
|
||||||
* TODO (b/179541791): Add revocation history to dumpsys.
|
* TODO (b/179541791): Add revocation history to dumpsys.
|
||||||
*/
|
*/
|
||||||
void removeExactAlarmsOnPermissionRevokedLocked(int uid, String packageName) {
|
void removeExactAlarmsOnPermissionRevokedLocked(int uid, String packageName) {
|
||||||
if (isExemptFromExactAlarmPermission(uid)) {
|
Slog.w(TAG, "Package " + packageName + ", uid " + uid + " lost SCHEDULE_EXACT_ALARM!");
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!CompatChanges.isChangeEnabled(
|
if (!CompatChanges.isChangeEnabled(
|
||||||
AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION,
|
AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION,
|
||||||
packageName, UserHandle.getUserHandleForUid(uid))) {
|
packageName, UserHandle.getUserHandleForUid(uid))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final Predicate<Alarm> whichAlarms =
|
final Predicate<Alarm> whichAlarms = a -> {
|
||||||
a -> (a.uid == uid && a.packageName.equals(packageName)
|
if (a.uid == uid && a.packageName.equals(packageName) && a.windowLength == 0) {
|
||||||
&& a.windowLength == AlarmManager.WINDOW_EXACT);
|
return a.alarmClock != null || !isExemptFromExactAlarmPermission(uid);
|
||||||
final ArrayList<Alarm> removed = mAlarmStore.remove(whichAlarms);
|
}
|
||||||
final boolean didRemove = !removed.isEmpty();
|
return false;
|
||||||
|
};
|
||||||
|
removeAlarmsInternalLocked(whichAlarms);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removeAlarmsInternalLocked(Predicate<Alarm> whichAlarms) {
|
||||||
|
final ArrayList<Alarm> removedAlarms = mAlarmStore.remove(whichAlarms);
|
||||||
|
final boolean didRemove = !removedAlarms.isEmpty();
|
||||||
if (didRemove) {
|
if (didRemove) {
|
||||||
decrementAlarmCount(uid, removed.size());
|
for (final Alarm removed : removedAlarms) {
|
||||||
|
decrementAlarmCount(removed.uid, 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = mPendingBackgroundAlarms.size() - 1; i >= 0; i--) {
|
for (int i = mPendingBackgroundAlarms.size() - 1; i >= 0; i--) {
|
||||||
@@ -3119,21 +3236,22 @@ public class AlarmManagerService extends SystemService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (didRemove) {
|
if (didRemove) {
|
||||||
|
boolean idleUntilUpdated = false;
|
||||||
|
if (mPendingIdleUntil != null && whichAlarms.test(mPendingIdleUntil)) {
|
||||||
|
mPendingIdleUntil = null;
|
||||||
|
idleUntilUpdated = true;
|
||||||
|
}
|
||||||
if (mNextWakeFromIdle != null && whichAlarms.test(mNextWakeFromIdle)) {
|
if (mNextWakeFromIdle != null && whichAlarms.test(mNextWakeFromIdle)) {
|
||||||
mNextWakeFromIdle = mAlarmStore.getNextWakeFromIdleAlarm();
|
mNextWakeFromIdle = mAlarmStore.getNextWakeFromIdleAlarm();
|
||||||
if (mPendingIdleUntil != null) {
|
if (mPendingIdleUntil != null) {
|
||||||
final boolean idleUntilUpdated = mAlarmStore.updateAlarmDeliveries(alarm -> {
|
idleUntilUpdated |= mAlarmStore.updateAlarmDeliveries(alarm ->
|
||||||
if (alarm != mPendingIdleUntil) {
|
(alarm == mPendingIdleUntil && adjustIdleUntilTime(alarm)));
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return adjustIdleUntilTime(alarm);
|
|
||||||
});
|
|
||||||
if (idleUntilUpdated) {
|
|
||||||
mAlarmStore.updateAlarmDeliveries(
|
|
||||||
alarm -> adjustDeliveryTimeBasedOnDeviceIdle(alarm));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (idleUntilUpdated) {
|
||||||
|
mAlarmStore.updateAlarmDeliveries(
|
||||||
|
alarm -> adjustDeliveryTimeBasedOnDeviceIdle(alarm));
|
||||||
|
}
|
||||||
rescheduleKernelAlarmsLocked();
|
rescheduleKernelAlarmsLocked();
|
||||||
updateNextAlarmClockLocked();
|
updateNextAlarmClockLocked();
|
||||||
}
|
}
|
||||||
@@ -3147,63 +3265,7 @@ public class AlarmManagerService extends SystemService {
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
removeAlarmsInternalLocked(a -> a.matches(operation, directReceiver));
|
||||||
final ArrayList<Alarm> removedAlarms = mAlarmStore.remove(
|
|
||||||
a -> a.matches(operation, directReceiver));
|
|
||||||
for (final Alarm removed : removedAlarms) {
|
|
||||||
decrementAlarmCount(removed.uid, 1);
|
|
||||||
}
|
|
||||||
final boolean didRemove = !removedAlarms.isEmpty();
|
|
||||||
|
|
||||||
for (int i = mPendingBackgroundAlarms.size() - 1; i >= 0; i--) {
|
|
||||||
final ArrayList<Alarm> alarmsForUid = mPendingBackgroundAlarms.valueAt(i);
|
|
||||||
for (int j = alarmsForUid.size() - 1; j >= 0; j--) {
|
|
||||||
final Alarm alarm = alarmsForUid.get(j);
|
|
||||||
if (alarm.matches(operation, directReceiver)) {
|
|
||||||
// Don't set didRemove, since this doesn't impact the scheduled alarms.
|
|
||||||
alarmsForUid.remove(j);
|
|
||||||
decrementAlarmCount(alarm.uid, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (alarmsForUid.size() == 0) {
|
|
||||||
mPendingBackgroundAlarms.removeAt(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (int i = mPendingNonWakeupAlarms.size() - 1; i >= 0; i--) {
|
|
||||||
final Alarm a = mPendingNonWakeupAlarms.get(i);
|
|
||||||
if (a.matches(operation, directReceiver)) {
|
|
||||||
// Don't set didRemove, since this doesn't impact the scheduled alarms.
|
|
||||||
mPendingNonWakeupAlarms.remove(i);
|
|
||||||
decrementAlarmCount(a.uid, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (didRemove) {
|
|
||||||
if (DEBUG_BATCH) {
|
|
||||||
Slog.v(TAG, "remove(operation) changed bounds; rebatching");
|
|
||||||
}
|
|
||||||
boolean idleUntilUpdated = false;
|
|
||||||
if (mPendingIdleUntil != null && mPendingIdleUntil.matches(operation, directReceiver)) {
|
|
||||||
mPendingIdleUntil = null;
|
|
||||||
idleUntilUpdated = true;
|
|
||||||
}
|
|
||||||
if (mNextWakeFromIdle != null && mNextWakeFromIdle.matches(operation, directReceiver)) {
|
|
||||||
mNextWakeFromIdle = mAlarmStore.getNextWakeFromIdleAlarm();
|
|
||||||
if (mPendingIdleUntil != null) {
|
|
||||||
idleUntilUpdated |= mAlarmStore.updateAlarmDeliveries(alarm -> {
|
|
||||||
if (alarm != mPendingIdleUntil) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return adjustIdleUntilTime(alarm);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (idleUntilUpdated) {
|
|
||||||
mAlarmStore.updateAlarmDeliveries(
|
|
||||||
alarm -> adjustDeliveryTimeBasedOnDeviceIdle(alarm));
|
|
||||||
}
|
|
||||||
rescheduleKernelAlarmsLocked();
|
|
||||||
updateNextAlarmClockLocked();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void removeLocked(final int uid) {
|
void removeLocked(final int uid) {
|
||||||
@@ -3211,55 +3273,7 @@ public class AlarmManagerService extends SystemService {
|
|||||||
// If a force-stop occurs for a system-uid package, ignore it.
|
// If a force-stop occurs for a system-uid package, ignore it.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
removeAlarmsInternalLocked(a -> a.uid == uid);
|
||||||
final ArrayList<Alarm> removed = mAlarmStore.remove(a -> a.uid == uid);
|
|
||||||
final boolean didRemove = !removed.isEmpty();
|
|
||||||
if (didRemove) {
|
|
||||||
decrementAlarmCount(uid, removed.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = mPendingBackgroundAlarms.size() - 1; i >= 0; i--) {
|
|
||||||
final ArrayList<Alarm> alarmsForUid = mPendingBackgroundAlarms.valueAt(i);
|
|
||||||
for (int j = alarmsForUid.size() - 1; j >= 0; j--) {
|
|
||||||
if (alarmsForUid.get(j).uid == uid) {
|
|
||||||
alarmsForUid.remove(j);
|
|
||||||
decrementAlarmCount(uid, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (alarmsForUid.size() == 0) {
|
|
||||||
mPendingBackgroundAlarms.removeAt(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// If we're currently using this app's alarms to come out of doze,
|
|
||||||
// make sure to reset to any remaining WAKE_FROM_IDLE alarms.
|
|
||||||
boolean idleUntilUpdated = false;
|
|
||||||
if (mNextWakeFromIdle != null && mNextWakeFromIdle.uid == uid) {
|
|
||||||
mNextWakeFromIdle = mAlarmStore.getNextWakeFromIdleAlarm();
|
|
||||||
if (mPendingIdleUntil != null) {
|
|
||||||
idleUntilUpdated |= mAlarmStore.updateAlarmDeliveries(alarm -> {
|
|
||||||
if (alarm != mPendingIdleUntil) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return adjustIdleUntilTime(alarm);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (mPendingIdleUntil != null && mPendingIdleUntil.uid == uid) {
|
|
||||||
// Should never happen - only the system uid is allowed to set idle-until alarms
|
|
||||||
Slog.wtf(TAG, "Removed app uid " + uid + " set idle-until alarm!");
|
|
||||||
mPendingIdleUntil = null;
|
|
||||||
idleUntilUpdated = true;
|
|
||||||
}
|
|
||||||
if (idleUntilUpdated) {
|
|
||||||
mAlarmStore.updateAlarmDeliveries(alarm -> adjustDeliveryTimeBasedOnDeviceIdle(alarm));
|
|
||||||
}
|
|
||||||
if (didRemove) {
|
|
||||||
if (DEBUG_BATCH) {
|
|
||||||
Slog.v(TAG, "remove(uid) changed bounds; rebatching");
|
|
||||||
}
|
|
||||||
rescheduleKernelAlarmsLocked();
|
|
||||||
updateNextAlarmClockLocked();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void removeLocked(final String packageName) {
|
void removeLocked(final String packageName) {
|
||||||
@@ -3270,50 +3284,7 @@ public class AlarmManagerService extends SystemService {
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
removeAlarmsInternalLocked(a -> a.matches(packageName));
|
||||||
final ArrayList<Alarm> removed = mAlarmStore.remove(a -> a.matches(packageName));
|
|
||||||
final boolean didRemove = !removed.isEmpty();
|
|
||||||
if (didRemove) {
|
|
||||||
decrementAlarmCount(removed.get(0).uid, removed.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = mPendingBackgroundAlarms.size() - 1; i >= 0; i--) {
|
|
||||||
final ArrayList<Alarm> alarmsForUid = mPendingBackgroundAlarms.valueAt(i);
|
|
||||||
for (int j = alarmsForUid.size() - 1; j >= 0; j--) {
|
|
||||||
final Alarm alarm = alarmsForUid.get(j);
|
|
||||||
if (alarm.matches(packageName)) {
|
|
||||||
alarmsForUid.remove(j);
|
|
||||||
decrementAlarmCount(alarm.uid, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (alarmsForUid.size() == 0) {
|
|
||||||
mPendingBackgroundAlarms.removeAt(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// If we're currently using this app's alarms to come out of doze,
|
|
||||||
// make sure to reset to any remaining WAKE_FROM_IDLE alarms.
|
|
||||||
if (mNextWakeFromIdle != null && mNextWakeFromIdle.matches(packageName)) {
|
|
||||||
mNextWakeFromIdle = mAlarmStore.getNextWakeFromIdleAlarm();
|
|
||||||
if (mPendingIdleUntil != null) {
|
|
||||||
final boolean updated = mAlarmStore.updateAlarmDeliveries(alarm -> {
|
|
||||||
if (alarm != mPendingIdleUntil) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return adjustIdleUntilTime(alarm);
|
|
||||||
});
|
|
||||||
if (updated) {
|
|
||||||
mAlarmStore.updateAlarmDeliveries(
|
|
||||||
alarm -> adjustDeliveryTimeBasedOnDeviceIdle(alarm));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (didRemove) {
|
|
||||||
if (DEBUG_BATCH) {
|
|
||||||
Slog.v(TAG, "remove(package) changed bounds; rebatching");
|
|
||||||
}
|
|
||||||
rescheduleKernelAlarmsLocked();
|
|
||||||
updateNextAlarmClockLocked();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only called for ephemeral apps
|
// Only called for ephemeral apps
|
||||||
@@ -3324,28 +3295,7 @@ public class AlarmManagerService extends SystemService {
|
|||||||
}
|
}
|
||||||
final Predicate<Alarm> whichAlarms = (a) -> (a.uid == uid
|
final Predicate<Alarm> whichAlarms = (a) -> (a.uid == uid
|
||||||
&& mActivityManagerInternal.isAppStartModeDisabled(uid, a.packageName));
|
&& mActivityManagerInternal.isAppStartModeDisabled(uid, a.packageName));
|
||||||
final ArrayList<Alarm> removed = mAlarmStore.remove(whichAlarms);
|
removeAlarmsInternalLocked(whichAlarms);
|
||||||
final boolean didRemove = !removed.isEmpty();
|
|
||||||
if (didRemove) {
|
|
||||||
decrementAlarmCount(uid, removed.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = mPendingBackgroundAlarms.size() - 1; i >= 0; i--) {
|
|
||||||
if (mPendingBackgroundAlarms.keyAt(i) == uid) {
|
|
||||||
final ArrayList<Alarm> toRemove = mPendingBackgroundAlarms.valueAt(i);
|
|
||||||
if (toRemove != null) {
|
|
||||||
decrementAlarmCount(uid, toRemove.size());
|
|
||||||
}
|
|
||||||
mPendingBackgroundAlarms.removeAt(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (didRemove) {
|
|
||||||
if (DEBUG_BATCH) {
|
|
||||||
Slog.v(TAG, "remove(package) changed bounds; rebatching");
|
|
||||||
}
|
|
||||||
rescheduleKernelAlarmsLocked();
|
|
||||||
updateNextAlarmClockLocked();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void removeUserLocked(int userHandle) {
|
void removeUserLocked(int userHandle) {
|
||||||
@@ -3720,6 +3670,10 @@ public class AlarmManagerService extends SystemService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int getCallingUid() {
|
||||||
|
return Binder.getCallingUid();
|
||||||
|
}
|
||||||
|
|
||||||
long getNextAlarm(int type) {
|
long getNextAlarm(int type) {
|
||||||
return AlarmManagerService.getNextAlarm(mNativeData, type);
|
return AlarmManagerService.getNextAlarm(mNativeData, type);
|
||||||
}
|
}
|
||||||
@@ -3751,8 +3705,7 @@ public class AlarmManagerService extends SystemService {
|
|||||||
return pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*alarm*");
|
return pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*alarm*");
|
||||||
}
|
}
|
||||||
|
|
||||||
int getSystemUiUid() {
|
int getSystemUiUid(PackageManagerInternal pm) {
|
||||||
PackageManagerInternal pm = LocalServices.getService(PackageManagerInternal.class);
|
|
||||||
return pm.getPackageUid(pm.getSystemUiServiceComponent().getPackageName(),
|
return pm.getPackageUid(pm.getSystemUiServiceComponent().getPackageName(),
|
||||||
MATCH_SYSTEM_ONLY, USER_SYSTEM);
|
MATCH_SYSTEM_ONLY, USER_SYSTEM);
|
||||||
}
|
}
|
||||||
@@ -3962,6 +3915,7 @@ public class AlarmManagerService extends SystemService {
|
|||||||
public static final int CHARGING_STATUS_CHANGED = 6;
|
public static final int CHARGING_STATUS_CHANGED = 6;
|
||||||
public static final int REMOVE_FOR_CANCELED = 7;
|
public static final int REMOVE_FOR_CANCELED = 7;
|
||||||
public static final int REMOVE_EXACT_ALARMS = 8;
|
public static final int REMOVE_EXACT_ALARMS = 8;
|
||||||
|
public static final int EXACT_ALARM_DENY_LIST_CHANGED = 9;
|
||||||
|
|
||||||
AlarmHandler() {
|
AlarmHandler() {
|
||||||
super(Looper.myLooper());
|
super(Looper.myLooper());
|
||||||
@@ -4048,7 +4002,11 @@ public class AlarmManagerService extends SystemService {
|
|||||||
removeExactAlarmsOnPermissionRevokedLocked(uid, packageName);
|
removeExactAlarmsOnPermissionRevokedLocked(uid, packageName);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case EXACT_ALARM_DENY_LIST_CHANGED:
|
||||||
|
synchronized (mLock) {
|
||||||
|
handlePackagesAddedToExactAlarmsDenyListLocked((ArraySet<String>) msg.obj);
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
// nope, just ignore it
|
// nope, just ignore it
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -111,6 +111,7 @@ import com.android.internal.annotations.VisibleForTesting;
|
|||||||
import com.android.internal.app.IBatteryStats;
|
import com.android.internal.app.IBatteryStats;
|
||||||
import com.android.internal.util.ArrayUtils;
|
import com.android.internal.util.ArrayUtils;
|
||||||
import com.android.internal.util.ConcurrentUtils;
|
import com.android.internal.util.ConcurrentUtils;
|
||||||
|
import com.android.server.AlarmManagerInternal;
|
||||||
import com.android.server.JobSchedulerBackgroundThread;
|
import com.android.server.JobSchedulerBackgroundThread;
|
||||||
import com.android.server.LocalServices;
|
import com.android.server.LocalServices;
|
||||||
import com.android.server.pm.parsing.pkg.AndroidPackage;
|
import com.android.server.pm.parsing.pkg.AndroidPackage;
|
||||||
@@ -1191,6 +1192,10 @@ public class AppStandbyController
|
|||||||
if (mInjector.isWellbeingPackage(packageName)) {
|
if (mInjector.isWellbeingPackage(packageName)) {
|
||||||
return STANDBY_BUCKET_WORKING_SET;
|
return STANDBY_BUCKET_WORKING_SET;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mInjector.hasScheduleExactAlarm(packageName, UserHandle.getUid(userId, appId))) {
|
||||||
|
return STANDBY_BUCKET_WORKING_SET;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check this last, as it can be the most expensive check
|
// Check this last, as it can be the most expensive check
|
||||||
@@ -2007,6 +2012,7 @@ public class AppStandbyController
|
|||||||
private PowerManager mPowerManager;
|
private PowerManager mPowerManager;
|
||||||
private IDeviceIdleController mDeviceIdleController;
|
private IDeviceIdleController mDeviceIdleController;
|
||||||
private CrossProfileAppsInternal mCrossProfileAppsInternal;
|
private CrossProfileAppsInternal mCrossProfileAppsInternal;
|
||||||
|
private AlarmManagerInternal mAlarmManagerInternal;
|
||||||
int mBootPhase;
|
int mBootPhase;
|
||||||
/**
|
/**
|
||||||
* The minimum amount of time required since the last user interaction before an app can be
|
* The minimum amount of time required since the last user interaction before an app can be
|
||||||
@@ -2047,6 +2053,7 @@ public class AppStandbyController
|
|||||||
mBatteryManager = mContext.getSystemService(BatteryManager.class);
|
mBatteryManager = mContext.getSystemService(BatteryManager.class);
|
||||||
mCrossProfileAppsInternal = LocalServices.getService(
|
mCrossProfileAppsInternal = LocalServices.getService(
|
||||||
CrossProfileAppsInternal.class);
|
CrossProfileAppsInternal.class);
|
||||||
|
mAlarmManagerInternal = LocalServices.getService(AlarmManagerInternal.class);
|
||||||
|
|
||||||
final ActivityManager activityManager =
|
final ActivityManager activityManager =
|
||||||
(ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
|
(ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
|
||||||
@@ -2110,6 +2117,10 @@ public class AppStandbyController
|
|||||||
return mWellbeingApp != null && mWellbeingApp.equals(packageName);
|
return mWellbeingApp != null && mWellbeingApp.equals(packageName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean hasScheduleExactAlarm(String packageName, int uid) {
|
||||||
|
return mAlarmManagerInternal.hasScheduleExactAlarm(packageName, uid);
|
||||||
|
}
|
||||||
|
|
||||||
void updatePowerWhitelistCache() {
|
void updatePowerWhitelistCache() {
|
||||||
try {
|
try {
|
||||||
// Don't call out to DeviceIdleController with the lock held.
|
// Don't call out to DeviceIdleController with the lock held.
|
||||||
|
|||||||
@@ -204,6 +204,10 @@ package android.app {
|
|||||||
method public void onTaskRemovalStarted(int);
|
method public void onTaskRemovalStarted(int);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class AlarmManager {
|
||||||
|
method public boolean hasScheduleExactAlarm(@NonNull String, int);
|
||||||
|
}
|
||||||
|
|
||||||
public class AppDetailsActivity extends android.app.Activity {
|
public class AppDetailsActivity extends android.app.Activity {
|
||||||
ctor public AppDetailsActivity();
|
ctor public AppDetailsActivity();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1277,18 +1277,32 @@
|
|||||||
<!-- Label for the settings activity for controlling apps that can schedule alarms [CHAR LIMIT=30] -->
|
<!-- Label for the settings activity for controlling apps that can schedule alarms [CHAR LIMIT=30] -->
|
||||||
<string name="alarms_and_reminders_label">Alarms and reminders</string>
|
<string name="alarms_and_reminders_label">Alarms and reminders</string>
|
||||||
<!-- Label for the switch to toggler the permission for scheduling alarms [CHAR LIMIT=50] -->
|
<!-- Label for the switch to toggler the permission for scheduling alarms [CHAR LIMIT=50] -->
|
||||||
<string name="alarms_and_reminders_switch_title">Allow to set alarms or reminders</string>
|
<string name="alarms_and_reminders_switch_title">Allow setting alarms and reminders</string>
|
||||||
<!-- Title for the setting screen for controlling apps that can schedule alarms [CHAR LIMIT=30] -->
|
<!-- Title for the setting screen for controlling apps that can schedule alarms [CHAR LIMIT=30] -->
|
||||||
<string name="alarms_and_reminders_title">Alarms and reminders</string>
|
<string name="alarms_and_reminders_title">Alarms & reminders</string>
|
||||||
<!-- Description that appears below the alarms_and_reminders switch [CHAR LIMIT=NONE] -->
|
<!-- Description that appears below the alarms_and_reminders switch [CHAR LIMIT=NONE] -->
|
||||||
<string name="alarms_and_reminders_footer_title">
|
<string name="alarms_and_reminders_footer_title" product="default">
|
||||||
Allow this app to schedule alarms or other timing based events.
|
Allow this app to set alarms and schedule other actions.
|
||||||
This will allow the app to wake up and run even when you are not using the device.
|
This app may be used when you\u2019re not using your phone, which may use more battery.
|
||||||
Note that revoking this permission may cause the app to malfunction, specifically any alarms
|
If this permission is off, this app may not function normally,
|
||||||
that the app has scheduled will no longer work.
|
and its alarms won\u2019t work as scheduled.
|
||||||
|
</string>
|
||||||
|
<!-- Description that appears below the alarms_and_reminders switch [CHAR LIMIT=NONE] -->
|
||||||
|
<string name="alarms_and_reminders_footer_title" product="tablet">
|
||||||
|
Allow this app to set alarms and schedule other actions.
|
||||||
|
This app may be used when you\u2019re not using your tablet, which may use more battery.
|
||||||
|
If this permission is off, this app may not function normally,
|
||||||
|
and its alarms won\u2019t work as scheduled.
|
||||||
|
</string>
|
||||||
|
<!-- Description that appears below the alarms_and_reminders switch [CHAR LIMIT=NONE] -->
|
||||||
|
<string name="alarms_and_reminders_footer_title" product="device">
|
||||||
|
Allow this app to set alarms and schedule other actions.
|
||||||
|
This app may be used when you\u2019re not using your device, which may use more battery.
|
||||||
|
If this permission is off, this app may not function normally,
|
||||||
|
and its alarms won\u2019t work as scheduled.
|
||||||
</string>
|
</string>
|
||||||
<!-- Keywords for setting screen for controlling apps that can schedule alarms [CHAR LIMIT=100] -->
|
<!-- Keywords for setting screen for controlling apps that can schedule alarms [CHAR LIMIT=100] -->
|
||||||
<string name="keywords_alarms_and_reminders">schedule, alarm, reminder, event</string>
|
<string name="keywords_alarms_and_reminders">schedule, alarm, reminder, clock</string>
|
||||||
|
|
||||||
<!-- Do not disturb: Label for button in enable zen dialog that will turn on zen mode. [CHAR LIMIT=30] -->
|
<!-- Do not disturb: Label for button in enable zen dialog that will turn on zen mode. [CHAR LIMIT=30] -->
|
||||||
<string name="zen_mode_enable_dialog_turn_on">Turn on</string>
|
<string name="zen_mode_enable_dialog_turn_on">Turn on</string>
|
||||||
|
|||||||
@@ -24,13 +24,16 @@ public interface AlarmManagerInternal {
|
|||||||
public interface InFlightListener {
|
public interface InFlightListener {
|
||||||
/** There is now an alarm pending delivery to the given app */
|
/** There is now an alarm pending delivery to the given app */
|
||||||
void broadcastAlarmPending(int recipientUid);
|
void broadcastAlarmPending(int recipientUid);
|
||||||
|
|
||||||
/** A broadcast alarm targeted to the given app has completed delivery */
|
/** A broadcast alarm targeted to the given app has completed delivery */
|
||||||
void broadcastAlarmComplete(int recipientUid);
|
void broadcastAlarmComplete(int recipientUid);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns true if AlarmManager is delaying alarms due to device idle. */
|
/** Returns true if AlarmManager is delaying alarms due to device idle. */
|
||||||
boolean isIdling();
|
boolean isIdling();
|
||||||
|
|
||||||
public void removeAlarmsForUid(int uid);
|
public void removeAlarmsForUid(int uid);
|
||||||
|
|
||||||
public void registerInFlightListener(InFlightListener callback);
|
public void registerInFlightListener(InFlightListener callback);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -38,4 +41,10 @@ public interface AlarmManagerInternal {
|
|||||||
* {@link android.app.PendingIntent#equals(java.lang.Object) PendingIntent.equals}
|
* {@link android.app.PendingIntent#equals(java.lang.Object) PendingIntent.equals}
|
||||||
*/
|
*/
|
||||||
void remove(PendingIntent rec);
|
void remove(PendingIntent rec);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns if the given package in the given user holds
|
||||||
|
* {@link android.Manifest.permission#SCHEDULE_EXACT_ALARM}
|
||||||
|
*/
|
||||||
|
boolean hasScheduleExactAlarm(String packageName, int uid);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,10 @@ import static android.app.AlarmManager.RTC;
|
|||||||
import static android.app.AlarmManager.RTC_WAKEUP;
|
import static android.app.AlarmManager.RTC_WAKEUP;
|
||||||
import static android.app.AlarmManager.WINDOW_EXACT;
|
import static android.app.AlarmManager.WINDOW_EXACT;
|
||||||
import static android.app.AlarmManager.WINDOW_HEURISTIC;
|
import static android.app.AlarmManager.WINDOW_HEURISTIC;
|
||||||
|
import static android.app.AppOpsManager.MODE_ALLOWED;
|
||||||
|
import static android.app.AppOpsManager.MODE_DEFAULT;
|
||||||
|
import static android.app.AppOpsManager.MODE_ERRORED;
|
||||||
|
import static android.app.AppOpsManager.MODE_IGNORED;
|
||||||
import static android.app.AppOpsManager.OP_SCHEDULE_EXACT_ALARM;
|
import static android.app.AppOpsManager.OP_SCHEDULE_EXACT_ALARM;
|
||||||
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_ACTIVE;
|
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_ACTIVE;
|
||||||
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_FREQUENT;
|
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_FREQUENT;
|
||||||
@@ -49,6 +53,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
|
|||||||
import static com.android.server.alarm.AlarmManagerService.ACTIVE_INDEX;
|
import static com.android.server.alarm.AlarmManagerService.ACTIVE_INDEX;
|
||||||
import static com.android.server.alarm.AlarmManagerService.AlarmHandler.APP_STANDBY_BUCKET_CHANGED;
|
import static com.android.server.alarm.AlarmManagerService.AlarmHandler.APP_STANDBY_BUCKET_CHANGED;
|
||||||
import static com.android.server.alarm.AlarmManagerService.AlarmHandler.CHARGING_STATUS_CHANGED;
|
import static com.android.server.alarm.AlarmManagerService.AlarmHandler.CHARGING_STATUS_CHANGED;
|
||||||
|
import static com.android.server.alarm.AlarmManagerService.AlarmHandler.EXACT_ALARM_DENY_LIST_CHANGED;
|
||||||
import static com.android.server.alarm.AlarmManagerService.AlarmHandler.REMOVE_EXACT_ALARMS;
|
import static com.android.server.alarm.AlarmManagerService.AlarmHandler.REMOVE_EXACT_ALARMS;
|
||||||
import static com.android.server.alarm.AlarmManagerService.AlarmHandler.REMOVE_FOR_CANCELED;
|
import static com.android.server.alarm.AlarmManagerService.AlarmHandler.REMOVE_FOR_CANCELED;
|
||||||
import static com.android.server.alarm.AlarmManagerService.Constants.KEY_ALLOW_WHILE_IDLE_COMPAT_QUOTA;
|
import static com.android.server.alarm.AlarmManagerService.Constants.KEY_ALLOW_WHILE_IDLE_COMPAT_QUOTA;
|
||||||
@@ -57,6 +62,7 @@ import static com.android.server.alarm.AlarmManagerService.Constants.KEY_ALLOW_W
|
|||||||
import static com.android.server.alarm.AlarmManagerService.Constants.KEY_ALLOW_WHILE_IDLE_WHITELIST_DURATION;
|
import static com.android.server.alarm.AlarmManagerService.Constants.KEY_ALLOW_WHILE_IDLE_WHITELIST_DURATION;
|
||||||
import static com.android.server.alarm.AlarmManagerService.Constants.KEY_ALLOW_WHILE_IDLE_WINDOW;
|
import static com.android.server.alarm.AlarmManagerService.Constants.KEY_ALLOW_WHILE_IDLE_WINDOW;
|
||||||
import static com.android.server.alarm.AlarmManagerService.Constants.KEY_CRASH_NON_CLOCK_APPS;
|
import static com.android.server.alarm.AlarmManagerService.Constants.KEY_CRASH_NON_CLOCK_APPS;
|
||||||
|
import static com.android.server.alarm.AlarmManagerService.Constants.KEY_EXACT_ALARM_DENY_LIST;
|
||||||
import static com.android.server.alarm.AlarmManagerService.Constants.KEY_LAZY_BATCHING;
|
import static com.android.server.alarm.AlarmManagerService.Constants.KEY_LAZY_BATCHING;
|
||||||
import static com.android.server.alarm.AlarmManagerService.Constants.KEY_LISTENER_TIMEOUT;
|
import static com.android.server.alarm.AlarmManagerService.Constants.KEY_LISTENER_TIMEOUT;
|
||||||
import static com.android.server.alarm.AlarmManagerService.Constants.KEY_MAX_INTERVAL;
|
import static com.android.server.alarm.AlarmManagerService.Constants.KEY_MAX_INTERVAL;
|
||||||
@@ -64,6 +70,7 @@ import static com.android.server.alarm.AlarmManagerService.Constants.KEY_MIN_FUT
|
|||||||
import static com.android.server.alarm.AlarmManagerService.Constants.KEY_MIN_INTERVAL;
|
import static com.android.server.alarm.AlarmManagerService.Constants.KEY_MIN_INTERVAL;
|
||||||
import static com.android.server.alarm.AlarmManagerService.Constants.KEY_MIN_WINDOW;
|
import static com.android.server.alarm.AlarmManagerService.Constants.KEY_MIN_WINDOW;
|
||||||
import static com.android.server.alarm.AlarmManagerService.Constants.KEY_PRIORITY_ALARM_DELAY;
|
import static com.android.server.alarm.AlarmManagerService.Constants.KEY_PRIORITY_ALARM_DELAY;
|
||||||
|
import static com.android.server.alarm.AlarmManagerService.Constants.MAX_EXACT_ALARM_DENY_LIST_SIZE;
|
||||||
import static com.android.server.alarm.AlarmManagerService.FREQUENT_INDEX;
|
import static com.android.server.alarm.AlarmManagerService.FREQUENT_INDEX;
|
||||||
import static com.android.server.alarm.AlarmManagerService.INDEFINITE_DELAY;
|
import static com.android.server.alarm.AlarmManagerService.INDEFINITE_DELAY;
|
||||||
import static com.android.server.alarm.AlarmManagerService.IS_WAKEUP_MASK;
|
import static com.android.server.alarm.AlarmManagerService.IS_WAKEUP_MASK;
|
||||||
@@ -87,8 +94,10 @@ import static org.mockito.ArgumentMatchers.argThat;
|
|||||||
import static org.mockito.ArgumentMatchers.eq;
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
import static org.mockito.ArgumentMatchers.isNull;
|
import static org.mockito.ArgumentMatchers.isNull;
|
||||||
import static org.mockito.Mockito.atLeastOnce;
|
import static org.mockito.Mockito.atLeastOnce;
|
||||||
|
import static org.mockito.Mockito.clearInvocations;
|
||||||
import static org.mockito.Mockito.never;
|
import static org.mockito.Mockito.never;
|
||||||
import static org.mockito.Mockito.times;
|
import static org.mockito.Mockito.times;
|
||||||
|
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||||
|
|
||||||
import android.Manifest;
|
import android.Manifest;
|
||||||
import android.app.ActivityManager;
|
import android.app.ActivityManager;
|
||||||
@@ -106,6 +115,7 @@ import android.app.usage.UsageStatsManagerInternal;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.PermissionChecker;
|
import android.content.PermissionChecker;
|
||||||
|
import android.content.pm.PackageManagerInternal;
|
||||||
import android.os.BatteryManager;
|
import android.os.BatteryManager;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
@@ -113,13 +123,13 @@ import android.os.IBinder;
|
|||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import android.os.Message;
|
import android.os.Message;
|
||||||
import android.os.PowerManager;
|
import android.os.PowerManager;
|
||||||
import android.os.Process;
|
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.os.ServiceManager;
|
import android.os.ServiceManager;
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
import android.platform.test.annotations.Presubmit;
|
import android.platform.test.annotations.Presubmit;
|
||||||
import android.provider.DeviceConfig;
|
import android.provider.DeviceConfig;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
|
import android.util.ArraySet;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.SparseArray;
|
import android.util.SparseArray;
|
||||||
|
|
||||||
@@ -176,6 +186,8 @@ public class AlarmManagerServiceTest {
|
|||||||
@Mock
|
@Mock
|
||||||
private IAppOpsService mIAppOpsService;
|
private IAppOpsService mIAppOpsService;
|
||||||
@Mock
|
@Mock
|
||||||
|
private AppOpsManager mAppOpsManager;
|
||||||
|
@Mock
|
||||||
private DeviceIdleInternal mDeviceIdleInternal;
|
private DeviceIdleInternal mDeviceIdleInternal;
|
||||||
@Mock
|
@Mock
|
||||||
private UsageStatsManagerInternal mUsageStatsManagerInternal;
|
private UsageStatsManagerInternal mUsageStatsManagerInternal;
|
||||||
@@ -184,6 +196,8 @@ public class AlarmManagerServiceTest {
|
|||||||
@Mock
|
@Mock
|
||||||
private ActivityManagerInternal mActivityManagerInternal;
|
private ActivityManagerInternal mActivityManagerInternal;
|
||||||
@Mock
|
@Mock
|
||||||
|
private PackageManagerInternal mPackageManagerInternal;
|
||||||
|
@Mock
|
||||||
private AppStateTrackerImpl mAppStateTracker;
|
private AppStateTrackerImpl mAppStateTracker;
|
||||||
@Mock
|
@Mock
|
||||||
private AlarmManagerService.ClockReceiver mClockReceiver;
|
private AlarmManagerService.ClockReceiver mClockReceiver;
|
||||||
@@ -269,6 +283,11 @@ public class AlarmManagerServiceTest {
|
|||||||
// Do nothing.
|
// Do nothing.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
int getCallingUid() {
|
||||||
|
return TEST_CALLING_UID;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void setAlarm(int type, long millis) {
|
void setAlarm(int type, long millis) {
|
||||||
mTestTimer.set(type, millis);
|
mTestTimer.set(type, millis);
|
||||||
@@ -279,7 +298,7 @@ public class AlarmManagerServiceTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
int getSystemUiUid() {
|
int getSystemUiUid(PackageManagerInternal unused) {
|
||||||
return SYSTEM_UI_UID;
|
return SYSTEM_UI_UID;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -344,6 +363,8 @@ public class AlarmManagerServiceTest {
|
|||||||
() -> LocalServices.getService(DeviceIdleInternal.class));
|
() -> LocalServices.getService(DeviceIdleInternal.class));
|
||||||
doReturn(mActivityManagerInternal).when(
|
doReturn(mActivityManagerInternal).when(
|
||||||
() -> LocalServices.getService(ActivityManagerInternal.class));
|
() -> LocalServices.getService(ActivityManagerInternal.class));
|
||||||
|
doReturn(mPackageManagerInternal).when(
|
||||||
|
() -> LocalServices.getService(PackageManagerInternal.class));
|
||||||
doReturn(mAppStateTracker).when(() -> LocalServices.getService(AppStateTracker.class));
|
doReturn(mAppStateTracker).when(() -> LocalServices.getService(AppStateTracker.class));
|
||||||
doReturn(mAppStandbyInternal).when(
|
doReturn(mAppStandbyInternal).when(
|
||||||
() -> LocalServices.getService(AppStandbyInternal.class));
|
() -> LocalServices.getService(AppStandbyInternal.class));
|
||||||
@@ -376,8 +397,10 @@ public class AlarmManagerServiceTest {
|
|||||||
() -> DeviceConfig.getProperties(
|
() -> DeviceConfig.getProperties(
|
||||||
eq(DeviceConfig.NAMESPACE_ALARM_MANAGER), ArgumentMatchers.<String>any()));
|
eq(DeviceConfig.NAMESPACE_ALARM_MANAGER), ArgumentMatchers.<String>any()));
|
||||||
|
|
||||||
when(mMockContext.getSystemService(Context.APP_OPS_SERVICE)).thenReturn(
|
when(mMockContext.getSystemService(Context.APP_OPS_SERVICE)).thenReturn(mAppOpsManager);
|
||||||
mock(AppOpsManager.class));
|
|
||||||
|
when(mPackageManagerInternal.getPackageUid(eq(TEST_CALLING_PACKAGE), anyInt(),
|
||||||
|
eq(TEST_CALLING_USER))).thenReturn(TEST_CALLING_UID);
|
||||||
|
|
||||||
mInjector = new Injector(mMockContext);
|
mInjector = new Injector(mMockContext);
|
||||||
mService = new AlarmManagerService(mMockContext, mInjector);
|
mService = new AlarmManagerService(mMockContext, mInjector);
|
||||||
@@ -464,8 +487,15 @@ public class AlarmManagerServiceTest {
|
|||||||
|
|
||||||
private void setTestAlarm(int type, long triggerTime, long windowLength,
|
private void setTestAlarm(int type, long triggerTime, long windowLength,
|
||||||
PendingIntent operation, long interval, int flags, int callingUid, Bundle idleOptions) {
|
PendingIntent operation, long interval, int flags, int callingUid, Bundle idleOptions) {
|
||||||
|
setTestAlarm(type, triggerTime, windowLength, operation, interval, flags, callingUid,
|
||||||
|
TEST_CALLING_PACKAGE, idleOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setTestAlarm(int type, long triggerTime, long windowLength,
|
||||||
|
PendingIntent operation, long interval, int flags, int callingUid,
|
||||||
|
String callingPackage, Bundle idleOptions) {
|
||||||
mService.setImpl(type, triggerTime, windowLength, interval, operation, null, "test", flags,
|
mService.setImpl(type, triggerTime, windowLength, interval, operation, null, "test", flags,
|
||||||
null, null, callingUid, TEST_CALLING_PACKAGE, idleOptions);
|
null, null, callingUid, callingPackage, idleOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setTestAlarmWithListener(int type, long triggerTime, IAlarmListener listener) {
|
private void setTestAlarmWithListener(int type, long triggerTime, IAlarmListener listener) {
|
||||||
@@ -503,6 +533,12 @@ public class AlarmManagerServiceTest {
|
|||||||
mService.mConstants.onPropertiesChanged(mDeviceConfigProperties);
|
mService.mConstants.onPropertiesChanged(mDeviceConfigProperties);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setDeviceConfigString(String key, String val) {
|
||||||
|
mDeviceConfigKeys.add(key);
|
||||||
|
doReturn(val).when(mDeviceConfigProperties).getString(eq(key), anyString());
|
||||||
|
mService.mConstants.onPropertiesChanged(mDeviceConfigProperties);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Lowers quotas to make testing feasible. Careful while calling as this will replace any
|
* Lowers quotas to make testing feasible. Careful while calling as this will replace any
|
||||||
* existing settings for the calling test.
|
* existing settings for the calling test.
|
||||||
@@ -601,6 +637,47 @@ public class AlarmManagerServiceTest {
|
|||||||
assertEquals(55, mService.mConstants.PRIORITY_ALARM_DELAY);
|
assertEquals(55, mService.mConstants.PRIORITY_ALARM_DELAY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void updatingExactAlarmDenyList() {
|
||||||
|
ArraySet<String> denyListed = new ArraySet<>(new String[]{
|
||||||
|
"com.example.package1",
|
||||||
|
"com.example.package2",
|
||||||
|
"com.example.package3",
|
||||||
|
});
|
||||||
|
setDeviceConfigString(KEY_EXACT_ALARM_DENY_LIST,
|
||||||
|
"com.example.package1,com.example.package2,com.example.package3");
|
||||||
|
assertEquals(denyListed, mService.mConstants.EXACT_ALARM_DENY_LIST);
|
||||||
|
|
||||||
|
|
||||||
|
denyListed = new ArraySet<>(new String[]{
|
||||||
|
"com.example.package1",
|
||||||
|
"com.example.package4",
|
||||||
|
});
|
||||||
|
setDeviceConfigString(KEY_EXACT_ALARM_DENY_LIST,
|
||||||
|
"com.example.package1,com.example.package4");
|
||||||
|
assertEquals(denyListed, mService.mConstants.EXACT_ALARM_DENY_LIST);
|
||||||
|
|
||||||
|
setDeviceConfigString(KEY_EXACT_ALARM_DENY_LIST, "");
|
||||||
|
assertEquals(0, mService.mConstants.EXACT_ALARM_DENY_LIST.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void exactAlarmDenyListMaxSize() {
|
||||||
|
final ArraySet<String> expectedSet = new ArraySet<>();
|
||||||
|
final StringBuilder sb = new StringBuilder("package1");
|
||||||
|
expectedSet.add("package1");
|
||||||
|
for (int i = 2; i <= 2 * MAX_EXACT_ALARM_DENY_LIST_SIZE; i++) {
|
||||||
|
sb.append(",package");
|
||||||
|
sb.append(i);
|
||||||
|
if (i <= MAX_EXACT_ALARM_DENY_LIST_SIZE) {
|
||||||
|
expectedSet.add("package" + i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assertEquals(MAX_EXACT_ALARM_DENY_LIST_SIZE, expectedSet.size());
|
||||||
|
setDeviceConfigString(KEY_EXACT_ALARM_DENY_LIST, sb.toString());
|
||||||
|
assertEquals(expectedSet, mService.mConstants.EXACT_ALARM_DENY_LIST);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void positiveWhileIdleQuotas() {
|
public void positiveWhileIdleQuotas() {
|
||||||
setDeviceConfigInt(KEY_ALLOW_WHILE_IDLE_QUOTA, -3);
|
setDeviceConfigInt(KEY_ALLOW_WHILE_IDLE_QUOTA, -3);
|
||||||
@@ -1717,21 +1794,70 @@ public class AlarmManagerServiceTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void canScheduleExactAlarms() throws RemoteException {
|
public void hasScheduleExactAlarmBinderCallEmptyDenyList() throws RemoteException {
|
||||||
doReturn(PermissionChecker.PERMISSION_GRANTED).when(
|
doReturn(PermissionChecker.PERMISSION_GRANTED).when(
|
||||||
() -> PermissionChecker.checkCallingOrSelfPermissionForPreflight(mMockContext,
|
() -> PermissionChecker.checkPermissionForPreflight(eq(mMockContext),
|
||||||
Manifest.permission.SCHEDULE_EXACT_ALARM));
|
eq(Manifest.permission.SCHEDULE_EXACT_ALARM), anyInt(),
|
||||||
assertTrue(mBinder.canScheduleExactAlarms());
|
eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE)));
|
||||||
|
assertTrue(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER));
|
||||||
|
|
||||||
doReturn(PermissionChecker.PERMISSION_HARD_DENIED).when(
|
doReturn(PermissionChecker.PERMISSION_HARD_DENIED).when(
|
||||||
() -> PermissionChecker.checkCallingOrSelfPermissionForPreflight(mMockContext,
|
() -> PermissionChecker.checkPermissionForPreflight(eq(mMockContext),
|
||||||
Manifest.permission.SCHEDULE_EXACT_ALARM));
|
eq(Manifest.permission.SCHEDULE_EXACT_ALARM), anyInt(),
|
||||||
assertFalse(mBinder.canScheduleExactAlarms());
|
eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE)));
|
||||||
|
assertFalse(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER));
|
||||||
|
}
|
||||||
|
|
||||||
doReturn(PermissionChecker.PERMISSION_SOFT_DENIED).when(
|
@Test
|
||||||
() -> PermissionChecker.checkCallingOrSelfPermissionForPreflight(mMockContext,
|
public void hasScheduleExactAlarmBinderCallWithDenyList() throws RemoteException {
|
||||||
Manifest.permission.SCHEDULE_EXACT_ALARM));
|
setDeviceConfigString(KEY_EXACT_ALARM_DENY_LIST, TEST_CALLING_PACKAGE);
|
||||||
assertFalse(mBinder.canScheduleExactAlarms());
|
|
||||||
|
when(mAppOpsManager.checkOpNoThrow(OP_SCHEDULE_EXACT_ALARM, TEST_CALLING_UID,
|
||||||
|
TEST_CALLING_PACKAGE)).thenReturn(MODE_ERRORED);
|
||||||
|
|
||||||
|
assertFalse(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER));
|
||||||
|
verify(() -> PermissionChecker.checkPermissionForPreflight(eq(mMockContext),
|
||||||
|
eq(Manifest.permission.SCHEDULE_EXACT_ALARM), anyInt(),
|
||||||
|
eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE)), never());
|
||||||
|
|
||||||
|
when(mAppOpsManager.checkOpNoThrow(OP_SCHEDULE_EXACT_ALARM, TEST_CALLING_UID,
|
||||||
|
TEST_CALLING_PACKAGE)).thenReturn(MODE_DEFAULT);
|
||||||
|
|
||||||
|
assertFalse(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER));
|
||||||
|
verify(() -> PermissionChecker.checkPermissionForPreflight(eq(mMockContext),
|
||||||
|
eq(Manifest.permission.SCHEDULE_EXACT_ALARM), anyInt(),
|
||||||
|
eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE)), never());
|
||||||
|
|
||||||
|
when(mAppOpsManager.checkOpNoThrow(OP_SCHEDULE_EXACT_ALARM, TEST_CALLING_UID,
|
||||||
|
TEST_CALLING_PACKAGE)).thenReturn(MODE_IGNORED);
|
||||||
|
|
||||||
|
assertFalse(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER));
|
||||||
|
verify(() -> PermissionChecker.checkPermissionForPreflight(eq(mMockContext),
|
||||||
|
eq(Manifest.permission.SCHEDULE_EXACT_ALARM), anyInt(),
|
||||||
|
eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE)), never());
|
||||||
|
|
||||||
|
when(mAppOpsManager.checkOpNoThrow(OP_SCHEDULE_EXACT_ALARM, TEST_CALLING_UID,
|
||||||
|
TEST_CALLING_PACKAGE)).thenReturn(MODE_ALLOWED);
|
||||||
|
|
||||||
|
doReturn(PermissionChecker.PERMISSION_HARD_DENIED).when(
|
||||||
|
() -> PermissionChecker.checkPermissionForPreflight(eq(mMockContext),
|
||||||
|
eq(Manifest.permission.SCHEDULE_EXACT_ALARM), anyInt(),
|
||||||
|
eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE)));
|
||||||
|
|
||||||
|
assertFalse(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER));
|
||||||
|
verify(() -> PermissionChecker.checkPermissionForPreflight(eq(mMockContext),
|
||||||
|
eq(Manifest.permission.SCHEDULE_EXACT_ALARM), anyInt(),
|
||||||
|
eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE)));
|
||||||
|
|
||||||
|
doReturn(PermissionChecker.PERMISSION_GRANTED).when(
|
||||||
|
() -> PermissionChecker.checkPermissionForPreflight(eq(mMockContext),
|
||||||
|
eq(Manifest.permission.SCHEDULE_EXACT_ALARM), anyInt(),
|
||||||
|
eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE)));
|
||||||
|
|
||||||
|
assertTrue(mBinder.hasScheduleExactAlarm(TEST_CALLING_PACKAGE, TEST_CALLING_USER));
|
||||||
|
verify(() -> PermissionChecker.checkPermissionForPreflight(eq(mMockContext),
|
||||||
|
eq(Manifest.permission.SCHEDULE_EXACT_ALARM), anyInt(),
|
||||||
|
eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE)), times(2));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -1757,8 +1883,9 @@ public class AlarmManagerServiceTest {
|
|||||||
mBinder.set(TEST_CALLING_PACKAGE, ELAPSED_REALTIME_WAKEUP, 1234, WINDOW_HEURISTIC, 0,
|
mBinder.set(TEST_CALLING_PACKAGE, ELAPSED_REALTIME_WAKEUP, 1234, WINDOW_HEURISTIC, 0,
|
||||||
FLAG_ALLOW_WHILE_IDLE, getNewMockPendingIntent(), null, null, null, null);
|
FLAG_ALLOW_WHILE_IDLE, getNewMockPendingIntent(), null, null, null, null);
|
||||||
|
|
||||||
verify(() -> PermissionChecker.checkCallingOrSelfPermissionForPreflight(mMockContext,
|
verify(() -> PermissionChecker.checkPermissionForPreflight(eq(mMockContext),
|
||||||
Manifest.permission.SCHEDULE_EXACT_ALARM), never());
|
eq(Manifest.permission.SCHEDULE_EXACT_ALARM), anyInt(),
|
||||||
|
eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE)), never());
|
||||||
verify(mDeviceIdleInternal, never()).isAppOnWhitelist(anyInt());
|
verify(mDeviceIdleInternal, never()).isAppOnWhitelist(anyInt());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1775,7 +1902,7 @@ public class AlarmManagerServiceTest {
|
|||||||
verify(mService).setImpl(eq(ELAPSED_REALTIME_WAKEUP), eq(1234L), eq(WINDOW_EXACT), eq(0L),
|
verify(mService).setImpl(eq(ELAPSED_REALTIME_WAKEUP), eq(1234L), eq(WINDOW_EXACT), eq(0L),
|
||||||
eq(alarmPi), isNull(), isNull(),
|
eq(alarmPi), isNull(), isNull(),
|
||||||
eq(FLAG_STANDALONE), isNull(), isNull(),
|
eq(FLAG_STANDALONE), isNull(), isNull(),
|
||||||
eq(Process.myUid()), eq(TEST_CALLING_PACKAGE), isNull());
|
eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE), isNull());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -1792,7 +1919,7 @@ public class AlarmManagerServiceTest {
|
|||||||
verify(mService).setImpl(eq(ELAPSED_REALTIME_WAKEUP), eq(1234L), eq(WINDOW_EXACT), eq(0L),
|
verify(mService).setImpl(eq(ELAPSED_REALTIME_WAKEUP), eq(1234L), eq(WINDOW_EXACT), eq(0L),
|
||||||
eq(alarmPi), isNull(), isNull(),
|
eq(alarmPi), isNull(), isNull(),
|
||||||
eq(FLAG_ALLOW_WHILE_IDLE_COMPAT | FLAG_STANDALONE), isNull(), isNull(),
|
eq(FLAG_ALLOW_WHILE_IDLE_COMPAT | FLAG_STANDALONE), isNull(), isNull(),
|
||||||
eq(Process.myUid()), eq(TEST_CALLING_PACKAGE), bundleCaptor.capture());
|
eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE), bundleCaptor.capture());
|
||||||
|
|
||||||
final BroadcastOptions idleOptions = new BroadcastOptions(bundleCaptor.getValue());
|
final BroadcastOptions idleOptions = new BroadcastOptions(bundleCaptor.getValue());
|
||||||
final int type = idleOptions.getTemporaryAppAllowlistType();
|
final int type = idleOptions.getTemporaryAppAllowlistType();
|
||||||
@@ -1812,7 +1939,7 @@ public class AlarmManagerServiceTest {
|
|||||||
final ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
|
final ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
|
||||||
verify(mService).setImpl(eq(ELAPSED_REALTIME_WAKEUP), eq(1234L), anyLong(), eq(0L),
|
verify(mService).setImpl(eq(ELAPSED_REALTIME_WAKEUP), eq(1234L), anyLong(), eq(0L),
|
||||||
eq(alarmPi), isNull(), isNull(), eq(FLAG_ALLOW_WHILE_IDLE_COMPAT), isNull(),
|
eq(alarmPi), isNull(), isNull(), eq(FLAG_ALLOW_WHILE_IDLE_COMPAT), isNull(),
|
||||||
isNull(), eq(Process.myUid()), eq(TEST_CALLING_PACKAGE), bundleCaptor.capture());
|
isNull(), eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE), bundleCaptor.capture());
|
||||||
|
|
||||||
final BroadcastOptions idleOptions = new BroadcastOptions(bundleCaptor.getValue());
|
final BroadcastOptions idleOptions = new BroadcastOptions(bundleCaptor.getValue());
|
||||||
final int type = idleOptions.getTemporaryAppAllowlistType();
|
final int type = idleOptions.getTemporaryAppAllowlistType();
|
||||||
@@ -1832,7 +1959,7 @@ public class AlarmManagerServiceTest {
|
|||||||
|
|
||||||
verify(mService).setImpl(eq(RTC_WAKEUP), eq(1234L), eq(WINDOW_EXACT), eq(0L),
|
verify(mService).setImpl(eq(RTC_WAKEUP), eq(1234L), eq(WINDOW_EXACT), eq(0L),
|
||||||
eq(alarmPi), isNull(), isNull(), eq(FLAG_STANDALONE | FLAG_WAKE_FROM_IDLE),
|
eq(alarmPi), isNull(), isNull(), eq(FLAG_STANDALONE | FLAG_WAKE_FROM_IDLE),
|
||||||
isNull(), eq(alarmClock), eq(Process.myUid()), eq(TEST_CALLING_PACKAGE), isNull());
|
isNull(), eq(alarmClock), eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE), isNull());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -1842,8 +1969,9 @@ public class AlarmManagerServiceTest {
|
|||||||
anyString(), any(UserHandle.class)));
|
anyString(), any(UserHandle.class)));
|
||||||
|
|
||||||
doReturn(PermissionChecker.PERMISSION_GRANTED).when(
|
doReturn(PermissionChecker.PERMISSION_GRANTED).when(
|
||||||
() -> PermissionChecker.checkCallingOrSelfPermissionForPreflight(mMockContext,
|
() -> PermissionChecker.checkPermissionForPreflight(eq(mMockContext),
|
||||||
Manifest.permission.SCHEDULE_EXACT_ALARM));
|
eq(Manifest.permission.SCHEDULE_EXACT_ALARM), anyInt(),
|
||||||
|
eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE)));
|
||||||
|
|
||||||
final PendingIntent alarmPi = getNewMockPendingIntent();
|
final PendingIntent alarmPi = getNewMockPendingIntent();
|
||||||
final AlarmManager.AlarmClockInfo alarmClock = mock(AlarmManager.AlarmClockInfo.class);
|
final AlarmManager.AlarmClockInfo alarmClock = mock(AlarmManager.AlarmClockInfo.class);
|
||||||
@@ -1851,14 +1979,15 @@ public class AlarmManagerServiceTest {
|
|||||||
alarmPi, null, null, null, alarmClock);
|
alarmPi, null, null, null, alarmClock);
|
||||||
|
|
||||||
// Correct permission checks are invoked.
|
// Correct permission checks are invoked.
|
||||||
verify(() -> PermissionChecker.checkCallingOrSelfPermissionForPreflight(mMockContext,
|
verify(() -> PermissionChecker.checkPermissionForPreflight(eq(mMockContext),
|
||||||
Manifest.permission.SCHEDULE_EXACT_ALARM));
|
eq(Manifest.permission.SCHEDULE_EXACT_ALARM), anyInt(),
|
||||||
|
eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE)));
|
||||||
verify(mDeviceIdleInternal, never()).isAppOnWhitelist(anyInt());
|
verify(mDeviceIdleInternal, never()).isAppOnWhitelist(anyInt());
|
||||||
|
|
||||||
final ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
|
final ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
|
||||||
verify(mService).setImpl(eq(RTC_WAKEUP), eq(1234L), eq(WINDOW_EXACT), eq(0L),
|
verify(mService).setImpl(eq(RTC_WAKEUP), eq(1234L), eq(WINDOW_EXACT), eq(0L),
|
||||||
eq(alarmPi), isNull(), isNull(), eq(FLAG_STANDALONE | FLAG_WAKE_FROM_IDLE),
|
eq(alarmPi), isNull(), isNull(), eq(FLAG_STANDALONE | FLAG_WAKE_FROM_IDLE),
|
||||||
isNull(), eq(alarmClock), eq(Process.myUid()), eq(TEST_CALLING_PACKAGE),
|
isNull(), eq(alarmClock), eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE),
|
||||||
bundleCaptor.capture());
|
bundleCaptor.capture());
|
||||||
|
|
||||||
final BroadcastOptions idleOptions = new BroadcastOptions(bundleCaptor.getValue());
|
final BroadcastOptions idleOptions = new BroadcastOptions(bundleCaptor.getValue());
|
||||||
@@ -1874,8 +2003,9 @@ public class AlarmManagerServiceTest {
|
|||||||
anyString(), any(UserHandle.class)));
|
anyString(), any(UserHandle.class)));
|
||||||
|
|
||||||
doReturn(PermissionChecker.PERMISSION_HARD_DENIED).when(
|
doReturn(PermissionChecker.PERMISSION_HARD_DENIED).when(
|
||||||
() -> PermissionChecker.checkCallingOrSelfPermissionForPreflight(mMockContext,
|
() -> PermissionChecker.checkPermissionForPreflight(eq(mMockContext),
|
||||||
Manifest.permission.SCHEDULE_EXACT_ALARM));
|
eq(Manifest.permission.SCHEDULE_EXACT_ALARM), anyInt(),
|
||||||
|
eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE)));
|
||||||
when(mDeviceIdleInternal.isAppOnWhitelist(anyInt())).thenReturn(true);
|
when(mDeviceIdleInternal.isAppOnWhitelist(anyInt())).thenReturn(true);
|
||||||
|
|
||||||
final PendingIntent alarmPi = getNewMockPendingIntent();
|
final PendingIntent alarmPi = getNewMockPendingIntent();
|
||||||
@@ -1887,9 +2017,9 @@ public class AlarmManagerServiceTest {
|
|||||||
} catch (SecurityException se) {
|
} catch (SecurityException se) {
|
||||||
// Expected.
|
// Expected.
|
||||||
}
|
}
|
||||||
|
verify(() -> PermissionChecker.checkPermissionForPreflight(eq(mMockContext),
|
||||||
verify(() -> PermissionChecker.checkCallingOrSelfPermissionForPreflight(mMockContext,
|
eq(Manifest.permission.SCHEDULE_EXACT_ALARM), anyInt(),
|
||||||
Manifest.permission.SCHEDULE_EXACT_ALARM));
|
eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE)));
|
||||||
verify(mDeviceIdleInternal, never()).isAppOnWhitelist(anyInt());
|
verify(mDeviceIdleInternal, never()).isAppOnWhitelist(anyInt());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1904,15 +2034,16 @@ public class AlarmManagerServiceTest {
|
|||||||
mBinder.set(TEST_CALLING_PACKAGE, ELAPSED_REALTIME_WAKEUP, 1234, WINDOW_EXACT, 0,
|
mBinder.set(TEST_CALLING_PACKAGE, ELAPSED_REALTIME_WAKEUP, 1234, WINDOW_EXACT, 0,
|
||||||
0, alarmPi, null, null, null, null);
|
0, alarmPi, null, null, null, null);
|
||||||
|
|
||||||
verify(() -> PermissionChecker.checkCallingOrSelfPermissionForPreflight(mMockContext,
|
verify(() -> PermissionChecker.checkPermissionForPreflight(eq(mMockContext),
|
||||||
Manifest.permission.SCHEDULE_EXACT_ALARM));
|
eq(Manifest.permission.SCHEDULE_EXACT_ALARM), anyInt(),
|
||||||
|
eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE)));
|
||||||
verify(mDeviceIdleInternal, never()).isAppOnWhitelist(anyInt());
|
verify(mDeviceIdleInternal, never()).isAppOnWhitelist(anyInt());
|
||||||
|
|
||||||
final ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
|
final ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
|
||||||
verify(mService).setImpl(eq(ELAPSED_REALTIME_WAKEUP), eq(1234L), eq(WINDOW_EXACT), eq(0L),
|
verify(mService).setImpl(eq(ELAPSED_REALTIME_WAKEUP), eq(1234L), eq(WINDOW_EXACT), eq(0L),
|
||||||
eq(alarmPi), isNull(), isNull(),
|
eq(alarmPi), isNull(), isNull(),
|
||||||
eq(FLAG_STANDALONE), isNull(), isNull(),
|
eq(FLAG_STANDALONE), isNull(), isNull(),
|
||||||
eq(Process.myUid()), eq(TEST_CALLING_PACKAGE), bundleCaptor.capture());
|
eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE), bundleCaptor.capture());
|
||||||
|
|
||||||
final BroadcastOptions idleOptions = new BroadcastOptions(bundleCaptor.getValue());
|
final BroadcastOptions idleOptions = new BroadcastOptions(bundleCaptor.getValue());
|
||||||
final int type = idleOptions.getTemporaryAppAllowlistType();
|
final int type = idleOptions.getTemporaryAppAllowlistType();
|
||||||
@@ -1926,24 +2057,24 @@ public class AlarmManagerServiceTest {
|
|||||||
anyString(), any(UserHandle.class)));
|
anyString(), any(UserHandle.class)));
|
||||||
// If permission is denied, only then allowlist will be checked.
|
// If permission is denied, only then allowlist will be checked.
|
||||||
doReturn(PermissionChecker.PERMISSION_HARD_DENIED).when(
|
doReturn(PermissionChecker.PERMISSION_HARD_DENIED).when(
|
||||||
() -> PermissionChecker.checkCallingOrSelfPermissionForPreflight(mMockContext,
|
() -> PermissionChecker.checkPermissionForPreflight(eq(mMockContext),
|
||||||
Manifest.permission.SCHEDULE_EXACT_ALARM));
|
eq(Manifest.permission.SCHEDULE_EXACT_ALARM), anyInt(),
|
||||||
|
eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE)));
|
||||||
when(mDeviceIdleInternal.isAppOnWhitelist(anyInt())).thenReturn(true);
|
when(mDeviceIdleInternal.isAppOnWhitelist(anyInt())).thenReturn(true);
|
||||||
|
|
||||||
final PendingIntent alarmPi = getNewMockPendingIntent();
|
final PendingIntent alarmPi = getNewMockPendingIntent();
|
||||||
mBinder.set(TEST_CALLING_PACKAGE, ELAPSED_REALTIME_WAKEUP, 1234, WINDOW_EXACT, 0,
|
mBinder.set(TEST_CALLING_PACKAGE, ELAPSED_REALTIME_WAKEUP, 1234, WINDOW_EXACT, 0,
|
||||||
0, alarmPi, null, null, null, null);
|
0, alarmPi, null, null, null, null);
|
||||||
|
|
||||||
verify(() -> PermissionChecker.checkCallingOrSelfPermissionForPreflight(mMockContext,
|
verify(() -> PermissionChecker.checkPermissionForPreflight(eq(mMockContext),
|
||||||
Manifest.permission.SCHEDULE_EXACT_ALARM));
|
eq(Manifest.permission.SCHEDULE_EXACT_ALARM), anyInt(),
|
||||||
verify(mDeviceIdleInternal).isAppOnWhitelist(UserHandle.getAppId(Process.myUid()));
|
eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE)));
|
||||||
|
verify(mDeviceIdleInternal).isAppOnWhitelist(UserHandle.getAppId(TEST_CALLING_UID));
|
||||||
|
|
||||||
final ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
|
|
||||||
verify(mService).setImpl(eq(ELAPSED_REALTIME_WAKEUP), eq(1234L), eq(WINDOW_EXACT), eq(0L),
|
verify(mService).setImpl(eq(ELAPSED_REALTIME_WAKEUP), eq(1234L), eq(WINDOW_EXACT), eq(0L),
|
||||||
eq(alarmPi), isNull(), isNull(),
|
eq(alarmPi), isNull(), isNull(),
|
||||||
eq(FLAG_STANDALONE), isNull(), isNull(),
|
eq(FLAG_STANDALONE), isNull(), isNull(),
|
||||||
eq(Process.myUid()), eq(TEST_CALLING_PACKAGE), bundleCaptor.capture());
|
eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE), isNull());
|
||||||
System.out.println("what got captured: " + bundleCaptor.getValue());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -1957,15 +2088,16 @@ public class AlarmManagerServiceTest {
|
|||||||
mBinder.set(TEST_CALLING_PACKAGE, ELAPSED_REALTIME_WAKEUP, 1234, WINDOW_EXACT, 0,
|
mBinder.set(TEST_CALLING_PACKAGE, ELAPSED_REALTIME_WAKEUP, 1234, WINDOW_EXACT, 0,
|
||||||
FLAG_ALLOW_WHILE_IDLE, alarmPi, null, null, null, null);
|
FLAG_ALLOW_WHILE_IDLE, alarmPi, null, null, null, null);
|
||||||
|
|
||||||
verify(() -> PermissionChecker.checkCallingOrSelfPermissionForPreflight(mMockContext,
|
verify(() -> PermissionChecker.checkPermissionForPreflight(eq(mMockContext),
|
||||||
Manifest.permission.SCHEDULE_EXACT_ALARM));
|
eq(Manifest.permission.SCHEDULE_EXACT_ALARM), anyInt(),
|
||||||
|
eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE)));
|
||||||
verify(mDeviceIdleInternal, never()).isAppOnWhitelist(anyInt());
|
verify(mDeviceIdleInternal, never()).isAppOnWhitelist(anyInt());
|
||||||
|
|
||||||
final ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
|
final ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
|
||||||
verify(mService).setImpl(eq(ELAPSED_REALTIME_WAKEUP), eq(1234L), eq(WINDOW_EXACT), eq(0L),
|
verify(mService).setImpl(eq(ELAPSED_REALTIME_WAKEUP), eq(1234L), eq(WINDOW_EXACT), eq(0L),
|
||||||
eq(alarmPi), isNull(), isNull(),
|
eq(alarmPi), isNull(), isNull(),
|
||||||
eq(FLAG_ALLOW_WHILE_IDLE | FLAG_STANDALONE), isNull(), isNull(),
|
eq(FLAG_ALLOW_WHILE_IDLE | FLAG_STANDALONE), isNull(), isNull(),
|
||||||
eq(Process.myUid()), eq(TEST_CALLING_PACKAGE), bundleCaptor.capture());
|
eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE), bundleCaptor.capture());
|
||||||
|
|
||||||
final BroadcastOptions idleOptions = new BroadcastOptions(bundleCaptor.getValue());
|
final BroadcastOptions idleOptions = new BroadcastOptions(bundleCaptor.getValue());
|
||||||
final int type = idleOptions.getTemporaryAppAllowlistType();
|
final int type = idleOptions.getTemporaryAppAllowlistType();
|
||||||
@@ -1979,23 +2111,25 @@ public class AlarmManagerServiceTest {
|
|||||||
anyString(), any(UserHandle.class)));
|
anyString(), any(UserHandle.class)));
|
||||||
// If permission is denied, only then allowlist will be checked.
|
// If permission is denied, only then allowlist will be checked.
|
||||||
doReturn(PermissionChecker.PERMISSION_HARD_DENIED).when(
|
doReturn(PermissionChecker.PERMISSION_HARD_DENIED).when(
|
||||||
() -> PermissionChecker.checkCallingOrSelfPermissionForPreflight(mMockContext,
|
() -> PermissionChecker.checkPermissionForPreflight(eq(mMockContext),
|
||||||
Manifest.permission.SCHEDULE_EXACT_ALARM));
|
eq(Manifest.permission.SCHEDULE_EXACT_ALARM), anyInt(),
|
||||||
|
eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE)));
|
||||||
when(mDeviceIdleInternal.isAppOnWhitelist(anyInt())).thenReturn(true);
|
when(mDeviceIdleInternal.isAppOnWhitelist(anyInt())).thenReturn(true);
|
||||||
|
|
||||||
final PendingIntent alarmPi = getNewMockPendingIntent();
|
final PendingIntent alarmPi = getNewMockPendingIntent();
|
||||||
mBinder.set(TEST_CALLING_PACKAGE, ELAPSED_REALTIME_WAKEUP, 1234, WINDOW_EXACT, 0,
|
mBinder.set(TEST_CALLING_PACKAGE, ELAPSED_REALTIME_WAKEUP, 1234, WINDOW_EXACT, 0,
|
||||||
FLAG_ALLOW_WHILE_IDLE, alarmPi, null, null, null, null);
|
FLAG_ALLOW_WHILE_IDLE, alarmPi, null, null, null, null);
|
||||||
|
|
||||||
verify(() -> PermissionChecker.checkCallingOrSelfPermissionForPreflight(mMockContext,
|
verify(() -> PermissionChecker.checkPermissionForPreflight(eq(mMockContext),
|
||||||
Manifest.permission.SCHEDULE_EXACT_ALARM));
|
eq(Manifest.permission.SCHEDULE_EXACT_ALARM), anyInt(),
|
||||||
verify(mDeviceIdleInternal).isAppOnWhitelist(UserHandle.getAppId(Process.myUid()));
|
eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE)));
|
||||||
|
verify(mDeviceIdleInternal).isAppOnWhitelist(UserHandle.getAppId(TEST_CALLING_UID));
|
||||||
|
|
||||||
final ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
|
final ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
|
||||||
verify(mService).setImpl(eq(ELAPSED_REALTIME_WAKEUP), eq(1234L), eq(WINDOW_EXACT), eq(0L),
|
verify(mService).setImpl(eq(ELAPSED_REALTIME_WAKEUP), eq(1234L), eq(WINDOW_EXACT), eq(0L),
|
||||||
eq(alarmPi), isNull(), isNull(),
|
eq(alarmPi), isNull(), isNull(),
|
||||||
eq(FLAG_ALLOW_WHILE_IDLE_COMPAT | FLAG_STANDALONE), isNull(), isNull(),
|
eq(FLAG_ALLOW_WHILE_IDLE_COMPAT | FLAG_STANDALONE), isNull(), isNull(),
|
||||||
eq(Process.myUid()), eq(TEST_CALLING_PACKAGE), bundleCaptor.capture());
|
eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE), bundleCaptor.capture());
|
||||||
|
|
||||||
final BroadcastOptions idleOptions = new BroadcastOptions(bundleCaptor.getValue());
|
final BroadcastOptions idleOptions = new BroadcastOptions(bundleCaptor.getValue());
|
||||||
final int type = idleOptions.getTemporaryAppAllowlistType();
|
final int type = idleOptions.getTemporaryAppAllowlistType();
|
||||||
@@ -2011,8 +2145,9 @@ public class AlarmManagerServiceTest {
|
|||||||
anyString(), any(UserHandle.class)));
|
anyString(), any(UserHandle.class)));
|
||||||
|
|
||||||
doReturn(PermissionChecker.PERMISSION_HARD_DENIED).when(
|
doReturn(PermissionChecker.PERMISSION_HARD_DENIED).when(
|
||||||
() -> PermissionChecker.checkCallingOrSelfPermissionForPreflight(mMockContext,
|
() -> PermissionChecker.checkPermissionForPreflight(eq(mMockContext),
|
||||||
Manifest.permission.SCHEDULE_EXACT_ALARM));
|
eq(Manifest.permission.SCHEDULE_EXACT_ALARM), anyInt(),
|
||||||
|
eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE)));
|
||||||
when(mDeviceIdleInternal.isAppOnWhitelist(anyInt())).thenReturn(false);
|
when(mDeviceIdleInternal.isAppOnWhitelist(anyInt())).thenReturn(false);
|
||||||
|
|
||||||
final PendingIntent alarmPi = getNewMockPendingIntent();
|
final PendingIntent alarmPi = getNewMockPendingIntent();
|
||||||
@@ -2030,8 +2165,9 @@ public class AlarmManagerServiceTest {
|
|||||||
} catch (SecurityException se) {
|
} catch (SecurityException se) {
|
||||||
// Expected.
|
// Expected.
|
||||||
}
|
}
|
||||||
verify(() -> PermissionChecker.checkCallingOrSelfPermissionForPreflight(mMockContext,
|
verify(() -> PermissionChecker.checkPermissionForPreflight(eq(mMockContext),
|
||||||
Manifest.permission.SCHEDULE_EXACT_ALARM), times(2));
|
eq(Manifest.permission.SCHEDULE_EXACT_ALARM), anyInt(),
|
||||||
|
eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE)), times(2));
|
||||||
verify(mDeviceIdleInternal, times(2)).isAppOnWhitelist(anyInt());
|
verify(mDeviceIdleInternal, times(2)).isAppOnWhitelist(anyInt());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2047,14 +2183,15 @@ public class AlarmManagerServiceTest {
|
|||||||
mBinder.set(TEST_CALLING_PACKAGE, ELAPSED_REALTIME_WAKEUP, 4321, WINDOW_HEURISTIC, 0,
|
mBinder.set(TEST_CALLING_PACKAGE, ELAPSED_REALTIME_WAKEUP, 4321, WINDOW_HEURISTIC, 0,
|
||||||
FLAG_ALLOW_WHILE_IDLE, alarmPi, null, null, null, null);
|
FLAG_ALLOW_WHILE_IDLE, alarmPi, null, null, null, null);
|
||||||
|
|
||||||
verify(() -> PermissionChecker.checkCallingOrSelfPermissionForPreflight(mMockContext,
|
verify(() -> PermissionChecker.checkPermissionForPreflight(eq(mMockContext),
|
||||||
Manifest.permission.SCHEDULE_EXACT_ALARM), never());
|
eq(Manifest.permission.SCHEDULE_EXACT_ALARM), anyInt(),
|
||||||
|
eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE)), never());
|
||||||
verify(mDeviceIdleInternal, never()).isAppOnWhitelist(anyInt());
|
verify(mDeviceIdleInternal, never()).isAppOnWhitelist(anyInt());
|
||||||
|
|
||||||
final ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
|
final ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
|
||||||
verify(mService).setImpl(eq(ELAPSED_REALTIME_WAKEUP), eq(4321L), anyLong(), eq(0L),
|
verify(mService).setImpl(eq(ELAPSED_REALTIME_WAKEUP), eq(4321L), anyLong(), eq(0L),
|
||||||
eq(alarmPi), isNull(), isNull(), eq(FLAG_ALLOW_WHILE_IDLE_COMPAT), isNull(),
|
eq(alarmPi), isNull(), isNull(), eq(FLAG_ALLOW_WHILE_IDLE_COMPAT), isNull(),
|
||||||
isNull(), eq(Process.myUid()), eq(TEST_CALLING_PACKAGE), bundleCaptor.capture());
|
isNull(), eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE), bundleCaptor.capture());
|
||||||
|
|
||||||
final BroadcastOptions idleOptions = new BroadcastOptions(bundleCaptor.getValue());
|
final BroadcastOptions idleOptions = new BroadcastOptions(bundleCaptor.getValue());
|
||||||
final int type = idleOptions.getTemporaryAppAllowlistType();
|
final int type = idleOptions.getTemporaryAppAllowlistType();
|
||||||
@@ -2068,10 +2205,11 @@ public class AlarmManagerServiceTest {
|
|||||||
anyString(), any(UserHandle.class)));
|
anyString(), any(UserHandle.class)));
|
||||||
|
|
||||||
doReturn(PermissionChecker.PERMISSION_HARD_DENIED).when(
|
doReturn(PermissionChecker.PERMISSION_HARD_DENIED).when(
|
||||||
() -> PermissionChecker.checkCallingOrSelfPermissionForPreflight(mMockContext,
|
() -> PermissionChecker.checkPermissionForPreflight(eq(mMockContext),
|
||||||
Manifest.permission.SCHEDULE_EXACT_ALARM));
|
eq(Manifest.permission.SCHEDULE_EXACT_ALARM), anyInt(),
|
||||||
|
eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE)));
|
||||||
when(mDeviceIdleInternal.isAppOnWhitelist(anyInt())).thenReturn(true);
|
when(mDeviceIdleInternal.isAppOnWhitelist(anyInt())).thenReturn(true);
|
||||||
when(mAppStateTracker.isUidPowerSaveUserExempt(Process.myUid())).thenReturn(true);
|
when(mAppStateTracker.isUidPowerSaveUserExempt(TEST_CALLING_UID)).thenReturn(true);
|
||||||
|
|
||||||
final PendingIntent alarmPi = getNewMockPendingIntent();
|
final PendingIntent alarmPi = getNewMockPendingIntent();
|
||||||
mBinder.set(TEST_CALLING_PACKAGE, ELAPSED_REALTIME_WAKEUP, 1234, WINDOW_EXACT, 0,
|
mBinder.set(TEST_CALLING_PACKAGE, ELAPSED_REALTIME_WAKEUP, 1234, WINDOW_EXACT, 0,
|
||||||
@@ -2081,7 +2219,7 @@ public class AlarmManagerServiceTest {
|
|||||||
verify(mService).setImpl(eq(ELAPSED_REALTIME_WAKEUP), eq(1234L), eq(WINDOW_EXACT), eq(0L),
|
verify(mService).setImpl(eq(ELAPSED_REALTIME_WAKEUP), eq(1234L), eq(WINDOW_EXACT), eq(0L),
|
||||||
eq(alarmPi), isNull(), isNull(),
|
eq(alarmPi), isNull(), isNull(),
|
||||||
eq(FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED | FLAG_STANDALONE), isNull(), isNull(),
|
eq(FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED | FLAG_STANDALONE), isNull(), isNull(),
|
||||||
eq(Process.myUid()), eq(TEST_CALLING_PACKAGE), isNull());
|
eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE), isNull());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -2100,10 +2238,80 @@ public class AlarmManagerServiceTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void denyListPackagesAdded() {
|
||||||
|
mService.mConstants.EXACT_ALARM_DENY_LIST = new ArraySet<>(new String[]{"p1", "p2", "p3"});
|
||||||
|
setDeviceConfigString(KEY_EXACT_ALARM_DENY_LIST, "p2,p4,p5");
|
||||||
|
assertAndHandleMessageSync(EXACT_ALARM_DENY_LIST_CHANGED);
|
||||||
|
|
||||||
|
ArraySet<String> added = new ArraySet<>(new String[]{"p4", "p5"});
|
||||||
|
verify(mService).handlePackagesAddedToExactAlarmsDenyListLocked(eq(added));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void denyListPackagesRemoved() {
|
||||||
|
clearInvocations(mService.mHandler);
|
||||||
|
mService.mConstants.EXACT_ALARM_DENY_LIST = new ArraySet<>(new String[]{"p1", "p2", "p3"});
|
||||||
|
setDeviceConfigString(KEY_EXACT_ALARM_DENY_LIST, "p2");
|
||||||
|
verifyNoMoreInteractions(mService.mHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void removeExactAlarmsOnPackageAddedToDenyList() {
|
||||||
|
doReturn(true).when(
|
||||||
|
() -> CompatChanges.isChangeEnabled(eq(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION),
|
||||||
|
anyString(), any(UserHandle.class)));
|
||||||
|
|
||||||
|
// basic exact alarm
|
||||||
|
setTestAlarm(ELAPSED_REALTIME, 1, 0, getNewMockPendingIntent(), 0, 0, TEST_CALLING_UID,
|
||||||
|
null);
|
||||||
|
// exact and allow-while-idle alarm
|
||||||
|
setTestAlarm(ELAPSED_REALTIME, 2, 0, getNewMockPendingIntent(), 0, FLAG_ALLOW_WHILE_IDLE,
|
||||||
|
TEST_CALLING_UID, null);
|
||||||
|
// alarm clock
|
||||||
|
setWakeFromIdle(RTC_WAKEUP, 3, getNewMockPendingIntent());
|
||||||
|
|
||||||
|
final PendingIntent inexact = getNewMockPendingIntent();
|
||||||
|
setTestAlarm(ELAPSED_REALTIME, 4, 10, inexact, 0, 0, TEST_CALLING_UID, null);
|
||||||
|
|
||||||
|
final PendingIntent inexactAwi = getNewMockPendingIntent();
|
||||||
|
setTestAlarm(ELAPSED_REALTIME, 5, 10, inexactAwi, 0, FLAG_ALLOW_WHILE_IDLE,
|
||||||
|
TEST_CALLING_UID, null);
|
||||||
|
|
||||||
|
final String differentPackage = "different.package";
|
||||||
|
final PendingIntent exactButDifferentPackage = getNewMockPendingIntent(
|
||||||
|
TEST_CALLING_UID, differentPackage);
|
||||||
|
setTestAlarm(ELAPSED_REALTIME, 6, 0, exactButDifferentPackage, 0, 0,
|
||||||
|
TEST_CALLING_UID, differentPackage, null);
|
||||||
|
assertEquals(6, mService.mAlarmStore.size());
|
||||||
|
|
||||||
|
when(mAppOpsManager.checkOpNoThrow(eq(OP_SCHEDULE_EXACT_ALARM), anyInt(),
|
||||||
|
anyString())).thenReturn(MODE_DEFAULT);
|
||||||
|
setDeviceConfigString(KEY_EXACT_ALARM_DENY_LIST, TEST_CALLING_PACKAGE);
|
||||||
|
assertAndHandleMessageSync(EXACT_ALARM_DENY_LIST_CHANGED);
|
||||||
|
verify(mService).handlePackagesAddedToExactAlarmsDenyListLocked(
|
||||||
|
argThat(set -> (set.size() == 1 && set.contains(TEST_CALLING_PACKAGE))));
|
||||||
|
|
||||||
|
final ArrayList<Alarm> remaining = mService.mAlarmStore.asList();
|
||||||
|
assertEquals(3, remaining.size());
|
||||||
|
assertTrue("Basic inexact alarm removed",
|
||||||
|
remaining.removeIf(a -> a.matches(inexact, null)));
|
||||||
|
assertTrue("Inexact allow-while-idle alarm removed",
|
||||||
|
remaining.removeIf(a -> a.matches(inexactAwi, null)));
|
||||||
|
assertTrue("Alarm from different package removed",
|
||||||
|
remaining.removeIf(a -> a.matches(exactButDifferentPackage, null)));
|
||||||
|
|
||||||
|
// Mock should return false by default.
|
||||||
|
verify(mDeviceIdleInternal, atLeastOnce()).isAppOnWhitelist(
|
||||||
|
UserHandle.getAppId(TEST_CALLING_UID));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void opScheduleExactAlarmRevoked() throws Exception {
|
public void opScheduleExactAlarmRevoked() throws Exception {
|
||||||
when(mIAppOpsService.checkOperation(OP_SCHEDULE_EXACT_ALARM, TEST_CALLING_UID,
|
doReturn(PermissionChecker.PERMISSION_HARD_DENIED).when(
|
||||||
TEST_CALLING_PACKAGE)).thenReturn(AppOpsManager.MODE_ERRORED);
|
() -> PermissionChecker.checkPermissionForPreflight(eq(mMockContext),
|
||||||
|
eq(Manifest.permission.SCHEDULE_EXACT_ALARM), anyInt(),
|
||||||
|
eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE)));
|
||||||
mIAppOpsCallback.opChanged(OP_SCHEDULE_EXACT_ALARM, TEST_CALLING_UID, TEST_CALLING_PACKAGE);
|
mIAppOpsCallback.opChanged(OP_SCHEDULE_EXACT_ALARM, TEST_CALLING_UID, TEST_CALLING_PACKAGE);
|
||||||
assertAndHandleMessageSync(REMOVE_EXACT_ALARMS);
|
assertAndHandleMessageSync(REMOVE_EXACT_ALARMS);
|
||||||
verify(mService).removeExactAlarmsOnPermissionRevokedLocked(TEST_CALLING_UID,
|
verify(mService).removeExactAlarmsOnPermissionRevokedLocked(TEST_CALLING_UID,
|
||||||
@@ -2149,7 +2357,8 @@ public class AlarmManagerServiceTest {
|
|||||||
remaining.removeIf(a -> a.matches(exactButDifferentUid, null)));
|
remaining.removeIf(a -> a.matches(exactButDifferentUid, null)));
|
||||||
|
|
||||||
// Mock should return false by default.
|
// Mock should return false by default.
|
||||||
verify(mDeviceIdleInternal).isAppOnWhitelist(UserHandle.getAppId(TEST_CALLING_UID));
|
verify(mDeviceIdleInternal, atLeastOnce()).isAppOnWhitelist(
|
||||||
|
UserHandle.getAppId(TEST_CALLING_UID));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ import android.os.UserHandle;
|
|||||||
import android.platform.test.annotations.Presubmit;
|
import android.platform.test.annotations.Presubmit;
|
||||||
import android.provider.DeviceConfig;
|
import android.provider.DeviceConfig;
|
||||||
import android.util.ArraySet;
|
import android.util.ArraySet;
|
||||||
|
import android.util.Pair;
|
||||||
import android.view.Display;
|
import android.view.Display;
|
||||||
|
|
||||||
import androidx.test.InstrumentationRegistry;
|
import androidx.test.InstrumentationRegistry;
|
||||||
@@ -114,8 +115,10 @@ import java.util.concurrent.TimeUnit;
|
|||||||
@SmallTest
|
@SmallTest
|
||||||
public class AppStandbyControllerTests {
|
public class AppStandbyControllerTests {
|
||||||
|
|
||||||
private static final String PACKAGE_1 = "com.example.foo";
|
private static final String PACKAGE_1 = "com.example.foo.1";
|
||||||
private static final int UID_1 = 10000;
|
private static final int UID_1 = 10000;
|
||||||
|
private static final String PACKAGE_2 = "com.example.foo.2";
|
||||||
|
private static final int UID_2 = 20000;
|
||||||
private static final String PACKAGE_EXEMPTED_1 = "com.android.exempted";
|
private static final String PACKAGE_EXEMPTED_1 = "com.android.exempted";
|
||||||
private static final int UID_EXEMPTED_1 = 10001;
|
private static final int UID_EXEMPTED_1 = 10001;
|
||||||
private static final String PACKAGE_SYSTEM_HEADFULL = "com.example.system.headfull";
|
private static final String PACKAGE_SYSTEM_HEADFULL = "com.example.system.headfull";
|
||||||
@@ -196,6 +199,7 @@ public class AppStandbyControllerTests {
|
|||||||
int[] mRunningUsers = new int[] {USER_ID};
|
int[] mRunningUsers = new int[] {USER_ID};
|
||||||
List<UserHandle> mCrossProfileTargets = Collections.emptyList();
|
List<UserHandle> mCrossProfileTargets = Collections.emptyList();
|
||||||
boolean mDeviceIdleMode = false;
|
boolean mDeviceIdleMode = false;
|
||||||
|
Set<Pair<String, Integer>> mClockApps = new ArraySet<>();
|
||||||
DeviceConfig.Properties.Builder mSettingsBuilder =
|
DeviceConfig.Properties.Builder mSettingsBuilder =
|
||||||
new DeviceConfig.Properties.Builder(DeviceConfig.NAMESPACE_APP_STANDBY)
|
new DeviceConfig.Properties.Builder(DeviceConfig.NAMESPACE_APP_STANDBY)
|
||||||
.setLong("screen_threshold_active", 0)
|
.setLong("screen_threshold_active", 0)
|
||||||
@@ -253,6 +257,11 @@ public class AppStandbyControllerTests {
|
|||||||
return PACKAGE_WELLBEING.equals(packageName);
|
return PACKAGE_WELLBEING.equals(packageName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
boolean hasScheduleExactAlarm(String packageName, int uid) {
|
||||||
|
return mClockApps.contains(Pair.create(packageName, uid));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void updatePowerWhitelistCache() {
|
void updatePowerWhitelistCache() {
|
||||||
}
|
}
|
||||||
@@ -349,6 +358,12 @@ public class AppStandbyControllerTests {
|
|||||||
pi.packageName = PACKAGE_1;
|
pi.packageName = PACKAGE_1;
|
||||||
packages.add(pi);
|
packages.add(pi);
|
||||||
|
|
||||||
|
PackageInfo pInfo = new PackageInfo();
|
||||||
|
pInfo.applicationInfo = new ApplicationInfo();
|
||||||
|
pInfo.applicationInfo.uid = UID_2;
|
||||||
|
pInfo.packageName = PACKAGE_2;
|
||||||
|
packages.add(pInfo);
|
||||||
|
|
||||||
PackageInfo pie = new PackageInfo();
|
PackageInfo pie = new PackageInfo();
|
||||||
pie.applicationInfo = new ApplicationInfo();
|
pie.applicationInfo = new ApplicationInfo();
|
||||||
pie.applicationInfo.uid = UID_EXEMPTED_1;
|
pie.applicationInfo.uid = UID_EXEMPTED_1;
|
||||||
@@ -1661,6 +1676,29 @@ public class AppStandbyControllerTests {
|
|||||||
assertBucket(STANDBY_BUCKET_RARE, PACKAGE_1);
|
assertBucket(STANDBY_BUCKET_RARE, PACKAGE_1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testClockAppElevated() throws Exception {
|
||||||
|
mInjector.mClockApps.add(Pair.create(PACKAGE_1, UID_1));
|
||||||
|
|
||||||
|
reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1);
|
||||||
|
assertBucket(STANDBY_BUCKET_ACTIVE, PACKAGE_1);
|
||||||
|
|
||||||
|
reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_2);
|
||||||
|
assertBucket(STANDBY_BUCKET_ACTIVE, PACKAGE_2);
|
||||||
|
|
||||||
|
mInjector.mElapsedRealtime += RESTRICTED_THRESHOLD;
|
||||||
|
|
||||||
|
// Make sure a clock app does not get lowered below WORKING_SET.
|
||||||
|
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE,
|
||||||
|
REASON_MAIN_TIMEOUT);
|
||||||
|
assertBucket(STANDBY_BUCKET_WORKING_SET, PACKAGE_1);
|
||||||
|
|
||||||
|
// A non clock app should be able to fall lower than WORKING_SET.
|
||||||
|
mController.setAppStandbyBucket(PACKAGE_2, USER_ID, STANDBY_BUCKET_RARE,
|
||||||
|
REASON_MAIN_TIMEOUT);
|
||||||
|
assertBucket(STANDBY_BUCKET_RARE, PACKAGE_2);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testChangingSettings_ElapsedThreshold_Invalid() {
|
public void testChangingSettings_ElapsedThreshold_Invalid() {
|
||||||
mInjector.mSettingsBuilder
|
mInjector.mSettingsBuilder
|
||||||
|
|||||||
Reference in New Issue
Block a user