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.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      */
     87     private DumpUtils() {
     88     }
     89 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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