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.text.format.DateFormat;
25 import android.util.ArrayMap;
26 import android.util.ArraySet;
27 import android.util.DebugUtils;
28 import android.util.Log;
29 import android.util.Slog;
30 import android.util.SparseArray;
31 import android.util.TimeUtils;
32 
33 import static com.android.internal.app.procstats.ProcessStats.*;
34 
35 import java.io.IOException;
36 import java.io.InputStream;
37 import java.io.PrintWriter;
38 import java.util.ArrayList;
39 import java.util.Arrays;
40 import java.util.Collections;
41 import java.util.Comparator;
42 import java.util.Objects;
43 
44 /**
45  * Utilities for dumping.
46  */
47 public final class DumpUtils {
48     public static final String[] STATE_NAMES = new String[] {
49             "Persist", "Top    ", "ImpFg  ", "ImpBg  ",
50             "Backup ", "HeavyWt", "Service", "ServRst",
51             "Receivr", "Home   ",
52             "LastAct", "CchAct ", "CchCAct", "CchEmty"
53     };
54 
55     public static final String[] ADJ_SCREEN_NAMES_CSV = new String[] {
56             "off", "on"
57     };
58 
59     public static final String[] ADJ_MEM_NAMES_CSV = new String[] {
60             "norm", "mod",  "low", "crit"
61     };
62 
63     public static final String[] STATE_NAMES_CSV = new String[] {
64             "pers", "top", "impfg", "impbg", "backup", "heavy",
65             "service", "service-rs", "receiver", "home", "lastact",
66             "cch-activity", "cch-aclient", "cch-empty"
67     };
68 
69     static final String[] ADJ_SCREEN_TAGS = new String[] {
70             "0", "1"
71     };
72 
73     static final String[] ADJ_MEM_TAGS = new String[] {
74             "n", "m",  "l", "c"
75     };
76 
77     static final String[] STATE_TAGS = new String[] {
78             "p", "t", "f", "b", "u", "w",
79             "s", "x", "r", "h", "l", "a", "c", "e"
80     };
81 
82     static final String CSV_SEP = "\t";
83 
84     /**
85      * No instantiate
86      */
DumpUtils()87     private DumpUtils() {
88     }
89 
printScreenLabel(PrintWriter pw, int offset)90     public static void printScreenLabel(PrintWriter pw, int offset) {
91         switch (offset) {
92             case ADJ_NOTHING:
93                 pw.print("     ");
94                 break;
95             case ADJ_SCREEN_OFF:
96                 pw.print("SOff/");
97                 break;
98             case ADJ_SCREEN_ON:
99                 pw.print("SOn /");
100                 break;
101             default:
102                 pw.print("????/");
103                 break;
104         }
105     }
106 
printScreenLabelCsv(PrintWriter pw, int offset)107     public static void printScreenLabelCsv(PrintWriter pw, int offset) {
108         switch (offset) {
109             case ADJ_NOTHING:
110                 break;
111             case ADJ_SCREEN_OFF:
112                 pw.print(ADJ_SCREEN_NAMES_CSV[0]);
113                 break;
114             case ADJ_SCREEN_ON:
115                 pw.print(ADJ_SCREEN_NAMES_CSV[1]);
116                 break;
117             default:
118                 pw.print("???");
119                 break;
120         }
121     }
122 
printMemLabel(PrintWriter pw, int offset, char sep)123     public static void printMemLabel(PrintWriter pw, int offset, char sep) {
124         switch (offset) {
125             case ADJ_NOTHING:
126                 pw.print("    ");
127                 if (sep != 0) pw.print(' ');
128                 break;
129             case ADJ_MEM_FACTOR_NORMAL:
130                 pw.print("Norm");
131                 if (sep != 0) pw.print(sep);
132                 break;
133             case ADJ_MEM_FACTOR_MODERATE:
134                 pw.print("Mod ");
135                 if (sep != 0) pw.print(sep);
136                 break;
137             case ADJ_MEM_FACTOR_LOW:
138                 pw.print("Low ");
139                 if (sep != 0) pw.print(sep);
140                 break;
141             case ADJ_MEM_FACTOR_CRITICAL:
142                 pw.print("Crit");
143                 if (sep != 0) pw.print(sep);
144                 break;
145             default:
146                 pw.print("????");
147                 if (sep != 0) pw.print(sep);
148                 break;
149         }
150     }
151 
printMemLabelCsv(PrintWriter pw, int offset)152     public static void printMemLabelCsv(PrintWriter pw, int offset) {
153         if (offset >= ADJ_MEM_FACTOR_NORMAL) {
154             if (offset <= ADJ_MEM_FACTOR_CRITICAL) {
155                 pw.print(ADJ_MEM_NAMES_CSV[offset]);
156             } else {
157                 pw.print("???");
158             }
159         }
160     }
161 
printPercent(PrintWriter pw, double fraction)162     public static void printPercent(PrintWriter pw, double fraction) {
163         fraction *= 100;
164         if (fraction < 1) {
165             pw.print(String.format("%.2f", fraction));
166         } else if (fraction < 10) {
167             pw.print(String.format("%.1f", fraction));
168         } else {
169             pw.print(String.format("%.0f", fraction));
170         }
171         pw.print("%");
172     }
173 
printProcStateTag(PrintWriter pw, int state)174     public static void printProcStateTag(PrintWriter pw, int state) {
175         state = printArrayEntry(pw, ADJ_SCREEN_TAGS,  state, ADJ_SCREEN_MOD*STATE_COUNT);
176         state = printArrayEntry(pw, ADJ_MEM_TAGS,  state, STATE_COUNT);
177         printArrayEntry(pw, STATE_TAGS,  state, 1);
178     }
179 
printAdjTag(PrintWriter pw, int state)180     public static void printAdjTag(PrintWriter pw, int state) {
181         state = printArrayEntry(pw, ADJ_SCREEN_TAGS,  state, ADJ_SCREEN_MOD);
182         printArrayEntry(pw, ADJ_MEM_TAGS, state, 1);
183     }
184 
printProcStateTagAndValue(PrintWriter pw, int state, long value)185     public static void printProcStateTagAndValue(PrintWriter pw, int state, long value) {
186         pw.print(',');
187         printProcStateTag(pw, state);
188         pw.print(':');
189         pw.print(value);
190     }
191 
printAdjTagAndValue(PrintWriter pw, int state, long value)192     public static void printAdjTagAndValue(PrintWriter pw, int state, long value) {
193         pw.print(',');
194         printAdjTag(pw, state);
195         pw.print(':');
196         pw.print(value);
197     }
198 
dumpSingleTime(PrintWriter pw, String prefix, long[] durations, int curState, long curStartTime, long now)199     public static long dumpSingleTime(PrintWriter pw, String prefix, long[] durations,
200             int curState, long curStartTime, long now) {
201         long totalTime = 0;
202         int printedScreen = -1;
203         for (int iscreen=0; iscreen<ADJ_COUNT; iscreen+=ADJ_SCREEN_MOD) {
204             int printedMem = -1;
205             for (int imem=0; imem<ADJ_MEM_FACTOR_COUNT; imem++) {
206                 int state = imem+iscreen;
207                 long time = durations[state];
208                 String running = "";
209                 if (curState == state) {
210                     time += now - curStartTime;
211                     if (pw != null) {
212                         running = " (running)";
213                     }
214                 }
215                 if (time != 0) {
216                     if (pw != null) {
217                         pw.print(prefix);
218                         printScreenLabel(pw, printedScreen != iscreen
219                                 ? iscreen : STATE_NOTHING);
220                         printedScreen = iscreen;
221                         printMemLabel(pw, printedMem != imem ? imem : STATE_NOTHING, (char)0);
222                         printedMem = imem;
223                         pw.print(": ");
224                         TimeUtils.formatDuration(time, pw); pw.println(running);
225                     }
226                     totalTime += time;
227                 }
228             }
229         }
230         if (totalTime != 0 && pw != null) {
231             pw.print(prefix);
232             pw.print("    TOTAL: ");
233             TimeUtils.formatDuration(totalTime, pw);
234             pw.println();
235         }
236         return totalTime;
237     }
238 
dumpAdjTimesCheckin(PrintWriter pw, String sep, long[] durations, int curState, long curStartTime, long now)239     public static void dumpAdjTimesCheckin(PrintWriter pw, String sep, long[] durations,
240             int curState, long curStartTime, long now) {
241         for (int iscreen=0; iscreen<ADJ_COUNT; iscreen+=ADJ_SCREEN_MOD) {
242             for (int imem=0; imem<ADJ_MEM_FACTOR_COUNT; imem++) {
243                 int state = imem+iscreen;
244                 long time = durations[state];
245                 if (curState == state) {
246                     time += now - curStartTime;
247                 }
248                 if (time != 0) {
249                     printAdjTagAndValue(pw, state, time);
250                 }
251             }
252         }
253     }
254 
dumpStateHeadersCsv(PrintWriter pw, String sep, int[] screenStates, int[] memStates, int[] procStates)255     private static void dumpStateHeadersCsv(PrintWriter pw, String sep, int[] screenStates,
256             int[] memStates, int[] procStates) {
257         final int NS = screenStates != null ? screenStates.length : 1;
258         final int NM = memStates != null ? memStates.length : 1;
259         final int NP = procStates != null ? procStates.length : 1;
260         for (int is=0; is<NS; is++) {
261             for (int im=0; im<NM; im++) {
262                 for (int ip=0; ip<NP; ip++) {
263                     pw.print(sep);
264                     boolean printed = false;
265                     if (screenStates != null && screenStates.length > 1) {
266                         printScreenLabelCsv(pw, screenStates[is]);
267                         printed = true;
268                     }
269                     if (memStates != null && memStates.length > 1) {
270                         if (printed) {
271                             pw.print("-");
272                         }
273                         printMemLabelCsv(pw, memStates[im]);
274                         printed = true;
275                     }
276                     if (procStates != null && procStates.length > 1) {
277                         if (printed) {
278                             pw.print("-");
279                         }
280                         pw.print(STATE_NAMES_CSV[procStates[ip]]);
281                     }
282                 }
283             }
284         }
285     }
286 
287     /*
288      * Doesn't seem to be used.
289      *
290     public static void dumpProcessList(PrintWriter pw, String prefix, ArrayList<ProcessState> procs,
291             int[] screenStates, int[] memStates, int[] procStates, long now) {
292         String innerPrefix = prefix + "  ";
293         for (int i=procs.size()-1; i>=0; i--) {
294             ProcessState proc = procs.get(i);
295             pw.print(prefix);
296             pw.print(proc.mName);
297             pw.print(" / ");
298             UserHandle.formatUid(pw, proc.mUid);
299             pw.print(" (");
300             pw.print(proc.durations.getKeyCount());
301             pw.print(" entries)");
302             pw.println(":");
303             proc.dumpProcessState(pw, innerPrefix, screenStates, memStates, procStates, now);
304             if (proc.pssTable.getKeyCount() > 0) {
305                 proc.dumpPss(pw, innerPrefix, screenStates, memStates, procStates);
306             }
307         }
308     }
309     */
310 
dumpProcessSummaryLocked(PrintWriter pw, String prefix, ArrayList<ProcessState> procs, int[] screenStates, int[] memStates, int[] procStates, long now, long totalTime)311     public static void dumpProcessSummaryLocked(PrintWriter pw, String prefix,
312             ArrayList<ProcessState> procs, int[] screenStates, int[] memStates, int[] procStates,
313             long now, long totalTime) {
314         for (int i=procs.size()-1; i>=0; i--) {
315             final ProcessState proc = procs.get(i);
316             proc.dumpSummary(pw, prefix, screenStates, memStates, procStates, now, totalTime);
317         }
318     }
319 
dumpProcessListCsv(PrintWriter pw, ArrayList<ProcessState> procs, boolean sepScreenStates, int[] screenStates, boolean sepMemStates, int[] memStates, boolean sepProcStates, int[] procStates, long now)320     public static void dumpProcessListCsv(PrintWriter pw, ArrayList<ProcessState> procs,
321             boolean sepScreenStates, int[] screenStates, boolean sepMemStates, int[] memStates,
322             boolean sepProcStates, int[] procStates, long now) {
323         pw.print("process");
324         pw.print(CSV_SEP);
325         pw.print("uid");
326         pw.print(CSV_SEP);
327         pw.print("vers");
328         dumpStateHeadersCsv(pw, CSV_SEP, sepScreenStates ? screenStates : null,
329                 sepMemStates ? memStates : null,
330                 sepProcStates ? procStates : null);
331         pw.println();
332         for (int i=procs.size()-1; i>=0; i--) {
333             ProcessState proc = procs.get(i);
334             pw.print(proc.getName());
335             pw.print(CSV_SEP);
336             UserHandle.formatUid(pw, proc.getUid());
337             pw.print(CSV_SEP);
338             pw.print(proc.getVersion());
339             proc.dumpCsv(pw, sepScreenStates, screenStates, sepMemStates,
340                     memStates, sepProcStates, procStates, now);
341             pw.println();
342         }
343     }
344 
printArrayEntry(PrintWriter pw, String[] array, int value, int mod)345     public static int printArrayEntry(PrintWriter pw, String[] array, int value, int mod) {
346         int index = value/mod;
347         if (index >= 0 && index < array.length) {
348             pw.print(array[index]);
349         } else {
350             pw.print('?');
351         }
352         return value - index*mod;
353     }
354 
collapseString(String pkgName, String itemName)355     public static String collapseString(String pkgName, String itemName) {
356         if (itemName.startsWith(pkgName)) {
357             final int ITEMLEN = itemName.length();
358             final int PKGLEN = pkgName.length();
359             if (ITEMLEN == PKGLEN) {
360                 return "";
361             } else if (ITEMLEN >= PKGLEN) {
362                 if (itemName.charAt(PKGLEN) == '.') {
363                     return itemName.substring(PKGLEN);
364                 }
365             }
366         }
367         return itemName;
368     }
369 }
370