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.server.am; 18 19 import android.os.Binder; 20 import android.os.Parcel; 21 import android.os.ParcelFileDescriptor; 22 import android.os.RemoteException; 23 import android.os.SystemClock; 24 import android.os.SystemProperties; 25 import android.service.procstats.ProcessStatsServiceDumpProto; 26 import android.text.format.DateFormat; 27 import android.util.ArrayMap; 28 import android.util.AtomicFile; 29 import android.util.Log; 30 import android.util.LongSparseArray; 31 import android.util.Slog; 32 import android.util.SparseArray; 33 import android.util.TimeUtils; 34 import android.util.proto.ProtoOutputStream; 35 36 import com.android.internal.annotations.GuardedBy; 37 import com.android.internal.app.procstats.DumpUtils; 38 import com.android.internal.app.procstats.IProcessStats; 39 import com.android.internal.app.procstats.ProcessState; 40 import com.android.internal.app.procstats.ProcessStats; 41 import com.android.internal.app.procstats.ServiceState; 42 import com.android.internal.os.BackgroundThread; 43 44 import java.io.File; 45 import java.io.FileDescriptor; 46 import java.io.FileInputStream; 47 import java.io.FileOutputStream; 48 import java.io.IOException; 49 import java.io.InputStream; 50 import java.io.PrintWriter; 51 import java.util.ArrayList; 52 import java.util.Arrays; 53 import java.util.Collections; 54 import java.util.List; 55 import java.util.concurrent.locks.ReentrantLock; 56 57 public final class ProcessStatsService extends IProcessStats.Stub { 58 static final String TAG = "ProcessStatsService"; 59 static final boolean DEBUG = false; 60 61 // Most data is kept in a sparse data structure: an integer array which integer 62 // holds the type of the entry, and the identifier for a long array that data 63 // exists in and the offset into the array to find it. The constants below 64 // define the encoding of that data in an integer. 65 66 static final int MAX_HISTORIC_STATES = 8; // Maximum number of historic states we will keep. 67 static final String STATE_FILE_PREFIX = "state-"; // Prefix to use for state filenames. 68 static final String STATE_FILE_SUFFIX = ".bin"; // Suffix to use for state filenames. 69 static final String STATE_FILE_CHECKIN_SUFFIX = ".ci"; // State files that have checked in. 70 static long WRITE_PERIOD = 30*60*1000; // Write file every 30 minutes or so. 71 72 final ActivityManagerService mAm; 73 final File mBaseDir; 74 ProcessStats mProcessStats; 75 AtomicFile mFile; 76 boolean mCommitPending; 77 boolean mShuttingDown; 78 int mLastMemOnlyState = -1; 79 boolean mMemFactorLowered; 80 81 final ReentrantLock mWriteLock = new ReentrantLock(); 82 final Object mPendingWriteLock = new Object(); 83 AtomicFile mPendingWriteFile; 84 Parcel mPendingWrite; 85 boolean mPendingWriteCommitted; 86 long mLastWriteTime; 87 88 /** For CTS to inject the screen state. */ 89 @GuardedBy("mAm") 90 Boolean mInjectedScreenState; 91 ProcessStatsService(ActivityManagerService am, File file)92 public ProcessStatsService(ActivityManagerService am, File file) { 93 mAm = am; 94 mBaseDir = file; 95 mBaseDir.mkdirs(); 96 mProcessStats = new ProcessStats(true); 97 updateFile(); 98 SystemProperties.addChangeCallback(new Runnable() { 99 @Override public void run() { 100 synchronized (mAm) { 101 if (mProcessStats.evaluateSystemProperties(false)) { 102 mProcessStats.mFlags |= ProcessStats.FLAG_SYSPROPS; 103 writeStateLocked(true, true); 104 mProcessStats.evaluateSystemProperties(true); 105 } 106 } 107 } 108 }); 109 } 110 111 @Override onTransact(int code, Parcel data, Parcel reply, int flags)112 public boolean onTransact(int code, Parcel data, Parcel reply, int flags) 113 throws RemoteException { 114 try { 115 return super.onTransact(code, data, reply, flags); 116 } catch (RuntimeException e) { 117 if (!(e instanceof SecurityException)) { 118 Slog.wtf(TAG, "Process Stats Crash", e); 119 } 120 throw e; 121 } 122 } 123 124 @GuardedBy("mAm") updateProcessStateHolderLocked(ProcessStats.ProcessStateHolder holder, String packageName, int uid, long versionCode, String processName)125 public void updateProcessStateHolderLocked(ProcessStats.ProcessStateHolder holder, 126 String packageName, int uid, long versionCode, String processName) { 127 holder.pkg = mProcessStats.getPackageStateLocked(packageName, uid, versionCode); 128 holder.state = mProcessStats.getProcessStateLocked(holder.pkg, processName); 129 } 130 131 @GuardedBy("mAm") getProcessStateLocked(String packageName, int uid, long versionCode, String processName)132 public ProcessState getProcessStateLocked(String packageName, 133 int uid, long versionCode, String processName) { 134 return mProcessStats.getProcessStateLocked(packageName, uid, versionCode, processName); 135 } 136 137 @GuardedBy("mAm") getServiceStateLocked(String packageName, int uid, long versionCode, String processName, String className)138 public ServiceState getServiceStateLocked(String packageName, int uid, 139 long versionCode, String processName, String className) { 140 return mProcessStats.getServiceStateLocked(packageName, uid, versionCode, processName, 141 className); 142 } 143 isMemFactorLowered()144 public boolean isMemFactorLowered() { 145 return mMemFactorLowered; 146 } 147 148 @GuardedBy("mAm") setMemFactorLocked(int memFactor, boolean screenOn, long now)149 public boolean setMemFactorLocked(int memFactor, boolean screenOn, long now) { 150 mMemFactorLowered = memFactor < mLastMemOnlyState; 151 mLastMemOnlyState = memFactor; 152 if (mInjectedScreenState != null) { 153 screenOn = mInjectedScreenState; 154 } 155 if (screenOn) { 156 memFactor += ProcessStats.ADJ_SCREEN_ON; 157 } 158 if (memFactor != mProcessStats.mMemFactor) { 159 if (mProcessStats.mMemFactor != ProcessStats.STATE_NOTHING) { 160 mProcessStats.mMemFactorDurations[mProcessStats.mMemFactor] 161 += now - mProcessStats.mStartTime; 162 } 163 mProcessStats.mMemFactor = memFactor; 164 mProcessStats.mStartTime = now; 165 final ArrayMap<String, SparseArray<LongSparseArray<ProcessStats.PackageState>>> pmap 166 = mProcessStats.mPackages.getMap(); 167 for (int ipkg=pmap.size()-1; ipkg>=0; ipkg--) { 168 final SparseArray<LongSparseArray<ProcessStats.PackageState>> uids = 169 pmap.valueAt(ipkg); 170 for (int iuid=uids.size()-1; iuid>=0; iuid--) { 171 final LongSparseArray<ProcessStats.PackageState> vers = uids.valueAt(iuid); 172 for (int iver=vers.size()-1; iver>=0; iver--) { 173 final ProcessStats.PackageState pkg = vers.valueAt(iver); 174 final ArrayMap<String, ServiceState> services = pkg.mServices; 175 for (int isvc=services.size()-1; isvc>=0; isvc--) { 176 final ServiceState service = services.valueAt(isvc); 177 service.setMemFactor(memFactor, now); 178 } 179 } 180 } 181 } 182 return true; 183 } 184 return false; 185 } 186 187 @GuardedBy("mAm") getMemFactorLocked()188 public int getMemFactorLocked() { 189 return mProcessStats.mMemFactor != ProcessStats.STATE_NOTHING ? mProcessStats.mMemFactor : 0; 190 } 191 192 @GuardedBy("mAm") addSysMemUsageLocked(long cachedMem, long freeMem, long zramMem, long kernelMem, long nativeMem)193 public void addSysMemUsageLocked(long cachedMem, long freeMem, long zramMem, long kernelMem, 194 long nativeMem) { 195 mProcessStats.addSysMemUsage(cachedMem, freeMem, zramMem, kernelMem, nativeMem); 196 } 197 198 @GuardedBy("mAm") updateTrackingAssociationsLocked(int curSeq, long now)199 public void updateTrackingAssociationsLocked(int curSeq, long now) { 200 mProcessStats.updateTrackingAssociationsLocked(curSeq, now); 201 } 202 203 @GuardedBy("mAm") shouldWriteNowLocked(long now)204 public boolean shouldWriteNowLocked(long now) { 205 if (now > (mLastWriteTime+WRITE_PERIOD)) { 206 if (SystemClock.elapsedRealtime() 207 > (mProcessStats.mTimePeriodStartRealtime+ProcessStats.COMMIT_PERIOD) && 208 SystemClock.uptimeMillis() 209 > (mProcessStats.mTimePeriodStartUptime+ProcessStats.COMMIT_UPTIME_PERIOD)) { 210 mCommitPending = true; 211 } 212 return true; 213 } 214 return false; 215 } 216 217 @GuardedBy("mAm") shutdownLocked()218 public void shutdownLocked() { 219 Slog.w(TAG, "Writing process stats before shutdown..."); 220 mProcessStats.mFlags |= ProcessStats.FLAG_SHUTDOWN; 221 writeStateSyncLocked(); 222 mShuttingDown = true; 223 } 224 225 @GuardedBy("mAm") writeStateAsyncLocked()226 public void writeStateAsyncLocked() { 227 writeStateLocked(false); 228 } 229 230 @GuardedBy("mAm") writeStateSyncLocked()231 public void writeStateSyncLocked() { 232 writeStateLocked(true); 233 } 234 235 @GuardedBy("mAm") writeStateLocked(boolean sync)236 private void writeStateLocked(boolean sync) { 237 if (mShuttingDown) { 238 return; 239 } 240 boolean commitPending = mCommitPending; 241 mCommitPending = false; 242 writeStateLocked(sync, commitPending); 243 } 244 245 @GuardedBy("mAm") writeStateLocked(boolean sync, final boolean commit)246 public void writeStateLocked(boolean sync, final boolean commit) { 247 final long totalTime; 248 synchronized (mPendingWriteLock) { 249 final long now = SystemClock.uptimeMillis(); 250 if (mPendingWrite == null || !mPendingWriteCommitted) { 251 mPendingWrite = Parcel.obtain(); 252 mProcessStats.mTimePeriodEndRealtime = SystemClock.elapsedRealtime(); 253 mProcessStats.mTimePeriodEndUptime = now; 254 if (commit) { 255 mProcessStats.mFlags |= ProcessStats.FLAG_COMPLETE; 256 } 257 mProcessStats.writeToParcel(mPendingWrite, 0); 258 mPendingWriteFile = new AtomicFile(mFile.getBaseFile()); 259 mPendingWriteCommitted = commit; 260 } 261 if (commit) { 262 mProcessStats.resetSafely(); 263 updateFile(); 264 mAm.requestPssAllProcsLocked(SystemClock.uptimeMillis(), true, false); 265 } 266 mLastWriteTime = SystemClock.uptimeMillis(); 267 totalTime = SystemClock.uptimeMillis() - now; 268 if (DEBUG) Slog.d(TAG, "Prepared write state in " + now + "ms"); 269 if (!sync) { 270 BackgroundThread.getHandler().post(new Runnable() { 271 @Override public void run() { 272 performWriteState(totalTime); 273 } 274 }); 275 return; 276 } 277 } 278 279 performWriteState(totalTime); 280 } 281 updateFile()282 private void updateFile() { 283 mFile = new AtomicFile(new File(mBaseDir, STATE_FILE_PREFIX 284 + mProcessStats.mTimePeriodStartClockStr + STATE_FILE_SUFFIX)); 285 mLastWriteTime = SystemClock.uptimeMillis(); 286 } 287 performWriteState(long initialTime)288 void performWriteState(long initialTime) { 289 if (DEBUG) Slog.d(TAG, "Performing write to " + mFile.getBaseFile()); 290 Parcel data; 291 AtomicFile file; 292 synchronized (mPendingWriteLock) { 293 data = mPendingWrite; 294 file = mPendingWriteFile; 295 mPendingWriteCommitted = false; 296 if (data == null) { 297 return; 298 } 299 mPendingWrite = null; 300 mPendingWriteFile = null; 301 mWriteLock.lock(); 302 } 303 304 final long startTime = SystemClock.uptimeMillis(); 305 FileOutputStream stream = null; 306 try { 307 stream = file.startWrite(); 308 stream.write(data.marshall()); 309 stream.flush(); 310 file.finishWrite(stream); 311 com.android.internal.logging.EventLogTags.writeCommitSysConfigFile( 312 "procstats", SystemClock.uptimeMillis() - startTime + initialTime); 313 if (DEBUG) Slog.d(TAG, "Write completed successfully!"); 314 } catch (IOException e) { 315 Slog.w(TAG, "Error writing process statistics", e); 316 file.failWrite(stream); 317 } finally { 318 data.recycle(); 319 trimHistoricStatesWriteLocked(); 320 mWriteLock.unlock(); 321 } 322 } 323 324 @GuardedBy("mAm") readLocked(ProcessStats stats, AtomicFile file)325 boolean readLocked(ProcessStats stats, AtomicFile file) { 326 try { 327 FileInputStream stream = file.openRead(); 328 stats.read(stream); 329 stream.close(); 330 if (stats.mReadError != null) { 331 Slog.w(TAG, "Ignoring existing stats; " + stats.mReadError); 332 if (DEBUG) { 333 ArrayMap<String, SparseArray<ProcessState>> procMap = stats.mProcesses.getMap(); 334 final int NPROC = procMap.size(); 335 for (int ip=0; ip<NPROC; ip++) { 336 Slog.w(TAG, "Process: " + procMap.keyAt(ip)); 337 SparseArray<ProcessState> uids = procMap.valueAt(ip); 338 final int NUID = uids.size(); 339 for (int iu=0; iu<NUID; iu++) { 340 Slog.w(TAG, " Uid " + uids.keyAt(iu) + ": " + uids.valueAt(iu)); 341 } 342 } 343 ArrayMap<String, SparseArray<LongSparseArray<ProcessStats.PackageState>>> pkgMap 344 = stats.mPackages.getMap(); 345 final int NPKG = pkgMap.size(); 346 for (int ip=0; ip<NPKG; ip++) { 347 Slog.w(TAG, "Package: " + pkgMap.keyAt(ip)); 348 SparseArray<LongSparseArray<ProcessStats.PackageState>> uids 349 = pkgMap.valueAt(ip); 350 final int NUID = uids.size(); 351 for (int iu=0; iu<NUID; iu++) { 352 Slog.w(TAG, " Uid: " + uids.keyAt(iu)); 353 LongSparseArray<ProcessStats.PackageState> vers = uids.valueAt(iu); 354 final int NVERS = vers.size(); 355 for (int iv=0; iv<NVERS; iv++) { 356 Slog.w(TAG, " Vers: " + vers.keyAt(iv)); 357 ProcessStats.PackageState pkgState = vers.valueAt(iv); 358 final int NPROCS = pkgState.mProcesses.size(); 359 for (int iproc=0; iproc<NPROCS; iproc++) { 360 Slog.w(TAG, " Process " + pkgState.mProcesses.keyAt(iproc) 361 + ": " + pkgState.mProcesses.valueAt(iproc)); 362 } 363 final int NSRVS = pkgState.mServices.size(); 364 for (int isvc=0; isvc<NSRVS; isvc++) { 365 Slog.w(TAG, " Service " + pkgState.mServices.keyAt(isvc) 366 + ": " + pkgState.mServices.valueAt(isvc)); 367 368 } 369 final int NASCS = pkgState.mAssociations.size(); 370 for (int iasc=0; iasc<NASCS; iasc++) { 371 Slog.w(TAG, " Association " 372 + pkgState.mServices.keyAt(iasc) 373 + ": " + pkgState.mAssociations.valueAt(iasc)); 374 375 } 376 } 377 } 378 } 379 } 380 return false; 381 } 382 } catch (Throwable e) { 383 stats.mReadError = "caught exception: " + e; 384 Slog.e(TAG, "Error reading process statistics", e); 385 return false; 386 } 387 return true; 388 } 389 getCommittedFiles(int minNum, boolean inclCurrent, boolean inclCheckedIn)390 private ArrayList<String> getCommittedFiles(int minNum, boolean inclCurrent, 391 boolean inclCheckedIn) { 392 File[] files = mBaseDir.listFiles(); 393 if (files == null || files.length <= minNum) { 394 return null; 395 } 396 ArrayList<String> filesArray = new ArrayList<String>(files.length); 397 String currentFile = mFile.getBaseFile().getPath(); 398 if (DEBUG) Slog.d(TAG, "Collecting " + files.length + " files except: " + currentFile); 399 for (int i=0; i<files.length; i++) { 400 File file = files[i]; 401 String fileStr = file.getPath(); 402 if (DEBUG) Slog.d(TAG, "Collecting: " + fileStr); 403 if (!inclCheckedIn && fileStr.endsWith(STATE_FILE_CHECKIN_SUFFIX)) { 404 if (DEBUG) Slog.d(TAG, "Skipping: already checked in"); 405 continue; 406 } 407 if (!inclCurrent && fileStr.equals(currentFile)) { 408 if (DEBUG) Slog.d(TAG, "Skipping: current stats"); 409 continue; 410 } 411 filesArray.add(fileStr); 412 } 413 Collections.sort(filesArray); 414 return filesArray; 415 } 416 417 @GuardedBy("mAm") trimHistoricStatesWriteLocked()418 public void trimHistoricStatesWriteLocked() { 419 ArrayList<String> filesArray = getCommittedFiles(MAX_HISTORIC_STATES, false, true); 420 if (filesArray == null) { 421 return; 422 } 423 while (filesArray.size() > MAX_HISTORIC_STATES) { 424 String file = filesArray.remove(0); 425 Slog.i(TAG, "Pruning old procstats: " + file); 426 (new File(file)).delete(); 427 } 428 } 429 430 @GuardedBy("mAm") dumpFilteredProcessesCsvLocked(PrintWriter pw, String header, boolean sepScreenStates, int[] screenStates, boolean sepMemStates, int[] memStates, boolean sepProcStates, int[] procStates, long now, String reqPackage)431 boolean dumpFilteredProcessesCsvLocked(PrintWriter pw, String header, 432 boolean sepScreenStates, int[] screenStates, boolean sepMemStates, int[] memStates, 433 boolean sepProcStates, int[] procStates, long now, String reqPackage) { 434 ArrayList<ProcessState> procs = mProcessStats.collectProcessesLocked( 435 screenStates, memStates, procStates, procStates, now, reqPackage, false); 436 if (procs.size() > 0) { 437 if (header != null) { 438 pw.println(header); 439 } 440 DumpUtils.dumpProcessListCsv(pw, procs, sepScreenStates, screenStates, 441 sepMemStates, memStates, sepProcStates, procStates, now); 442 return true; 443 } 444 return false; 445 } 446 parseStateList(String[] states, int mult, String arg, boolean[] outSep, String[] outError)447 static int[] parseStateList(String[] states, int mult, String arg, boolean[] outSep, 448 String[] outError) { 449 ArrayList<Integer> res = new ArrayList<Integer>(); 450 int lastPos = 0; 451 for (int i=0; i<=arg.length(); i++) { 452 char c = i < arg.length() ? arg.charAt(i) : 0; 453 if (c != ',' && c != '+' && c != ' ' && c != 0) { 454 continue; 455 } 456 boolean isSep = c == ','; 457 if (lastPos == 0) { 458 // We now know the type of op. 459 outSep[0] = isSep; 460 } else if (c != 0 && outSep[0] != isSep) { 461 outError[0] = "inconsistent separators (can't mix ',' with '+')"; 462 return null; 463 } 464 if (lastPos < (i-1)) { 465 String str = arg.substring(lastPos, i); 466 for (int j=0; j<states.length; j++) { 467 if (str.equals(states[j])) { 468 res.add(j); 469 str = null; 470 break; 471 } 472 } 473 if (str != null) { 474 outError[0] = "invalid word \"" + str + "\""; 475 return null; 476 } 477 } 478 lastPos = i + 1; 479 } 480 481 int[] finalRes = new int[res.size()]; 482 for (int i=0; i<res.size(); i++) { 483 finalRes[i] = res.get(i) * mult; 484 } 485 return finalRes; 486 } 487 488 static int parseSectionOptions(String optionsStr) { 489 final String sep = ","; 490 String[] sectionsStr = optionsStr.split(sep); 491 if (sectionsStr.length == 0) { 492 return ProcessStats.REPORT_ALL; 493 } 494 int res = 0; 495 List<String> optionStrList = Arrays.asList(ProcessStats.OPTIONS_STR); 496 for (String sectionStr : sectionsStr) { 497 int optionIndex = optionStrList.indexOf(sectionStr); 498 if (optionIndex != -1) { 499 res |= ProcessStats.OPTIONS[optionIndex]; 500 } 501 } 502 return res; 503 } 504 505 public byte[] getCurrentStats(List<ParcelFileDescriptor> historic) { 506 mAm.mContext.enforceCallingOrSelfPermission( 507 android.Manifest.permission.PACKAGE_USAGE_STATS, null); 508 Parcel current = Parcel.obtain(); 509 synchronized (mAm) { 510 long now = SystemClock.uptimeMillis(); 511 mProcessStats.mTimePeriodEndRealtime = SystemClock.elapsedRealtime(); 512 mProcessStats.mTimePeriodEndUptime = now; 513 mProcessStats.writeToParcel(current, now, 0); 514 } 515 mWriteLock.lock(); 516 try { 517 if (historic != null) { 518 ArrayList<String> files = getCommittedFiles(0, false, true); 519 if (files != null) { 520 for (int i=files.size()-1; i>=0; i--) { 521 try { 522 ParcelFileDescriptor pfd = ParcelFileDescriptor.open( 523 new File(files.get(i)), ParcelFileDescriptor.MODE_READ_ONLY); 524 historic.add(pfd); 525 } catch (IOException e) { 526 Slog.w(TAG, "Failure opening procstat file " + files.get(i), e); 527 } 528 } 529 } 530 } 531 } finally { 532 mWriteLock.unlock(); 533 } 534 return current.marshall(); 535 } 536 537 /** 538 * Get stats committed after highWaterMarkMs 539 * @param highWaterMarkMs Report stats committed after this time. 540 * @param section Integer mask to indicage which sections to include in the stats. 541 * @param doAggregate Whether to aggregate the stats or keep them separated. 542 * @return List of proto binary of individual commit files or one that is merged from them 543 */ 544 @Override 545 public long getCommittedStats(long highWaterMarkMs, int section, boolean doAggregate, 546 List<ParcelFileDescriptor> committedStats) { 547 return getCommittedStatsMerged(highWaterMarkMs, section, doAggregate, committedStats, 548 new ProcessStats(false)); 549 } 550 551 /** 552 * Get stats committed after highWaterMarkMs 553 * @param highWaterMarkMs Report stats committed after this time. 554 * @param section Integer mask to indicage which sections to include in the stats. 555 * @param doAggregate Whether to aggregate the stats or keep them separated. 556 * @return List of proto binary of individual commit files or one that is merged from them; 557 * the merged, final ProcessStats object. 558 */ 559 @Override 560 public long getCommittedStatsMerged(long highWaterMarkMs, int section, boolean doAggregate, 561 List<ParcelFileDescriptor> committedStats, ProcessStats mergedStats) { 562 mAm.mContext.enforceCallingOrSelfPermission( 563 android.Manifest.permission.PACKAGE_USAGE_STATS, null); 564 565 long newHighWaterMark = highWaterMarkMs; 566 mWriteLock.lock(); 567 try { 568 ArrayList<String> files = getCommittedFiles(0, false, true); 569 if (files != null) { 570 String highWaterMarkStr = 571 DateFormat.format("yyyy-MM-dd-HH-mm-ss", highWaterMarkMs).toString(); 572 ProcessStats stats = new ProcessStats(false); 573 for (int i = files.size() - 1; i >= 0; i--) { 574 String fileName = files.get(i); 575 try { 576 String startTimeStr = fileName.substring( 577 fileName.lastIndexOf(STATE_FILE_PREFIX) 578 + STATE_FILE_PREFIX.length(), 579 fileName.lastIndexOf(STATE_FILE_SUFFIX)); 580 if (startTimeStr.compareToIgnoreCase(highWaterMarkStr) > 0) { 581 ParcelFileDescriptor pfd = ParcelFileDescriptor.open( 582 new File(fileName), 583 ParcelFileDescriptor.MODE_READ_ONLY); 584 InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(pfd); 585 stats.reset(); 586 stats.read(is); 587 is.close(); 588 if (stats.mTimePeriodStartClock > newHighWaterMark) { 589 newHighWaterMark = stats.mTimePeriodStartClock; 590 } 591 if (doAggregate) { 592 mergedStats.add(stats); 593 } else if (committedStats != null) { 594 committedStats.add(protoToParcelFileDescriptor(stats, section)); 595 } 596 if (stats.mReadError != null) { 597 Log.w(TAG, "Failure reading process stats: " + stats.mReadError); 598 continue; 599 } 600 } 601 } catch (IOException e) { 602 Slog.w(TAG, "Failure opening procstat file " + fileName, e); 603 } catch (IndexOutOfBoundsException e) { 604 Slog.w(TAG, "Failure to read and parse commit file " + fileName, e); 605 } 606 } 607 if (doAggregate && committedStats != null) { 608 committedStats.add(protoToParcelFileDescriptor(mergedStats, section)); 609 } 610 return newHighWaterMark; 611 } 612 } catch (IOException e) { 613 Slog.w(TAG, "Failure opening procstat file", e); 614 } finally { mWriteLock.unlock()615 mWriteLock.unlock(); 616 } 617 return newHighWaterMark; 618 } 619 620 /** 621 * @return The threshold to decide if a given association should be dumped into metrics. 622 */ 623 @Override 624 public long getMinAssociationDumpDuration() { 625 return mAm.mConstants.MIN_ASSOC_LOG_DURATION; 626 } 627 628 private ParcelFileDescriptor protoToParcelFileDescriptor(ProcessStats stats, int section) 629 throws IOException { 630 final ParcelFileDescriptor[] fds = ParcelFileDescriptor.createPipe(); 631 Thread thr = new Thread("ProcessStats pipe output") { 632 public void run() { 633 try { 634 FileOutputStream fout = new ParcelFileDescriptor.AutoCloseOutputStream(fds[1]); 635 final ProtoOutputStream proto = new ProtoOutputStream(fout); 636 stats.dumpDebug(proto, stats.mTimePeriodEndRealtime, section); 637 proto.flush(); 638 fout.close(); 639 } catch (IOException e) { 640 Slog.w(TAG, "Failure writing pipe", e); 641 } 642 } 643 }; 644 thr.start(); 645 return fds[0]; 646 } 647 648 public ParcelFileDescriptor getStatsOverTime(long minTime) { 649 mAm.mContext.enforceCallingOrSelfPermission( 650 android.Manifest.permission.PACKAGE_USAGE_STATS, null); 651 Parcel current = Parcel.obtain(); 652 long curTime; 653 synchronized (mAm) { 654 long now = SystemClock.uptimeMillis(); 655 mProcessStats.mTimePeriodEndRealtime = SystemClock.elapsedRealtime(); 656 mProcessStats.mTimePeriodEndUptime = now; 657 mProcessStats.writeToParcel(current, now, 0); 658 curTime = mProcessStats.mTimePeriodEndRealtime 659 - mProcessStats.mTimePeriodStartRealtime; 660 } 661 mWriteLock.lock(); 662 try { 663 if (curTime < minTime) { 664 // Need to add in older stats to reach desired time. 665 ArrayList<String> files = getCommittedFiles(0, false, true); 666 if (files != null && files.size() > 0) { 667 current.setDataPosition(0); 668 ProcessStats stats = ProcessStats.CREATOR.createFromParcel(current); 669 current.recycle(); 670 int i = files.size()-1; 671 while (i >= 0 && (stats.mTimePeriodEndRealtime 672 - stats.mTimePeriodStartRealtime) < minTime) { 673 AtomicFile file = new AtomicFile(new File(files.get(i))); 674 i--; 675 ProcessStats moreStats = new ProcessStats(false); 676 readLocked(moreStats, file); 677 if (moreStats.mReadError == null) { 678 stats.add(moreStats); 679 StringBuilder sb = new StringBuilder(); 680 sb.append("Added stats: "); 681 sb.append(moreStats.mTimePeriodStartClockStr); 682 sb.append(", over "); 683 TimeUtils.formatDuration(moreStats.mTimePeriodEndRealtime 684 - moreStats.mTimePeriodStartRealtime, sb); 685 Slog.i(TAG, sb.toString()); 686 } else { 687 Slog.w(TAG, "Failure reading " + files.get(i+1) + "; " 688 + moreStats.mReadError); 689 continue; 690 } 691 } 692 current = Parcel.obtain(); 693 stats.writeToParcel(current, 0); 694 } 695 } 696 final byte[] outData = current.marshall(); 697 current.recycle(); 698 final ParcelFileDescriptor[] fds = ParcelFileDescriptor.createPipe(); 699 Thread thr = new Thread("ProcessStats pipe output") { 700 public void run() { 701 FileOutputStream fout = new ParcelFileDescriptor.AutoCloseOutputStream(fds[1]); 702 try { 703 fout.write(outData); 704 fout.close(); 705 } catch (IOException e) { 706 Slog.w(TAG, "Failure writing pipe", e); 707 } 708 } 709 }; 710 thr.start(); 711 return fds[0]; 712 } catch (IOException e) { 713 Slog.w(TAG, "Failed building output pipe", e); 714 } finally { 715 mWriteLock.unlock(); 716 } 717 return null; 718 } 719 720 public int getCurrentMemoryState() { 721 synchronized (mAm) { 722 return mLastMemOnlyState; 723 } 724 } 725 726 private void dumpAggregatedStats(PrintWriter pw, long aggregateHours, long now, 727 String reqPackage, boolean isCompact, boolean dumpDetails, boolean dumpFullDetails, 728 boolean dumpAll, boolean activeOnly, int section) { 729 ParcelFileDescriptor pfd = getStatsOverTime(aggregateHours*60*60*1000 730 - (ProcessStats.COMMIT_PERIOD/2)); 731 if (pfd == null) { 732 pw.println("Unable to build stats!"); 733 return; 734 } 735 ProcessStats stats = new ProcessStats(false); 736 InputStream stream = new ParcelFileDescriptor.AutoCloseInputStream(pfd); 737 stats.read(stream); 738 if (stats.mReadError != null) { 739 pw.print("Failure reading: "); pw.println(stats.mReadError); 740 return; 741 } 742 if (isCompact) { 743 stats.dumpCheckinLocked(pw, reqPackage, section); 744 } else { 745 if (dumpDetails || dumpFullDetails) { 746 stats.dumpLocked(pw, reqPackage, now, !dumpFullDetails, dumpDetails, dumpAll, 747 activeOnly, section); 748 } else { 749 stats.dumpSummaryLocked(pw, reqPackage, now, activeOnly); 750 } 751 } 752 } 753 754 static private void dumpHelp(PrintWriter pw) { 755 pw.println("Process stats (procstats) dump options:"); 756 pw.println(" [--checkin|-c|--csv] [--csv-screen] [--csv-proc] [--csv-mem]"); 757 pw.println(" [--details] [--full-details] [--current] [--hours N] [--last N]"); 758 pw.println(" [--max N] --active] [--commit] [--reset] [--clear] [--write] [-h]"); 759 pw.println(" [--start-testing] [--stop-testing] "); 760 pw.println(" [--pretend-screen-on] [--pretend-screen-off] [--stop-pretend-screen]"); 761 pw.println(" [<package.name>]"); 762 pw.println(" --checkin: perform a checkin: print and delete old committed states."); 763 pw.println(" -c: print only state in checkin format."); 764 pw.println(" --csv: output data suitable for putting in a spreadsheet."); 765 pw.println(" --csv-screen: on, off."); 766 pw.println(" --csv-mem: norm, mod, low, crit."); 767 pw.println(" --csv-proc: pers, top, fore, vis, precept, backup,"); 768 pw.println(" service, home, prev, cached"); 769 pw.println(" --details: dump per-package details, not just summary."); 770 pw.println(" --full-details: dump all timing and active state details."); 771 pw.println(" --current: only dump current state."); 772 pw.println(" --hours: aggregate over about N last hours."); 773 pw.println(" --last: only show the last committed stats at index N (starting at 1)."); 774 pw.println(" --max: for -a, max num of historical batches to print."); 775 pw.println(" --active: only show currently active processes/services."); 776 pw.println(" --commit: commit current stats to disk and reset to start new stats."); 777 pw.println(" --section: proc|pkg-proc|pkg-svc|pkg-asc|pkg-all|all "); 778 pw.println(" options can be combined to select desired stats"); 779 pw.println(" --reset: reset current stats, without committing."); 780 pw.println(" --clear: clear all stats; does both --reset and deletes old stats."); 781 pw.println(" --write: write current in-memory stats to disk."); 782 pw.println(" --read: replace current stats with last-written stats."); 783 pw.println(" --start-testing: clear all stats and starting high frequency pss sampling."); 784 pw.println(" --stop-testing: stop high frequency pss sampling."); 785 pw.println(" --pretend-screen-on: pretend screen is on."); 786 pw.println(" --pretend-screen-off: pretend screen is off."); 787 pw.println(" --stop-pretend-screen: forget \"pretend screen\" and use the real state."); 788 pw.println(" -a: print everything."); 789 pw.println(" -h: print this help text."); 790 pw.println(" <package.name>: optional name of package to filter output by."); 791 } 792 793 @Override 794 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 795 if (!com.android.internal.util.DumpUtils.checkDumpAndUsageStatsPermission(mAm.mContext, 796 TAG, pw)) return; 797 798 long ident = Binder.clearCallingIdentity(); 799 try { 800 if (args.length > 0) { 801 if ("--proto".equals(args[0])) { 802 dumpProto(fd); 803 return; 804 } else if ("--statsd".equals(args[0])) { 805 dumpProtoForStatsd(fd); 806 return; 807 } 808 } 809 dumpInner(pw, args); 810 } finally { 811 Binder.restoreCallingIdentity(ident); 812 } 813 } 814 815 private void dumpInner(PrintWriter pw, String[] args) { 816 final long now = SystemClock.uptimeMillis(); 817 818 boolean isCheckin = false; 819 boolean isCompact = false; 820 boolean isCsv = false; 821 boolean currentOnly = false; 822 boolean dumpDetails = false; 823 boolean dumpFullDetails = false; 824 boolean dumpAll = false; 825 boolean quit = false; 826 int aggregateHours = 0; 827 int lastIndex = 0; 828 int maxNum = 2; 829 boolean activeOnly = false; 830 String reqPackage = null; 831 boolean csvSepScreenStats = false; 832 int[] csvScreenStats = new int[] { ProcessStats.ADJ_SCREEN_OFF, ProcessStats.ADJ_SCREEN_ON}; 833 boolean csvSepMemStats = false; 834 int[] csvMemStats = new int[] { ProcessStats.ADJ_MEM_FACTOR_CRITICAL}; 835 boolean csvSepProcStats = true; 836 int[] csvProcStats = ProcessStats.ALL_PROC_STATES; 837 int section = ProcessStats.REPORT_ALL; 838 if (args != null) { 839 for (int i=0; i<args.length; i++) { 840 String arg = args[i]; 841 if ("--checkin".equals(arg)) { 842 isCheckin = true; 843 } else if ("-c".equals(arg)) { 844 isCompact = true; 845 } else if ("--csv".equals(arg)) { 846 isCsv = true; 847 } else if ("--csv-screen".equals(arg)) { 848 i++; 849 if (i >= args.length) { 850 pw.println("Error: argument required for --csv-screen"); 851 dumpHelp(pw); 852 return; 853 } 854 boolean[] sep = new boolean[1]; 855 String[] error = new String[1]; 856 csvScreenStats = parseStateList(DumpUtils.ADJ_SCREEN_NAMES_CSV, 857 ProcessStats.ADJ_SCREEN_MOD, args[i], sep, error); 858 if (csvScreenStats == null) { 859 pw.println("Error in \"" + args[i] + "\": " + error[0]); 860 dumpHelp(pw); 861 return; 862 } 863 csvSepScreenStats = sep[0]; 864 } else if ("--csv-mem".equals(arg)) { 865 i++; 866 if (i >= args.length) { 867 pw.println("Error: argument required for --csv-mem"); 868 dumpHelp(pw); 869 return; 870 } 871 boolean[] sep = new boolean[1]; 872 String[] error = new String[1]; 873 csvMemStats = parseStateList(DumpUtils.ADJ_MEM_NAMES_CSV, 1, args[i], 874 sep, error); 875 if (csvMemStats == null) { 876 pw.println("Error in \"" + args[i] + "\": " + error[0]); 877 dumpHelp(pw); 878 return; 879 } 880 csvSepMemStats = sep[0]; 881 } else if ("--csv-proc".equals(arg)) { 882 i++; 883 if (i >= args.length) { 884 pw.println("Error: argument required for --csv-proc"); 885 dumpHelp(pw); 886 return; 887 } 888 boolean[] sep = new boolean[1]; 889 String[] error = new String[1]; 890 csvProcStats = parseStateList(DumpUtils.STATE_NAMES_CSV, 1, args[i], 891 sep, error); 892 if (csvProcStats == null) { 893 pw.println("Error in \"" + args[i] + "\": " + error[0]); 894 dumpHelp(pw); 895 return; 896 } 897 csvSepProcStats = sep[0]; 898 } else if ("--details".equals(arg)) { 899 dumpDetails = true; 900 } else if ("--full-details".equals(arg)) { 901 dumpFullDetails = true; 902 } else if ("--hours".equals(arg)) { 903 i++; 904 if (i >= args.length) { 905 pw.println("Error: argument required for --hours"); 906 dumpHelp(pw); 907 return; 908 } 909 try { 910 aggregateHours = Integer.parseInt(args[i]); 911 } catch (NumberFormatException e) { 912 pw.println("Error: --hours argument not an int -- " + args[i]); 913 dumpHelp(pw); 914 return; 915 } 916 } else if ("--last".equals(arg)) { 917 i++; 918 if (i >= args.length) { 919 pw.println("Error: argument required for --last"); 920 dumpHelp(pw); 921 return; 922 } 923 try { 924 lastIndex = Integer.parseInt(args[i]); 925 } catch (NumberFormatException e) { 926 pw.println("Error: --last argument not an int -- " + args[i]); 927 dumpHelp(pw); 928 return; 929 } 930 } else if ("--max".equals(arg)) { 931 i++; 932 if (i >= args.length) { 933 pw.println("Error: argument required for --max"); 934 dumpHelp(pw); 935 return; 936 } 937 try { 938 maxNum = Integer.parseInt(args[i]); 939 } catch (NumberFormatException e) { 940 pw.println("Error: --max argument not an int -- " + args[i]); 941 dumpHelp(pw); 942 return; 943 } 944 } else if ("--active".equals(arg)) { 945 activeOnly = true; 946 currentOnly = true; 947 } else if ("--current".equals(arg)) { 948 currentOnly = true; 949 } else if ("--commit".equals(arg)) { 950 synchronized (mAm) { 951 mProcessStats.mFlags |= ProcessStats.FLAG_COMPLETE; 952 writeStateLocked(true, true); 953 pw.println("Process stats committed."); 954 quit = true; 955 } 956 } else if ("--section".equals(arg)) { 957 i++; 958 if (i >= args.length) { 959 pw.println("Error: argument required for --section"); 960 dumpHelp(pw); 961 return; 962 } 963 section = parseSectionOptions(args[i]); 964 } else if ("--clear".equals(arg)) { 965 synchronized (mAm) { 966 mProcessStats.resetSafely(); 967 mAm.requestPssAllProcsLocked(SystemClock.uptimeMillis(), true, false); 968 ArrayList<String> files = getCommittedFiles(0, true, true); 969 if (files != null) { 970 for (int fi=0; fi<files.size(); fi++) { 971 (new File(files.get(fi))).delete(); 972 } 973 } 974 pw.println("All process stats cleared."); 975 quit = true; 976 } 977 } else if ("--write".equals(arg)) { 978 synchronized (mAm) { 979 writeStateSyncLocked(); 980 pw.println("Process stats written."); 981 quit = true; 982 } 983 } else if ("--read".equals(arg)) { 984 synchronized (mAm) { 985 readLocked(mProcessStats, mFile); 986 pw.println("Process stats read."); 987 quit = true; 988 } 989 } else if ("--start-testing".equals(arg)) { 990 synchronized (mAm) { 991 mAm.setTestPssMode(true); 992 pw.println("Started high frequency sampling."); 993 quit = true; 994 } 995 } else if ("--stop-testing".equals(arg)) { 996 synchronized (mAm) { 997 mAm.setTestPssMode(false); 998 pw.println("Stopped high frequency sampling."); 999 quit = true; 1000 } 1001 } else if ("--pretend-screen-on".equals(arg)) { 1002 synchronized (mAm) { 1003 mInjectedScreenState = true; 1004 } 1005 quit = true; 1006 } else if ("--pretend-screen-off".equals(arg)) { 1007 synchronized (mAm) { 1008 mInjectedScreenState = false; 1009 } 1010 quit = true; 1011 } else if ("--stop-pretend-screen".equals(arg)) { 1012 synchronized (mAm) { 1013 mInjectedScreenState = null; 1014 } 1015 quit = true; 1016 } else if ("-h".equals(arg)) { 1017 dumpHelp(pw); 1018 return; 1019 } else if ("-a".equals(arg)) { 1020 dumpDetails = true; 1021 dumpAll = true; 1022 } else if (arg.length() > 0 && arg.charAt(0) == '-'){ 1023 pw.println("Unknown option: " + arg); 1024 dumpHelp(pw); 1025 return; 1026 } else { 1027 // Not an option, last argument must be a package name. 1028 reqPackage = arg; 1029 // Include all details, since we know we are only going to 1030 // be dumping a smaller set of data. In fact only the details 1031 // contain per-package data, so this is needed to be able 1032 // to dump anything at all when filtering by package. 1033 dumpDetails = true; 1034 } 1035 } 1036 } 1037 1038 if (quit) { 1039 return; 1040 } 1041 1042 if (isCsv) { 1043 pw.print("Processes running summed over"); 1044 if (!csvSepScreenStats) { 1045 for (int i=0; i<csvScreenStats.length; i++) { 1046 pw.print(" "); 1047 DumpUtils.printScreenLabelCsv(pw, csvScreenStats[i]); 1048 } 1049 } 1050 if (!csvSepMemStats) { 1051 for (int i=0; i<csvMemStats.length; i++) { 1052 pw.print(" "); 1053 DumpUtils.printMemLabelCsv(pw, csvMemStats[i]); 1054 } 1055 } 1056 if (!csvSepProcStats) { 1057 for (int i=0; i<csvProcStats.length; i++) { 1058 pw.print(" "); 1059 pw.print(DumpUtils.STATE_NAMES_CSV[csvProcStats[i]]); 1060 } 1061 } 1062 pw.println(); 1063 synchronized (mAm) { 1064 dumpFilteredProcessesCsvLocked(pw, null, 1065 csvSepScreenStats, csvScreenStats, csvSepMemStats, csvMemStats, 1066 csvSepProcStats, csvProcStats, now, reqPackage); 1067 /* 1068 dumpFilteredProcessesCsvLocked(pw, "Processes running while critical mem:", 1069 false, new int[] {ADJ_SCREEN_OFF, ADJ_SCREEN_ON}, 1070 true, new int[] {ADJ_MEM_FACTOR_CRITICAL}, 1071 true, new int[] {STATE_PERSISTENT, STATE_TOP, STATE_FOREGROUND, STATE_VISIBLE, 1072 STATE_PERCEPTIBLE, STATE_BACKUP, STATE_SERVICE, STATE_HOME, 1073 STATE_PREVIOUS, STATE_CACHED}, 1074 now, reqPackage); 1075 dumpFilteredProcessesCsvLocked(pw, "Processes running over all mem:", 1076 false, new int[] {ADJ_SCREEN_OFF, ADJ_SCREEN_ON}, 1077 false, new int[] {ADJ_MEM_FACTOR_CRITICAL, ADJ_MEM_FACTOR_LOW, 1078 ADJ_MEM_FACTOR_MODERATE, ADJ_MEM_FACTOR_MODERATE}, 1079 true, new int[] {STATE_PERSISTENT, STATE_TOP, STATE_FOREGROUND, STATE_VISIBLE, 1080 STATE_PERCEPTIBLE, STATE_BACKUP, STATE_SERVICE, STATE_HOME, 1081 STATE_PREVIOUS, STATE_CACHED}, 1082 now, reqPackage); 1083 */ 1084 } 1085 return; 1086 } else if (aggregateHours != 0) { 1087 pw.print("AGGREGATED OVER LAST "); pw.print(aggregateHours); pw.println(" HOURS:"); 1088 dumpAggregatedStats(pw, aggregateHours, now, reqPackage, isCompact, 1089 dumpDetails, dumpFullDetails, dumpAll, activeOnly, section); 1090 return; 1091 } else if (lastIndex > 0) { 1092 pw.print("LAST STATS AT INDEX "); pw.print(lastIndex); pw.println(":"); 1093 ArrayList<String> files = getCommittedFiles(0, false, true); 1094 if (lastIndex >= files.size()) { 1095 pw.print("Only have "); pw.print(files.size()); pw.println(" data sets"); 1096 return; 1097 } 1098 AtomicFile file = new AtomicFile(new File(files.get(lastIndex))); 1099 ProcessStats processStats = new ProcessStats(false); 1100 readLocked(processStats, file); 1101 if (processStats.mReadError != null) { 1102 if (isCheckin || isCompact) pw.print("err,"); 1103 pw.print("Failure reading "); pw.print(files.get(lastIndex)); 1104 pw.print("; "); pw.println(processStats.mReadError); 1105 return; 1106 } 1107 String fileStr = file.getBaseFile().getPath(); 1108 boolean checkedIn = fileStr.endsWith(STATE_FILE_CHECKIN_SUFFIX); 1109 if (isCheckin || isCompact) { 1110 // Don't really need to lock because we uniquely own this object. 1111 processStats.dumpCheckinLocked(pw, reqPackage, section); 1112 } else { 1113 pw.print("COMMITTED STATS FROM "); 1114 pw.print(processStats.mTimePeriodStartClockStr); 1115 if (checkedIn) pw.print(" (checked in)"); 1116 pw.println(":"); 1117 if (dumpDetails || dumpFullDetails) { 1118 processStats.dumpLocked(pw, reqPackage, now, !dumpFullDetails, dumpDetails, 1119 dumpAll, activeOnly, section); 1120 if (dumpAll) { 1121 pw.print(" mFile="); pw.println(mFile.getBaseFile()); 1122 } 1123 } else { 1124 processStats.dumpSummaryLocked(pw, reqPackage, now, activeOnly); 1125 } 1126 } 1127 return; 1128 } 1129 1130 boolean sepNeeded = false; 1131 if ((dumpAll || isCheckin) && !currentOnly) { 1132 mWriteLock.lock(); 1133 try { 1134 ArrayList<String> files = getCommittedFiles(0, false, !isCheckin); 1135 if (files != null) { 1136 int start = isCheckin ? 0 : (files.size() - maxNum); 1137 if (start < 0) { 1138 start = 0; 1139 } 1140 for (int i=start; i<files.size(); i++) { 1141 if (DEBUG) Slog.d(TAG, "Retrieving state: " + files.get(i)); 1142 try { 1143 AtomicFile file = new AtomicFile(new File(files.get(i))); 1144 ProcessStats processStats = new ProcessStats(false); 1145 readLocked(processStats, file); 1146 if (processStats.mReadError != null) { 1147 if (isCheckin || isCompact) pw.print("err,"); 1148 pw.print("Failure reading "); pw.print(files.get(i)); 1149 pw.print("; "); pw.println(processStats.mReadError); 1150 if (DEBUG) Slog.d(TAG, "Deleting state: " + files.get(i)); 1151 (new File(files.get(i))).delete(); 1152 continue; 1153 } 1154 String fileStr = file.getBaseFile().getPath(); 1155 boolean checkedIn = fileStr.endsWith(STATE_FILE_CHECKIN_SUFFIX); 1156 if (isCheckin || isCompact) { 1157 // Don't really need to lock because we uniquely own this object. 1158 processStats.dumpCheckinLocked(pw, reqPackage, section); 1159 } else { 1160 if (sepNeeded) { 1161 pw.println(); 1162 } else { 1163 sepNeeded = true; 1164 } 1165 pw.print("COMMITTED STATS FROM "); 1166 pw.print(processStats.mTimePeriodStartClockStr); 1167 if (checkedIn) pw.print(" (checked in)"); 1168 pw.println(":"); 1169 // Don't really need to lock because we uniquely own this object. 1170 // Always dump summary here, dumping all details is just too 1171 // much crud. 1172 if (dumpFullDetails) { 1173 processStats.dumpLocked(pw, reqPackage, now, false, false, 1174 false, activeOnly, section); 1175 } else { 1176 processStats.dumpSummaryLocked(pw, reqPackage, now, activeOnly); 1177 } 1178 } 1179 if (isCheckin) { 1180 // Rename file suffix to mark that it has checked in. 1181 file.getBaseFile().renameTo(new File( 1182 fileStr + STATE_FILE_CHECKIN_SUFFIX)); 1183 } 1184 } catch (Throwable e) { 1185 pw.print("**** FAILURE DUMPING STATE: "); pw.println(files.get(i)); 1186 e.printStackTrace(pw); 1187 } 1188 } 1189 } 1190 } finally { 1191 mWriteLock.unlock(); 1192 } 1193 } 1194 if (!isCheckin) { 1195 synchronized (mAm) { 1196 if (isCompact) { 1197 mProcessStats.dumpCheckinLocked(pw, reqPackage, section); 1198 } else { 1199 if (sepNeeded) { 1200 pw.println(); 1201 } 1202 pw.println("CURRENT STATS:"); 1203 if (dumpDetails || dumpFullDetails) { 1204 mProcessStats.dumpLocked(pw, reqPackage, now, !dumpFullDetails, dumpDetails, 1205 dumpAll, activeOnly, section); 1206 if (dumpAll) { 1207 pw.print(" mFile="); pw.println(mFile.getBaseFile()); 1208 } 1209 } else { 1210 mProcessStats.dumpSummaryLocked(pw, reqPackage, now, activeOnly); 1211 } 1212 sepNeeded = true; 1213 } 1214 } 1215 if (!currentOnly) { 1216 if (sepNeeded) { 1217 pw.println(); 1218 } 1219 pw.println("AGGREGATED OVER LAST 24 HOURS:"); 1220 dumpAggregatedStats(pw, 24, now, reqPackage, isCompact, 1221 dumpDetails, dumpFullDetails, dumpAll, activeOnly, section); 1222 pw.println(); 1223 pw.println("AGGREGATED OVER LAST 3 HOURS:"); 1224 dumpAggregatedStats(pw, 3, now, reqPackage, isCompact, 1225 dumpDetails, dumpFullDetails, dumpAll, activeOnly, section); 1226 } 1227 } 1228 } 1229 1230 private void dumpAggregatedStats(ProtoOutputStream proto, long fieldId, int aggregateHours, long now) { 1231 ParcelFileDescriptor pfd = getStatsOverTime(aggregateHours*60*60*1000 1232 - (ProcessStats.COMMIT_PERIOD/2)); 1233 if (pfd == null) { 1234 return; 1235 } 1236 ProcessStats stats = new ProcessStats(false); 1237 InputStream stream = new ParcelFileDescriptor.AutoCloseInputStream(pfd); 1238 stats.read(stream); 1239 if (stats.mReadError != null) { 1240 return; 1241 } 1242 final long token = proto.start(fieldId); 1243 stats.dumpDebug(proto, now, ProcessStats.REPORT_ALL); 1244 proto.end(token); 1245 } 1246 1247 private void dumpProto(FileDescriptor fd) { 1248 final ProtoOutputStream proto = new ProtoOutputStream(fd); 1249 1250 // dump current procstats 1251 long now; 1252 synchronized (mAm) { 1253 now = SystemClock.uptimeMillis(); 1254 final long token = proto.start(ProcessStatsServiceDumpProto.PROCSTATS_NOW); 1255 mProcessStats.dumpDebug(proto, now, ProcessStats.REPORT_ALL); 1256 proto.end(token); 1257 } 1258 1259 // aggregated over last 3 hours procstats 1260 dumpAggregatedStats(proto, ProcessStatsServiceDumpProto.PROCSTATS_OVER_3HRS, 3, now); 1261 1262 // aggregated over last 24 hours procstats 1263 dumpAggregatedStats(proto, ProcessStatsServiceDumpProto.PROCSTATS_OVER_24HRS, 24, now); 1264 1265 proto.flush(); 1266 } 1267 1268 /** 1269 * Dump proto for the statsd, mainly for testing. 1270 */ 1271 private void dumpProtoForStatsd(FileDescriptor fd) { 1272 final ProtoOutputStream[] protos = {new ProtoOutputStream(fd)}; 1273 1274 ProcessStats procStats = new ProcessStats(false); 1275 getCommittedStatsMerged(0, 0, true, null, procStats); 1276 procStats.dumpAggregatedProtoForStatsd(protos, 999999 /* max bytes per shard */); 1277 1278 protos[0].flush(); 1279 } 1280 } 1281