Deny SCHEDULE_EXACT_ALARM by default to newer apps
Apps targeting T will not get SCHEDULE_EXACT_ALARM permission by default, except in a few privileged special cases. Test: atest FrameworksMockingServicesTests:AlarmManagerServiceTest atest CtsAlarmManagerTestCases:ExactAlarmsTest Bug: 226439802 Change-Id: Ie81a9c3bd8b863c3fd64aaf413209ff8862de74b
This commit is contained in:
@@ -27,6 +27,7 @@ import android.annotation.SystemApi;
|
|||||||
import android.annotation.SystemService;
|
import android.annotation.SystemService;
|
||||||
import android.annotation.TestApi;
|
import android.annotation.TestApi;
|
||||||
import android.compat.annotation.ChangeId;
|
import android.compat.annotation.ChangeId;
|
||||||
|
import android.compat.annotation.EnabledAfter;
|
||||||
import android.compat.annotation.EnabledSince;
|
import android.compat.annotation.EnabledSince;
|
||||||
import android.compat.annotation.UnsupportedAppUsage;
|
import android.compat.annotation.UnsupportedAppUsage;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
@@ -280,6 +281,18 @@ public class AlarmManager {
|
|||||||
@EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU)
|
@EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU)
|
||||||
public static final long ENABLE_USE_EXACT_ALARM = 218533173L;
|
public static final long ENABLE_USE_EXACT_ALARM = 218533173L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For apps targeting {@link Build.VERSION_CODES#TIRAMISU} or above, the permission
|
||||||
|
* {@link Manifest.permission#SCHEDULE_EXACT_ALARM} will be denied, unless the user explicitly
|
||||||
|
* allows it from Settings.
|
||||||
|
*
|
||||||
|
* TODO (b/226439802): change to EnabledSince(T) after SDK finalization.
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
@ChangeId
|
||||||
|
@EnabledAfter(targetSdkVersion = Build.VERSION_CODES.S_V2)
|
||||||
|
public static final long SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT = 226439802L;
|
||||||
|
|
||||||
@UnsupportedAppUsage
|
@UnsupportedAppUsage
|
||||||
private final IAlarmManager mService;
|
private final IAlarmManager mService;
|
||||||
private final Context mContext;
|
private final Context mContext;
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ import android.app.IAlarmListener;
|
|||||||
import android.app.IAlarmManager;
|
import android.app.IAlarmManager;
|
||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
import android.app.compat.CompatChanges;
|
import android.app.compat.CompatChanges;
|
||||||
|
import android.app.role.RoleManager;
|
||||||
import android.app.usage.UsageStatsManager;
|
import android.app.usage.UsageStatsManager;
|
||||||
import android.app.usage.UsageStatsManagerInternal;
|
import android.app.usage.UsageStatsManagerInternal;
|
||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
@@ -164,6 +165,7 @@ import java.util.Collections;
|
|||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
@@ -224,6 +226,7 @@ public class AlarmManagerService extends SystemService {
|
|||||||
private ActivityManagerInternal mActivityManagerInternal;
|
private ActivityManagerInternal mActivityManagerInternal;
|
||||||
private final EconomyManagerInternal mEconomyManagerInternal;
|
private final EconomyManagerInternal mEconomyManagerInternal;
|
||||||
private PackageManagerInternal mPackageManagerInternal;
|
private PackageManagerInternal mPackageManagerInternal;
|
||||||
|
private RoleManager mRoleManager;
|
||||||
private volatile PermissionManagerServiceInternal mLocalPermissionManager;
|
private volatile PermissionManagerServiceInternal mLocalPermissionManager;
|
||||||
|
|
||||||
final Object mLock = new Object();
|
final Object mLock = new Object();
|
||||||
@@ -562,6 +565,9 @@ public class AlarmManagerService extends SystemService {
|
|||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
static final String KEY_KILL_ON_SCHEDULE_EXACT_ALARM_REVOKED =
|
static final String KEY_KILL_ON_SCHEDULE_EXACT_ALARM_REVOKED =
|
||||||
"kill_on_schedule_exact_alarm_revoked";
|
"kill_on_schedule_exact_alarm_revoked";
|
||||||
|
@VisibleForTesting
|
||||||
|
static final String KEY_SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT =
|
||||||
|
"schedule_exact_alarm_denied_by_default";
|
||||||
|
|
||||||
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;
|
||||||
@@ -606,6 +612,9 @@ public class AlarmManagerService extends SystemService {
|
|||||||
|
|
||||||
private static final boolean DEFAULT_KILL_ON_SCHEDULE_EXACT_ALARM_REVOKED = true;
|
private static final boolean DEFAULT_KILL_ON_SCHEDULE_EXACT_ALARM_REVOKED = true;
|
||||||
|
|
||||||
|
// TODO(b/226439802): Flip to true.
|
||||||
|
private static final boolean DEFAULT_SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT = false;
|
||||||
|
|
||||||
// Minimum futurity of a new alarm
|
// Minimum futurity of a new alarm
|
||||||
public long MIN_FUTURITY = DEFAULT_MIN_FUTURITY;
|
public long MIN_FUTURITY = DEFAULT_MIN_FUTURITY;
|
||||||
|
|
||||||
@@ -693,6 +702,14 @@ public class AlarmManagerService extends SystemService {
|
|||||||
public boolean KILL_ON_SCHEDULE_EXACT_ALARM_REVOKED =
|
public boolean KILL_ON_SCHEDULE_EXACT_ALARM_REVOKED =
|
||||||
DEFAULT_KILL_ON_SCHEDULE_EXACT_ALARM_REVOKED;
|
DEFAULT_KILL_ON_SCHEDULE_EXACT_ALARM_REVOKED;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When this is {@code true}, apps with the change
|
||||||
|
* {@link AlarmManager#SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT} enabled will not get
|
||||||
|
* {@link Manifest.permission#SCHEDULE_EXACT_ALARM} unless the user grants it to them.
|
||||||
|
*/
|
||||||
|
public volatile boolean SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT =
|
||||||
|
DEFAULT_SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT;
|
||||||
|
|
||||||
public boolean USE_TARE_POLICY = Settings.Global.DEFAULT_ENABLE_TARE == 1;
|
public boolean USE_TARE_POLICY = Settings.Global.DEFAULT_ENABLE_TARE == 1;
|
||||||
|
|
||||||
private long mLastAllowWhileIdleWhitelistDuration = -1;
|
private long mLastAllowWhileIdleWhitelistDuration = -1;
|
||||||
@@ -876,6 +893,15 @@ public class AlarmManagerService extends SystemService {
|
|||||||
KEY_KILL_ON_SCHEDULE_EXACT_ALARM_REVOKED,
|
KEY_KILL_ON_SCHEDULE_EXACT_ALARM_REVOKED,
|
||||||
DEFAULT_KILL_ON_SCHEDULE_EXACT_ALARM_REVOKED);
|
DEFAULT_KILL_ON_SCHEDULE_EXACT_ALARM_REVOKED);
|
||||||
break;
|
break;
|
||||||
|
case KEY_SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT:
|
||||||
|
final boolean oldValue = SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT;
|
||||||
|
|
||||||
|
SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT = properties.getBoolean(
|
||||||
|
KEY_SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT,
|
||||||
|
DEFAULT_SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT);
|
||||||
|
handleScheduleExactAlarmDeniedByDefaultChange(oldValue,
|
||||||
|
SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT);
|
||||||
|
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
|
||||||
@@ -946,6 +972,15 @@ public class AlarmManagerService extends SystemService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void handleScheduleExactAlarmDeniedByDefaultChange(boolean oldValue,
|
||||||
|
boolean newValue) {
|
||||||
|
if (oldValue == newValue) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mHandler.obtainMessage(AlarmHandler.CHECK_EXACT_ALARM_PERMISSION_ON_FEATURE_TOGGLE,
|
||||||
|
newValue).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();
|
||||||
@@ -1122,6 +1157,9 @@ public class AlarmManagerService extends SystemService {
|
|||||||
pw.print(KEY_KILL_ON_SCHEDULE_EXACT_ALARM_REVOKED,
|
pw.print(KEY_KILL_ON_SCHEDULE_EXACT_ALARM_REVOKED,
|
||||||
KILL_ON_SCHEDULE_EXACT_ALARM_REVOKED);
|
KILL_ON_SCHEDULE_EXACT_ALARM_REVOKED);
|
||||||
pw.println();
|
pw.println();
|
||||||
|
pw.print(KEY_SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT,
|
||||||
|
SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT);
|
||||||
|
pw.println();
|
||||||
|
|
||||||
pw.print(Settings.Global.ENABLE_TARE, USE_TARE_POLICY);
|
pw.print(Settings.Global.ENABLE_TARE, USE_TARE_POLICY);
|
||||||
pw.println();
|
pw.println();
|
||||||
@@ -1892,11 +1930,10 @@ public class AlarmManagerService extends SystemService {
|
|||||||
if (hasUseExactAlarmInternal(packageName, uid)) {
|
if (hasUseExactAlarmInternal(packageName, uid)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (!mExactAlarmCandidates.contains(UserHandle.getAppId(uid))) {
|
||||||
final boolean requested = mExactAlarmCandidates.contains(
|
// Permission not requested, app op doesn't matter.
|
||||||
UserHandle.getAppId(uid));
|
return;
|
||||||
final boolean denyListed =
|
}
|
||||||
mConstants.EXACT_ALARM_DENY_LIST.contains(packageName);
|
|
||||||
|
|
||||||
final int newMode = mAppOps.checkOpNoThrow(
|
final int newMode = mAppOps.checkOpNoThrow(
|
||||||
AppOpsManager.OP_SCHEDULE_EXACT_ALARM, uid, packageName);
|
AppOpsManager.OP_SCHEDULE_EXACT_ALARM, uid, packageName);
|
||||||
@@ -1913,11 +1950,24 @@ public class AlarmManagerService extends SystemService {
|
|||||||
mLastOpScheduleExactAlarm.setValueAt(index, newMode);
|
mLastOpScheduleExactAlarm.setValueAt(index, newMode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (oldMode == newMode) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final boolean allowedByDefault =
|
||||||
|
isScheduleExactAlarmAllowedByDefault(packageName, uid);
|
||||||
|
|
||||||
final boolean hadPermission = getScheduleExactAlarmState(requested,
|
final boolean hadPermission;
|
||||||
denyListed, oldMode);
|
if (oldMode != AppOpsManager.MODE_DEFAULT) {
|
||||||
final boolean hasPermission = getScheduleExactAlarmState(requested,
|
hadPermission = (oldMode == AppOpsManager.MODE_ALLOWED);
|
||||||
denyListed, newMode);
|
} else {
|
||||||
|
hadPermission = allowedByDefault;
|
||||||
|
}
|
||||||
|
final boolean hasPermission;
|
||||||
|
if (newMode != AppOpsManager.MODE_DEFAULT) {
|
||||||
|
hasPermission = (newMode == AppOpsManager.MODE_ALLOWED);
|
||||||
|
} else {
|
||||||
|
hasPermission = allowedByDefault;
|
||||||
|
}
|
||||||
|
|
||||||
if (hadPermission && !hasPermission) {
|
if (hadPermission && !hasPermission) {
|
||||||
mHandler.obtainMessage(AlarmHandler.REMOVE_EXACT_ALARMS,
|
mHandler.obtainMessage(AlarmHandler.REMOVE_EXACT_ALARMS,
|
||||||
@@ -1939,6 +1989,8 @@ public class AlarmManagerService extends SystemService {
|
|||||||
LocalServices.getService(AppStandbyInternal.class);
|
LocalServices.getService(AppStandbyInternal.class);
|
||||||
appStandbyInternal.addListener(new AppStandbyTracker());
|
appStandbyInternal.addListener(new AppStandbyTracker());
|
||||||
|
|
||||||
|
mRoleManager = getContext().getSystemService(RoleManager.class);
|
||||||
|
|
||||||
mMetricsHelper.registerPuller(() -> mAlarmStore);
|
mMetricsHelper.registerPuller(() -> mAlarmStore);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2525,19 +2577,6 @@ public class AlarmManagerService extends SystemService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean getScheduleExactAlarmState(boolean requested, boolean denyListed,
|
|
||||||
int appOpMode) {
|
|
||||||
// This does not account for the state of the USE_EXACT_ALARM permission.
|
|
||||||
// The caller should do that separately.
|
|
||||||
if (!requested) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (appOpMode == AppOpsManager.MODE_DEFAULT) {
|
|
||||||
return !denyListed;
|
|
||||||
}
|
|
||||||
return appOpMode == AppOpsManager.MODE_ALLOWED;
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean hasUseExactAlarmInternal(String packageName, int uid) {
|
boolean hasUseExactAlarmInternal(String packageName, int uid) {
|
||||||
return isUseExactAlarmEnabled(packageName, UserHandle.getUserId(uid))
|
return isUseExactAlarmEnabled(packageName, UserHandle.getUserId(uid))
|
||||||
&& (PermissionChecker.checkPermissionForPreflight(getContext(),
|
&& (PermissionChecker.checkPermissionForPreflight(getContext(),
|
||||||
@@ -2545,6 +2584,32 @@ public class AlarmManagerService extends SystemService {
|
|||||||
packageName) == PermissionChecker.PERMISSION_GRANTED);
|
packageName) == PermissionChecker.PERMISSION_GRANTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether SCHEDULE_EXACT_ALARM is allowed by default.
|
||||||
|
*/
|
||||||
|
boolean isScheduleExactAlarmAllowedByDefault(String packageName, int uid) {
|
||||||
|
if (isScheduleExactAlarmDeniedByDefault(packageName, UserHandle.getUserId(uid))) {
|
||||||
|
|
||||||
|
// This is essentially like changing the protection level of the permission to
|
||||||
|
// (privileged|signature|role|appop), but have to implement this logic to maintain
|
||||||
|
// compatibility for older apps.
|
||||||
|
if (mPackageManagerInternal.isPlatformSigned(packageName)
|
||||||
|
|| mPackageManagerInternal.isUidPrivileged(uid)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
final long token = Binder.clearCallingIdentity();
|
||||||
|
try {
|
||||||
|
final List<String> wellbeingHolders = (mRoleManager != null)
|
||||||
|
? mRoleManager.getRoleHolders(RoleManager.ROLE_SYSTEM_WELLBEING)
|
||||||
|
: Collections.emptyList();
|
||||||
|
return wellbeingHolders.contains(packageName);
|
||||||
|
} finally {
|
||||||
|
Binder.restoreCallingIdentity(token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return !mConstants.EXACT_ALARM_DENY_LIST.contains(packageName);
|
||||||
|
}
|
||||||
|
|
||||||
boolean hasScheduleExactAlarmInternal(String packageName, int uid) {
|
boolean hasScheduleExactAlarmInternal(String packageName, int uid) {
|
||||||
final long start = mStatLogger.getTime();
|
final long start = mStatLogger.getTime();
|
||||||
|
|
||||||
@@ -2560,7 +2625,7 @@ public class AlarmManagerService extends SystemService {
|
|||||||
final int mode = mAppOps.checkOpNoThrow(AppOpsManager.OP_SCHEDULE_EXACT_ALARM, uid,
|
final int mode = mAppOps.checkOpNoThrow(AppOpsManager.OP_SCHEDULE_EXACT_ALARM, uid,
|
||||||
packageName);
|
packageName);
|
||||||
if (mode == AppOpsManager.MODE_DEFAULT) {
|
if (mode == AppOpsManager.MODE_DEFAULT) {
|
||||||
hasPermission = !mConstants.EXACT_ALARM_DENY_LIST.contains(packageName);
|
hasPermission = isScheduleExactAlarmAllowedByDefault(packageName, uid);
|
||||||
} else {
|
} else {
|
||||||
hasPermission = (mode == AppOpsManager.MODE_ALLOWED);
|
hasPermission = (mode == AppOpsManager.MODE_ALLOWED);
|
||||||
}
|
}
|
||||||
@@ -2860,6 +2925,13 @@ public class AlarmManagerService extends SystemService {
|
|||||||
packageName, UserHandle.of(userId));
|
packageName, UserHandle.of(userId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isScheduleExactAlarmDeniedByDefault(String packageName, int userId) {
|
||||||
|
return mConstants.SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT
|
||||||
|
&& CompatChanges.isChangeEnabled(
|
||||||
|
AlarmManager.SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT, packageName,
|
||||||
|
UserHandle.of(userId));
|
||||||
|
}
|
||||||
|
|
||||||
@NeverCompile // Avoid size overhead of debugging code.
|
@NeverCompile // Avoid size overhead of debugging code.
|
||||||
void dumpImpl(IndentingPrintWriter pw) {
|
void dumpImpl(IndentingPrintWriter pw) {
|
||||||
synchronized (mLock) {
|
synchronized (mLock) {
|
||||||
@@ -3769,26 +3841,27 @@ public class AlarmManagerService extends SystemService {
|
|||||||
if (!isExactAlarmChangeEnabled(changedPackage, userId)) {
|
if (!isExactAlarmChangeEnabled(changedPackage, userId)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (isScheduleExactAlarmDeniedByDefault(changedPackage, userId)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (hasUseExactAlarmInternal(changedPackage, uid)) {
|
if (hasUseExactAlarmInternal(changedPackage, uid)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (!mExactAlarmCandidates.contains(UserHandle.getAppId(uid))) {
|
||||||
|
// Permission isn't requested, deny list doesn't matter.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
final int appOpMode;
|
final int appOpMode;
|
||||||
synchronized (mLock) {
|
synchronized (mLock) {
|
||||||
appOpMode = mLastOpScheduleExactAlarm.get(uid,
|
appOpMode = mLastOpScheduleExactAlarm.get(uid,
|
||||||
AppOpsManager.opToDefaultMode(AppOpsManager.OP_SCHEDULE_EXACT_ALARM));
|
AppOpsManager.opToDefaultMode(AppOpsManager.OP_SCHEDULE_EXACT_ALARM));
|
||||||
}
|
}
|
||||||
final boolean requested = mExactAlarmCandidates.contains(UserHandle.getAppId(uid));
|
if (appOpMode != AppOpsManager.MODE_DEFAULT) {
|
||||||
|
// Deny list doesn't matter.
|
||||||
// added: true => package was added to the deny list
|
|
||||||
// added: false => package was removed from the deny list
|
|
||||||
final boolean hadPermission = getScheduleExactAlarmState(requested, !added,
|
|
||||||
appOpMode);
|
|
||||||
final boolean hasPermission = getScheduleExactAlarmState(requested, added,
|
|
||||||
appOpMode);
|
|
||||||
|
|
||||||
if (hadPermission == hasPermission) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
// added: true => package was added to the deny list
|
||||||
|
// added: false => package was removed from the deny list
|
||||||
if (added) {
|
if (added) {
|
||||||
synchronized (mLock) {
|
synchronized (mLock) {
|
||||||
removeExactAlarmsOnPermissionRevokedLocked(uid,
|
removeExactAlarmsOnPermissionRevokedLocked(uid,
|
||||||
@@ -4634,6 +4707,7 @@ public class AlarmManagerService extends SystemService {
|
|||||||
public static final int REFRESH_EXACT_ALARM_CANDIDATES = 11;
|
public static final int REFRESH_EXACT_ALARM_CANDIDATES = 11;
|
||||||
public static final int TARE_AFFORDABILITY_CHANGED = 12;
|
public static final int TARE_AFFORDABILITY_CHANGED = 12;
|
||||||
public static final int CHECK_EXACT_ALARM_PERMISSION_ON_UPDATE = 13;
|
public static final int CHECK_EXACT_ALARM_PERMISSION_ON_UPDATE = 13;
|
||||||
|
public static final int CHECK_EXACT_ALARM_PERMISSION_ON_FEATURE_TOGGLE = 14;
|
||||||
|
|
||||||
AlarmHandler() {
|
AlarmHandler() {
|
||||||
super(Looper.myLooper());
|
super(Looper.myLooper());
|
||||||
@@ -4759,6 +4833,35 @@ public class AlarmManagerService extends SystemService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case CHECK_EXACT_ALARM_PERMISSION_ON_FEATURE_TOGGLE:
|
||||||
|
final boolean defaultDenied = (Boolean) msg.obj;
|
||||||
|
|
||||||
|
final int[] startedUserIds = mActivityManagerInternal.getStartedUserIds();
|
||||||
|
for (int appId : mExactAlarmCandidates) {
|
||||||
|
for (int userId : startedUserIds) {
|
||||||
|
uid = UserHandle.getUid(userId, appId);
|
||||||
|
|
||||||
|
final AndroidPackage packageForUid =
|
||||||
|
mPackageManagerInternal.getPackage(uid);
|
||||||
|
if (packageForUid == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
final String pkg = packageForUid.getPackageName();
|
||||||
|
if (defaultDenied) {
|
||||||
|
if (!hasScheduleExactAlarmInternal(pkg, uid)
|
||||||
|
&& !hasUseExactAlarmInternal(pkg, uid)) {
|
||||||
|
synchronized (mLock) {
|
||||||
|
removeExactAlarmsOnPermissionRevokedLocked(uid, pkg,
|
||||||
|
true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (hasScheduleExactAlarmInternal(pkg, uid)) {
|
||||||
|
sendScheduleExactAlarmPermissionStateChangedBroadcast(pkg,
|
||||||
|
UserHandle.getUserId(uid));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
// nope, just ignore it
|
// nope, just ignore it
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -1207,6 +1207,11 @@ public abstract class PackageManagerInternal {
|
|||||||
@Nullable
|
@Nullable
|
||||||
public abstract SharedUserApi getSharedUserApi(int sharedUserAppId);
|
public abstract SharedUserApi getSharedUserApi(int sharedUserAppId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns if the given uid is privileged or not.
|
||||||
|
*/
|
||||||
|
public abstract boolean isUidPrivileged(int uid);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initiates a package state mutation request, returning the current state as known by
|
* Initiates a package state mutation request, returning the current state as known by
|
||||||
* PackageManager. This allows the later commit request to compare the initial values and
|
* PackageManager. This allows the later commit request to compare the initial values and
|
||||||
|
|||||||
@@ -722,6 +722,11 @@ abstract class PackageManagerInternalBase extends PackageManagerInternal {
|
|||||||
return snapshot().getSharedUser(sharedUserAppId);
|
return snapshot().getSharedUser(sharedUserAppId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isUidPrivileged(int uid) {
|
||||||
|
return snapshot().isUidPrivileged(uid);
|
||||||
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
@Deprecated
|
@Deprecated
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import static android.app.AlarmManager.FLAG_STANDALONE;
|
|||||||
import static android.app.AlarmManager.FLAG_WAKE_FROM_IDLE;
|
import static android.app.AlarmManager.FLAG_WAKE_FROM_IDLE;
|
||||||
import static android.app.AlarmManager.RTC;
|
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.SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT;
|
||||||
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_ALLOWED;
|
||||||
@@ -122,6 +123,7 @@ import android.app.IAlarmListener;
|
|||||||
import android.app.IAlarmManager;
|
import android.app.IAlarmManager;
|
||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
import android.app.compat.CompatChanges;
|
import android.app.compat.CompatChanges;
|
||||||
|
import android.app.role.RoleManager;
|
||||||
import android.app.usage.UsageStatsManagerInternal;
|
import android.app.usage.UsageStatsManagerInternal;
|
||||||
import android.content.ContentResolver;
|
import android.content.ContentResolver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
@@ -184,6 +186,7 @@ import org.mockito.quality.Strictness;
|
|||||||
import org.mockito.stubbing.Answer;
|
import org.mockito.stubbing.Answer;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -232,6 +235,8 @@ public class AlarmManagerServiceTest {
|
|||||||
@Mock
|
@Mock
|
||||||
private PackageManagerInternal mPackageManagerInternal;
|
private PackageManagerInternal mPackageManagerInternal;
|
||||||
@Mock
|
@Mock
|
||||||
|
private RoleManager mRoleManager;
|
||||||
|
@Mock
|
||||||
private AppStateTrackerImpl mAppStateTracker;
|
private AppStateTrackerImpl mAppStateTracker;
|
||||||
@Mock
|
@Mock
|
||||||
private AlarmManagerService.ClockReceiver mClockReceiver;
|
private AlarmManagerService.ClockReceiver mClockReceiver;
|
||||||
@@ -457,6 +462,7 @@ public class AlarmManagerServiceTest {
|
|||||||
|
|
||||||
when(mMockContext.getSystemService(Context.APP_OPS_SERVICE)).thenReturn(mAppOpsManager);
|
when(mMockContext.getSystemService(Context.APP_OPS_SERVICE)).thenReturn(mAppOpsManager);
|
||||||
when(mMockContext.getSystemService(BatteryManager.class)).thenReturn(mBatteryManager);
|
when(mMockContext.getSystemService(BatteryManager.class)).thenReturn(mBatteryManager);
|
||||||
|
when(mMockContext.getSystemService(RoleManager.class)).thenReturn(mRoleManager);
|
||||||
|
|
||||||
registerAppIds(new String[]{TEST_CALLING_PACKAGE},
|
registerAppIds(new String[]{TEST_CALLING_PACKAGE},
|
||||||
new Integer[]{UserHandle.getAppId(TEST_CALLING_UID)});
|
new Integer[]{UserHandle.getAppId(TEST_CALLING_UID)});
|
||||||
@@ -3190,6 +3196,70 @@ public class AlarmManagerServiceTest {
|
|||||||
assertEquals(0, remaining.size());
|
assertEquals(0, remaining.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void isScheduleExactAlarmAllowedByDefault() {
|
||||||
|
final String package1 = "priv";
|
||||||
|
final String package2 = "signed";
|
||||||
|
final String package3 = "normal";
|
||||||
|
final String package4 = "wellbeing";
|
||||||
|
final int uid1 = 1294;
|
||||||
|
final int uid2 = 8321;
|
||||||
|
final int uid3 = 3412;
|
||||||
|
final int uid4 = 4591;
|
||||||
|
|
||||||
|
when(mPackageManagerInternal.isUidPrivileged(uid1)).thenReturn(true);
|
||||||
|
when(mPackageManagerInternal.isUidPrivileged(uid2)).thenReturn(false);
|
||||||
|
when(mPackageManagerInternal.isUidPrivileged(uid3)).thenReturn(false);
|
||||||
|
when(mPackageManagerInternal.isUidPrivileged(uid4)).thenReturn(false);
|
||||||
|
|
||||||
|
when(mPackageManagerInternal.isPlatformSigned(package1)).thenReturn(false);
|
||||||
|
when(mPackageManagerInternal.isPlatformSigned(package2)).thenReturn(true);
|
||||||
|
when(mPackageManagerInternal.isPlatformSigned(package3)).thenReturn(false);
|
||||||
|
when(mPackageManagerInternal.isPlatformSigned(package4)).thenReturn(false);
|
||||||
|
|
||||||
|
when(mRoleManager.getRoleHolders(RoleManager.ROLE_SYSTEM_WELLBEING)).thenReturn(
|
||||||
|
Arrays.asList(package4));
|
||||||
|
|
||||||
|
mockChangeEnabled(SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT, true);
|
||||||
|
mService.mConstants.SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT = false;
|
||||||
|
mService.mConstants.EXACT_ALARM_DENY_LIST = new ArraySet<>(new String[] {
|
||||||
|
package1,
|
||||||
|
package3,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Deny listed packages will be false.
|
||||||
|
assertFalse(mService.isScheduleExactAlarmAllowedByDefault(package1, uid1));
|
||||||
|
assertTrue(mService.isScheduleExactAlarmAllowedByDefault(package2, uid2));
|
||||||
|
assertFalse(mService.isScheduleExactAlarmAllowedByDefault(package3, uid3));
|
||||||
|
assertTrue(mService.isScheduleExactAlarmAllowedByDefault(package4, uid4));
|
||||||
|
|
||||||
|
mockChangeEnabled(SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT, false);
|
||||||
|
mService.mConstants.SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT = true;
|
||||||
|
mService.mConstants.EXACT_ALARM_DENY_LIST = new ArraySet<>(new String[] {
|
||||||
|
package1,
|
||||||
|
package3,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Same as above, deny listed packages will be false.
|
||||||
|
assertFalse(mService.isScheduleExactAlarmAllowedByDefault(package1, uid1));
|
||||||
|
assertTrue(mService.isScheduleExactAlarmAllowedByDefault(package2, uid2));
|
||||||
|
assertFalse(mService.isScheduleExactAlarmAllowedByDefault(package3, uid3));
|
||||||
|
assertTrue(mService.isScheduleExactAlarmAllowedByDefault(package4, uid4));
|
||||||
|
|
||||||
|
mockChangeEnabled(SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT, true);
|
||||||
|
mService.mConstants.SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT = true;
|
||||||
|
mService.mConstants.EXACT_ALARM_DENY_LIST = new ArraySet<>(new String[] {
|
||||||
|
package1,
|
||||||
|
package3,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Deny list doesn't matter now, only exemptions should be true.
|
||||||
|
assertTrue(mService.isScheduleExactAlarmAllowedByDefault(package1, uid1));
|
||||||
|
assertTrue(mService.isScheduleExactAlarmAllowedByDefault(package2, uid2));
|
||||||
|
assertFalse(mService.isScheduleExactAlarmAllowedByDefault(package3, uid3));
|
||||||
|
assertTrue(mService.isScheduleExactAlarmAllowedByDefault(package4, uid4));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void alarmScheduledAtomPushed() {
|
public void alarmScheduledAtomPushed() {
|
||||||
for (int i = 0; i < 10; i++) {
|
for (int i = 0; i < 10; i++) {
|
||||||
|
|||||||
Reference in New Issue
Block a user