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