1 /*
2  * Copyright (C) 2023 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.telephony.statslib;
18 
19 import android.app.StatsManager;
20 import android.content.Context;
21 import android.util.Log;
22 import android.util.StatsEvent;
23 
24 import java.util.ArrayList;
25 import java.util.HashMap;
26 import java.util.List;
27 import java.util.concurrent.Executor;
28 
29 /**
30  * StatsLibPulledAtomCallback class
31  *
32  * <p>This class registers to statsd. Called once a day for this class pull stat to send to statsd.
33  */
34 class StatsLibPulledAtomCallback implements StatsManager.StatsPullAtomCallback {
35 
36     private static final String LOG_TAG = StatsLibPulledAtomCallback.class.getSimpleName();
37     private static final boolean DBG = true;
38     private static final StatsManager.PullAtomMetadata POLICY_PULL_DAILY =
39             new StatsManager.PullAtomMetadata.Builder()
40                     .setCoolDownMillis(5L)
41                     .setTimeoutMillis(2L)
42                     .build();
43     private final StatsManager mStatsManager;
44     private final StatsLibStorage mStatsLibStorage;
45     private final HashMap<Integer, PulledCallback> mRegisteredCallback;
46 
47     /**
48      * Constructor of StatsLibPulledAtomCallback
49      *
50      * @param context Context
51      */
StatsLibPulledAtomCallback(Context context)52     StatsLibPulledAtomCallback(Context context) {
53         mRegisteredCallback = new HashMap<>();
54         mStatsLibStorage = new StatsLibStorage(context);
55         mStatsManager = context.getSystemService(StatsManager.class);
56         log("created StatsLibPulledAtomCallback.");
57     }
58 
59     /** get a StatsLibStorage, which stores pulled atoms */
getStatsLibStorage()60     StatsLibStorage getStatsLibStorage() {
61         return mStatsLibStorage;
62     }
63 
log(String s)64     private void log(String s) {
65         if (DBG) Log.d(LOG_TAG, s);
66     }
67 
68     /**
69      * Register a callback
70      *
71      * @param atomTag The tag of the atom for this puller callback.
72      */
registerAtom(int atomTag)73     void registerAtom(int atomTag) {
74         registerAtom(atomTag, new EmptyCallback());
75     }
76 
77     /**
78      * Register a callback
79      *
80      * @param atomTag The tag of the atom for this puller callback.
81      */
registerAtom(int atomTag, PulledCallback callback)82     void registerAtom(int atomTag, PulledCallback callback) {
83         if (!mRegisteredCallback.containsKey(atomTag)) {
84             mStatsLibStorage.init(atomTag);
85             mStatsLibStorage.loadFromFile(atomTag);
86             mStatsManager.setPullAtomCallback(
87                     atomTag, POLICY_PULL_DAILY, new MetricExecutor(), this);
88             mRegisteredCallback.put(atomTag, callback);
89         }
90     }
91 
92     /**
93      * is registered a callback
94      *
95      * @param atomTag The tag of the atom for this puller callback.
96      */
isRegisteredAtom(int atomTag)97     boolean isRegisteredAtom(int atomTag) {
98         return mRegisteredCallback.containsKey(atomTag);
99     }
100 
101     /**
102      * Register a callback
103      *
104      * @param atomTag The tag of the atom for this puller callback.
105      */
unregisterAtom(int atomTag)106     void unregisterAtom(int atomTag) {
107         if (mRegisteredCallback.containsKey(atomTag)) {
108             mStatsManager.clearPullAtomCallback(atomTag);
109             mRegisteredCallback.remove(atomTag);
110             mStatsLibStorage.saveToFile(atomTag);
111         }
112     }
113 
114     @Override
onPullAtom(int atomTag, List<StatsEvent> data)115     public int onPullAtom(int atomTag, List<StatsEvent> data) {
116         log("onPullAtom: atomTag:" + atomTag);
117         AtomsPulled[] arrayPulled = getStatsLibStorage().popPulledAtoms(atomTag);
118         for (AtomsPulled pulled : arrayPulled) {
119             final StatsEvent.Builder builder = StatsEvent.newBuilder();
120             builder.setAtomId(pulled.getStatsId());
121             pulled.build(builder);
122             data.add(builder.build());
123         }
124 
125         PulledCallback callback = mRegisteredCallback.get(atomTag);
126         if (callback == null) {
127             return StatsManager.PULL_SUCCESS;
128         }
129         List<AtomsPulled> list = new ArrayList<>();
130         callback.onPulledCallback(atomTag, list);
131         for (AtomsPulled pulled : list) {
132             final StatsEvent.Builder builder = StatsEvent.newBuilder();
133             builder.setAtomId(pulled.getStatsId());
134             pulled.build(builder);
135             data.add(builder.build());
136         }
137 
138         return StatsManager.PULL_SUCCESS;
139     }
140 
141     private static class MetricExecutor implements Executor {
142         @Override
execute(Runnable command)143         public void execute(Runnable command) {
144             command.run();
145         }
146 
147         @Override
toString()148         public String toString() {
149             return "METRIC_EXECUTOR";
150         }
151     }
152 
153     static class EmptyCallback implements PulledCallback {
onPulledCallback(int atomTag, List<AtomsPulled> data)154         public void onPulledCallback(int atomTag, List<AtomsPulled> data) {}
155     }
156 }
157