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 static com.android.internal.app.procstats.ProcessStats.ADJ_COUNT;
20 import static com.android.internal.app.procstats.ProcessStats.ADJ_MEM_FACTOR_COUNT;
21 import static com.android.internal.app.procstats.ProcessStats.ADJ_MEM_FACTOR_CRITICAL;
22 import static com.android.internal.app.procstats.ProcessStats.ADJ_MEM_FACTOR_LOW;
23 import static com.android.internal.app.procstats.ProcessStats.ADJ_MEM_FACTOR_MODERATE;
24 import static com.android.internal.app.procstats.ProcessStats.ADJ_MEM_FACTOR_NORMAL;
25 import static com.android.internal.app.procstats.ProcessStats.ADJ_NOTHING;
26 import static com.android.internal.app.procstats.ProcessStats.ADJ_SCREEN_MOD;
27 import static com.android.internal.app.procstats.ProcessStats.ADJ_SCREEN_OFF;
28 import static com.android.internal.app.procstats.ProcessStats.ADJ_SCREEN_ON;
29 import static com.android.internal.app.procstats.ProcessStats.STATE_BACKUP;
30 import static com.android.internal.app.procstats.ProcessStats.STATE_CACHED_ACTIVITY;
31 import static com.android.internal.app.procstats.ProcessStats.STATE_CACHED_ACTIVITY_CLIENT;
32 import static com.android.internal.app.procstats.ProcessStats.STATE_CACHED_EMPTY;
33 import static com.android.internal.app.procstats.ProcessStats.STATE_COUNT;
34 import static com.android.internal.app.procstats.ProcessStats.STATE_HEAVY_WEIGHT;
35 import static com.android.internal.app.procstats.ProcessStats.STATE_HOME;
36 import static com.android.internal.app.procstats.ProcessStats.STATE_IMPORTANT_BACKGROUND;
37 import static com.android.internal.app.procstats.ProcessStats.STATE_IMPORTANT_FOREGROUND;
38 import static com.android.internal.app.procstats.ProcessStats.STATE_LAST_ACTIVITY;
39 import static com.android.internal.app.procstats.ProcessStats.STATE_NOTHING;
40 import static com.android.internal.app.procstats.ProcessStats.STATE_PERSISTENT;
41 import static com.android.internal.app.procstats.ProcessStats.STATE_RECEIVER;
42 import static com.android.internal.app.procstats.ProcessStats.STATE_SERVICE;
43 import static com.android.internal.app.procstats.ProcessStats.STATE_SERVICE_RESTARTING;
44 import static com.android.internal.app.procstats.ProcessStats.STATE_TOP;
45 
46 import android.os.UserHandle;
47 import android.service.procstats.ProcessStatsEnums;
48 import android.service.procstats.ProcessStatsStateProto;
49 import android.util.TimeUtils;
50 import android.util.proto.ProtoOutputStream;
51 
52 import java.io.PrintWriter;
53 import java.util.ArrayList;
54 
55 /**
56  * Utilities for dumping.
57  */
58 public final class DumpUtils {
59     public static final String[] STATE_NAMES;
60     public static final String[] STATE_LABELS;
61     public static final String STATE_LABEL_TOTAL;
62     public static final String STATE_LABEL_CACHED;
63     public static final String[] STATE_NAMES_CSV;
64     static final String[] STATE_TAGS;
65     static final int[] STATE_PROTO_ENUMS;
66     private static final int[] PROCESS_STATS_STATE_TO_AGGREGATED_STATE;
67 
68     // Make the mapping easy to update.
69     static {
70         STATE_NAMES = new String[STATE_COUNT];
71         STATE_NAMES[STATE_PERSISTENT]               = "Persist";
72         STATE_NAMES[STATE_TOP]                      = "Top";
73         STATE_NAMES[STATE_IMPORTANT_FOREGROUND]     = "ImpFg";
74         STATE_NAMES[STATE_IMPORTANT_BACKGROUND]     = "ImpBg";
75         STATE_NAMES[STATE_BACKUP]                   = "Backup";
76         STATE_NAMES[STATE_SERVICE]                  = "Service";
77         STATE_NAMES[STATE_SERVICE_RESTARTING]       = "ServRst";
78         STATE_NAMES[STATE_RECEIVER]                 = "Receivr";
79         STATE_NAMES[STATE_HEAVY_WEIGHT]             = "HeavyWt";
80         STATE_NAMES[STATE_HOME]                     = "Home";
81         STATE_NAMES[STATE_LAST_ACTIVITY]            = "LastAct";
82         STATE_NAMES[STATE_CACHED_ACTIVITY]          = "CchAct";
83         STATE_NAMES[STATE_CACHED_ACTIVITY_CLIENT]   = "CchCAct";
84         STATE_NAMES[STATE_CACHED_EMPTY]             = "CchEmty";
85 
86         STATE_LABELS = new String[STATE_COUNT];
87         STATE_LABELS[STATE_PERSISTENT]              = "Persistent";
88         STATE_LABELS[STATE_TOP]                     = "       Top";
89         STATE_LABELS[STATE_IMPORTANT_FOREGROUND]    = "    Imp Fg";
90         STATE_LABELS[STATE_IMPORTANT_BACKGROUND]    = "    Imp Bg";
91         STATE_LABELS[STATE_BACKUP]                  = "    Backup";
92         STATE_LABELS[STATE_SERVICE]                 = "   Service";
93         STATE_LABELS[STATE_SERVICE_RESTARTING]      = "Service Rs";
94         STATE_LABELS[STATE_RECEIVER]                = "  Receiver";
95         STATE_LABELS[STATE_HEAVY_WEIGHT]            = " Heavy Wgt";
96         STATE_LABELS[STATE_HOME]                    = "    (Home)";
97         STATE_LABELS[STATE_LAST_ACTIVITY]           = "(Last Act)";
98         STATE_LABELS[STATE_CACHED_ACTIVITY]         = " (Cch Act)";
99         STATE_LABELS[STATE_CACHED_ACTIVITY_CLIENT]  = "(Cch CAct)";
100         STATE_LABELS[STATE_CACHED_EMPTY]            = "(Cch Emty)";
101         STATE_LABEL_CACHED                          = "  (Cached)";
102         STATE_LABEL_TOTAL                           = "     TOTAL";
103 
104         STATE_NAMES_CSV = new String[STATE_COUNT];
105         STATE_NAMES_CSV[STATE_PERSISTENT]               = "pers";
106         STATE_NAMES_CSV[STATE_TOP]                      = "top";
107         STATE_NAMES_CSV[STATE_IMPORTANT_FOREGROUND]     = "impfg";
108         STATE_NAMES_CSV[STATE_IMPORTANT_BACKGROUND]     = "impbg";
109         STATE_NAMES_CSV[STATE_BACKUP]                   = "backup";
110         STATE_NAMES_CSV[STATE_SERVICE]                  = "service";
111         STATE_NAMES_CSV[STATE_SERVICE_RESTARTING]       = "service-rs";
112         STATE_NAMES_CSV[STATE_RECEIVER]                 = "receiver";
113         STATE_NAMES_CSV[STATE_HEAVY_WEIGHT]             = "heavy";
114         STATE_NAMES_CSV[STATE_HOME]                     = "home";
115         STATE_NAMES_CSV[STATE_LAST_ACTIVITY]            = "lastact";
116         STATE_NAMES_CSV[STATE_CACHED_ACTIVITY]          = "cch-activity";
117         STATE_NAMES_CSV[STATE_CACHED_ACTIVITY_CLIENT]   = "cch-aclient";
118         STATE_NAMES_CSV[STATE_CACHED_EMPTY]             = "cch-empty";
119 
120         STATE_TAGS = new String[STATE_COUNT];
121         STATE_TAGS[STATE_PERSISTENT]                = "p";
122         STATE_TAGS[STATE_TOP]                       = "t";
123         STATE_TAGS[STATE_IMPORTANT_FOREGROUND]      = "f";
124         STATE_TAGS[STATE_IMPORTANT_BACKGROUND]      = "b";
125         STATE_TAGS[STATE_BACKUP]                    = "u";
126         STATE_TAGS[STATE_SERVICE]                   = "s";
127         STATE_TAGS[STATE_SERVICE_RESTARTING]        = "x";
128         STATE_TAGS[STATE_RECEIVER]                  = "r";
129         STATE_TAGS[STATE_HEAVY_WEIGHT]              = "w";
130         STATE_TAGS[STATE_HOME]                      = "h";
131         STATE_TAGS[STATE_LAST_ACTIVITY]             = "l";
132         STATE_TAGS[STATE_CACHED_ACTIVITY]           = "a";
133         STATE_TAGS[STATE_CACHED_ACTIVITY_CLIENT]    = "c";
134         STATE_TAGS[STATE_CACHED_EMPTY]              = "e";
135 
136         STATE_PROTO_ENUMS = new int[STATE_COUNT];
137         STATE_PROTO_ENUMS[STATE_PERSISTENT] = ProcessStatsEnums.PROCESS_STATE_PERSISTENT;
138         STATE_PROTO_ENUMS[STATE_TOP] = ProcessStatsEnums.PROCESS_STATE_TOP;
139         STATE_PROTO_ENUMS[STATE_IMPORTANT_FOREGROUND] =
140                 ProcessStatsEnums.PROCESS_STATE_IMPORTANT_FOREGROUND;
141         STATE_PROTO_ENUMS[STATE_IMPORTANT_BACKGROUND] =
142                 ProcessStatsEnums.PROCESS_STATE_IMPORTANT_BACKGROUND;
143         STATE_PROTO_ENUMS[STATE_BACKUP] = ProcessStatsEnums.PROCESS_STATE_BACKUP;
144         STATE_PROTO_ENUMS[STATE_SERVICE] = ProcessStatsEnums.PROCESS_STATE_SERVICE;
145         STATE_PROTO_ENUMS[STATE_SERVICE_RESTARTING] =
146                 ProcessStatsEnums.PROCESS_STATE_SERVICE_RESTARTING;
147         STATE_PROTO_ENUMS[STATE_RECEIVER] = ProcessStatsEnums.PROCESS_STATE_RECEIVER;
148         STATE_PROTO_ENUMS[STATE_HEAVY_WEIGHT] = ProcessStatsEnums.PROCESS_STATE_HEAVY_WEIGHT;
149         STATE_PROTO_ENUMS[STATE_HOME] = ProcessStatsEnums.PROCESS_STATE_HOME;
150         STATE_PROTO_ENUMS[STATE_LAST_ACTIVITY] = ProcessStatsEnums.PROCESS_STATE_LAST_ACTIVITY;
151         STATE_PROTO_ENUMS[STATE_CACHED_ACTIVITY] = ProcessStatsEnums.PROCESS_STATE_CACHED_ACTIVITY;
152         STATE_PROTO_ENUMS[STATE_CACHED_ACTIVITY_CLIENT] =
153                 ProcessStatsEnums.PROCESS_STATE_CACHED_ACTIVITY_CLIENT;
154         STATE_PROTO_ENUMS[STATE_CACHED_EMPTY] = ProcessStatsEnums.PROCESS_STATE_CACHED_EMPTY;
155 
156         // Remap states, as defined by ProcessStats.java, to a reduced subset of states for data
157         // aggregation / size reduction purposes.
158         PROCESS_STATS_STATE_TO_AGGREGATED_STATE = new int[STATE_COUNT];
159         PROCESS_STATS_STATE_TO_AGGREGATED_STATE[STATE_PERSISTENT] =
160                 ProcessStatsEnums.AGGREGATED_PROCESS_STATE_PERSISTENT;
161         PROCESS_STATS_STATE_TO_AGGREGATED_STATE[STATE_TOP] =
162                 ProcessStatsEnums.AGGREGATED_PROCESS_STATE_TOP;
163         PROCESS_STATS_STATE_TO_AGGREGATED_STATE[STATE_IMPORTANT_FOREGROUND] =
164                 ProcessStatsEnums.AGGREGATED_PROCESS_STATE_IMPORTANT_FOREGROUND;
165         PROCESS_STATS_STATE_TO_AGGREGATED_STATE[STATE_IMPORTANT_BACKGROUND] =
166                 ProcessStatsEnums.AGGREGATED_PROCESS_STATE_BACKGROUND;
167         PROCESS_STATS_STATE_TO_AGGREGATED_STATE[STATE_BACKUP] =
168                 ProcessStatsEnums.AGGREGATED_PROCESS_STATE_BACKGROUND;
169         PROCESS_STATS_STATE_TO_AGGREGATED_STATE[STATE_SERVICE] =
170                 ProcessStatsEnums.AGGREGATED_PROCESS_STATE_BACKGROUND;
171         // "Restarting" is not a real state, so this shouldn't exist.
172         PROCESS_STATS_STATE_TO_AGGREGATED_STATE[STATE_SERVICE_RESTARTING] =
173                 ProcessStatsEnums.AGGREGATED_PROCESS_STATE_UNKNOWN;
174         PROCESS_STATS_STATE_TO_AGGREGATED_STATE[STATE_RECEIVER] =
175                 ProcessStatsEnums.AGGREGATED_PROCESS_STATE_RECEIVER;
176         PROCESS_STATS_STATE_TO_AGGREGATED_STATE[STATE_HEAVY_WEIGHT] =
177                 ProcessStatsEnums.AGGREGATED_PROCESS_STATE_BACKGROUND;
178         PROCESS_STATS_STATE_TO_AGGREGATED_STATE[STATE_HOME] =
179                 ProcessStatsEnums.AGGREGATED_PROCESS_STATE_CACHED;
180         PROCESS_STATS_STATE_TO_AGGREGATED_STATE[STATE_LAST_ACTIVITY] =
181                 ProcessStatsEnums.AGGREGATED_PROCESS_STATE_CACHED;
182         PROCESS_STATS_STATE_TO_AGGREGATED_STATE[STATE_CACHED_ACTIVITY] =
183                 ProcessStatsEnums.AGGREGATED_PROCESS_STATE_CACHED;
184         PROCESS_STATS_STATE_TO_AGGREGATED_STATE[STATE_CACHED_ACTIVITY_CLIENT] =
185                 ProcessStatsEnums.AGGREGATED_PROCESS_STATE_CACHED;
186         PROCESS_STATS_STATE_TO_AGGREGATED_STATE[STATE_CACHED_EMPTY] =
187                 ProcessStatsEnums.AGGREGATED_PROCESS_STATE_CACHED;
188     }
189 
190     public static final String[] ADJ_SCREEN_NAMES_CSV = new String[] {
191             "off", "on"
192     };
193 
194     public static final String[] ADJ_MEM_NAMES_CSV = new String[] {
195             "norm", "mod",  "low", "crit"
196     };
197 
198     // State enum is defined in frameworks/base/core/proto/android/service/procstats.proto
199     // Update states must sync enum definition as well, the ordering must not be changed.
200     static final String[] ADJ_SCREEN_TAGS = new String[] {
201             "0", "1"
202     };
203 
204     static final int[] ADJ_SCREEN_PROTO_ENUMS = new int[] {
205             ProcessStatsEnums.SCREEN_STATE_OFF,
206             ProcessStatsEnums.SCREEN_STATE_ON
207     };
208 
209     static final String[] ADJ_MEM_TAGS = new String[] {
210             "n", "m",  "l", "c"
211     };
212 
213     static final int[] ADJ_MEM_PROTO_ENUMS = new int[] {
214             ProcessStatsEnums.MEMORY_STATE_NORMAL,
215             ProcessStatsEnums.MEMORY_STATE_MODERATE,
216             ProcessStatsEnums.MEMORY_STATE_LOW,
217             ProcessStatsEnums.MEMORY_STATE_CRITICAL
218     };
219 
220     static final String CSV_SEP = "\t";
221 
222     /**
223      * No instantiate
224      */
DumpUtils()225     private DumpUtils() {
226     }
227 
printScreenLabel(PrintWriter pw, int offset)228     public static void printScreenLabel(PrintWriter pw, int offset) {
229         switch (offset) {
230             case ADJ_NOTHING:
231                 pw.print("     ");
232                 break;
233             case ADJ_SCREEN_OFF:
234                 pw.print("SOff/");
235                 break;
236             case ADJ_SCREEN_ON:
237                 pw.print(" SOn/");
238                 break;
239             default:
240                 pw.print("????/");
241                 break;
242         }
243     }
244 
printScreenLabelCsv(PrintWriter pw, int offset)245     public static void printScreenLabelCsv(PrintWriter pw, int offset) {
246         switch (offset) {
247             case ADJ_NOTHING:
248                 break;
249             case ADJ_SCREEN_OFF:
250                 pw.print(ADJ_SCREEN_NAMES_CSV[0]);
251                 break;
252             case ADJ_SCREEN_ON:
253                 pw.print(ADJ_SCREEN_NAMES_CSV[1]);
254                 break;
255             default:
256                 pw.print("???");
257                 break;
258         }
259     }
260 
printMemLabel(PrintWriter pw, int offset, char sep)261     public static void printMemLabel(PrintWriter pw, int offset, char sep) {
262         switch (offset) {
263             case ADJ_NOTHING:
264                 pw.print("    ");
265                 if (sep != 0) pw.print(' ');
266                 break;
267             case ADJ_MEM_FACTOR_NORMAL:
268                 pw.print("Norm");
269                 if (sep != 0) pw.print(sep);
270                 break;
271             case ADJ_MEM_FACTOR_MODERATE:
272                 pw.print(" Mod");
273                 if (sep != 0) pw.print(sep);
274                 break;
275             case ADJ_MEM_FACTOR_LOW:
276                 pw.print(" Low");
277                 if (sep != 0) pw.print(sep);
278                 break;
279             case ADJ_MEM_FACTOR_CRITICAL:
280                 pw.print("Crit");
281                 if (sep != 0) pw.print(sep);
282                 break;
283             default:
284                 pw.print("????");
285                 if (sep != 0) pw.print(sep);
286                 break;
287         }
288     }
289 
printMemLabelCsv(PrintWriter pw, int offset)290     public static void printMemLabelCsv(PrintWriter pw, int offset) {
291         if (offset >= ADJ_MEM_FACTOR_NORMAL) {
292             if (offset <= ADJ_MEM_FACTOR_CRITICAL) {
293                 pw.print(ADJ_MEM_NAMES_CSV[offset]);
294             } else {
295                 pw.print("???");
296             }
297         }
298     }
299 
printPercent(PrintWriter pw, double fraction)300     public static void printPercent(PrintWriter pw, double fraction) {
301         fraction *= 100;
302         if (fraction < 1) {
303             pw.print(String.format("%.2f", fraction));
304         } else if (fraction < 10) {
305             pw.print(String.format("%.1f", fraction));
306         } else {
307             pw.print(String.format("%.0f", fraction));
308         }
309         pw.print("%");
310     }
311 
printProcStateTag(PrintWriter pw, int state)312     public static void printProcStateTag(PrintWriter pw, int state) {
313         state = printArrayEntry(pw, ADJ_SCREEN_TAGS,  state, ADJ_SCREEN_MOD*STATE_COUNT);
314         state = printArrayEntry(pw, ADJ_MEM_TAGS,  state, STATE_COUNT);
315         printArrayEntry(pw, STATE_TAGS,  state, 1);
316     }
317 
printProcStateTagProto(ProtoOutputStream proto, long screenId, long memId, long stateId, int state)318     public static void printProcStateTagProto(ProtoOutputStream proto, long screenId, long memId,
319             long stateId, int state) {
320         state = printProto(proto, screenId, ADJ_SCREEN_PROTO_ENUMS,
321                 state, ADJ_SCREEN_MOD * STATE_COUNT);
322         state = printProto(proto, memId, ADJ_MEM_PROTO_ENUMS, state, STATE_COUNT);
323         printProto(proto, stateId, STATE_PROTO_ENUMS, state, 1);
324     }
325 
printAdjTag(PrintWriter pw, int state)326     public static void printAdjTag(PrintWriter pw, int state) {
327         state = printArrayEntry(pw, ADJ_SCREEN_TAGS,  state, ADJ_SCREEN_MOD);
328         printArrayEntry(pw, ADJ_MEM_TAGS, state, 1);
329     }
330 
printProcStateAdjTagProto(ProtoOutputStream proto, long screenId, long memId, int state)331     public static void printProcStateAdjTagProto(ProtoOutputStream proto, long screenId, long memId,
332             int state) {
333         state = printProto(proto, screenId, ADJ_SCREEN_PROTO_ENUMS,
334                 state, ADJ_SCREEN_MOD * STATE_COUNT);
335         printProto(proto, memId, ADJ_MEM_PROTO_ENUMS, state, STATE_COUNT);
336     }
337 
printProcStateDurationProto(ProtoOutputStream proto, long fieldId, int procState, long duration)338     public static void printProcStateDurationProto(ProtoOutputStream proto, long fieldId,
339             int procState, long duration) {
340         final long stateToken = proto.start(fieldId);
341         DumpUtils.printProto(proto, ProcessStatsStateProto.PROCESS_STATE,
342                 DumpUtils.STATE_PROTO_ENUMS, procState, 1);
343         proto.write(ProcessStatsStateProto.DURATION_MS, duration);
344         proto.end(stateToken);
345     }
346 
printProcStateTagAndValue(PrintWriter pw, int state, long value)347     public static void printProcStateTagAndValue(PrintWriter pw, int state, long value) {
348         pw.print(',');
349         printProcStateTag(pw, state);
350         pw.print(':');
351         pw.print(value);
352     }
353 
printAdjTagAndValue(PrintWriter pw, int state, long value)354     public static void printAdjTagAndValue(PrintWriter pw, int state, long value) {
355         pw.print(',');
356         printAdjTag(pw, state);
357         pw.print(':');
358         pw.print(value);
359     }
360 
dumpSingleTime(PrintWriter pw, String prefix, long[] durations, int curState, long curStartTime, long now)361     public static long dumpSingleTime(PrintWriter pw, String prefix, long[] durations,
362             int curState, long curStartTime, long now) {
363         long totalTime = 0;
364         int printedScreen = -1;
365         for (int iscreen=0; iscreen<ADJ_COUNT; iscreen+=ADJ_SCREEN_MOD) {
366             int printedMem = -1;
367             for (int imem=0; imem<ADJ_MEM_FACTOR_COUNT; imem++) {
368                 int state = imem+iscreen;
369                 long time = durations[state];
370                 String running = "";
371                 if (curState == state) {
372                     time += now - curStartTime;
373                     if (pw != null) {
374                         running = " (running)";
375                     }
376                 }
377                 if (time != 0) {
378                     if (pw != null) {
379                         pw.print(prefix);
380                         printScreenLabel(pw, printedScreen != iscreen
381                                 ? iscreen : STATE_NOTHING);
382                         printedScreen = iscreen;
383                         printMemLabel(pw, printedMem != imem ? imem : STATE_NOTHING, (char)0);
384                         printedMem = imem;
385                         pw.print(": ");
386                         TimeUtils.formatDuration(time, pw); pw.println(running);
387                     }
388                     totalTime += time;
389                 }
390             }
391         }
392         if (totalTime != 0 && pw != null) {
393             pw.print(prefix);
394             pw.print("    TOTAL: ");
395             TimeUtils.formatDuration(totalTime, pw);
396             pw.println();
397         }
398         return totalTime;
399     }
400 
dumpAdjTimesCheckin(PrintWriter pw, String sep, long[] durations, int curState, long curStartTime, long now)401     public static void dumpAdjTimesCheckin(PrintWriter pw, String sep, long[] durations,
402             int curState, long curStartTime, long now) {
403         for (int iscreen=0; iscreen<ADJ_COUNT; iscreen+=ADJ_SCREEN_MOD) {
404             for (int imem=0; imem<ADJ_MEM_FACTOR_COUNT; imem++) {
405                 int state = imem+iscreen;
406                 long time = durations[state];
407                 if (curState == state) {
408                     time += now - curStartTime;
409                 }
410                 if (time != 0) {
411                     printAdjTagAndValue(pw, state, time);
412                 }
413             }
414         }
415     }
416 
dumpStateHeadersCsv(PrintWriter pw, String sep, int[] screenStates, int[] memStates, int[] procStates)417     private static void dumpStateHeadersCsv(PrintWriter pw, String sep, int[] screenStates,
418             int[] memStates, int[] procStates) {
419         final int NS = screenStates != null ? screenStates.length : 1;
420         final int NM = memStates != null ? memStates.length : 1;
421         final int NP = procStates != null ? procStates.length : 1;
422         for (int is=0; is<NS; is++) {
423             for (int im=0; im<NM; im++) {
424                 for (int ip=0; ip<NP; ip++) {
425                     pw.print(sep);
426                     boolean printed = false;
427                     if (screenStates != null && screenStates.length > 1) {
428                         printScreenLabelCsv(pw, screenStates[is]);
429                         printed = true;
430                     }
431                     if (memStates != null && memStates.length > 1) {
432                         if (printed) {
433                             pw.print("-");
434                         }
435                         printMemLabelCsv(pw, memStates[im]);
436                         printed = true;
437                     }
438                     if (procStates != null && procStates.length > 1) {
439                         if (printed) {
440                             pw.print("-");
441                         }
442                         pw.print(STATE_NAMES_CSV[procStates[ip]]);
443                     }
444                 }
445             }
446         }
447     }
448 
dumpProcessSummaryLocked(PrintWriter pw, String prefix, String header, ArrayList<ProcessState> procs, int[] screenStates, int[] memStates, int[] procStates, long now, long totalTime)449     public static void dumpProcessSummaryLocked(PrintWriter pw, String prefix, String header,
450             ArrayList<ProcessState> procs, int[] screenStates, int[] memStates, int[] procStates,
451             long now, long totalTime) {
452         for (int i=procs.size()-1; i>=0; i--) {
453             final ProcessState proc = procs.get(i);
454             proc.dumpSummary(pw, prefix, header, screenStates, memStates, procStates, now,
455                     totalTime);
456         }
457     }
458 
dumpProcessListCsv(PrintWriter pw, ArrayList<ProcessState> procs, boolean sepScreenStates, int[] screenStates, boolean sepMemStates, int[] memStates, boolean sepProcStates, int[] procStates, long now)459     public static void dumpProcessListCsv(PrintWriter pw, ArrayList<ProcessState> procs,
460             boolean sepScreenStates, int[] screenStates, boolean sepMemStates, int[] memStates,
461             boolean sepProcStates, int[] procStates, long now) {
462         pw.print("process");
463         pw.print(CSV_SEP);
464         pw.print("uid");
465         pw.print(CSV_SEP);
466         pw.print("vers");
467         dumpStateHeadersCsv(pw, CSV_SEP, sepScreenStates ? screenStates : null,
468                 sepMemStates ? memStates : null,
469                 sepProcStates ? procStates : null);
470         pw.println();
471         for (int i=procs.size()-1; i>=0; i--) {
472             ProcessState proc = procs.get(i);
473             pw.print(proc.getName());
474             pw.print(CSV_SEP);
475             UserHandle.formatUid(pw, proc.getUid());
476             pw.print(CSV_SEP);
477             pw.print(proc.getVersion());
478             proc.dumpCsv(pw, sepScreenStates, screenStates, sepMemStates,
479                     memStates, sepProcStates, procStates, now);
480             pw.println();
481         }
482     }
483 
printArrayEntry(PrintWriter pw, String[] array, int value, int mod)484     public static int printArrayEntry(PrintWriter pw, String[] array, int value, int mod) {
485         int index = value/mod;
486         if (index >= 0 && index < array.length) {
487             pw.print(array[index]);
488         } else {
489             pw.print('?');
490         }
491         return value - index*mod;
492     }
493 
printProto(ProtoOutputStream proto, long fieldId, int[] enums, int value, int mod)494     public static int printProto(ProtoOutputStream proto, long fieldId,
495             int[] enums, int value, int mod) {
496         int index = value/mod;
497         if (index >= 0 && index < enums.length) {
498             proto.write(fieldId, enums[index]);
499         } // else enum default is always zero in proto3
500         return value - index*mod;
501     }
502 
collapseString(String pkgName, String itemName)503     public static String collapseString(String pkgName, String itemName) {
504         if (itemName.startsWith(pkgName)) {
505             final int ITEMLEN = itemName.length();
506             final int PKGLEN = pkgName.length();
507             if (ITEMLEN == PKGLEN) {
508                 return "";
509             } else if (ITEMLEN >= PKGLEN) {
510                 if (itemName.charAt(PKGLEN) == '.') {
511                     return itemName.substring(PKGLEN);
512                 }
513             }
514         }
515         return itemName;
516     }
517 
518     /**
519      * Aggregate process states to reduce size of statistics logs.
520      *
521      * <p>Involves unpacking the three parts of state (process state / device memory state /
522      * screen state), manipulating the elements, then re-packing the new values into a single
523      * int. This integer is guaranteed to be unique for any given combination of state elements.
524      *
525      * @param curState current state as used in mCurState in {@class ProcessState} ie. a value
526      *                 combined from the process's state, the device's memory pressure state, and
527      *                 the device's screen on/off state.
528      * @return an integer representing the combination of screen state and process state, where
529      *         process state has been aggregated.
530      */
aggregateCurrentProcessState(int curState)531     public static int aggregateCurrentProcessState(int curState) {
532         int screenStateIndex = curState / (ADJ_SCREEN_MOD * STATE_COUNT);
533         // extract process state from the compound state variable (discarding memory state)
534         int procStateIndex = curState % STATE_COUNT;
535 
536         // Remap process state per array above.
537         try {
538             procStateIndex = PROCESS_STATS_STATE_TO_AGGREGATED_STATE[procStateIndex];
539         } catch (IndexOutOfBoundsException e) {
540             procStateIndex = ProcessStatsEnums.AGGREGATED_PROCESS_STATE_UNKNOWN;
541         }
542 
543         // Pack screen & process state using bit shifting
544         return (procStateIndex << 0xf) | screenStateIndex;
545     }
546 
547     /** Print aggregated tags generated via {@code #aggregateCurrentProcessState}. */
printAggregatedProcStateTagProto(ProtoOutputStream proto, long screenId, long stateId, int state)548     public static void printAggregatedProcStateTagProto(ProtoOutputStream proto, long screenId,
549             long stateId, int state) {
550         // screen state is in lowest 0xf bits, process state is in next 0xf bits up
551 
552         try {
553             proto.write(stateId, state >> 0xf);
554         } catch (IndexOutOfBoundsException e) {
555             proto.write(stateId, ProcessStatsEnums.PROCESS_STATE_UNKNOWN);
556         }
557 
558         try {
559             proto.write(screenId, ADJ_SCREEN_PROTO_ENUMS[state & 0xf]);
560         } catch (IndexOutOfBoundsException e) {
561             proto.write(screenId, ProcessStatsEnums.SCREEN_STATE_UNKNOWN);
562         }
563     }
564 }
565