Adding metrics to alarm manager

Push atoms:
 - Every time an alarm is scheduled, we push some attributes of the
 alarm and the reason why such an alarm was allowed. This will help
 audit spammy behavior from apps that misuse alarm API, e.g.
 apps that have SCHEDULE_EXACT_ALARM.
 - Every time an alarm batch is delivered, we log the size of the batch
 and whether or not it was a wakeup batch. This is the essential measure
 of alarm manager's batching efficiency.

Pulled atoms:
 - Logging general stats on pending alarms every once in a while.

Test: atest CtsAlarmManagerTestCases
atest FrameworksMockingServicesTests:com.android.server.alarm

statsd-testdrive 377 378 10106

Bug: 161497385
Bug: 171306433
Bug: 177556103
Change-Id: Ib13c9c380b641d318c6b8777996aa37f9b3d1bfc
This commit is contained in:
Suprabh Shukla
2021-04-21 13:49:14 -07:00
parent c9fcf22f2b
commit 1d5ea8c336
10 changed files with 312 additions and 41 deletions

View File

@@ -66,6 +66,23 @@ class Alarm {
*/
public static final int BATTERY_SAVER_POLICY_INDEX = 3;
/**
* Reason to use for inexact alarms.
*/
static final int EXACT_ALLOW_REASON_NOT_APPLICABLE = -1;
/**
* Caller had SCHEDULE_EXACT_ALARM permission.
*/
static final int EXACT_ALLOW_REASON_PERMISSION = 0;
/**
* Caller was in the power allow-list.
*/
static final int EXACT_ALLOW_REASON_ALLOW_LIST = 1;
/**
* Change wasn't enable for the caller due to compat reasons.
*/
static final int EXACT_ALLOW_REASON_COMPAT = 2;
public final int type;
/**
* The original trigger time supplied by the caller. This can be in the elapsed or rtc time base
@@ -92,13 +109,15 @@ class Alarm {
/** The ultimate delivery time to be used for this alarm */
private long mWhenElapsed;
private long mMaxWhenElapsed;
public int mExactAllowReason;
public AlarmManagerService.PriorityClass priorityClass;
/** Broadcast options to use when delivering this alarm */
public Bundle mIdleOptions;
Alarm(int type, long when, long requestedWhenElapsed, long windowLength, long interval,
PendingIntent op, IAlarmListener rec, String listenerTag, WorkSource ws, int flags,
AlarmManager.AlarmClockInfo info, int uid, String pkgName, Bundle idleOptions) {
AlarmManager.AlarmClockInfo info, int uid, String pkgName, Bundle idleOptions,
int exactAllowReason) {
this.type = type;
origWhen = when;
wakeup = type == AlarmManager.ELAPSED_REALTIME_WAKEUP
@@ -119,6 +138,7 @@ class Alarm {
this.uid = uid;
packageName = pkgName;
mIdleOptions = idleOptions;
mExactAllowReason = exactAllowReason;
sourcePackage = (operation != null) ? operation.getCreatorPackage() : packageName;
creatorUid = (operation != null) ? operation.getCreatorUid() : this.uid;
}
@@ -216,7 +236,6 @@ class Alarm {
sb.append(type);
sb.append(" origWhen ");
sb.append(origWhen);
sb.append(" ");
sb.append(" whenElapsed ");
sb.append(getWhenElapsed());
sb.append(" ");
@@ -240,6 +259,21 @@ class Alarm {
}
}
private static String exactReasonToString(int reason) {
switch (reason) {
case EXACT_ALLOW_REASON_ALLOW_LIST:
return "allow-listed";
case EXACT_ALLOW_REASON_COMPAT:
return "compat";
case EXACT_ALLOW_REASON_PERMISSION:
return "permission";
case EXACT_ALLOW_REASON_NOT_APPLICABLE:
return "N/A";
default:
return "--unknown--";
}
}
public static String typeToString(int type) {
switch (type) {
case RTC:
@@ -270,6 +304,10 @@ class Alarm {
}
ipw.print(" window=");
TimeUtils.formatDuration(windowLength, ipw);
if (mExactAllowReason != EXACT_ALLOW_REASON_NOT_APPLICABLE) {
ipw.print(" exactAllowReason=");
ipw.print(exactReasonToString(mExactAllowReason));
}
ipw.print(" repeatInterval=");
ipw.print(repeatInterval);
ipw.print(" count=");

View File

@@ -38,6 +38,10 @@ import static android.os.UserHandle.USER_SYSTEM;
import static com.android.server.alarm.Alarm.APP_STANDBY_POLICY_INDEX;
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_NOT_APPLICABLE;
import static com.android.server.alarm.Alarm.EXACT_ALLOW_REASON_PERMISSION;
import static com.android.server.alarm.Alarm.REQUESTER_POLICY_INDEX;
import android.Manifest;
@@ -223,6 +227,7 @@ public class AlarmManagerService extends SystemService {
private final Injector mInjector;
int mBroadcastRefCount = 0;
MetricsHelper mMetricsHelper;
PowerManager.WakeLock mWakeLock;
SparseIntArray mAlarmsPerUid = new SparseIntArray();
ArrayList<Alarm> mPendingNonWakeupAlarms = new ArrayList<>();
@@ -1221,7 +1226,7 @@ public class AlarmManagerService extends SystemService {
setImplLocked(alarm.type, alarm.origWhen + delta, nextElapsed,
nextMaxElapsed - nextElapsed, alarm.repeatInterval, alarm.operation, null,
null, alarm.flags, alarm.workSource, alarm.alarmClock, alarm.uid,
alarm.packageName, null);
alarm.packageName, null, EXACT_ALLOW_REASON_NOT_APPLICABLE);
// Kernel alarms will be rescheduled as needed in setImplLocked
}
}
@@ -1442,6 +1447,7 @@ public class AlarmManagerService extends SystemService {
@Override
public void onStart() {
mInjector.init();
mMetricsHelper = new MetricsHelper(getContext());
mListenerDeathRecipient = new IBinder.DeathRecipient() {
@Override
@@ -1584,6 +1590,7 @@ public class AlarmManagerService extends SystemService {
});
} catch (RemoteException e) {
}
mMetricsHelper.registerPuller(mAlarmStore);
mLocalDeviceIdleController =
LocalServices.getService(DeviceIdleInternal.class);
@@ -1691,7 +1698,7 @@ public class AlarmManagerService extends SystemService {
void setImpl(int type, long triggerAtTime, long windowLength, long interval,
PendingIntent operation, IAlarmListener directReceiver, String listenerTag,
int flags, WorkSource workSource, AlarmManager.AlarmClockInfo alarmClock,
int callingUid, String callingPackage, Bundle idleOptions) {
int callingUid, String callingPackage, Bundle idleOptions, int exactAllowReason) {
if ((operation == null && directReceiver == null)
|| (operation != null && directReceiver != null)) {
Slog.w(TAG, "Alarms must either supply a PendingIntent or an AlarmReceiver");
@@ -1788,7 +1795,7 @@ public class AlarmManagerService extends SystemService {
}
setImplLocked(type, triggerAtTime, triggerElapsed, windowLength, interval, operation,
directReceiver, listenerTag, flags, workSource, alarmClock, callingUid,
callingPackage, idleOptions);
callingPackage, idleOptions, exactAllowReason);
}
}
@@ -1796,10 +1803,10 @@ public class AlarmManagerService extends SystemService {
long interval, PendingIntent operation, IAlarmListener directReceiver,
String listenerTag, int flags, WorkSource workSource,
AlarmManager.AlarmClockInfo alarmClock, int callingUid, String callingPackage,
Bundle idleOptions) {
Bundle idleOptions, int exactAllowReason) {
final Alarm a = new Alarm(type, when, whenElapsed, windowLength, interval,
operation, directReceiver, listenerTag, workSource, flags, alarmClock,
callingUid, callingPackage, idleOptions);
callingUid, callingPackage, idleOptions, exactAllowReason);
if (mActivityManagerInternal.isAppStartModeDisabled(callingUid, callingPackage)) {
Slog.w(TAG, "Not setting alarm from " + callingUid + ":" + a
+ " -- package not allowed to start");
@@ -1808,6 +1815,7 @@ public class AlarmManagerService extends SystemService {
removeLocked(operation, directReceiver);
incrementAlarmCount(a.uid);
setImplLocked(a);
MetricsHelper.pushAlarmScheduled(a);
}
/**
@@ -2220,6 +2228,8 @@ public class AlarmManagerService extends SystemService {
// Make sure the caller is allowed to use the requested kind of alarm, and also
// decide what quota and broadcast options to use.
boolean allowListed = false; // For logging the reason.
boolean changeDisabled = false; // For logging the reason.
Bundle idleOptions = null;
if ((flags & FLAG_PRIORITIZE) != 0) {
getContext().enforcePermission(
@@ -2236,6 +2246,7 @@ public class AlarmManagerService extends SystemService {
lowerQuota = !exact;
idleOptions = exact ? mOptsWithFgs.toBundle() : mOptsWithoutFgs.toBundle();
} else {
changeDisabled = true;
needsPermission = false;
lowerQuota = allowWhileIdle;
idleOptions = allowWhileIdle ? mOptsWithFgs.toBundle() : null;
@@ -2250,6 +2261,8 @@ public class AlarmManagerService extends SystemService {
} else {
Slog.wtf(TAG, errorMessage);
}
} else {
allowListed = true;
}
// If the app is on the full system power allow-list (not except-idle), or we're
// in a soft failure mode, we still allow the alarms.
@@ -2263,15 +2276,25 @@ public class AlarmManagerService extends SystemService {
flags |= FLAG_ALLOW_WHILE_IDLE_COMPAT;
}
}
// If this is an exact time alarm, then it can't be batched with other alarms.
final int exactAllowReason;
if (exact) {
// If this is an exact time alarm, then it can't be batched with other alarms.
flags |= AlarmManager.FLAG_STANDALONE;
if (changeDisabled) {
exactAllowReason = EXACT_ALLOW_REASON_COMPAT;
} else if (allowListed) {
exactAllowReason = EXACT_ALLOW_REASON_ALLOW_LIST;
} else {
exactAllowReason = EXACT_ALLOW_REASON_PERMISSION;
}
} else {
exactAllowReason = EXACT_ALLOW_REASON_NOT_APPLICABLE;
}
setImpl(type, triggerAtTime, windowLength, interval, operation, directReceiver,
listenerTag, flags, workSource, alarmClock, callingUid, callingPackage,
idleOptions);
idleOptions, exactAllowReason);
}
@Override
@@ -3501,8 +3524,8 @@ public class AlarmManagerService extends SystemService {
private static native int setKernelTimezone(long nativeData, int minuteswest);
private static native long getNextAlarm(long nativeData, int type);
boolean triggerAlarmsLocked(ArrayList<Alarm> triggerList, final long nowELAPSED) {
boolean hasWakeup = false;
int triggerAlarmsLocked(ArrayList<Alarm> triggerList, final long nowELAPSED) {
int wakeUps = 0;
final ArrayList<Alarm> pendingAlarms = mAlarmStore.removePendingAlarms(nowELAPSED);
for (final Alarm alarm : pendingAlarms) {
if (isBackgroundRestricted(alarm)) {
@@ -3559,11 +3582,11 @@ public class AlarmManagerService extends SystemService {
setImplLocked(alarm.type, alarm.origWhen + delta, nextElapsed,
nextMaxElapsed - nextElapsed, alarm.repeatInterval, alarm.operation, null,
null, alarm.flags, alarm.workSource, alarm.alarmClock, alarm.uid,
alarm.packageName, null);
alarm.packageName, null, EXACT_ALLOW_REASON_NOT_APPLICABLE);
}
if (alarm.wakeup) {
hasWakeup = true;
wakeUps++;
}
// We removed an alarm clock. Let the caller recompute the next alarm clock.
@@ -3584,7 +3607,7 @@ public class AlarmManagerService extends SystemService {
}
}
return hasWakeup;
return wakeUps;
}
long currentNonWakeupFuzzLocked(long nowELAPSED) {
@@ -3843,8 +3866,8 @@ public class AlarmManagerService extends SystemService {
}
mLastTrigger = nowELAPSED;
boolean hasWakeup = triggerAlarmsLocked(triggerList, nowELAPSED);
if (!hasWakeup && checkAllowNonWakeupDelayLocked(nowELAPSED)) {
final int wakeUps = triggerAlarmsLocked(triggerList, nowELAPSED);
if (wakeUps == 0 && checkAllowNonWakeupDelayLocked(nowELAPSED)) {
// if there are no wakeup alarms and the screen is off, we can
// delay what we have so far until the future.
if (mPendingNonWakeupAlarms.size() == 0) {
@@ -3896,6 +3919,7 @@ public class AlarmManagerService extends SystemService {
reorderAlarmsBasedOnStandbyBuckets(triggerPackages);
rescheduleKernelAlarmsLocked();
updateNextAlarmClockLocked();
MetricsHelper.pushAlarmBatchDelivered(triggerList.size(), wakeUps);
}
}
@@ -4126,7 +4150,7 @@ public class AlarmManagerService extends SystemService {
setImpl(ELAPSED_REALTIME, mInjector.getElapsedRealtime() + tickEventDelay, 0,
0, null, mTimeTickTrigger, TIME_TICK_TAG, flags, workSource, null,
Process.myUid(), "android", null);
Process.myUid(), "android", null, EXACT_ALLOW_REASON_ALLOW_LIST);
// Finally, remember when we set the tick alarm
synchronized (mLock) {
@@ -4146,7 +4170,7 @@ public class AlarmManagerService extends SystemService {
final WorkSource workSource = null; // Let system take blame for date change events.
setImpl(RTC, calendar.getTimeInMillis(), 0, 0, mDateChangeSender, null, null,
AlarmManager.FLAG_STANDALONE, workSource, null,
Process.myUid(), "android", null);
Process.myUid(), "android", null, EXACT_ALLOW_REASON_ALLOW_LIST);
}
}

View File

@@ -138,6 +138,11 @@ public interface AlarmStore {
*/
String getName();
/**
* Returns the number of alarms that satisfy the given condition.
*/
int getCount(Predicate<Alarm> condition);
/**
* A functional interface used to update the alarm. Used to describe the update in
* {@link #updateAlarmDeliveries(AlarmDeliveryCalculator)}
@@ -153,4 +158,3 @@ public interface AlarmStore {
boolean updateAlarmDelivery(Alarm a);
}
}

View File

@@ -17,7 +17,6 @@
package com.android.server.alarm;
import static com.android.server.alarm.AlarmManagerService.DEBUG_BATCH;
import static com.android.server.alarm.AlarmManagerService.TAG;
import static com.android.server.alarm.AlarmManagerService.clampPositive;
import static com.android.server.alarm.AlarmManagerService.dumpAlarmList;
import static com.android.server.alarm.AlarmManagerService.isTimeTickAlarm;
@@ -50,10 +49,12 @@ public class BatchingAlarmStore implements AlarmStore {
interface Stats {
int REBATCH_ALL_ALARMS = 0;
int GET_COUNT = 1;
}
final StatLogger mStatLogger = new StatLogger(TAG + " stats", new String[]{
"REBATCH_ALL_ALARMS",
"GET_COUNT",
});
private static final Comparator<Batch> sBatchOrder = Comparator.comparingLong(b -> b.mStart);
@@ -219,6 +220,22 @@ public class BatchingAlarmStore implements AlarmStore {
return TAG;
}
@Override
public int getCount(Predicate<Alarm> condition) {
long start = mStatLogger.getTime();
int count = 0;
for (Batch b : mAlarmBatches) {
for (int i = 0; i < b.size(); i++) {
if (condition.test(b.get(i))) {
count++;
}
}
}
mStatLogger.logDurationStat(Stats.GET_COUNT, start);
return count;
}
private void insertAndBatchAlarm(Alarm alarm) {
final int whichBatch = ((alarm.flags & AlarmManager.FLAG_STANDALONE) != 0) ? -1
: attemptCoalesce(alarm.getWhenElapsed(), alarm.getMaxWhenElapsed());

View File

@@ -47,11 +47,13 @@ public class LazyAlarmStore implements AlarmStore {
interface Stats {
int GET_NEXT_DELIVERY_TIME = 0;
int GET_NEXT_WAKEUP_DELIVERY_TIME = 1;
int GET_COUNT = 2;
}
final StatLogger mStatLogger = new StatLogger(TAG + " stats", new String[]{
"GET_NEXT_DELIVERY_TIME",
"GET_NEXT_WAKEUP_DELIVERY_TIME",
"GET_COUNT",
});
// Decreasing time order because it is more efficient to remove from the tail of an array list.
@@ -221,4 +223,18 @@ public class LazyAlarmStore implements AlarmStore {
public String getName() {
return TAG;
}
@Override
public int getCount(Predicate<Alarm> condition) {
long start = mStatLogger.getTime();
int count = 0;
for (final Alarm a : mAlarms) {
if (condition.test(a)) {
count++;
}
}
mStatLogger.logDurationStat(Stats.GET_COUNT, start);
return count;
}
}

View File

@@ -0,0 +1,105 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
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__NOT_APPLICABLE;
import static com.android.internal.util.FrameworkStatsLog.ALARM_SCHEDULED__EXACT_ALARM_ALLOWED_REASON__PERMISSION;
import static com.android.server.alarm.AlarmManagerService.INDEFINITE_DELAY;
import android.app.AlarmManager;
import android.app.StatsManager;
import android.content.Context;
import android.os.SystemClock;
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.FrameworkStatsLog;
/**
* A helper class to write logs to statsd.
*/
class MetricsHelper {
private Context mContext;
MetricsHelper(Context context) {
mContext = context;
}
void registerPuller(AlarmStore alarmStore) {
final StatsManager statsManager = mContext.getSystemService(StatsManager.class);
statsManager.setPullAtomCallback(FrameworkStatsLog.PENDING_ALARM_INFO, null,
BackgroundThread.getExecutor(), (atomTag, data) -> {
if (atomTag != FrameworkStatsLog.PENDING_ALARM_INFO) {
throw new UnsupportedOperationException("Unknown tag" + atomTag);
}
final long now = SystemClock.elapsedRealtime();
data.add(FrameworkStatsLog.buildStatsEvent(atomTag,
alarmStore.size(),
alarmStore.getCount(a -> a.windowLength == 0),
alarmStore.getCount(a -> a.wakeup),
alarmStore.getCount(
a -> (a.flags & AlarmManager.FLAG_ALLOW_WHILE_IDLE) != 0),
alarmStore.getCount(a -> (a.flags & AlarmManager.FLAG_PRIORITIZE) != 0),
alarmStore.getCount(a -> (a.operation != null
&& a.operation.isForegroundService())),
alarmStore.getCount(
a -> (a.operation != null && a.operation.isActivity())),
alarmStore.getCount(
a -> (a.operation != null && a.operation.isService())),
alarmStore.getCount(a -> (a.listener != null)),
alarmStore.getCount(
a -> (a.getRequestedElapsed() > now + INDEFINITE_DELAY)),
alarmStore.getCount(a -> (a.repeatInterval != 0)),
alarmStore.getCount(a -> (a.alarmClock != null))
));
return StatsManager.PULL_SUCCESS;
});
}
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_COMPAT:
return ALARM_SCHEDULED__EXACT_ALARM_ALLOWED_REASON__CHANGE_DISABLED;
default:
return ALARM_SCHEDULED__EXACT_ALARM_ALLOWED_REASON__NOT_APPLICABLE;
}
}
static void pushAlarmScheduled(Alarm a) {
FrameworkStatsLog.write(
FrameworkStatsLog.ALARM_SCHEDULED,
a.uid,
a.windowLength == 0,
a.wakeup,
(a.flags & AlarmManager.FLAG_ALLOW_WHILE_IDLE) != 0,
a.alarmClock != null,
a.repeatInterval != 0,
reasonToStatsReason(a.mExactAllowReason));
}
static void pushAlarmBatchDelivered(int numAlarms, int wakeups) {
FrameworkStatsLog.write(
FrameworkStatsLog.ALARM_BATCH_DELIVERED,
numAlarms,
wakeups);
}
}

View File

@@ -51,6 +51,10 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSess
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
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_NOT_APPLICABLE;
import static com.android.server.alarm.Alarm.EXACT_ALLOW_REASON_PERMISSION;
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.CHARGING_STATUS_CHANGED;
@@ -359,6 +363,7 @@ public class AlarmManagerServiceTest {
.spyStatic(DeviceConfig.class)
.mockStatic(LocalServices.class)
.spyStatic(Looper.class)
.mockStatic(MetricsHelper.class)
.mockStatic(Settings.Global.class)
.mockStatic(ServiceManager.class)
.spyStatic(UserHandle.class)
@@ -418,6 +423,9 @@ public class AlarmManagerServiceTest {
spyOn(mService);
mService.onStart();
// Unable to mock mMockContext to return a mock stats manager.
// So just mocking the whole MetricsHelper instance.
mService.mMetricsHelper = mock(MetricsHelper.class);
spyOn(mService.mHandler);
// Stubbing the handler. Test should simulate any handling of messages synchronously.
doReturn(true).when(mService.mHandler).sendMessageAtTime(any(Message.class), anyLong());
@@ -492,7 +500,7 @@ public class AlarmManagerServiceTest {
IAlarmListener listener) {
mService.setImpl(type, triggerTime, windowLength, 0, null, listener, "test",
FLAG_STANDALONE | FLAG_PRIORITIZE, null, null, TEST_CALLING_UID,
TEST_CALLING_PACKAGE, null);
TEST_CALLING_PACKAGE, null, 0);
}
private void setAllowWhileIdleAlarm(int type, long triggerTime, PendingIntent pi,
@@ -516,12 +524,12 @@ public class AlarmManagerServiceTest {
PendingIntent operation, long interval, int flags, int callingUid,
String callingPackage, Bundle idleOptions) {
mService.setImpl(type, triggerTime, windowLength, interval, operation, null, "test", flags,
null, null, callingUid, callingPackage, idleOptions);
null, null, callingUid, callingPackage, idleOptions, 0);
}
private void setTestAlarmWithListener(int type, long triggerTime, IAlarmListener listener) {
mService.setImpl(type, triggerTime, WINDOW_EXACT, 0, null, listener, "test",
FLAG_STANDALONE, null, null, TEST_CALLING_UID, TEST_CALLING_PACKAGE, null);
FLAG_STANDALONE, null, null, TEST_CALLING_UID, TEST_CALLING_PACKAGE, null, 0);
}
@@ -1898,7 +1906,8 @@ public class AlarmManagerServiceTest {
verify(mService).setImpl(eq(ELAPSED_REALTIME_WAKEUP), eq(1234L), eq(WINDOW_EXACT), eq(0L),
eq(alarmPi), isNull(), isNull(),
eq(FLAG_STANDALONE), isNull(), isNull(),
eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE), isNull());
eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE), isNull(),
eq(EXACT_ALLOW_REASON_COMPAT));
}
@Test
@@ -1915,7 +1924,8 @@ public class AlarmManagerServiceTest {
verify(mService).setImpl(eq(ELAPSED_REALTIME_WAKEUP), eq(1234L), eq(WINDOW_EXACT), eq(0L),
eq(alarmPi), isNull(), isNull(),
eq(FLAG_ALLOW_WHILE_IDLE_COMPAT | FLAG_STANDALONE), isNull(), isNull(),
eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE), bundleCaptor.capture());
eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE), bundleCaptor.capture(),
eq(EXACT_ALLOW_REASON_COMPAT));
final BroadcastOptions idleOptions = new BroadcastOptions(bundleCaptor.getValue());
final int type = idleOptions.getTemporaryAppAllowlistType();
@@ -1935,7 +1945,8 @@ public class AlarmManagerServiceTest {
final ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
verify(mService).setImpl(eq(ELAPSED_REALTIME_WAKEUP), eq(1234L), anyLong(), eq(0L),
eq(alarmPi), isNull(), isNull(), eq(FLAG_ALLOW_WHILE_IDLE_COMPAT), isNull(),
isNull(), eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE), bundleCaptor.capture());
isNull(), eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE), bundleCaptor.capture(),
eq(EXACT_ALLOW_REASON_NOT_APPLICABLE));
final BroadcastOptions idleOptions = new BroadcastOptions(bundleCaptor.getValue());
final int type = idleOptions.getTemporaryAppAllowlistType();
@@ -1955,7 +1966,8 @@ public class AlarmManagerServiceTest {
verify(mService).setImpl(eq(RTC_WAKEUP), eq(1234L), eq(WINDOW_EXACT), eq(0L),
eq(alarmPi), isNull(), isNull(), eq(FLAG_STANDALONE | FLAG_WAKE_FROM_IDLE),
isNull(), eq(alarmClock), eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE), isNull());
isNull(), eq(alarmClock), eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE), isNull(),
eq(EXACT_ALLOW_REASON_COMPAT));
}
@Test
@@ -1979,7 +1991,7 @@ public class AlarmManagerServiceTest {
verify(mService).setImpl(eq(RTC_WAKEUP), eq(1234L), eq(WINDOW_EXACT), eq(0L),
eq(alarmPi), isNull(), isNull(), eq(FLAG_STANDALONE | FLAG_WAKE_FROM_IDLE),
isNull(), eq(alarmClock), eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE),
bundleCaptor.capture());
bundleCaptor.capture(), eq(EXACT_ALLOW_REASON_PERMISSION));
final BroadcastOptions idleOptions = new BroadcastOptions(bundleCaptor.getValue());
final int type = idleOptions.getTemporaryAppAllowlistType();
@@ -2042,7 +2054,8 @@ public class AlarmManagerServiceTest {
verify(mService).setImpl(eq(ELAPSED_REALTIME_WAKEUP), eq(1234L), eq(WINDOW_EXACT), eq(0L),
eq(alarmPi), isNull(), isNull(),
eq(FLAG_STANDALONE), isNull(), isNull(),
eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE), bundleCaptor.capture());
eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE), bundleCaptor.capture(),
eq(EXACT_ALLOW_REASON_PERMISSION));
final BroadcastOptions idleOptions = new BroadcastOptions(bundleCaptor.getValue());
final int type = idleOptions.getTemporaryAppAllowlistType();
@@ -2067,7 +2080,8 @@ public class AlarmManagerServiceTest {
verify(mService).setImpl(eq(ELAPSED_REALTIME_WAKEUP), eq(1234L), eq(WINDOW_EXACT), eq(0L),
eq(alarmPi), isNull(), isNull(),
eq(FLAG_STANDALONE), isNull(), isNull(),
eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE), isNull());
eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE), isNull(),
eq(EXACT_ALLOW_REASON_ALLOW_LIST));
}
@Test
@@ -2087,7 +2101,8 @@ public class AlarmManagerServiceTest {
verify(mService).setImpl(eq(ELAPSED_REALTIME_WAKEUP), eq(1234L), eq(WINDOW_EXACT), eq(0L),
eq(alarmPi), isNull(), isNull(),
eq(FLAG_ALLOW_WHILE_IDLE | FLAG_STANDALONE), isNull(), isNull(),
eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE), bundleCaptor.capture());
eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE), bundleCaptor.capture(),
eq(EXACT_ALLOW_REASON_PERMISSION));
final BroadcastOptions idleOptions = new BroadcastOptions(bundleCaptor.getValue());
final int type = idleOptions.getTemporaryAppAllowlistType();
@@ -2113,7 +2128,8 @@ public class AlarmManagerServiceTest {
verify(mService).setImpl(eq(ELAPSED_REALTIME_WAKEUP), eq(1234L), eq(WINDOW_EXACT), eq(0L),
eq(alarmPi), isNull(), isNull(),
eq(FLAG_ALLOW_WHILE_IDLE_COMPAT | FLAG_STANDALONE), isNull(), isNull(),
eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE), bundleCaptor.capture());
eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE), bundleCaptor.capture(),
eq(EXACT_ALLOW_REASON_ALLOW_LIST));
final BroadcastOptions idleOptions = new BroadcastOptions(bundleCaptor.getValue());
final int type = idleOptions.getTemporaryAppAllowlistType();
@@ -2167,7 +2183,8 @@ public class AlarmManagerServiceTest {
final ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
verify(mService).setImpl(eq(ELAPSED_REALTIME_WAKEUP), eq(4321L), anyLong(), eq(0L),
eq(alarmPi), isNull(), isNull(), eq(FLAG_ALLOW_WHILE_IDLE_COMPAT), isNull(),
isNull(), eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE), bundleCaptor.capture());
isNull(), eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE), bundleCaptor.capture(),
eq(EXACT_ALLOW_REASON_NOT_APPLICABLE));
final BroadcastOptions idleOptions = new BroadcastOptions(bundleCaptor.getValue());
final int type = idleOptions.getTemporaryAppAllowlistType();
@@ -2192,7 +2209,8 @@ public class AlarmManagerServiceTest {
verify(mService).setImpl(eq(ELAPSED_REALTIME_WAKEUP), eq(1234L), eq(WINDOW_EXACT), eq(0L),
eq(alarmPi), isNull(), isNull(),
eq(FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED | FLAG_STANDALONE), isNull(), isNull(),
eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE), isNull());
eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE), isNull(),
eq(EXACT_ALLOW_REASON_ALLOW_LIST));
}
@Test
@@ -2492,6 +2510,28 @@ public class AlarmManagerServiceTest {
assertEquals(new ArraySet<>(appIds), mService.mExactAlarmCandidates);
}
@Test
public void alarmScheduledAtomPushed() {
for (int i = 0; i < 10; i++) {
final PendingIntent pi = getNewMockPendingIntent();
setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + i, pi);
verify(() -> MetricsHelper.pushAlarmScheduled(argThat(a -> a.matches(pi, null))));
}
}
@Test
public void alarmBatchDeliveredAtomPushed() throws InterruptedException {
for (int i = 0; i < 10; i++) {
final int type = ((i & 1) == 0) ? ELAPSED_REALTIME : ELAPSED_REALTIME_WAKEUP;
setTestAlarm(type, mNowElapsedTest + i, getNewMockPendingIntent());
}
mNowElapsedTest += 100;
mTestTimer.expire();
verify(() -> MetricsHelper.pushAlarmBatchDelivered(10, 5));
}
@After
public void tearDown() {
if (mMockingSession != null) {

View File

@@ -18,7 +18,10 @@ package com.android.server.alarm;
import static android.app.AlarmManager.ELAPSED_REALTIME;
import static android.app.AlarmManager.ELAPSED_REALTIME_WAKEUP;
import static android.app.AlarmManager.RTC;
import static android.app.AlarmManager.RTC_WAKEUP;
import static com.android.server.alarm.Alarm.EXACT_ALLOW_REASON_NOT_APPLICABLE;
import static com.android.server.alarm.Constants.TEST_CALLING_PACKAGE;
import static com.android.server.alarm.Constants.TEST_CALLING_UID;
@@ -33,6 +36,7 @@ import android.app.AlarmManager;
import android.app.PendingIntent;
import android.platform.test.annotations.Presubmit;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -69,12 +73,13 @@ public class AlarmStoreTest {
mock(PendingIntent.class));
return new Alarm(ELAPSED_REALTIME_WAKEUP, whenElapsed, whenElapsed, 0, 0,
mock(PendingIntent.class), null, null, null, 0, info, TEST_CALLING_UID,
TEST_CALLING_PACKAGE, null);
TEST_CALLING_PACKAGE, null, EXACT_ALLOW_REASON_NOT_APPLICABLE);
}
private static Alarm createAlarm(int type, long whenElapsed, long windowLength, int flags) {
return new Alarm(type, whenElapsed, whenElapsed, windowLength, 0, mock(PendingIntent.class),
null, null, null, flags, null, TEST_CALLING_UID, TEST_CALLING_PACKAGE, null);
null, null, null, flags, null, TEST_CALLING_UID, TEST_CALLING_PACKAGE, null,
EXACT_ALLOW_REASON_NOT_APPLICABLE);
}
private void addAlarmsToStore(Alarm... alarms) {
@@ -83,6 +88,11 @@ public class AlarmStoreTest {
}
}
@Before
public void clear() {
mAlarmStore.remove(unused -> true);
}
@Test
public void add() {
final Alarm a1 = createAlarm(1, 0);
@@ -209,7 +219,6 @@ public class AlarmStoreTest {
final Alarm a8 = createAlarm(8, 0);
final Alarm a10 = createAlarm(10, 0);
addAlarmsToStore(a8, a10, a5);
assertEquals(5, mAlarmStore.getNextDeliveryTime());
mAlarmStore.updateAlarmDeliveries(a -> {
@@ -241,4 +250,22 @@ public class AlarmStoreTest {
mAlarmStore.remove(alarmClock::equals);
verify(onRemoved).run();
}
@Test
public void getCount() {
for (int i = 0; i < 10; i++) {
mAlarmStore.add(createAlarm(ELAPSED_REALTIME, i, 4, 0));
}
assertEquals(5, mAlarmStore.getCount(a -> a.getRequestedElapsed() < 5));
assertEquals(10, mAlarmStore.getCount(a -> a.windowLength == 4));
addAlarmsToStore(
createAlarm(RTC_WAKEUP, 45, 0, 53),
createAlarm(ELAPSED_REALTIME_WAKEUP, 60, 0, 53)
);
assertEquals(2, mAlarmStore.getCount(a -> a.wakeup));
assertEquals(2, mAlarmStore.getCount(a -> a.flags == 53));
assertEquals(0, mAlarmStore.getCount(a -> a.type == RTC));
}
}

View File

@@ -55,14 +55,14 @@ public class AlarmTest {
private Alarm createDefaultAlarm(long requestedElapsed, long windowLength, int flags) {
return new Alarm(ELAPSED_REALTIME, 0, requestedElapsed, windowLength, 0,
createAlarmSender(), null, null, null, flags, null, TEST_CALLING_UID,
TEST_CALLING_PACKAGE, null);
TEST_CALLING_PACKAGE, null, 0);
}
private Alarm createAlarmClock(long requestedRtc) {
final AlarmManager.AlarmClockInfo info = mock(AlarmManager.AlarmClockInfo.class);
return new Alarm(RTC_WAKEUP, requestedRtc, requestedRtc, 0, 0, createAlarmSender(),
null, null, null, FLAG_WAKE_FROM_IDLE | FLAG_STANDALONE, info, TEST_CALLING_UID,
TEST_CALLING_PACKAGE, null);
TEST_CALLING_PACKAGE, null, 0);
}
private PendingIntent createAlarmSender() {

View File

@@ -45,7 +45,7 @@ public class BackgroundRestrictedAlarmsTest {
}
uidAlarms.add(new Alarm(
removeIt ? RTC : RTC_WAKEUP,
0, 0, 0, 0, null, null, null, null, 0, null, uid, name, null));
0, 0, 0, 0, null, null, null, null, 0, null, uid, name, null, 0));
return all;
}