• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 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.telecom.metrics;
18 
19 import android.annotation.NonNull;
20 import android.app.StatsManager;
21 import android.content.Context;
22 import android.os.Handler;
23 import android.os.Looper;
24 import android.os.Message;
25 import android.telecom.Log;
26 import android.util.StatsEvent;
27 
28 import androidx.annotation.VisibleForTesting;
29 
30 import com.android.server.telecom.nano.PulledAtomsClass.PulledAtoms;
31 
32 import java.io.FileOutputStream;
33 import java.io.IOException;
34 import java.nio.file.Files;
35 import java.nio.file.NoSuchFileException;
36 import java.util.List;
37 
38 public abstract class TelecomPulledAtom extends Handler {
39     /**
40      * Min interval to persist the data.
41      */
42     protected static final int DELAY_FOR_PERSISTENT_MILLIS = 30000;
43     protected static final int EVENT_SUB_BASE = 1000;
44     private static final String TAG = TelecomPulledAtom.class.getSimpleName();
45     private static final long MIN_PULL_INTERVAL_MILLIS = 23L * 60 * 60 * 1000;
46     private static final int EVENT_SAVE = 1;
47     protected final Context mContext;
48     protected final boolean mIsTestMode;
49     @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
50     public PulledAtoms mPulledAtoms;
51     protected long mLastPulledTimestamps;
52 
TelecomPulledAtom(@onNull Context context, @NonNull Looper looper, boolean isTestMode)53     protected TelecomPulledAtom(@NonNull Context context, @NonNull Looper looper,
54                                 boolean isTestMode) {
55         super(looper);
56         mContext = context;
57         mIsTestMode = isTestMode;
58         mPulledAtoms = loadAtomsFromFile();
59         onLoad();
60     }
61 
pull(final List<StatsEvent> data)62     public synchronized int pull(final List<StatsEvent> data) {
63         if (!mIsTestMode) {
64             long cur = System.currentTimeMillis();
65             if (cur - mLastPulledTimestamps < MIN_PULL_INTERVAL_MILLIS) {
66                 return StatsManager.PULL_SKIP;
67             }
68             mLastPulledTimestamps = cur;
69         }
70         return onPull(data);
71     }
72 
73     @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
getTag()74     abstract public int getTag();
75 
76     @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
onPull(List<StatsEvent> data)77     public abstract int onPull(List<StatsEvent> data);
78 
onLoad()79     protected abstract void onLoad();
80 
81     @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
onAggregate()82     public abstract void onAggregate();
83 
flush()84     public void flush() {
85         save(0);
86     }
87 
getFileName()88     protected abstract String getFileName();
89 
loadAtomsFromFile()90     private synchronized PulledAtoms loadAtomsFromFile() {
91         if (!mIsTestMode) {
92             try {
93                 return PulledAtoms.parseFrom(
94                         Files.readAllBytes(mContext.getFileStreamPath(getFileName()).toPath()));
95             } catch (NoSuchFileException e) {
96                 Log.e(TAG, e, "the atom file not found");
97             } catch (IOException | NullPointerException e) {
98                 Log.e(TAG, e, "cannot load/parse the atom file");
99             }
100         }
101         return makeNewPulledAtoms();
102     }
103 
clearAtoms()104     protected synchronized void clearAtoms() {
105         mPulledAtoms = makeNewPulledAtoms();
106     }
107 
onSave()108     private synchronized void onSave() {
109         if (!mIsTestMode) {
110             try (FileOutputStream stream = mContext.openFileOutput(getFileName(),
111                     Context.MODE_PRIVATE)) {
112                 Log.d(TAG, "save " + getTag());
113                 stream.write(PulledAtoms.toByteArray(mPulledAtoms));
114             } catch (IOException e) {
115                 Log.e(TAG, e, "cannot save the atom to file");
116             } catch (UnsupportedOperationException e) {
117                 Log.e(TAG, e, "cannot open the file");
118             }
119         }
120     }
121 
makeNewPulledAtoms()122     private PulledAtoms makeNewPulledAtoms() {
123         return new PulledAtoms();
124     }
125 
126     @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
save(int delayMillis)127     public void save(int delayMillis) {
128         if (delayMillis > 0) {
129             if (!hasMessages(EVENT_SAVE)) {
130                 sendMessageDelayed(obtainMessage(EVENT_SAVE), delayMillis);
131             }
132         } else {
133             onSave();
134         }
135     }
136 
137     @Override
handleMessage(Message msg)138     public void handleMessage(Message msg) {
139         if (msg.what == EVENT_SAVE) {
140             onSave();
141         }
142     }
143 }
144