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 mAm.mContext.enforceCallingOrSelfPermission( 548 android.Manifest.permission.PACKAGE_USAGE_STATS, null); 549 550 ProcessStats mergedStats = new ProcessStats(false); 551 long newHighWaterMark = highWaterMarkMs; 552 mWriteLock.lock(); 553 try { 554 ArrayList<String> files = getCommittedFiles(0, false, true); 555 if (files != null) { 556 String highWaterMarkStr = 557 DateFormat.format("yyyy-MM-dd-HH-mm-ss", highWaterMarkMs).toString(); 558 ProcessStats stats = new ProcessStats(false); 559 for (int i = files.size() - 1; i >= 0; i--) { 560 String fileName = files.get(i); 561 try { 562 String startTimeStr = fileName.substring( 563 fileName.lastIndexOf(STATE_FILE_PREFIX) 564 + STATE_FILE_PREFIX.length(), 565 fileName.lastIndexOf(STATE_FILE_SUFFIX)); 566 if (startTimeStr.compareToIgnoreCase(highWaterMarkStr) > 0) { 567 ParcelFileDescriptor pfd = ParcelFileDescriptor.open( 568 new File(fileName), 569 ParcelFileDescriptor.MODE_READ_ONLY); 570 InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(pfd); 571 stats.reset(); 572 stats.read(is); 573 is.close(); 574 if (stats.mTimePeriodStartClock > newHighWaterMark) { 575 newHighWaterMark = stats.mTimePeriodStartClock; 576 } 577 if (doAggregate) { 578 mergedStats.add(stats); 579 } else { 580 committedStats.add(protoToParcelFileDescriptor(stats, section)); 581 } 582 if (stats.mReadError != null) { 583 Log.w(TAG, "Failure reading process stats: " + stats.mReadError); 584 continue; 585 } 586 } 587 } catch (IOException e) { 588 Slog.w(TAG, "Failure opening procstat file " + fileName, e); 589 } catch (IndexOutOfBoundsException e) { 590 Slog.w(TAG, "Failure to read and parse commit file " + fileName, e); 591 } 592 } 593 if (doAggregate) { 594 committedStats.add(protoToParcelFileDescriptor(mergedStats, section)); 595 } 596 return newHighWaterMark; 597 } 598 } catch (IOException e) { 599 Slog.w(TAG, "Failure opening procstat file", e); 600 } finally { mWriteLock.unlock()601 mWriteLock.unlock(); 602 } 603 return newHighWaterMark; 604 } 605 606 private ParcelFileDescriptor protoToParcelFileDescriptor(ProcessStats stats, int section) 607 throws IOException { 608 final ParcelFileDescriptor[] fds = ParcelFileDescriptor.createPipe(); 609 Thread thr = new Thread("ProcessStats pipe output") { 610 public void run() { 611 try { 612 FileOutputStream fout = new ParcelFileDescriptor.AutoCloseOutputStream(fds[1]); 613 final ProtoOutputStream proto = new ProtoOutputStream(fout); 614 stats.writeToProto(proto, stats.mTimePeriodEndRealtime, section); 615 proto.flush(); 616 fout.close(); 617 } catch (IOException e) { 618 Slog.w(TAG, "Failure writing pipe", e); 619 } 620 } 621 }; 622 thr.start(); 623 return fds[0]; 624 } 625 626 public ParcelFileDescriptor getStatsOverTime(long minTime) { 627 mAm.mContext.enforceCallingOrSelfPermission( 628 android.Manifest.permission.PACKAGE_USAGE_STATS, null); 629 Parcel current = Parcel.obtain(); 630 long curTime; 631 synchronized (mAm) { 632 long now = SystemClock.uptimeMillis(); 633 mProcessStats.mTimePeriodEndRealtime = SystemClock.elapsedRealtime(); 634 mProcessStats.mTimePeriodEndUptime = now; 635 mProcessStats.writeToParcel(current, now, 0); 636 curTime = mProcessStats.mTimePeriodEndRealtime 637 - mProcessStats.mTimePeriodStartRealtime; 638 } 639 mWriteLock.lock(); 640 try { 641 if (curTime < minTime) { 642 // Need to add in older stats to reach desired time. 643 ArrayList<String> files = getCommittedFiles(0, false, true); 644 if (files != null && files.size() > 0) { 645 current.setDataPosition(0); 646 ProcessStats stats = ProcessStats.CREATOR.createFromParcel(current); 647 current.recycle(); 648 int i = files.size()-1; 649 while (i >= 0 && (stats.mTimePeriodEndRealtime 650 - stats.mTimePeriodStartRealtime) < minTime) { 651 AtomicFile file = new AtomicFile(new File(files.get(i))); 652 i--; 653 ProcessStats moreStats = new ProcessStats(false); 654 readLocked(moreStats, file); 655 if (moreStats.mReadError == null) { 656 stats.add(moreStats); 657 StringBuilder sb = new StringBuilder(); 658 sb.append("Added stats: "); 659 sb.append(moreStats.mTimePeriodStartClockStr); 660 sb.append(", over "); 661 TimeUtils.formatDuration(moreStats.mTimePeriodEndRealtime 662 - moreStats.mTimePeriodStartRealtime, sb); 663 Slog.i(TAG, sb.toString()); 664 } else { 665 Slog.w(TAG, "Failure reading " + files.get(i+1) + "; " 666 + moreStats.mReadError); 667 continue; 668 } 669 } 670 current = Parcel.obtain(); 671 stats.writeToParcel(current, 0); 672 } 673 } 674 final byte[] outData = current.marshall(); 675 current.recycle(); 676 final ParcelFileDescriptor[] fds = ParcelFileDescriptor.createPipe(); 677 Thread thr = new Thread("ProcessStats pipe output") { 678 public void run() { 679 FileOutputStream fout = new ParcelFileDescriptor.AutoCloseOutputStream(fds[1]); 680 try { 681 fout.write(outData); 682 fout.close(); 683 } catch (IOException e) { 684 Slog.w(TAG, "Failure writing pipe", e); 685 } 686 } 687 }; 688 thr.start(); 689 return fds[0]; 690 } catch (IOException e) { 691 Slog.w(TAG, "Failed building output pipe", e); 692 } finally { 693 mWriteLock.unlock(); 694 } 695 return null; 696 } 697 698 public int getCurrentMemoryState() { 699 synchronized (mAm) { 700 return mLastMemOnlyState; 701 } 702 } 703 704 private void dumpAggregatedStats(PrintWriter pw, long aggregateHours, long now, 705 String reqPackage, boolean isCompact, boolean dumpDetails, boolean dumpFullDetails, 706 boolean dumpAll, boolean activeOnly, int section) { 707 ParcelFileDescriptor pfd = getStatsOverTime(aggregateHours*60*60*1000 708 - (ProcessStats.COMMIT_PERIOD/2)); 709 if (pfd == null) { 710 pw.println("Unable to build stats!"); 711 return; 712 } 713 ProcessStats stats = new ProcessStats(false); 714 InputStream stream = new ParcelFileDescriptor.AutoCloseInputStream(pfd); 715 stats.read(stream); 716 if (stats.mReadError != null) { 717 pw.print("Failure reading: "); pw.println(stats.mReadError); 718 return; 719 } 720 if (isCompact) { 721 stats.dumpCheckinLocked(pw, reqPackage, section); 722 } else { 723 if (dumpDetails || dumpFullDetails) { 724 stats.dumpLocked(pw, reqPackage, now, !dumpFullDetails, dumpDetails, dumpAll, 725 activeOnly, section); 726 } else { 727 stats.dumpSummaryLocked(pw, reqPackage, now, activeOnly); 728 } 729 } 730 } 731 732 static private void dumpHelp(PrintWriter pw) { 733 pw.println("Process stats (procstats) dump options:"); 734 pw.println(" [--checkin|-c|--csv] [--csv-screen] [--csv-proc] [--csv-mem]"); 735 pw.println(" [--details] [--full-details] [--current] [--hours N] [--last N]"); 736 pw.println(" [--max N] --active] [--commit] [--reset] [--clear] [--write] [-h]"); 737 pw.println(" [--start-testing] [--stop-testing] "); 738 pw.println(" [--pretend-screen-on] [--pretend-screen-off] [--stop-pretend-screen]"); 739 pw.println(" [<package.name>]"); 740 pw.println(" --checkin: perform a checkin: print and delete old committed states."); 741 pw.println(" -c: print only state in checkin format."); 742 pw.println(" --csv: output data suitable for putting in a spreadsheet."); 743 pw.println(" --csv-screen: on, off."); 744 pw.println(" --csv-mem: norm, mod, low, crit."); 745 pw.println(" --csv-proc: pers, top, fore, vis, precept, backup,"); 746 pw.println(" service, home, prev, cached"); 747 pw.println(" --details: dump per-package details, not just summary."); 748 pw.println(" --full-details: dump all timing and active state details."); 749 pw.println(" --current: only dump current state."); 750 pw.println(" --hours: aggregate over about N last hours."); 751 pw.println(" --last: only show the last committed stats at index N (starting at 1)."); 752 pw.println(" --max: for -a, max num of historical batches to print."); 753 pw.println(" --active: only show currently active processes/services."); 754 pw.println(" --commit: commit current stats to disk and reset to start new stats."); 755 pw.println(" --section: proc|pkg-proc|pkg-svc|pkg-asc|pkg-all|all "); 756 pw.println(" options can be combined to select desired stats"); 757 pw.println(" --reset: reset current stats, without committing."); 758 pw.println(" --clear: clear all stats; does both --reset and deletes old stats."); 759 pw.println(" --write: write current in-memory stats to disk."); 760 pw.println(" --read: replace current stats with last-written stats."); 761 pw.println(" --start-testing: clear all stats and starting high frequency pss sampling."); 762 pw.println(" --stop-testing: stop high frequency pss sampling."); 763 pw.println(" --pretend-screen-on: pretend screen is on."); 764 pw.println(" --pretend-screen-off: pretend screen is off."); 765 pw.println(" --stop-pretend-screen: forget \"pretend screen\" and use the real state."); 766 pw.println(" -a: print everything."); 767 pw.println(" -h: print this help text."); 768 pw.println(" <package.name>: optional name of package to filter output by."); 769 } 770 771 @Override 772 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 773 if (!com.android.internal.util.DumpUtils.checkDumpAndUsageStatsPermission(mAm.mContext, 774 TAG, pw)) return; 775 776 long ident = Binder.clearCallingIdentity(); 777 try { 778 if (args.length > 0 && "--proto".equals(args[0])) { 779 dumpProto(fd); 780 } else { 781 dumpInner(pw, args); 782 } 783 } finally { 784 Binder.restoreCallingIdentity(ident); 785 } 786 } 787 788 private void dumpInner(PrintWriter pw, String[] args) { 789 final long now = SystemClock.uptimeMillis(); 790 791 boolean isCheckin = false; 792 boolean isCompact = false; 793 boolean isCsv = false; 794 boolean currentOnly = false; 795 boolean dumpDetails = false; 796 boolean dumpFullDetails = false; 797 boolean dumpAll = false; 798 boolean quit = false; 799 int aggregateHours = 0; 800 int lastIndex = 0; 801 int maxNum = 2; 802 boolean activeOnly = false; 803 String reqPackage = null; 804 boolean csvSepScreenStats = false; 805 int[] csvScreenStats = new int[] { ProcessStats.ADJ_SCREEN_OFF, ProcessStats.ADJ_SCREEN_ON}; 806 boolean csvSepMemStats = false; 807 int[] csvMemStats = new int[] { ProcessStats.ADJ_MEM_FACTOR_CRITICAL}; 808 boolean csvSepProcStats = true; 809 int[] csvProcStats = ProcessStats.ALL_PROC_STATES; 810 int section = ProcessStats.REPORT_ALL; 811 if (args != null) { 812 for (int i=0; i<args.length; i++) { 813 String arg = args[i]; 814 if ("--checkin".equals(arg)) { 815 isCheckin = true; 816 } else if ("-c".equals(arg)) { 817 isCompact = true; 818 } else if ("--csv".equals(arg)) { 819 isCsv = true; 820 } else if ("--csv-screen".equals(arg)) { 821 i++; 822 if (i >= args.length) { 823 pw.println("Error: argument required for --csv-screen"); 824 dumpHelp(pw); 825 return; 826 } 827 boolean[] sep = new boolean[1]; 828 String[] error = new String[1]; 829 csvScreenStats = parseStateList(DumpUtils.ADJ_SCREEN_NAMES_CSV, 830 ProcessStats.ADJ_SCREEN_MOD, args[i], sep, error); 831 if (csvScreenStats == null) { 832 pw.println("Error in \"" + args[i] + "\": " + error[0]); 833 dumpHelp(pw); 834 return; 835 } 836 csvSepScreenStats = sep[0]; 837 } else if ("--csv-mem".equals(arg)) { 838 i++; 839 if (i >= args.length) { 840 pw.println("Error: argument required for --csv-mem"); 841 dumpHelp(pw); 842 return; 843 } 844 boolean[] sep = new boolean[1]; 845 String[] error = new String[1]; 846 csvMemStats = parseStateList(DumpUtils.ADJ_MEM_NAMES_CSV, 1, args[i], 847 sep, error); 848 if (csvMemStats == null) { 849 pw.println("Error in \"" + args[i] + "\": " + error[0]); 850 dumpHelp(pw); 851 return; 852 } 853 csvSepMemStats = sep[0]; 854 } else if ("--csv-proc".equals(arg)) { 855 i++; 856 if (i >= args.length) { 857 pw.println("Error: argument required for --csv-proc"); 858 dumpHelp(pw); 859 return; 860 } 861 boolean[] sep = new boolean[1]; 862 String[] error = new String[1]; 863 csvProcStats = parseStateList(DumpUtils.STATE_NAMES_CSV, 1, args[i], 864 sep, error); 865 if (csvProcStats == null) { 866 pw.println("Error in \"" + args[i] + "\": " + error[0]); 867 dumpHelp(pw); 868 return; 869 } 870 csvSepProcStats = sep[0]; 871 } else if ("--details".equals(arg)) { 872 dumpDetails = true; 873 } else if ("--full-details".equals(arg)) { 874 dumpFullDetails = true; 875 } else if ("--hours".equals(arg)) { 876 i++; 877 if (i >= args.length) { 878 pw.println("Error: argument required for --hours"); 879 dumpHelp(pw); 880 return; 881 } 882 try { 883 aggregateHours = Integer.parseInt(args[i]); 884 } catch (NumberFormatException e) { 885 pw.println("Error: --hours argument not an int -- " + args[i]); 886 dumpHelp(pw); 887 return; 888 } 889 } else if ("--last".equals(arg)) { 890 i++; 891 if (i >= args.length) { 892 pw.println("Error: argument required for --last"); 893 dumpHelp(pw); 894 return; 895 } 896 try { 897 lastIndex = Integer.parseInt(args[i]); 898 } catch (NumberFormatException e) { 899 pw.println("Error: --last argument not an int -- " + args[i]); 900 dumpHelp(pw); 901 return; 902 } 903 } else if ("--max".equals(arg)) { 904 i++; 905 if (i >= args.length) { 906 pw.println("Error: argument required for --max"); 907 dumpHelp(pw); 908 return; 909 } 910 try { 911 maxNum = Integer.parseInt(args[i]); 912 } catch (NumberFormatException e) { 913 pw.println("Error: --max argument not an int -- " + args[i]); 914 dumpHelp(pw); 915 return; 916 } 917 } else if ("--active".equals(arg)) { 918 activeOnly = true; 919 currentOnly = true; 920 } else if ("--current".equals(arg)) { 921 currentOnly = true; 922 } else if ("--commit".equals(arg)) { 923 synchronized (mAm) { 924 mProcessStats.mFlags |= ProcessStats.FLAG_COMPLETE; 925 writeStateLocked(true, true); 926 pw.println("Process stats committed."); 927 quit = true; 928 } 929 } else if ("--section".equals(arg)) { 930 i++; 931 if (i >= args.length) { 932 pw.println("Error: argument required for --section"); 933 dumpHelp(pw); 934 return; 935 } 936 section = parseSectionOptions(args[i]); 937 } else if ("--clear".equals(arg)) { 938 synchronized (mAm) { 939 mProcessStats.resetSafely(); 940 mAm.requestPssAllProcsLocked(SystemClock.uptimeMillis(), true, false); 941 ArrayList<String> files = getCommittedFiles(0, true, true); 942 if (files != null) { 943 for (int fi=0; fi<files.size(); fi++) { 944 (new File(files.get(fi))).delete(); 945 } 946 } 947 pw.println("All process stats cleared."); 948 quit = true; 949 } 950 } else if ("--write".equals(arg)) { 951 synchronized (mAm) { 952 writeStateSyncLocked(); 953 pw.println("Process stats written."); 954 quit = true; 955 } 956 } else if ("--read".equals(arg)) { 957 synchronized (mAm) { 958 readLocked(mProcessStats, mFile); 959 pw.println("Process stats read."); 960 quit = true; 961 } 962 } else if ("--start-testing".equals(arg)) { 963 synchronized (mAm) { 964 mAm.setTestPssMode(true); 965 pw.println("Started high frequency sampling."); 966 quit = true; 967 } 968 } else if ("--stop-testing".equals(arg)) { 969 synchronized (mAm) { 970 mAm.setTestPssMode(false); 971 pw.println("Stopped high frequency sampling."); 972 quit = true; 973 } 974 } else if ("--pretend-screen-on".equals(arg)) { 975 synchronized (mAm) { 976 mInjectedScreenState = true; 977 } 978 quit = true; 979 } else if ("--pretend-screen-off".equals(arg)) { 980 synchronized (mAm) { 981 mInjectedScreenState = false; 982 } 983 quit = true; 984 } else if ("--stop-pretend-screen".equals(arg)) { 985 synchronized (mAm) { 986 mInjectedScreenState = null; 987 } 988 quit = true; 989 } else if ("-h".equals(arg)) { 990 dumpHelp(pw); 991 return; 992 } else if ("-a".equals(arg)) { 993 dumpDetails = true; 994 dumpAll = true; 995 } else if (arg.length() > 0 && arg.charAt(0) == '-'){ 996 pw.println("Unknown option: " + arg); 997 dumpHelp(pw); 998 return; 999 } else { 1000 // Not an option, last argument must be a package name. 1001 reqPackage = arg; 1002 // Include all details, since we know we are only going to 1003 // be dumping a smaller set of data. In fact only the details 1004 // contain per-package data, so this is needed to be able 1005 // to dump anything at all when filtering by package. 1006 dumpDetails = true; 1007 } 1008 } 1009 } 1010 1011 if (quit) { 1012 return; 1013 } 1014 1015 if (isCsv) { 1016 pw.print("Processes running summed over"); 1017 if (!csvSepScreenStats) { 1018 for (int i=0; i<csvScreenStats.length; i++) { 1019 pw.print(" "); 1020 DumpUtils.printScreenLabelCsv(pw, csvScreenStats[i]); 1021 } 1022 } 1023 if (!csvSepMemStats) { 1024 for (int i=0; i<csvMemStats.length; i++) { 1025 pw.print(" "); 1026 DumpUtils.printMemLabelCsv(pw, csvMemStats[i]); 1027 } 1028 } 1029 if (!csvSepProcStats) { 1030 for (int i=0; i<csvProcStats.length; i++) { 1031 pw.print(" "); 1032 pw.print(DumpUtils.STATE_NAMES_CSV[csvProcStats[i]]); 1033 } 1034 } 1035 pw.println(); 1036 synchronized (mAm) { 1037 dumpFilteredProcessesCsvLocked(pw, null, 1038 csvSepScreenStats, csvScreenStats, csvSepMemStats, csvMemStats, 1039 csvSepProcStats, csvProcStats, now, reqPackage); 1040 /* 1041 dumpFilteredProcessesCsvLocked(pw, "Processes running while critical mem:", 1042 false, new int[] {ADJ_SCREEN_OFF, ADJ_SCREEN_ON}, 1043 true, new int[] {ADJ_MEM_FACTOR_CRITICAL}, 1044 true, new int[] {STATE_PERSISTENT, STATE_TOP, STATE_FOREGROUND, STATE_VISIBLE, 1045 STATE_PERCEPTIBLE, STATE_BACKUP, STATE_SERVICE, STATE_HOME, 1046 STATE_PREVIOUS, STATE_CACHED}, 1047 now, reqPackage); 1048 dumpFilteredProcessesCsvLocked(pw, "Processes running over all mem:", 1049 false, new int[] {ADJ_SCREEN_OFF, ADJ_SCREEN_ON}, 1050 false, new int[] {ADJ_MEM_FACTOR_CRITICAL, ADJ_MEM_FACTOR_LOW, 1051 ADJ_MEM_FACTOR_MODERATE, ADJ_MEM_FACTOR_MODERATE}, 1052 true, new int[] {STATE_PERSISTENT, STATE_TOP, STATE_FOREGROUND, STATE_VISIBLE, 1053 STATE_PERCEPTIBLE, STATE_BACKUP, STATE_SERVICE, STATE_HOME, 1054 STATE_PREVIOUS, STATE_CACHED}, 1055 now, reqPackage); 1056 */ 1057 } 1058 return; 1059 } else if (aggregateHours != 0) { 1060 pw.print("AGGREGATED OVER LAST "); pw.print(aggregateHours); pw.println(" HOURS:"); 1061 dumpAggregatedStats(pw, aggregateHours, now, reqPackage, isCompact, 1062 dumpDetails, dumpFullDetails, dumpAll, activeOnly, section); 1063 return; 1064 } else if (lastIndex > 0) { 1065 pw.print("LAST STATS AT INDEX "); pw.print(lastIndex); pw.println(":"); 1066 ArrayList<String> files = getCommittedFiles(0, false, true); 1067 if (lastIndex >= files.size()) { 1068 pw.print("Only have "); pw.print(files.size()); pw.println(" data sets"); 1069 return; 1070 } 1071 AtomicFile file = new AtomicFile(new File(files.get(lastIndex))); 1072 ProcessStats processStats = new ProcessStats(false); 1073 readLocked(processStats, file); 1074 if (processStats.mReadError != null) { 1075 if (isCheckin || isCompact) pw.print("err,"); 1076 pw.print("Failure reading "); pw.print(files.get(lastIndex)); 1077 pw.print("; "); pw.println(processStats.mReadError); 1078 return; 1079 } 1080 String fileStr = file.getBaseFile().getPath(); 1081 boolean checkedIn = fileStr.endsWith(STATE_FILE_CHECKIN_SUFFIX); 1082 if (isCheckin || isCompact) { 1083 // Don't really need to lock because we uniquely own this object. 1084 processStats.dumpCheckinLocked(pw, reqPackage, section); 1085 } else { 1086 pw.print("COMMITTED STATS FROM "); 1087 pw.print(processStats.mTimePeriodStartClockStr); 1088 if (checkedIn) pw.print(" (checked in)"); 1089 pw.println(":"); 1090 if (dumpDetails || dumpFullDetails) { 1091 processStats.dumpLocked(pw, reqPackage, now, !dumpFullDetails, dumpDetails, 1092 dumpAll, activeOnly, section); 1093 if (dumpAll) { 1094 pw.print(" mFile="); pw.println(mFile.getBaseFile()); 1095 } 1096 } else { 1097 processStats.dumpSummaryLocked(pw, reqPackage, now, activeOnly); 1098 } 1099 } 1100 return; 1101 } 1102 1103 boolean sepNeeded = false; 1104 if (dumpAll || isCheckin) { 1105 mWriteLock.lock(); 1106 try { 1107 ArrayList<String> files = getCommittedFiles(0, false, !isCheckin); 1108 if (files != null) { 1109 int start = isCheckin ? 0 : (files.size() - maxNum); 1110 if (start < 0) { 1111 start = 0; 1112 } 1113 for (int i=start; i<files.size(); i++) { 1114 if (DEBUG) Slog.d(TAG, "Retrieving state: " + files.get(i)); 1115 try { 1116 AtomicFile file = new AtomicFile(new File(files.get(i))); 1117 ProcessStats processStats = new ProcessStats(false); 1118 readLocked(processStats, file); 1119 if (processStats.mReadError != null) { 1120 if (isCheckin || isCompact) pw.print("err,"); 1121 pw.print("Failure reading "); pw.print(files.get(i)); 1122 pw.print("; "); pw.println(processStats.mReadError); 1123 if (DEBUG) Slog.d(TAG, "Deleting state: " + files.get(i)); 1124 (new File(files.get(i))).delete(); 1125 continue; 1126 } 1127 String fileStr = file.getBaseFile().getPath(); 1128 boolean checkedIn = fileStr.endsWith(STATE_FILE_CHECKIN_SUFFIX); 1129 if (isCheckin || isCompact) { 1130 // Don't really need to lock because we uniquely own this object. 1131 processStats.dumpCheckinLocked(pw, reqPackage, section); 1132 } else { 1133 if (sepNeeded) { 1134 pw.println(); 1135 } else { 1136 sepNeeded = true; 1137 } 1138 pw.print("COMMITTED STATS FROM "); 1139 pw.print(processStats.mTimePeriodStartClockStr); 1140 if (checkedIn) pw.print(" (checked in)"); 1141 pw.println(":"); 1142 // Don't really need to lock because we uniquely own this object. 1143 // Always dump summary here, dumping all details is just too 1144 // much crud. 1145 if (dumpFullDetails) { 1146 processStats.dumpLocked(pw, reqPackage, now, false, false, 1147 false, activeOnly, section); 1148 } else { 1149 processStats.dumpSummaryLocked(pw, reqPackage, now, activeOnly); 1150 } 1151 } 1152 if (isCheckin) { 1153 // Rename file suffix to mark that it has checked in. 1154 file.getBaseFile().renameTo(new File( 1155 fileStr + STATE_FILE_CHECKIN_SUFFIX)); 1156 } 1157 } catch (Throwable e) { 1158 pw.print("**** FAILURE DUMPING STATE: "); pw.println(files.get(i)); 1159 e.printStackTrace(pw); 1160 } 1161 } 1162 } 1163 } finally { 1164 mWriteLock.unlock(); 1165 } 1166 } 1167 if (!isCheckin) { 1168 synchronized (mAm) { 1169 if (isCompact) { 1170 mProcessStats.dumpCheckinLocked(pw, reqPackage, section); 1171 } else { 1172 if (sepNeeded) { 1173 pw.println(); 1174 } 1175 pw.println("CURRENT STATS:"); 1176 if (dumpDetails || dumpFullDetails) { 1177 mProcessStats.dumpLocked(pw, reqPackage, now, !dumpFullDetails, dumpDetails, 1178 dumpAll, activeOnly, section); 1179 if (dumpAll) { 1180 pw.print(" mFile="); pw.println(mFile.getBaseFile()); 1181 } 1182 } else { 1183 mProcessStats.dumpSummaryLocked(pw, reqPackage, now, activeOnly); 1184 } 1185 sepNeeded = true; 1186 } 1187 } 1188 if (!currentOnly) { 1189 if (sepNeeded) { 1190 pw.println(); 1191 } 1192 pw.println("AGGREGATED OVER LAST 24 HOURS:"); 1193 dumpAggregatedStats(pw, 24, now, reqPackage, isCompact, 1194 dumpDetails, dumpFullDetails, dumpAll, activeOnly, section); 1195 pw.println(); 1196 pw.println("AGGREGATED OVER LAST 3 HOURS:"); 1197 dumpAggregatedStats(pw, 3, now, reqPackage, isCompact, 1198 dumpDetails, dumpFullDetails, dumpAll, activeOnly, section); 1199 } 1200 } 1201 } 1202 1203 private void dumpAggregatedStats(ProtoOutputStream proto, long fieldId, int aggregateHours, long now) { 1204 ParcelFileDescriptor pfd = getStatsOverTime(aggregateHours*60*60*1000 1205 - (ProcessStats.COMMIT_PERIOD/2)); 1206 if (pfd == null) { 1207 return; 1208 } 1209 ProcessStats stats = new ProcessStats(false); 1210 InputStream stream = new ParcelFileDescriptor.AutoCloseInputStream(pfd); 1211 stats.read(stream); 1212 if (stats.mReadError != null) { 1213 return; 1214 } 1215 final long token = proto.start(fieldId); 1216 stats.writeToProto(proto, now, ProcessStats.REPORT_ALL); 1217 proto.end(token); 1218 } 1219 1220 private void dumpProto(FileDescriptor fd) { 1221 final ProtoOutputStream proto = new ProtoOutputStream(fd); 1222 1223 // dump current procstats 1224 long now; 1225 synchronized (mAm) { 1226 now = SystemClock.uptimeMillis(); 1227 final long token = proto.start(ProcessStatsServiceDumpProto.PROCSTATS_NOW); 1228 mProcessStats.writeToProto(proto, now, ProcessStats.REPORT_ALL); 1229 proto.end(token); 1230 } 1231 1232 // aggregated over last 3 hours procstats 1233 dumpAggregatedStats(proto, ProcessStatsServiceDumpProto.PROCSTATS_OVER_3HRS, 3, now); 1234 1235 // aggregated over last 24 hours procstats 1236 dumpAggregatedStats(proto, ProcessStatsServiceDumpProto.PROCSTATS_OVER_24HRS, 24, now); 1237 1238 proto.flush(); 1239 } 1240 } 1241