Merge "Adding an API to cancel all alarms"

This commit is contained in:
TreeHugger Robot
2022-07-28 22:48:23 +00:00
committed by Android (Google) Code Review
5 changed files with 92 additions and 7 deletions

View File

@@ -1256,6 +1256,17 @@ public class AlarmManager {
wrapper.cancel();
}
/**
* Remove all alarms previously set by the caller, if any.
*/
public void cancelAll() {
try {
mService.removeAll(mContext.getOpPackageName());
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
}
/**
* Set the system wall clock time.
* Requires the permission android.permission.SET_TIME.

View File

@@ -37,6 +37,7 @@ interface IAlarmManager {
boolean setTime(long millis);
void setTimeZone(String zone);
void remove(in PendingIntent operation, in IAlarmListener listener);
void removeAll(String packageName);
long getNextWakeFromIdleTime();
@UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
AlarmManager.AlarmClockInfo getNextAlarmClock(int userId);

View File

@@ -2969,6 +2969,24 @@ public class AlarmManagerService extends SystemService {
}
}
@Override
public void removeAll(String callingPackage) {
final int callingUid = mInjector.getCallingUid();
if (callingUid == Process.SYSTEM_UID) {
Slog.wtfStack(TAG, "Attempt to remove all alarms from the system uid package: "
+ callingPackage);
return;
}
if (callingUid != mPackageManagerInternal.getPackageUid(callingPackage, 0,
UserHandle.getUserId(callingUid))) {
throw new SecurityException("Package " + callingPackage
+ " does not belong to the calling uid " + callingUid);
}
synchronized (mLock) {
removeLocked(callingPackage, REMOVE_REASON_ALARM_CANCELLED);
}
}
@Override
public long getNextWakeFromIdleTime() {
return getNextWakeFromIdleTimeImpl();
@@ -4081,7 +4099,7 @@ public class AlarmManagerService extends SystemService {
}
@GuardedBy("mLock")
void removeLocked(final String packageName) {
void removeLocked(final String packageName, int reason) {
if (packageName == null) {
if (localLOGV) {
Slog.w(TAG, "requested remove() of null packageName",
@@ -4089,7 +4107,7 @@ public class AlarmManagerService extends SystemService {
}
return;
}
removeAlarmsInternalLocked(a -> a.matches(packageName), REMOVE_REASON_UNDEFINED);
removeAlarmsInternalLocked(a -> a.matches(packageName), reason);
}
// Only called for ephemeral apps
@@ -5132,7 +5150,7 @@ public class AlarmManagerService extends SystemService {
removeLocked(uid, REMOVE_REASON_UNDEFINED);
} else {
// external-applications-unavailable case
removeLocked(pkg);
removeLocked(pkg, REMOVE_REASON_UNDEFINED);
}
mPriorities.remove(pkg);
for (int i = mBroadcastStats.size() - 1; i >= 0; i--) {

View File

@@ -4596,6 +4596,7 @@ package android.app {
method public boolean canScheduleExactAlarms();
method public void cancel(android.app.PendingIntent);
method public void cancel(android.app.AlarmManager.OnAlarmListener);
method public void cancelAll();
method public android.app.AlarmManager.AlarmClockInfo getNextAlarmClock();
method public void set(int, long, android.app.PendingIntent);
method public void set(int, long, String, android.app.AlarmManager.OnAlarmListener, android.os.Handler);

View File

@@ -254,6 +254,7 @@ public class AlarmManagerServiceTest {
private Injector mInjector;
private volatile long mNowElapsedTest;
private volatile long mNowRtcTest;
private volatile int mTestCallingUid = TEST_CALLING_UID;
@GuardedBy("mTestTimer")
private TestTimer mTestTimer = new TestTimer();
@@ -328,7 +329,7 @@ public class AlarmManagerServiceTest {
@Override
int getCallingUid() {
return TEST_CALLING_UID;
return mTestCallingUid;
}
@Override
@@ -1395,7 +1396,7 @@ public class AlarmManagerServiceTest {
setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + i + 10, getNewMockPendingIntent());
}
assertEquals(numAlarms, mService.mAlarmsPerUid.get(TEST_CALLING_UID));
mService.removeLocked(TEST_CALLING_PACKAGE);
mService.removeLocked(TEST_CALLING_PACKAGE, REMOVE_REASON_UNDEFINED);
assertEquals(0, mService.mAlarmsPerUid.get(TEST_CALLING_UID, 0));
}
@@ -2682,6 +2683,59 @@ public class AlarmManagerServiceTest {
eq(EXACT_ALLOW_REASON_ALLOW_LIST));
}
@Test
public void removeAllBinderCall() throws RemoteException {
for (int i = 0; i < 10; i++) {
setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + i + 1, getNewMockPendingIntent());
}
final String otherUidPackage1 = "other.uid.package1";
final String otherUidPackage2 = "other.uid.package2";
final int otherUid = 1243;
registerAppIds(
new String[]{TEST_CALLING_PACKAGE, otherUidPackage1, otherUidPackage2},
new Integer[]{TEST_CALLING_UID, otherUid, otherUid}
);
for (int i = 0; i < 9; i++) {
setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + i + 11, 0,
getNewMockPendingIntent(otherUid, otherUidPackage1), 0, 0, otherUid,
otherUidPackage1, null);
}
for (int i = 0; i < 8; i++) {
setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + i + 20, 0,
getNewMockPendingIntent(otherUid, otherUidPackage2), 0, 0, otherUid,
otherUidPackage2, null);
}
assertEquals(27, mService.mAlarmStore.size());
try {
mBinder.removeAll(otherUidPackage1);
fail("removeAll() for wrong package did not throw SecurityException");
} catch (SecurityException se) {
// Expected
}
try {
mBinder.removeAll(otherUidPackage2);
fail("removeAll() for wrong package did not throw SecurityException");
} catch (SecurityException se) {
// Expected
}
mBinder.removeAll(TEST_CALLING_PACKAGE);
assertEquals(17, mService.mAlarmStore.size());
assertEquals(0, mService.mAlarmStore.getCount(a -> a.matches(TEST_CALLING_PACKAGE)));
mTestCallingUid = otherUid;
mBinder.removeAll(otherUidPackage1);
assertEquals(0, mService.mAlarmStore.getCount(a -> a.matches(otherUidPackage1)));
assertEquals(8, mService.mAlarmStore.getCount(a -> a.matches(otherUidPackage2)));
}
@Test
public void minWindowChangeEnabled() {
mockChangeEnabled(AlarmManager.ENFORCE_MINIMUM_WINDOW_ON_INEXACT_ALARMS, true);
@@ -3577,7 +3631,7 @@ public class AlarmManagerServiceTest {
getNewMockPendingIntent()), standbyQuota + temporaryQuota, mAppStandbyWindow);
// refresh the state.
mService.removeLocked(TEST_CALLING_PACKAGE);
mService.removeLocked(TEST_CALLING_PACKAGE, REMOVE_REASON_UNDEFINED);
mService.mAppWakeupHistory.removeForPackage(TEST_CALLING_PACKAGE, TEST_CALLING_USER);
mService.mTemporaryQuotaReserve.removeForPackage(TEST_CALLING_PACKAGE, TEST_CALLING_USER);
@@ -3586,7 +3640,7 @@ public class AlarmManagerServiceTest {
getNewMockPendingIntent()), standbyQuota + temporaryQuota, mAppStandbyWindow);
// refresh the state.
mService.removeLocked(TEST_CALLING_PACKAGE);
mService.removeLocked(TEST_CALLING_PACKAGE, REMOVE_REASON_UNDEFINED);
mService.mAppWakeupHistory.removeForPackage(TEST_CALLING_PACKAGE, TEST_CALLING_USER);
mService.mTemporaryQuotaReserve.removeForPackage(TEST_CALLING_PACKAGE, TEST_CALLING_USER);