Home | History | Annotate | Download | only in procstats
      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      */
    157     private DumpUtils() {
    158     }
    159 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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