summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Suprabh Shukla <suprabh@google.com> 2021-04-27 07:27:06 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2021-04-27 07:27:06 +0000
commit36cb0aa1e178d73df05ecbb0e3ab144982b485a6 (patch)
tree7a3b47d7ff9018476e8cec13af56ff1269a9dab5
parente704f71c9a0144eed99659703deaa27048146f23 (diff)
parent1d5ea8c336fde11c959efcefb8bca822e91776cf (diff)
Merge "Adding metrics to alarm manager" into sc-dev
-rw-r--r--apex/jobscheduler/service/java/com/android/server/alarm/Alarm.java42
-rw-r--r--apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java58
-rw-r--r--apex/jobscheduler/service/java/com/android/server/alarm/AlarmStore.java6
-rw-r--r--apex/jobscheduler/service/java/com/android/server/alarm/BatchingAlarmStore.java19
-rw-r--r--apex/jobscheduler/service/java/com/android/server/alarm/LazyAlarmStore.java16
-rw-r--r--apex/jobscheduler/service/java/com/android/server/alarm/MetricsHelper.java105
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java68
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/alarm/AlarmStoreTest.java33
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/alarm/AlarmTest.java4
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/alarm/BackgroundRestrictedAlarmsTest.java2
10 files changed, 312 insertions, 41 deletions
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/Alarm.java b/apex/jobscheduler/service/java/com/android/server/alarm/Alarm.java
index 3bc7b307c334..9ffef9cdcbde 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/Alarm.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/Alarm.java
@@ -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=");
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
index e63a7c41ea98..5554ad27acd8 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
@@ -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);
}
}
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmStore.java b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmStore.java
index e684b84748b1..0172748a95fa 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmStore.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmStore.java
@@ -139,6 +139,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);
}
}
-
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/BatchingAlarmStore.java b/apex/jobscheduler/service/java/com/android/server/alarm/BatchingAlarmStore.java
index cb528ba2769a..1a4efb8ffcd9 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/BatchingAlarmStore.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/BatchingAlarmStore.java
@@ -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());
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/LazyAlarmStore.java b/apex/jobscheduler/service/java/com/android/server/alarm/LazyAlarmStore.java
index 9b1b06658a98..2e12e2f34ea0 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/LazyAlarmStore.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/LazyAlarmStore.java
@@ -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;
+ }
}
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/MetricsHelper.java b/apex/jobscheduler/service/java/com/android/server/alarm/MetricsHelper.java
new file mode 100644
index 000000000000..a8cf7b2ae3f8
--- /dev/null
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/MetricsHelper.java
@@ -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);
+ }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
index 683fbd17b78d..3bc1c8a4037d 100644
--- a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
@@ -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) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmStoreTest.java b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmStoreTest.java
index 12894ae4f75e..ba0e555020ac 100644
--- a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmStoreTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmStoreTest.java
@@ -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));
+ }
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmTest.java b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmTest.java
index b64528c2f4d4..f11cba0db7b9 100644
--- a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmTest.java
@@ -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() {
diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/BackgroundRestrictedAlarmsTest.java b/services/tests/mockingservicestests/src/com/android/server/alarm/BackgroundRestrictedAlarmsTest.java
index 0e795a938d48..403b4cd7e57e 100644
--- a/services/tests/mockingservicestests/src/com/android/server/alarm/BackgroundRestrictedAlarmsTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/alarm/BackgroundRestrictedAlarmsTest.java
@@ -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;
}