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 */ DumpUtils()157 private DumpUtils() { 158 } 159 printScreenLabel(PrintWriter pw, int offset)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 printScreenLabelCsv(PrintWriter pw, int offset)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 printMemLabel(PrintWriter pw, int offset, char sep)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 printMemLabelCsv(PrintWriter pw, int offset)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 printPercent(PrintWriter pw, double fraction)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 printProcStateTag(PrintWriter pw, int state)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 printProcStateTagProto(ProtoOutputStream proto, long screenId, long memId, long stateId, int state)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 printAdjTag(PrintWriter pw, int state)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 printProcStateTagAndValue(PrintWriter pw, int state, long value)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 printAdjTagAndValue(PrintWriter pw, int state, long value)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 dumpSingleTime(PrintWriter pw, String prefix, long[] durations, int curState, long curStartTime, long now)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 dumpAdjTimesCheckin(PrintWriter pw, String sep, long[] durations, int curState, long curStartTime, long now)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 dumpStateHeadersCsv(PrintWriter pw, String sep, int[] screenStates, int[] memStates, int[] procStates)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 dumpProcessSummaryLocked(PrintWriter pw, String prefix, ArrayList<ProcessState> procs, int[] screenStates, int[] memStates, int[] procStates, long now, long totalTime)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 dumpProcessListCsv(PrintWriter pw, ArrayList<ProcessState> procs, boolean sepScreenStates, int[] screenStates, boolean sepMemStates, int[] memStates, boolean sepProcStates, int[] procStates, long now)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 printArrayEntry(PrintWriter pw, String[] array, int value, int mod)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 printProto(ProtoOutputStream proto, long fieldId, int[] enums, int value, int mod)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 collapseString(String pkgName, String itemName)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