diff options
| author | 2021-04-27 07:27:06 +0000 | |
|---|---|---|
| committer | 2021-04-27 07:27:06 +0000 | |
| commit | 36cb0aa1e178d73df05ecbb0e3ab144982b485a6 (patch) | |
| tree | 7a3b47d7ff9018476e8cec13af56ff1269a9dab5 | |
| parent | e704f71c9a0144eed99659703deaa27048146f23 (diff) | |
| parent | 1d5ea8c336fde11c959efcefb8bca822e91776cf (diff) | |
Merge "Adding metrics to alarm manager" into sc-dev
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; } |