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.UserHandle; 20 import android.service.procstats.ProcessStatsEnums; 21 import android.service.procstats.ProcessStatsStateProto; 22 import android.util.TimeUtils; 23 import android.util.proto.ProtoOutputStream; 24 25 import static com.android.internal.app.procstats.ProcessStats.*; 26 27 import java.io.PrintWriter; 28 import java.util.ArrayList; 29 30 /** 31 * Utilities for dumping. 32 */ 33 public final class DumpUtils { 34 public static final String[] STATE_NAMES; 35 public static final String[] STATE_LABELS; 36 public static final String STATE_LABEL_TOTAL; 37 public static final String STATE_LABEL_CACHED; 38 public static final String[] STATE_NAMES_CSV; 39 static final String[] STATE_TAGS; 40 static final int[] STATE_PROTO_ENUMS; 41 42 // Make the mapping easy to update. 43 static { 44 STATE_NAMES = new String[STATE_COUNT]; 45 STATE_NAMES[STATE_PERSISTENT] = "Persist"; 46 STATE_NAMES[STATE_TOP] = "Top"; 47 STATE_NAMES[STATE_IMPORTANT_FOREGROUND] = "ImpFg"; 48 STATE_NAMES[STATE_IMPORTANT_BACKGROUND] = "ImpBg"; 49 STATE_NAMES[STATE_BACKUP] = "Backup"; 50 STATE_NAMES[STATE_SERVICE] = "Service"; 51 STATE_NAMES[STATE_SERVICE_RESTARTING] = "ServRst"; 52 STATE_NAMES[STATE_RECEIVER] = "Receivr"; 53 STATE_NAMES[STATE_HEAVY_WEIGHT] = "HeavyWt"; 54 STATE_NAMES[STATE_HOME] = "Home"; 55 STATE_NAMES[STATE_LAST_ACTIVITY] = "LastAct"; 56 STATE_NAMES[STATE_CACHED_ACTIVITY] = "CchAct"; 57 STATE_NAMES[STATE_CACHED_ACTIVITY_CLIENT] = "CchCAct"; 58 STATE_NAMES[STATE_CACHED_EMPTY] = "CchEmty"; 59 60 STATE_LABELS = new String[STATE_COUNT]; 61 STATE_LABELS[STATE_PERSISTENT] = "Persistent"; 62 STATE_LABELS[STATE_TOP] = " Top"; 63 STATE_LABELS[STATE_IMPORTANT_FOREGROUND] = " Imp Fg"; 64 STATE_LABELS[STATE_IMPORTANT_BACKGROUND] = " Imp Bg"; 65 STATE_LABELS[STATE_BACKUP] = " Backup"; 66 STATE_LABELS[STATE_SERVICE] = " Service"; 67 STATE_LABELS[STATE_SERVICE_RESTARTING] = "Service Rs"; 68 STATE_LABELS[STATE_RECEIVER] = " Receiver"; 69 STATE_LABELS[STATE_HEAVY_WEIGHT] = " Heavy Wgt"; 70 STATE_LABELS[STATE_HOME] = " (Home)"; 71 STATE_LABELS[STATE_LAST_ACTIVITY] = "(Last Act)"; 72 STATE_LABELS[STATE_CACHED_ACTIVITY] = " (Cch Act)"; 73 STATE_LABELS[STATE_CACHED_ACTIVITY_CLIENT] = "(Cch CAct)"; 74 STATE_LABELS[STATE_CACHED_EMPTY] = "(Cch Emty)"; 75 STATE_LABEL_CACHED = " (Cached)"; 76 STATE_LABEL_TOTAL = " TOTAL"; 77 78 STATE_NAMES_CSV = new String[STATE_COUNT]; 79 STATE_NAMES_CSV[STATE_PERSISTENT] = "pers"; 80 STATE_NAMES_CSV[STATE_TOP] = "top"; 81 STATE_NAMES_CSV[STATE_IMPORTANT_FOREGROUND] = "impfg"; 82 STATE_NAMES_CSV[STATE_IMPORTANT_BACKGROUND] = "impbg"; 83 STATE_NAMES_CSV[STATE_BACKUP] = "backup"; 84 STATE_NAMES_CSV[STATE_SERVICE] = "service"; 85 STATE_NAMES_CSV[STATE_SERVICE_RESTARTING] = "service-rs"; 86 STATE_NAMES_CSV[STATE_RECEIVER] = "receiver"; 87 STATE_NAMES_CSV[STATE_HEAVY_WEIGHT] = "heavy"; 88 STATE_NAMES_CSV[STATE_HOME] = "home"; 89 STATE_NAMES_CSV[STATE_LAST_ACTIVITY] = "lastact"; 90 STATE_NAMES_CSV[STATE_CACHED_ACTIVITY] = "cch-activity"; 91 STATE_NAMES_CSV[STATE_CACHED_ACTIVITY_CLIENT] = "cch-aclient"; 92 STATE_NAMES_CSV[STATE_CACHED_EMPTY] = "cch-empty"; 93 94 STATE_TAGS = new String[STATE_COUNT]; 95 STATE_TAGS[STATE_PERSISTENT] = "p"; 96 STATE_TAGS[STATE_TOP] = "t"; 97 STATE_TAGS[STATE_IMPORTANT_FOREGROUND] = "f"; 98 STATE_TAGS[STATE_IMPORTANT_BACKGROUND] = "b"; 99 STATE_TAGS[STATE_BACKUP] = "u"; 100 STATE_TAGS[STATE_SERVICE] = "s"; 101 STATE_TAGS[STATE_SERVICE_RESTARTING] = "x"; 102 STATE_TAGS[STATE_RECEIVER] = "r"; 103 STATE_TAGS[STATE_HEAVY_WEIGHT] = "w"; 104 STATE_TAGS[STATE_HOME] = "h"; 105 STATE_TAGS[STATE_LAST_ACTIVITY] = "l"; 106 STATE_TAGS[STATE_CACHED_ACTIVITY] = "a"; 107 STATE_TAGS[STATE_CACHED_ACTIVITY_CLIENT] = "c"; 108 STATE_TAGS[STATE_CACHED_EMPTY] = "e"; 109 110 STATE_PROTO_ENUMS = new int[STATE_COUNT]; 111 STATE_PROTO_ENUMS[STATE_PERSISTENT] = ProcessStatsEnums.PROCESS_STATE_PERSISTENT; 112 STATE_PROTO_ENUMS[STATE_TOP] = ProcessStatsEnums.PROCESS_STATE_TOP; 113 STATE_PROTO_ENUMS[STATE_IMPORTANT_FOREGROUND] = 114 ProcessStatsEnums.PROCESS_STATE_IMPORTANT_FOREGROUND; 115 STATE_PROTO_ENUMS[STATE_IMPORTANT_BACKGROUND] = 116 ProcessStatsEnums.PROCESS_STATE_IMPORTANT_BACKGROUND; 117 STATE_PROTO_ENUMS[STATE_BACKUP] = ProcessStatsEnums.PROCESS_STATE_BACKUP; 118 STATE_PROTO_ENUMS[STATE_SERVICE] = ProcessStatsEnums.PROCESS_STATE_SERVICE; 119 STATE_PROTO_ENUMS[STATE_SERVICE_RESTARTING] = 120 ProcessStatsEnums.PROCESS_STATE_SERVICE_RESTARTING; 121 STATE_PROTO_ENUMS[STATE_RECEIVER] = ProcessStatsEnums.PROCESS_STATE_RECEIVER; 122 STATE_PROTO_ENUMS[STATE_HEAVY_WEIGHT] = ProcessStatsEnums.PROCESS_STATE_HEAVY_WEIGHT; 123 STATE_PROTO_ENUMS[STATE_HOME] = ProcessStatsEnums.PROCESS_STATE_HOME; 124 STATE_PROTO_ENUMS[STATE_LAST_ACTIVITY] = ProcessStatsEnums.PROCESS_STATE_LAST_ACTIVITY; 125 STATE_PROTO_ENUMS[STATE_CACHED_ACTIVITY] = ProcessStatsEnums.PROCESS_STATE_CACHED_ACTIVITY; 126 STATE_PROTO_ENUMS[STATE_CACHED_ACTIVITY_CLIENT] = 127 ProcessStatsEnums.PROCESS_STATE_CACHED_ACTIVITY_CLIENT; 128 STATE_PROTO_ENUMS[STATE_CACHED_EMPTY] = ProcessStatsEnums.PROCESS_STATE_CACHED_EMPTY; 129 } 130 131 public static final String[] ADJ_SCREEN_NAMES_CSV = new String[] { 132 "off", "on" 133 }; 134 135 public static final String[] ADJ_MEM_NAMES_CSV = new String[] { 136 "norm", "mod", "low", "crit" 137 }; 138 139 // State enum is defined in frameworks/base/core/proto/android/service/procstats.proto 140 // Update states must sync enum definition as well, the ordering must not be changed. 141 static final String[] ADJ_SCREEN_TAGS = new String[] { 142 "0", "1" 143 }; 144 145 static final int[] ADJ_SCREEN_PROTO_ENUMS = new int[] { 146 ProcessStatsEnums.SCREEN_STATE_OFF, 147 ProcessStatsEnums.SCREEN_STATE_ON 148 }; 149 150 static final String[] ADJ_MEM_TAGS = new String[] { 151 "n", "m", "l", "c" 152 }; 153 154 static final int[] ADJ_MEM_PROTO_ENUMS = new int[] { 155 ProcessStatsEnums.MEMORY_STATE_NORMAL, 156 ProcessStatsEnums.MEMORY_STATE_MODERATE, 157 ProcessStatsEnums.MEMORY_STATE_LOW, 158 ProcessStatsEnums.MEMORY_STATE_CRITICAL 159 }; 160 161 static final String CSV_SEP = "\t"; 162 163 /** 164 * No instantiate 165 */ DumpUtils()166 private DumpUtils() { 167 } 168 printScreenLabel(PrintWriter pw, int offset)169 public static void printScreenLabel(PrintWriter pw, int offset) { 170 switch (offset) { 171 case ADJ_NOTHING: 172 pw.print(" "); 173 break; 174 case ADJ_SCREEN_OFF: 175 pw.print("SOff/"); 176 break; 177 case ADJ_SCREEN_ON: 178 pw.print(" SOn/"); 179 break; 180 default: 181 pw.print("????/"); 182 break; 183 } 184 } 185 printScreenLabelCsv(PrintWriter pw, int offset)186 public static void printScreenLabelCsv(PrintWriter pw, int offset) { 187 switch (offset) { 188 case ADJ_NOTHING: 189 break; 190 case ADJ_SCREEN_OFF: 191 pw.print(ADJ_SCREEN_NAMES_CSV[0]); 192 break; 193 case ADJ_SCREEN_ON: 194 pw.print(ADJ_SCREEN_NAMES_CSV[1]); 195 break; 196 default: 197 pw.print("???"); 198 break; 199 } 200 } 201 printMemLabel(PrintWriter pw, int offset, char sep)202 public static void printMemLabel(PrintWriter pw, int offset, char sep) { 203 switch (offset) { 204 case ADJ_NOTHING: 205 pw.print(" "); 206 if (sep != 0) pw.print(' '); 207 break; 208 case ADJ_MEM_FACTOR_NORMAL: 209 pw.print("Norm"); 210 if (sep != 0) pw.print(sep); 211 break; 212 case ADJ_MEM_FACTOR_MODERATE: 213 pw.print(" Mod"); 214 if (sep != 0) pw.print(sep); 215 break; 216 case ADJ_MEM_FACTOR_LOW: 217 pw.print(" Low"); 218 if (sep != 0) pw.print(sep); 219 break; 220 case ADJ_MEM_FACTOR_CRITICAL: 221 pw.print("Crit"); 222 if (sep != 0) pw.print(sep); 223 break; 224 default: 225 pw.print("????"); 226 if (sep != 0) pw.print(sep); 227 break; 228 } 229 } 230 printMemLabelCsv(PrintWriter pw, int offset)231 public static void printMemLabelCsv(PrintWriter pw, int offset) { 232 if (offset >= ADJ_MEM_FACTOR_NORMAL) { 233 if (offset <= ADJ_MEM_FACTOR_CRITICAL) { 234 pw.print(ADJ_MEM_NAMES_CSV[offset]); 235 } else { 236 pw.print("???"); 237 } 238 } 239 } 240 printPercent(PrintWriter pw, double fraction)241 public static void printPercent(PrintWriter pw, double fraction) { 242 fraction *= 100; 243 if (fraction < 1) { 244 pw.print(String.format("%.2f", fraction)); 245 } else if (fraction < 10) { 246 pw.print(String.format("%.1f", fraction)); 247 } else { 248 pw.print(String.format("%.0f", fraction)); 249 } 250 pw.print("%"); 251 } 252 printProcStateTag(PrintWriter pw, int state)253 public static void printProcStateTag(PrintWriter pw, int state) { 254 state = printArrayEntry(pw, ADJ_SCREEN_TAGS, state, ADJ_SCREEN_MOD*STATE_COUNT); 255 state = printArrayEntry(pw, ADJ_MEM_TAGS, state, STATE_COUNT); 256 printArrayEntry(pw, STATE_TAGS, state, 1); 257 } 258 printProcStateTagProto(ProtoOutputStream proto, long screenId, long memId, long stateId, int state)259 public static void printProcStateTagProto(ProtoOutputStream proto, long screenId, long memId, 260 long stateId, int state) { 261 state = printProto(proto, screenId, ADJ_SCREEN_PROTO_ENUMS, 262 state, ADJ_SCREEN_MOD * STATE_COUNT); 263 state = printProto(proto, memId, ADJ_MEM_PROTO_ENUMS, state, STATE_COUNT); 264 printProto(proto, stateId, STATE_PROTO_ENUMS, state, 1); 265 } 266 printAdjTag(PrintWriter pw, int state)267 public static void printAdjTag(PrintWriter pw, int state) { 268 state = printArrayEntry(pw, ADJ_SCREEN_TAGS, state, ADJ_SCREEN_MOD); 269 printArrayEntry(pw, ADJ_MEM_TAGS, state, 1); 270 } 271 printProcStateAdjTagProto(ProtoOutputStream proto, long screenId, long memId, int state)272 public static void printProcStateAdjTagProto(ProtoOutputStream proto, long screenId, long memId, 273 int state) { 274 state = printProto(proto, screenId, ADJ_SCREEN_PROTO_ENUMS, 275 state, ADJ_SCREEN_MOD * STATE_COUNT); 276 printProto(proto, memId, ADJ_MEM_PROTO_ENUMS, state, STATE_COUNT); 277 } 278 printProcStateDurationProto(ProtoOutputStream proto, long fieldId, int procState, long duration)279 public static void printProcStateDurationProto(ProtoOutputStream proto, long fieldId, 280 int procState, long duration) { 281 final long stateToken = proto.start(fieldId); 282 DumpUtils.printProto(proto, ProcessStatsStateProto.PROCESS_STATE, 283 DumpUtils.STATE_PROTO_ENUMS, procState, 1); 284 proto.write(ProcessStatsStateProto.DURATION_MS, duration); 285 proto.end(stateToken); 286 } 287 printProcStateTagAndValue(PrintWriter pw, int state, long value)288 public static void printProcStateTagAndValue(PrintWriter pw, int state, long value) { 289 pw.print(','); 290 printProcStateTag(pw, state); 291 pw.print(':'); 292 pw.print(value); 293 } 294 printAdjTagAndValue(PrintWriter pw, int state, long value)295 public static void printAdjTagAndValue(PrintWriter pw, int state, long value) { 296 pw.print(','); 297 printAdjTag(pw, state); 298 pw.print(':'); 299 pw.print(value); 300 } 301 dumpSingleTime(PrintWriter pw, String prefix, long[] durations, int curState, long curStartTime, long now)302 public static long dumpSingleTime(PrintWriter pw, String prefix, long[] durations, 303 int curState, long curStartTime, long now) { 304 long totalTime = 0; 305 int printedScreen = -1; 306 for (int iscreen=0; iscreen<ADJ_COUNT; iscreen+=ADJ_SCREEN_MOD) { 307 int printedMem = -1; 308 for (int imem=0; imem<ADJ_MEM_FACTOR_COUNT; imem++) { 309 int state = imem+iscreen; 310 long time = durations[state]; 311 String running = ""; 312 if (curState == state) { 313 time += now - curStartTime; 314 if (pw != null) { 315 running = " (running)"; 316 } 317 } 318 if (time != 0) { 319 if (pw != null) { 320 pw.print(prefix); 321 printScreenLabel(pw, printedScreen != iscreen 322 ? iscreen : STATE_NOTHING); 323 printedScreen = iscreen; 324 printMemLabel(pw, printedMem != imem ? imem : STATE_NOTHING, (char)0); 325 printedMem = imem; 326 pw.print(": "); 327 TimeUtils.formatDuration(time, pw); pw.println(running); 328 } 329 totalTime += time; 330 } 331 } 332 } 333 if (totalTime != 0 && pw != null) { 334 pw.print(prefix); 335 pw.print(" TOTAL: "); 336 TimeUtils.formatDuration(totalTime, pw); 337 pw.println(); 338 } 339 return totalTime; 340 } 341 dumpAdjTimesCheckin(PrintWriter pw, String sep, long[] durations, int curState, long curStartTime, long now)342 public static void dumpAdjTimesCheckin(PrintWriter pw, String sep, long[] durations, 343 int curState, long curStartTime, long now) { 344 for (int iscreen=0; iscreen<ADJ_COUNT; iscreen+=ADJ_SCREEN_MOD) { 345 for (int imem=0; imem<ADJ_MEM_FACTOR_COUNT; imem++) { 346 int state = imem+iscreen; 347 long time = durations[state]; 348 if (curState == state) { 349 time += now - curStartTime; 350 } 351 if (time != 0) { 352 printAdjTagAndValue(pw, state, time); 353 } 354 } 355 } 356 } 357 dumpStateHeadersCsv(PrintWriter pw, String sep, int[] screenStates, int[] memStates, int[] procStates)358 private static void dumpStateHeadersCsv(PrintWriter pw, String sep, int[] screenStates, 359 int[] memStates, int[] procStates) { 360 final int NS = screenStates != null ? screenStates.length : 1; 361 final int NM = memStates != null ? memStates.length : 1; 362 final int NP = procStates != null ? procStates.length : 1; 363 for (int is=0; is<NS; is++) { 364 for (int im=0; im<NM; im++) { 365 for (int ip=0; ip<NP; ip++) { 366 pw.print(sep); 367 boolean printed = false; 368 if (screenStates != null && screenStates.length > 1) { 369 printScreenLabelCsv(pw, screenStates[is]); 370 printed = true; 371 } 372 if (memStates != null && memStates.length > 1) { 373 if (printed) { 374 pw.print("-"); 375 } 376 printMemLabelCsv(pw, memStates[im]); 377 printed = true; 378 } 379 if (procStates != null && procStates.length > 1) { 380 if (printed) { 381 pw.print("-"); 382 } 383 pw.print(STATE_NAMES_CSV[procStates[ip]]); 384 } 385 } 386 } 387 } 388 } 389 dumpProcessSummaryLocked(PrintWriter pw, String prefix, String header, ArrayList<ProcessState> procs, int[] screenStates, int[] memStates, int[] procStates, long now, long totalTime)390 public static void dumpProcessSummaryLocked(PrintWriter pw, String prefix, String header, 391 ArrayList<ProcessState> procs, int[] screenStates, int[] memStates, int[] procStates, 392 long now, long totalTime) { 393 for (int i=procs.size()-1; i>=0; i--) { 394 final ProcessState proc = procs.get(i); 395 proc.dumpSummary(pw, prefix, header, screenStates, memStates, procStates, now, 396 totalTime); 397 } 398 } 399 dumpProcessListCsv(PrintWriter pw, ArrayList<ProcessState> procs, boolean sepScreenStates, int[] screenStates, boolean sepMemStates, int[] memStates, boolean sepProcStates, int[] procStates, long now)400 public static void dumpProcessListCsv(PrintWriter pw, ArrayList<ProcessState> procs, 401 boolean sepScreenStates, int[] screenStates, boolean sepMemStates, int[] memStates, 402 boolean sepProcStates, int[] procStates, long now) { 403 pw.print("process"); 404 pw.print(CSV_SEP); 405 pw.print("uid"); 406 pw.print(CSV_SEP); 407 pw.print("vers"); 408 dumpStateHeadersCsv(pw, CSV_SEP, sepScreenStates ? screenStates : null, 409 sepMemStates ? memStates : null, 410 sepProcStates ? procStates : null); 411 pw.println(); 412 for (int i=procs.size()-1; i>=0; i--) { 413 ProcessState proc = procs.get(i); 414 pw.print(proc.getName()); 415 pw.print(CSV_SEP); 416 UserHandle.formatUid(pw, proc.getUid()); 417 pw.print(CSV_SEP); 418 pw.print(proc.getVersion()); 419 proc.dumpCsv(pw, sepScreenStates, screenStates, sepMemStates, 420 memStates, sepProcStates, procStates, now); 421 pw.println(); 422 } 423 } 424 printArrayEntry(PrintWriter pw, String[] array, int value, int mod)425 public static int printArrayEntry(PrintWriter pw, String[] array, int value, int mod) { 426 int index = value/mod; 427 if (index >= 0 && index < array.length) { 428 pw.print(array[index]); 429 } else { 430 pw.print('?'); 431 } 432 return value - index*mod; 433 } 434 printProto(ProtoOutputStream proto, long fieldId, int[] enums, int value, int mod)435 public static int printProto(ProtoOutputStream proto, long fieldId, 436 int[] enums, int value, int mod) { 437 int index = value/mod; 438 if (index >= 0 && index < enums.length) { 439 proto.write(fieldId, enums[index]); 440 } // else enum default is always zero in proto3 441 return value - index*mod; 442 } 443 collapseString(String pkgName, String itemName)444 public static String collapseString(String pkgName, String itemName) { 445 if (itemName.startsWith(pkgName)) { 446 final int ITEMLEN = itemName.length(); 447 final int PKGLEN = pkgName.length(); 448 if (ITEMLEN == PKGLEN) { 449 return ""; 450 } else if (ITEMLEN >= PKGLEN) { 451 if (itemName.charAt(PKGLEN) == '.') { 452 return itemName.substring(PKGLEN); 453 } 454 } 455 } 456 return itemName; 457 } 458 } 459