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