1 /*
2  * Copyright (C) 2013 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.internal.app.procstats;
18 
19 import android.os.Parcel;
20 import android.os.Parcelable;
21 import android.os.SystemClock;
22 import android.os.SystemProperties;
23 import android.os.UserHandle;
24 import android.service.procstats.ProcessStatsProto;
25 import android.text.format.DateFormat;
26 import android.util.ArrayMap;
27 import android.util.ArraySet;
28 import android.util.DebugUtils;
29 import android.util.Log;
30 import android.util.Slog;
31 import android.util.SparseArray;
32 import android.util.TimeUtils;
33 import android.util.proto.ProtoOutputStream;
34 
35 import static com.android.internal.app.procstats.ProcessStats.*;
36 
37 import java.io.IOException;
38 import java.io.InputStream;
39 import java.io.PrintWriter;
40 import java.util.ArrayList;
41 import java.util.Arrays;
42 import java.util.Collections;
43 import java.util.Comparator;
44 import java.util.Objects;
45 
46 /**
47  * Utilities for dumping.
48  */
49 public final class DumpUtils {
50     public static final String[] STATE_NAMES;
51     public static final String[] STATE_NAMES_CSV;
52     static final String[] STATE_TAGS;
53     static final int[] STATE_PROTO_ENUMS;
54 
55     // Make the mapping easy to update.
56     static {
57         STATE_NAMES = new String[STATE_COUNT];
58         STATE_NAMES[STATE_PERSISTENT] = "Persist";
59         STATE_NAMES[STATE_TOP] = "Top";
60         STATE_NAMES[STATE_IMPORTANT_FOREGROUND] = "ImpFg";
61         STATE_NAMES[STATE_IMPORTANT_BACKGROUND] = "ImpBg";
62         STATE_NAMES[STATE_BACKUP] = "Backup";
63         STATE_NAMES[STATE_SERVICE] = "Service";
64         STATE_NAMES[STATE_SERVICE_RESTARTING] = "ServRst";
65         STATE_NAMES[STATE_RECEIVER] = "Receivr";
66         STATE_NAMES[STATE_HEAVY_WEIGHT] = "HeavyWt";
67         STATE_NAMES[STATE_HOME] = "Home";
68         STATE_NAMES[STATE_LAST_ACTIVITY] = "LastAct";
69         STATE_NAMES[STATE_CACHED_ACTIVITY] = "CchAct";
70         STATE_NAMES[STATE_CACHED_ACTIVITY_CLIENT] = "CchCAct";
71         STATE_NAMES[STATE_CACHED_EMPTY] = "CchEmty";
72 
73         STATE_NAMES_CSV = new String[STATE_COUNT];
74         STATE_NAMES_CSV[STATE_PERSISTENT] = "pers";
75         STATE_NAMES_CSV[STATE_TOP] = "top";
76         STATE_NAMES_CSV[STATE_IMPORTANT_FOREGROUND] = "impfg";
77         STATE_NAMES_CSV[STATE_IMPORTANT_BACKGROUND] = "impbg";
78         STATE_NAMES_CSV[STATE_BACKUP] = "backup";
79         STATE_NAMES_CSV[STATE_SERVICE] = "service";
80         STATE_NAMES_CSV[STATE_SERVICE_RESTARTING] = "service-rs";
81         STATE_NAMES_CSV[STATE_RECEIVER] = "receiver";
82         STATE_NAMES_CSV[STATE_HEAVY_WEIGHT] = "heavy";
83         STATE_NAMES_CSV[STATE_HOME] = "home";
84         STATE_NAMES_CSV[STATE_LAST_ACTIVITY] = "lastact";
85         STATE_NAMES_CSV[STATE_CACHED_ACTIVITY] = "cch-activity";
86         STATE_NAMES_CSV[STATE_CACHED_ACTIVITY_CLIENT] = "cch-aclient";
87         STATE_NAMES_CSV[STATE_CACHED_EMPTY] = "cch-empty";
88 
89         STATE_TAGS = new String[STATE_COUNT];
90         STATE_TAGS[STATE_PERSISTENT] = "p";
91         STATE_TAGS[STATE_TOP] = "t";
92         STATE_TAGS[STATE_IMPORTANT_FOREGROUND] = "f";
93         STATE_TAGS[STATE_IMPORTANT_BACKGROUND] = "b";
94         STATE_TAGS[STATE_BACKUP] = "u";
95         STATE_TAGS[STATE_SERVICE] = "s";
96         STATE_TAGS[STATE_SERVICE_RESTARTING] = "x";
97         STATE_TAGS[STATE_RECEIVER] = "r";
98         STATE_TAGS[STATE_HEAVY_WEIGHT] = "w";
99         STATE_TAGS[STATE_HOME] = "h";
100         STATE_TAGS[STATE_LAST_ACTIVITY] = "l";
101         STATE_TAGS[STATE_CACHED_ACTIVITY] = "a";
102         STATE_TAGS[STATE_CACHED_ACTIVITY_CLIENT] = "c";
103         STATE_TAGS[STATE_CACHED_EMPTY] = "e";
104 
105         STATE_PROTO_ENUMS = new int[STATE_COUNT];
106         STATE_PROTO_ENUMS[STATE_PERSISTENT] = ProcessStatsProto.State.PERSISTENT;
107         STATE_PROTO_ENUMS[STATE_TOP] = ProcessStatsProto.State.TOP;
108         STATE_PROTO_ENUMS[STATE_IMPORTANT_FOREGROUND] = ProcessStatsProto.State.IMPORTANT_FOREGROUND;
109         STATE_PROTO_ENUMS[STATE_IMPORTANT_BACKGROUND] = ProcessStatsProto.State.IMPORTANT_BACKGROUND;
110         STATE_PROTO_ENUMS[STATE_BACKUP] = ProcessStatsProto.State.BACKUP;
111         STATE_PROTO_ENUMS[STATE_SERVICE] = ProcessStatsProto.State.SERVICE;
112         STATE_PROTO_ENUMS[STATE_SERVICE_RESTARTING] = ProcessStatsProto.State.SERVICE_RESTARTING;
113         STATE_PROTO_ENUMS[STATE_RECEIVER] = ProcessStatsProto.State.RECEIVER;
114         STATE_PROTO_ENUMS[STATE_HEAVY_WEIGHT] = ProcessStatsProto.State.HEAVY_WEIGHT;
115         STATE_PROTO_ENUMS[STATE_HOME] = ProcessStatsProto.State.HOME;
116         STATE_PROTO_ENUMS[STATE_LAST_ACTIVITY] = ProcessStatsProto.State.LAST_ACTIVITY;
117         STATE_PROTO_ENUMS[STATE_CACHED_ACTIVITY] = ProcessStatsProto.State.CACHED_ACTIVITY;
118         STATE_PROTO_ENUMS[STATE_CACHED_ACTIVITY_CLIENT] = ProcessStatsProto.State.CACHED_ACTIVITY_CLIENT;
119         STATE_PROTO_ENUMS[STATE_CACHED_EMPTY] = ProcessStatsProto.State.CACHED_EMPTY;
120     }
121 
122     public static final String[] ADJ_SCREEN_NAMES_CSV = new String[] {
123             "off", "on"
124     };
125 
126     public static final String[] ADJ_MEM_NAMES_CSV = new String[] {
127             "norm", "mod",  "low", "crit"
128     };
129 
130     // State enum is defined in frameworks/base/core/proto/android/service/procstats.proto
131     // Update states must sync enum definition as well, the ordering must not be changed.
132     static final String[] ADJ_SCREEN_TAGS = new String[] {
133             "0", "1"
134     };
135 
136     static final int[] ADJ_SCREEN_PROTO_ENUMS = new int[] {
137             ProcessStatsProto.State.OFF,
138             ProcessStatsProto.State.ON
139     };
140 
141     static final String[] ADJ_MEM_TAGS = new String[] {
142             "n", "m",  "l", "c"
143     };
144 
145     static final int[] ADJ_MEM_PROTO_ENUMS = new int[] {
146             ProcessStatsProto.State.NORMAL,
147             ProcessStatsProto.State.MODERATE,
148             ProcessStatsProto.State.LOW,
149             ProcessStatsProto.State.CRITICAL
150     };
151 
152     static final String CSV_SEP = "\t";
153 
154     /**
155      * No instantiate
156      */
DumpUtils()157     private DumpUtils() {
158     }
159 
printScreenLabel(PrintWriter pw, int offset)160     public static void printScreenLabel(PrintWriter pw, int offset) {
161         switch (offset) {
162             case ADJ_NOTHING:
163                 pw.print("     ");
164                 break;
165             case ADJ_SCREEN_OFF:
166                 pw.print("SOff/");
167                 break;
168             case ADJ_SCREEN_ON:
169                 pw.print("SOn /");
170                 break;
171             default:
172                 pw.print("????/");
173                 break;
174         }
175     }
176 
printScreenLabelCsv(PrintWriter pw, int offset)177     public static void printScreenLabelCsv(PrintWriter pw, int offset) {
178         switch (offset) {
179             case ADJ_NOTHING:
180                 break;
181             case ADJ_SCREEN_OFF:
182                 pw.print(ADJ_SCREEN_NAMES_CSV[0]);
183                 break;
184             case ADJ_SCREEN_ON:
185                 pw.print(ADJ_SCREEN_NAMES_CSV[1]);
186                 break;
187             default:
188                 pw.print("???");
189                 break;
190         }
191     }
192 
printMemLabel(PrintWriter pw, int offset, char sep)193     public static void printMemLabel(PrintWriter pw, int offset, char sep) {
194         switch (offset) {
195             case ADJ_NOTHING:
196                 pw.print("    ");
197                 if (sep != 0) pw.print(' ');
198                 break;
199             case ADJ_MEM_FACTOR_NORMAL:
200                 pw.print("Norm");
201                 if (sep != 0) pw.print(sep);
202                 break;
203             case ADJ_MEM_FACTOR_MODERATE:
204                 pw.print("Mod ");
205                 if (sep != 0) pw.print(sep);
206                 break;
207             case ADJ_MEM_FACTOR_LOW:
208                 pw.print("Low ");
209                 if (sep != 0) pw.print(sep);
210                 break;
211             case ADJ_MEM_FACTOR_CRITICAL:
212                 pw.print("Crit");
213                 if (sep != 0) pw.print(sep);
214                 break;
215             default:
216                 pw.print("????");
217                 if (sep != 0) pw.print(sep);
218                 break;
219         }
220     }
221 
printMemLabelCsv(PrintWriter pw, int offset)222     public static void printMemLabelCsv(PrintWriter pw, int offset) {
223         if (offset >= ADJ_MEM_FACTOR_NORMAL) {
224             if (offset <= ADJ_MEM_FACTOR_CRITICAL) {
225                 pw.print(ADJ_MEM_NAMES_CSV[offset]);
226             } else {
227                 pw.print("???");
228             }
229         }
230     }
231 
printPercent(PrintWriter pw, double fraction)232     public static void printPercent(PrintWriter pw, double fraction) {
233         fraction *= 100;
234         if (fraction < 1) {
235             pw.print(String.format("%.2f", fraction));
236         } else if (fraction < 10) {
237             pw.print(String.format("%.1f", fraction));
238         } else {
239             pw.print(String.format("%.0f", fraction));
240         }
241         pw.print("%");
242     }
243 
printProcStateTag(PrintWriter pw, int state)244     public static void printProcStateTag(PrintWriter pw, int state) {
245         state = printArrayEntry(pw, ADJ_SCREEN_TAGS,  state, ADJ_SCREEN_MOD*STATE_COUNT);
246         state = printArrayEntry(pw, ADJ_MEM_TAGS,  state, STATE_COUNT);
247         printArrayEntry(pw, STATE_TAGS,  state, 1);
248     }
249 
printProcStateTagProto(ProtoOutputStream proto, long screenId, long memId, long stateId, int state)250     public static void printProcStateTagProto(ProtoOutputStream proto, long screenId, long memId,
251             long stateId, int state) {
252         state = printProto(proto, screenId, ADJ_SCREEN_PROTO_ENUMS,
253                 state, ADJ_SCREEN_MOD * STATE_COUNT);
254         state = printProto(proto, memId, ADJ_MEM_PROTO_ENUMS, state, STATE_COUNT);
255         printProto(proto, stateId, STATE_PROTO_ENUMS, state, 1);
256     }
257 
printAdjTag(PrintWriter pw, int state)258     public static void printAdjTag(PrintWriter pw, int state) {
259         state = printArrayEntry(pw, ADJ_SCREEN_TAGS,  state, ADJ_SCREEN_MOD);
260         printArrayEntry(pw, ADJ_MEM_TAGS, state, 1);
261     }
262 
printProcStateTagAndValue(PrintWriter pw, int state, long value)263     public static void printProcStateTagAndValue(PrintWriter pw, int state, long value) {
264         pw.print(',');
265         printProcStateTag(pw, state);
266         pw.print(':');
267         pw.print(value);
268     }
269 
printAdjTagAndValue(PrintWriter pw, int state, long value)270     public static void printAdjTagAndValue(PrintWriter pw, int state, long value) {
271         pw.print(',');
272         printAdjTag(pw, state);
273         pw.print(':');
274         pw.print(value);
275     }
276 
dumpSingleTime(PrintWriter pw, String prefix, long[] durations, int curState, long curStartTime, long now)277     public static long dumpSingleTime(PrintWriter pw, String prefix, long[] durations,
278             int curState, long curStartTime, long now) {
279         long totalTime = 0;
280         int printedScreen = -1;
281         for (int iscreen=0; iscreen<ADJ_COUNT; iscreen+=ADJ_SCREEN_MOD) {
282             int printedMem = -1;
283             for (int imem=0; imem<ADJ_MEM_FACTOR_COUNT; imem++) {
284                 int state = imem+iscreen;
285                 long time = durations[state];
286                 String running = "";
287                 if (curState == state) {
288                     time += now - curStartTime;
289                     if (pw != null) {
290                         running = " (running)";
291                     }
292                 }
293                 if (time != 0) {
294                     if (pw != null) {
295                         pw.print(prefix);
296                         printScreenLabel(pw, printedScreen != iscreen
297                                 ? iscreen : STATE_NOTHING);
298                         printedScreen = iscreen;
299                         printMemLabel(pw, printedMem != imem ? imem : STATE_NOTHING, (char)0);
300                         printedMem = imem;
301                         pw.print(": ");
302                         TimeUtils.formatDuration(time, pw); pw.println(running);
303                     }
304                     totalTime += time;
305                 }
306             }
307         }
308         if (totalTime != 0 && pw != null) {
309             pw.print(prefix);
310             pw.print("    TOTAL: ");
311             TimeUtils.formatDuration(totalTime, pw);
312             pw.println();
313         }
314         return totalTime;
315     }
316 
dumpAdjTimesCheckin(PrintWriter pw, String sep, long[] durations, int curState, long curStartTime, long now)317     public static void dumpAdjTimesCheckin(PrintWriter pw, String sep, long[] durations,
318             int curState, long curStartTime, long now) {
319         for (int iscreen=0; iscreen<ADJ_COUNT; iscreen+=ADJ_SCREEN_MOD) {
320             for (int imem=0; imem<ADJ_MEM_FACTOR_COUNT; imem++) {
321                 int state = imem+iscreen;
322                 long time = durations[state];
323                 if (curState == state) {
324                     time += now - curStartTime;
325                 }
326                 if (time != 0) {
327                     printAdjTagAndValue(pw, state, time);
328                 }
329             }
330         }
331     }
332 
dumpStateHeadersCsv(PrintWriter pw, String sep, int[] screenStates, int[] memStates, int[] procStates)333     private static void dumpStateHeadersCsv(PrintWriter pw, String sep, int[] screenStates,
334             int[] memStates, int[] procStates) {
335         final int NS = screenStates != null ? screenStates.length : 1;
336         final int NM = memStates != null ? memStates.length : 1;
337         final int NP = procStates != null ? procStates.length : 1;
338         for (int is=0; is<NS; is++) {
339             for (int im=0; im<NM; im++) {
340                 for (int ip=0; ip<NP; ip++) {
341                     pw.print(sep);
342                     boolean printed = false;
343                     if (screenStates != null && screenStates.length > 1) {
344                         printScreenLabelCsv(pw, screenStates[is]);
345                         printed = true;
346                     }
347                     if (memStates != null && memStates.length > 1) {
348                         if (printed) {
349                             pw.print("-");
350                         }
351                         printMemLabelCsv(pw, memStates[im]);
352                         printed = true;
353                     }
354                     if (procStates != null && procStates.length > 1) {
355                         if (printed) {
356                             pw.print("-");
357                         }
358                         pw.print(STATE_NAMES_CSV[procStates[ip]]);
359                     }
360                 }
361             }
362         }
363     }
364 
dumpProcessSummaryLocked(PrintWriter pw, String prefix, ArrayList<ProcessState> procs, int[] screenStates, int[] memStates, int[] procStates, long now, long totalTime)365     public static void dumpProcessSummaryLocked(PrintWriter pw, String prefix,
366             ArrayList<ProcessState> procs, int[] screenStates, int[] memStates, int[] procStates,
367             long now, long totalTime) {
368         for (int i=procs.size()-1; i>=0; i--) {
369             final ProcessState proc = procs.get(i);
370             proc.dumpSummary(pw, prefix, screenStates, memStates, procStates, now, totalTime);
371         }
372     }
373 
dumpProcessListCsv(PrintWriter pw, ArrayList<ProcessState> procs, boolean sepScreenStates, int[] screenStates, boolean sepMemStates, int[] memStates, boolean sepProcStates, int[] procStates, long now)374     public static void dumpProcessListCsv(PrintWriter pw, ArrayList<ProcessState> procs,
375             boolean sepScreenStates, int[] screenStates, boolean sepMemStates, int[] memStates,
376             boolean sepProcStates, int[] procStates, long now) {
377         pw.print("process");
378         pw.print(CSV_SEP);
379         pw.print("uid");
380         pw.print(CSV_SEP);
381         pw.print("vers");
382         dumpStateHeadersCsv(pw, CSV_SEP, sepScreenStates ? screenStates : null,
383                 sepMemStates ? memStates : null,
384                 sepProcStates ? procStates : null);
385         pw.println();
386         for (int i=procs.size()-1; i>=0; i--) {
387             ProcessState proc = procs.get(i);
388             pw.print(proc.getName());
389             pw.print(CSV_SEP);
390             UserHandle.formatUid(pw, proc.getUid());
391             pw.print(CSV_SEP);
392             pw.print(proc.getVersion());
393             proc.dumpCsv(pw, sepScreenStates, screenStates, sepMemStates,
394                     memStates, sepProcStates, procStates, now);
395             pw.println();
396         }
397     }
398 
printArrayEntry(PrintWriter pw, String[] array, int value, int mod)399     public static int printArrayEntry(PrintWriter pw, String[] array, int value, int mod) {
400         int index = value/mod;
401         if (index >= 0 && index < array.length) {
402             pw.print(array[index]);
403         } else {
404             pw.print('?');
405         }
406         return value - index*mod;
407     }
408 
printProto(ProtoOutputStream proto, long fieldId, int[] enums, int value, int mod)409     public static int printProto(ProtoOutputStream proto, long fieldId,
410             int[] enums, int value, int mod) {
411         int index = value/mod;
412         if (index >= 0 && index < enums.length) {
413             proto.write(fieldId, enums[index]);
414         } // else enum default is always zero in proto3
415         return value - index*mod;
416     }
417 
collapseString(String pkgName, String itemName)418     public static String collapseString(String pkgName, String itemName) {
419         if (itemName.startsWith(pkgName)) {
420             final int ITEMLEN = itemName.length();
421             final int PKGLEN = pkgName.length();
422             if (ITEMLEN == PKGLEN) {
423                 return "";
424             } else if (ITEMLEN >= PKGLEN) {
425                 if (itemName.charAt(PKGLEN) == '.') {
426                     return itemName.substring(PKGLEN);
427                 }
428             }
429         }
430         return itemName;
431     }
432 }
433