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 com.android.server.alarm;
18 
19 import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR;
20 import static com.android.internal.util.FrameworkStatsLog.ALARM_SCHEDULED__EXACT_ALARM_ALLOWED_REASON__ALLOW_LIST;
21 import static com.android.internal.util.FrameworkStatsLog.ALARM_SCHEDULED__EXACT_ALARM_ALLOWED_REASON__CHANGE_DISABLED;
22 import static com.android.internal.util.FrameworkStatsLog.ALARM_SCHEDULED__EXACT_ALARM_ALLOWED_REASON__LISTENER;
23 import static com.android.internal.util.FrameworkStatsLog.ALARM_SCHEDULED__EXACT_ALARM_ALLOWED_REASON__NOT_APPLICABLE;
24 import static com.android.internal.util.FrameworkStatsLog.ALARM_SCHEDULED__EXACT_ALARM_ALLOWED_REASON__PERMISSION;
25 import static com.android.internal.util.FrameworkStatsLog.ALARM_SCHEDULED__EXACT_ALARM_ALLOWED_REASON__POLICY_PERMISSION;
26 import static com.android.internal.util.FrameworkStatsLog.ALARM_SCHEDULED__EXACT_ALARM_ALLOWED_REASON__PRIORITIZED;
27 import static com.android.server.alarm.AlarmManagerService.INDEFINITE_DELAY;
28 
29 import android.app.ActivityManager;
30 import android.app.AlarmManager;
31 import android.app.StatsManager;
32 import android.content.Context;
33 import android.os.SystemClock;
34 
35 import com.android.internal.util.FrameworkStatsLog;
36 
37 import java.util.function.Supplier;
38 
39 /**
40  * A helper class to write logs to statsd.
41  */
42 class MetricsHelper {
43     private final Context mContext;
44     private final Object mLock;
45 
MetricsHelper(Context context, Object lock)46     MetricsHelper(Context context, Object lock) {
47         mContext = context;
48         mLock = lock;
49     }
50 
registerPuller(Supplier<AlarmStore> alarmStoreSupplier)51     void registerPuller(Supplier<AlarmStore> alarmStoreSupplier) {
52         final StatsManager statsManager = mContext.getSystemService(StatsManager.class);
53         statsManager.setPullAtomCallback(FrameworkStatsLog.PENDING_ALARM_INFO, null,
54                 DIRECT_EXECUTOR, (atomTag, data) -> {
55                     if (atomTag != FrameworkStatsLog.PENDING_ALARM_INFO) {
56                         throw new UnsupportedOperationException("Unknown tag" + atomTag);
57                     }
58                     final long now = SystemClock.elapsedRealtime();
59                     synchronized (mLock) {
60                         final AlarmStore alarmStore = alarmStoreSupplier.get();
61                         data.add(FrameworkStatsLog.buildStatsEvent(atomTag,
62                                 alarmStore.size(),
63                                 alarmStore.getCount(a -> a.windowLength == 0),
64                                 alarmStore.getCount(a -> a.wakeup),
65                                 alarmStore.getCount(
66                                         a -> (a.flags & AlarmManager.FLAG_ALLOW_WHILE_IDLE) != 0),
67                                 alarmStore.getCount(
68                                         a -> (a.flags & AlarmManager.FLAG_PRIORITIZE) != 0),
69                                 alarmStore.getCount(a -> (a.operation != null
70                                         && a.operation.isForegroundService())),
71                                 alarmStore.getCount(
72                                         a -> (a.operation != null && a.operation.isActivity())),
73                                 alarmStore.getCount(
74                                         a -> (a.operation != null && a.operation.isService())),
75                                 alarmStore.getCount(a -> (a.listener != null)),
76                                 alarmStore.getCount(
77                                         a -> (a.getRequestedElapsed() > now + INDEFINITE_DELAY)),
78                                 alarmStore.getCount(a -> (a.repeatInterval != 0)),
79                                 alarmStore.getCount(a -> (a.alarmClock != null)),
80                                 alarmStore.getCount(a -> AlarmManagerService.isRtc(a.type))
81                         ));
82                         return StatsManager.PULL_SUCCESS;
83                     }
84                 });
85     }
86 
reasonToStatsReason(int reasonCode)87     private static int reasonToStatsReason(int reasonCode) {
88         switch (reasonCode) {
89             case Alarm.EXACT_ALLOW_REASON_PERMISSION:
90                 return ALARM_SCHEDULED__EXACT_ALARM_ALLOWED_REASON__PERMISSION;
91             case Alarm.EXACT_ALLOW_REASON_ALLOW_LIST:
92                 return ALARM_SCHEDULED__EXACT_ALARM_ALLOWED_REASON__ALLOW_LIST;
93             case Alarm.EXACT_ALLOW_REASON_COMPAT:
94                 return ALARM_SCHEDULED__EXACT_ALARM_ALLOWED_REASON__CHANGE_DISABLED;
95             case Alarm.EXACT_ALLOW_REASON_POLICY_PERMISSION:
96                 return ALARM_SCHEDULED__EXACT_ALARM_ALLOWED_REASON__POLICY_PERMISSION;
97             case Alarm.EXACT_ALLOW_REASON_LISTENER:
98                 return ALARM_SCHEDULED__EXACT_ALARM_ALLOWED_REASON__LISTENER;
99             case Alarm.EXACT_ALLOW_REASON_PRIORITIZED:
100                 return ALARM_SCHEDULED__EXACT_ALARM_ALLOWED_REASON__PRIORITIZED;
101             default:
102                 return ALARM_SCHEDULED__EXACT_ALARM_ALLOWED_REASON__NOT_APPLICABLE;
103         }
104     }
105 
pushAlarmScheduled(Alarm a, int callerProcState)106     static void pushAlarmScheduled(Alarm a, int callerProcState) {
107         FrameworkStatsLog.write(
108                 FrameworkStatsLog.ALARM_SCHEDULED,
109                 a.uid,
110                 a.windowLength == 0,
111                 a.wakeup,
112                 (a.flags & AlarmManager.FLAG_ALLOW_WHILE_IDLE) != 0,
113                 a.alarmClock != null,
114                 a.repeatInterval != 0,
115                 reasonToStatsReason(a.exactAllowReason),
116                 AlarmManagerService.isRtc(a.type),
117                 ActivityManager.processStateAmToProto(callerProcState));
118     }
119 
pushAlarmBatchDelivered( int numAlarms, int wakeups, int[] uids, int[] alarmsPerUid, int[] wakeupAlarmsPerUid)120     static void pushAlarmBatchDelivered(
121             int numAlarms, int wakeups, int[] uids, int[] alarmsPerUid, int[] wakeupAlarmsPerUid) {
122         FrameworkStatsLog.write(
123                 FrameworkStatsLog.ALARM_BATCH_DELIVERED,
124                 numAlarms,
125                 wakeups,
126                 uids,
127                 alarmsPerUid,
128                 wakeupAlarmsPerUid);
129     }
130 }
131