Exempt exact alarms using listener from permission
Listener alarms rely on the caller staying in valid lifecycle till the alarm expires. In this case the caller should be encouraged to use exact alarms for use-cases requiring timing precisions without needing additional user consent. Adding explicit reason codes for listener and prioritized alarms for logging when these alarms are also exact. Also reducing the quota of listener allow-while-idle alarms to match other alarms that do not require permission. Test: atest CtsAlarmManagerTestCases:ExactAlarmsTest Bug: 228125912 Change-Id: I7636126c411b174a71ad91583c9fbd9d9457623d
This commit is contained in:
@@ -800,22 +800,12 @@ public class AlarmManager {
|
||||
* if {@code null} is passed as the {@code targetHandler} parameter.
|
||||
*
|
||||
* <p class="note"><strong>Note:</strong>
|
||||
* Starting with {@link Build.VERSION_CODES#S}, apps targeting SDK level 31 or higher
|
||||
* need to request the
|
||||
* {@link Manifest.permission#SCHEDULE_EXACT_ALARM SCHEDULE_EXACT_ALARM} permission to use this
|
||||
* API, unless the app is exempt from battery restrictions.
|
||||
* The user and the system can revoke this permission via the special app access screen in
|
||||
* Settings.
|
||||
* On previous android versions {@link Build.VERSION_CODES#S} and
|
||||
* {@link Build.VERSION_CODES#TIRAMISU}, apps targeting SDK level 31 or higher needed to hold
|
||||
* the {@link Manifest.permission#SCHEDULE_EXACT_ALARM SCHEDULE_EXACT_ALARM} permission to use
|
||||
* this API, unless the app was exempt from battery restrictions.
|
||||
*
|
||||
* <p class="note"><strong>Note:</strong>
|
||||
* Exact alarms should only be used for user-facing features.
|
||||
* For more details, see <a
|
||||
* href="{@docRoot}about/versions/12/behavior-changes-12#exact-alarm-permission">
|
||||
* Exact alarm permission</a>.
|
||||
*
|
||||
* @see Manifest.permission#SCHEDULE_EXACT_ALARM SCHEDULE_EXACT_ALARM
|
||||
*/
|
||||
@RequiresPermission(value = Manifest.permission.SCHEDULE_EXACT_ALARM, conditional = true)
|
||||
public void setExact(@AlarmType int type, long triggerAtMillis, @Nullable String tag,
|
||||
@NonNull OnAlarmListener listener, @Nullable Handler targetHandler) {
|
||||
setImpl(type, triggerAtMillis, WINDOW_EXACT, 0, 0, null, listener, tag,
|
||||
@@ -949,7 +939,8 @@ public class AlarmManager {
|
||||
* {@link #setExact(int, long, String, OnAlarmListener, Handler)} instead.
|
||||
*
|
||||
* <p>
|
||||
* Note that using this API requires you to hold
|
||||
* Note that on previous Android versions {@link Build.VERSION_CODES#S} and
|
||||
* {@link Build.VERSION_CODES#TIRAMISU}, using this API required you to hold
|
||||
* {@link Manifest.permission#SCHEDULE_EXACT_ALARM}, unless you are on the system's power
|
||||
* allowlist. This can be set, for example, by marking the app as {@code <allow-in-power-save>}
|
||||
* within the system config.
|
||||
@@ -970,9 +961,7 @@ public class AlarmManager {
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
@RequiresPermission(allOf = {
|
||||
Manifest.permission.UPDATE_DEVICE_STATS,
|
||||
Manifest.permission.SCHEDULE_EXACT_ALARM}, conditional = true)
|
||||
@RequiresPermission(Manifest.permission.UPDATE_DEVICE_STATS)
|
||||
public void setExact(@AlarmType int type, long triggerAtMillis, @Nullable String tag,
|
||||
@NonNull Executor executor, @NonNull WorkSource workSource,
|
||||
@NonNull OnAlarmListener listener) {
|
||||
@@ -1283,9 +1272,7 @@ public class AlarmManager {
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
@RequiresPermission(allOf = {
|
||||
Manifest.permission.UPDATE_DEVICE_STATS,
|
||||
Manifest.permission.SCHEDULE_EXACT_ALARM}, conditional = true)
|
||||
@RequiresPermission(Manifest.permission.UPDATE_DEVICE_STATS)
|
||||
public void setExactAndAllowWhileIdle(@AlarmType int type, long triggerAtMillis,
|
||||
@Nullable String tag, @NonNull Executor executor, @Nullable WorkSource workSource,
|
||||
@NonNull OnAlarmListener listener) {
|
||||
|
||||
@@ -92,6 +92,14 @@ class Alarm {
|
||||
* Caller had USE_EXACT_ALARM permission.
|
||||
*/
|
||||
static final int EXACT_ALLOW_REASON_POLICY_PERMISSION = 3;
|
||||
/**
|
||||
* Caller used a listener alarm, which does not need permission to be exact.
|
||||
*/
|
||||
static final int EXACT_ALLOW_REASON_LISTENER = 4;
|
||||
/**
|
||||
* Caller used a prioritized alarm, which does not need permission to be exact.
|
||||
*/
|
||||
static final int EXACT_ALLOW_REASON_PRIORITIZED = 5;
|
||||
|
||||
public final int type;
|
||||
/**
|
||||
|
||||
@@ -47,9 +47,11 @@ import static com.android.server.alarm.Alarm.BATTERY_SAVER_POLICY_INDEX;
|
||||
import static com.android.server.alarm.Alarm.DEVICE_IDLE_POLICY_INDEX;
|
||||
import static com.android.server.alarm.Alarm.EXACT_ALLOW_REASON_ALLOW_LIST;
|
||||
import static com.android.server.alarm.Alarm.EXACT_ALLOW_REASON_COMPAT;
|
||||
import static com.android.server.alarm.Alarm.EXACT_ALLOW_REASON_LISTENER;
|
||||
import static com.android.server.alarm.Alarm.EXACT_ALLOW_REASON_NOT_APPLICABLE;
|
||||
import static com.android.server.alarm.Alarm.EXACT_ALLOW_REASON_PERMISSION;
|
||||
import static com.android.server.alarm.Alarm.EXACT_ALLOW_REASON_POLICY_PERMISSION;
|
||||
import static com.android.server.alarm.Alarm.EXACT_ALLOW_REASON_PRIORITIZED;
|
||||
import static com.android.server.alarm.Alarm.REQUESTER_POLICY_INDEX;
|
||||
import static com.android.server.alarm.Alarm.TARE_POLICY_INDEX;
|
||||
import static com.android.server.alarm.AlarmManagerService.RemovedAlarm.REMOVE_REASON_ALARM_CANCELLED;
|
||||
@@ -2890,12 +2892,23 @@ public class AlarmManagerService extends SystemService {
|
||||
// The API doesn't allow using both together.
|
||||
flags &= ~FLAG_ALLOW_WHILE_IDLE;
|
||||
// Prioritized alarms don't need any extra permission to be exact.
|
||||
if (exact) {
|
||||
exactAllowReason = EXACT_ALLOW_REASON_PRIORITIZED;
|
||||
}
|
||||
} else if (exact || allowWhileIdle) {
|
||||
final boolean needsPermission;
|
||||
boolean lowerQuota;
|
||||
if (isExactAlarmChangeEnabled(callingPackage, callingUserId)) {
|
||||
needsPermission = exact;
|
||||
lowerQuota = !exact;
|
||||
if (directReceiver == null) {
|
||||
needsPermission = exact;
|
||||
lowerQuota = !exact;
|
||||
} else {
|
||||
needsPermission = false;
|
||||
lowerQuota = allowWhileIdle;
|
||||
if (exact) {
|
||||
exactAllowReason = EXACT_ALLOW_REASON_LISTENER;
|
||||
}
|
||||
}
|
||||
if (exact) {
|
||||
idleOptions = (alarmClock != null) ? mOptsWithFgsForAlarmClock.toBundle()
|
||||
: mOptsWithFgs.toBundle();
|
||||
@@ -2931,11 +2944,9 @@ public class AlarmManagerService extends SystemService {
|
||||
throw new SecurityException(errorMessage);
|
||||
}
|
||||
// If the app is on the full system power allow-list (not except-idle),
|
||||
// or the user-elected allow-list, or we're in a soft failure mode, we still
|
||||
// allow the alarms.
|
||||
// In both cases, ALLOW_WHILE_IDLE alarms get a lower quota equivalent to
|
||||
// what pre-S apps got. Note that user-allow-listed apps don't use the flag
|
||||
// ALLOW_WHILE_IDLE.
|
||||
// or the user-elected allow-list, we allow exact alarms.
|
||||
// ALLOW_WHILE_IDLE alarms get a lower quota equivalent to what pre-S apps
|
||||
// got. Note that user-allow-listed apps don't use FLAG_ALLOW_WHILE_IDLE.
|
||||
// We grant temporary allow-list to allow-while-idle alarms but without FGS
|
||||
// capability. AlarmClock alarms do not get the temporary allow-list.
|
||||
// This is consistent with pre-S behavior. Note that apps that are in
|
||||
|
||||
@@ -18,9 +18,11 @@ package com.android.server.alarm;
|
||||
|
||||
import static com.android.internal.util.FrameworkStatsLog.ALARM_SCHEDULED__EXACT_ALARM_ALLOWED_REASON__ALLOW_LIST;
|
||||
import static com.android.internal.util.FrameworkStatsLog.ALARM_SCHEDULED__EXACT_ALARM_ALLOWED_REASON__CHANGE_DISABLED;
|
||||
import static com.android.internal.util.FrameworkStatsLog.ALARM_SCHEDULED__EXACT_ALARM_ALLOWED_REASON__LISTENER;
|
||||
import static com.android.internal.util.FrameworkStatsLog.ALARM_SCHEDULED__EXACT_ALARM_ALLOWED_REASON__NOT_APPLICABLE;
|
||||
import static com.android.internal.util.FrameworkStatsLog.ALARM_SCHEDULED__EXACT_ALARM_ALLOWED_REASON__PERMISSION;
|
||||
import static com.android.internal.util.FrameworkStatsLog.ALARM_SCHEDULED__EXACT_ALARM_ALLOWED_REASON__POLICY_PERMISSION;
|
||||
import static com.android.internal.util.FrameworkStatsLog.ALARM_SCHEDULED__EXACT_ALARM_ALLOWED_REASON__PRIORITIZED;
|
||||
import static com.android.server.alarm.AlarmManagerService.INDEFINITE_DELAY;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
@@ -84,14 +86,18 @@ class MetricsHelper {
|
||||
|
||||
private static int reasonToStatsReason(int reasonCode) {
|
||||
switch (reasonCode) {
|
||||
case Alarm.EXACT_ALLOW_REASON_ALLOW_LIST:
|
||||
return ALARM_SCHEDULED__EXACT_ALARM_ALLOWED_REASON__ALLOW_LIST;
|
||||
case Alarm.EXACT_ALLOW_REASON_PERMISSION:
|
||||
return ALARM_SCHEDULED__EXACT_ALARM_ALLOWED_REASON__PERMISSION;
|
||||
case Alarm.EXACT_ALLOW_REASON_ALLOW_LIST:
|
||||
return ALARM_SCHEDULED__EXACT_ALARM_ALLOWED_REASON__ALLOW_LIST;
|
||||
case Alarm.EXACT_ALLOW_REASON_COMPAT:
|
||||
return ALARM_SCHEDULED__EXACT_ALARM_ALLOWED_REASON__CHANGE_DISABLED;
|
||||
case Alarm.EXACT_ALLOW_REASON_POLICY_PERMISSION:
|
||||
return ALARM_SCHEDULED__EXACT_ALARM_ALLOWED_REASON__POLICY_PERMISSION;
|
||||
case Alarm.EXACT_ALLOW_REASON_LISTENER:
|
||||
return ALARM_SCHEDULED__EXACT_ALARM_ALLOWED_REASON__LISTENER;
|
||||
case Alarm.EXACT_ALLOW_REASON_PRIORITIZED:
|
||||
return ALARM_SCHEDULED__EXACT_ALARM_ALLOWED_REASON__PRIORITIZED;
|
||||
default:
|
||||
return ALARM_SCHEDULED__EXACT_ALARM_ALLOWED_REASON__NOT_APPLICABLE;
|
||||
}
|
||||
|
||||
@@ -4673,7 +4673,7 @@ package android.app {
|
||||
method @RequiresPermission(android.Manifest.permission.SCHEDULE_EXACT_ALARM) public void setAlarmClock(@NonNull android.app.AlarmManager.AlarmClockInfo, @NonNull android.app.PendingIntent);
|
||||
method public void setAndAllowWhileIdle(int, long, @NonNull android.app.PendingIntent);
|
||||
method @RequiresPermission(value=android.Manifest.permission.SCHEDULE_EXACT_ALARM, conditional=true) public void setExact(int, long, @NonNull android.app.PendingIntent);
|
||||
method @RequiresPermission(value=android.Manifest.permission.SCHEDULE_EXACT_ALARM, conditional=true) public void setExact(int, long, @Nullable String, @NonNull android.app.AlarmManager.OnAlarmListener, @Nullable android.os.Handler);
|
||||
method public void setExact(int, long, @Nullable String, @NonNull android.app.AlarmManager.OnAlarmListener, @Nullable android.os.Handler);
|
||||
method @RequiresPermission(value=android.Manifest.permission.SCHEDULE_EXACT_ALARM, conditional=true) public void setExactAndAllowWhileIdle(int, long, @NonNull android.app.PendingIntent);
|
||||
method public void setInexactRepeating(int, long, long, @NonNull android.app.PendingIntent);
|
||||
method public void setRepeating(int, long, long, @NonNull android.app.PendingIntent);
|
||||
|
||||
@@ -541,8 +541,8 @@ package android.app {
|
||||
public class AlarmManager {
|
||||
method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void set(int, long, long, long, @NonNull android.app.PendingIntent, @Nullable android.os.WorkSource);
|
||||
method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void set(int, long, long, long, @NonNull android.app.AlarmManager.OnAlarmListener, @Nullable android.os.Handler, @Nullable android.os.WorkSource);
|
||||
method @RequiresPermission(allOf={android.Manifest.permission.UPDATE_DEVICE_STATS, android.Manifest.permission.SCHEDULE_EXACT_ALARM}, conditional=true) public void setExact(int, long, @Nullable String, @NonNull java.util.concurrent.Executor, @NonNull android.os.WorkSource, @NonNull android.app.AlarmManager.OnAlarmListener);
|
||||
method @RequiresPermission(allOf={android.Manifest.permission.UPDATE_DEVICE_STATS, android.Manifest.permission.SCHEDULE_EXACT_ALARM}, conditional=true) public void setExactAndAllowWhileIdle(int, long, @Nullable String, @NonNull java.util.concurrent.Executor, @Nullable android.os.WorkSource, @NonNull android.app.AlarmManager.OnAlarmListener);
|
||||
method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void setExact(int, long, @Nullable String, @NonNull java.util.concurrent.Executor, @NonNull android.os.WorkSource, @NonNull android.app.AlarmManager.OnAlarmListener);
|
||||
method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void setExactAndAllowWhileIdle(int, long, @Nullable String, @NonNull java.util.concurrent.Executor, @Nullable android.os.WorkSource, @NonNull android.app.AlarmManager.OnAlarmListener);
|
||||
method @RequiresPermission(android.Manifest.permission.SCHEDULE_PRIORITIZED_ALARM) public void setPrioritized(int, long, long, @Nullable String, @NonNull java.util.concurrent.Executor, @NonNull android.app.AlarmManager.OnAlarmListener);
|
||||
method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void setWindow(int, long, long, @Nullable String, @NonNull java.util.concurrent.Executor, @Nullable android.os.WorkSource, @NonNull android.app.AlarmManager.OnAlarmListener);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user