• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.alarmmanager.cts;
18 
19 import android.app.AlarmManager;
20 import android.app.PendingIntent;
21 import android.content.BroadcastReceiver;
22 import android.content.Context;
23 import android.content.Intent;
24 import android.os.SystemClock;
25 import android.util.Log;
26 
27 import androidx.annotation.GuardedBy;
28 import androidx.test.InstrumentationRegistry;
29 
30 import java.io.File;
31 import java.util.function.LongConsumer;
32 
33 public class AlarmReceiver extends BroadcastReceiver {
34     private static final String TAG = AlarmReceiver.class.getSimpleName();
35     private static final String ALARM_ACTION = "android.alarmmanager.cts.ALARM";
36     private static final String EXTRA_ALARM_ID = "android.alarmmanager.cts.extra.ALARM_ID";
37     private static final String EXTRA_QUOTAED = "android.alarmmanager.cts.extra.QUOTAED";
38 
39     private static final Context sContext = InstrumentationRegistry.getTargetContext();
40     /** Package global history of quotaed alarms received -- useful in quota calculations */
41     private static final PersistableEventHistory sHistory = new PersistableEventHistory(
42             new File(sContext.getFilesDir(), "alarm-history.xml"));
43     /** Listener alarms or older apps use a lower quota that is managed separately **/
44     private static final PersistableEventHistory sCompatHistory = new PersistableEventHistory(
45             new File(sContext.getFilesDir(), "alarm-compat-history.xml"));
46 
47     private static Object sWaitLock = new Object();
48     @GuardedBy("sWaitLock")
49     private static int sLastAlarmId;
50 
onAlarm(int id, LongConsumer historyRecorder)51     static void onAlarm(int id, LongConsumer historyRecorder) {
52         Log.d(TAG, "Alarm " + id + " received");
53 
54         historyRecorder.accept(SystemClock.elapsedRealtime());
55         synchronized (sWaitLock) {
56             sLastAlarmId = id;
57             sWaitLock.notifyAll();
58         }
59     }
60 
createListener(int id, boolean quotaed)61     static AlarmManager.OnAlarmListener createListener(int id, boolean quotaed) {
62         return () -> onAlarm(id, quotaed ? sCompatHistory::recordLatestEvent : (t -> {}));
63     }
64 
getAlarmSender(int id, boolean quotaed)65     static PendingIntent getAlarmSender(int id, boolean quotaed) {
66         final Intent alarmAction = new Intent(ALARM_ACTION)
67                 .setClass(sContext, AlarmReceiver.class)
68                 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
69                 .putExtra(EXTRA_ALARM_ID, id)
70                 .putExtra(EXTRA_QUOTAED, quotaed);
71         return PendingIntent.getBroadcast(sContext, 0, alarmAction,
72                 PendingIntent.FLAG_MUTABLE | PendingIntent.FLAG_UPDATE_CURRENT);
73     }
74 
75     @Override
onReceive(Context context, Intent intent)76     public void onReceive(Context context, Intent intent) {
77         if (ALARM_ACTION.equals(intent.getAction())) {
78             final int id = intent.getIntExtra(EXTRA_ALARM_ID, -1);
79             final boolean quotaed = intent.getBooleanExtra(EXTRA_QUOTAED, false);
80             onAlarm(id, quotaed ? sHistory::recordLatestEvent : (t -> {}));
81         }
82     }
83 
getNthLastAlarmTime(int n)84     static long getNthLastAlarmTime(int n) {
85         return sHistory.getNthLastEventTime(n);
86     }
87 
getNthLastCompatAlarmTime(int n)88     static long getNthLastCompatAlarmTime(int n) {
89         return sCompatHistory.getNthLastEventTime(n);
90     }
91 
waitForAlarm(int alarmId, long timeOut)92     static boolean waitForAlarm(int alarmId, long timeOut) throws InterruptedException {
93         final long deadline = SystemClock.elapsedRealtime() + timeOut;
94         synchronized (sWaitLock) {
95             while (sLastAlarmId != alarmId && SystemClock.elapsedRealtime() < deadline) {
96                 sWaitLock.wait(timeOut);
97             }
98             return sLastAlarmId == alarmId;
99         }
100     }
101 
102     /**
103      * Used to dump debugging information when the test fails.
104      */
dumpState()105     static void dumpState() {
106         synchronized (sWaitLock) {
107             Log.i(TAG, "Last alarm id: " + sLastAlarmId);
108         }
109         sHistory.dump("History of quotaed alarms");
110         sCompatHistory.dump("History of quotaed compat alarms");
111     }
112 }
113