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 @Override 580 public byte[] getCurrentStats(List<ParcelFileDescriptor> historic) { 581 mAm.mContext.enforceCallingOrSelfPermission( 582 android.Manifest.permission.PACKAGE_USAGE_STATS, null); 583 Parcel current = Parcel.obtain(); 584 synchronized (mLock) { 585 long now = SystemClock.uptimeMillis(); 586 mProcessStats.mTimePeriodEndRealtime = SystemClock.elapsedRealtime(); 587 mProcessStats.mTimePeriodEndUptime = now; 588 mProcessStats.writeToParcel(current, now, 0); 589 } 590 mFileLock.lock(); 591 try { 592 if (historic != null) { 593 ArrayList<String> files = getCommittedFilesLF(0, false, true); 594 if (files != null) { 595 for (int i=files.size()-1; i>=0; i--) { 596 try { 597 ParcelFileDescriptor pfd = ParcelFileDescriptor.open( 598 new File(files.get(i)), ParcelFileDescriptor.MODE_READ_ONLY); 599 historic.add(pfd); 600 } catch (IOException e) { 601 Slog.w(TAG, "Failure opening procstat file " + files.get(i), e); 602 } 603 } 604 } 605 } 606 } finally { 607 mFileLock.unlock(); 608 } 609 return current.marshall(); 610 } 611 612 /** 613 * Get stats committed after highWaterMarkMs 614 * @param highWaterMarkMs Report stats committed after this time. 615 * @param section Integer mask to indicage which sections to include in the stats. 616 * @param doAggregate Whether to aggregate the stats or keep them separated. 617 * @return List of proto binary of individual commit files or one that is merged from them 618 */ 619 @Override 620 public long getCommittedStats(long highWaterMarkMs, int section, boolean doAggregate, 621 List<ParcelFileDescriptor> committedStats) { 622 return getCommittedStatsMerged(highWaterMarkMs, section, doAggregate, committedStats, 623 new ProcessStats(false)); 624 } 625 626 /** 627 * Get stats committed after highWaterMarkMs 628 * @param highWaterMarkMs Report stats committed after this time. 629 * @param section Integer mask to indicage which sections to include in the stats. 630 * @param doAggregate Whether to aggregate the stats or keep them separated. 631 * @return List of proto binary of individual commit files or one that is merged from them; 632 * the merged, final ProcessStats object. 633 */ 634 @Override 635 public long getCommittedStatsMerged(long highWaterMarkMs, int section, boolean doAggregate, 636 List<ParcelFileDescriptor> committedStats, ProcessStats mergedStats) { 637 mAm.mContext.enforceCallingOrSelfPermission( 638 android.Manifest.permission.PACKAGE_USAGE_STATS, null); 639 640 long newHighWaterMark = highWaterMarkMs; 641 mFileLock.lock(); 642 try { 643 ArrayList<String> files = getCommittedFilesLF(0, false, true); 644 if (files != null) { 645 String highWaterMarkStr = 646 DateFormat.format("yyyy-MM-dd-HH-mm-ss", highWaterMarkMs).toString(); 647 ProcessStats stats = new ProcessStats(false); 648 for (int i = files.size() - 1; i >= 0; i--) { 649 String fileName = files.get(i); 650 try { 651 String startTimeStr = fileName.substring( 652 fileName.lastIndexOf(STATE_FILE_PREFIX) 653 + STATE_FILE_PREFIX.length(), 654 fileName.lastIndexOf(STATE_FILE_SUFFIX)); 655 if (startTimeStr.compareToIgnoreCase(highWaterMarkStr) > 0) { 656 ParcelFileDescriptor pfd = ParcelFileDescriptor.open( 657 new File(fileName), 658 ParcelFileDescriptor.MODE_READ_ONLY); 659 InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(pfd); 660 stats.reset(); 661 stats.read(is); 662 is.close(); 663 if (stats.mTimePeriodStartClock > newHighWaterMark) { 664 newHighWaterMark = stats.mTimePeriodStartClock; 665 } 666 if (doAggregate) { 667 mergedStats.add(stats); 668 } else if (committedStats != null) { 669 committedStats.add(protoToParcelFileDescriptor(stats, section)); 670 } 671 if (stats.mReadError != null) { 672 Log.w(TAG, "Failure reading process stats: " + stats.mReadError); 673 continue; 674 } 675 } 676 } catch (IOException e) { 677 Slog.w(TAG, "Failure opening procstat file " + fileName, e); 678 } catch (IndexOutOfBoundsException e) { 679 Slog.w(TAG, "Failure to read and parse commit file " + fileName, e); 680 } 681 } 682 if (doAggregate && committedStats != null) { 683 committedStats.add(protoToParcelFileDescriptor(mergedStats, section)); 684 } 685 return newHighWaterMark; 686 } 687 } catch (IOException e) { 688 Slog.w(TAG, "Failure opening procstat file", e); 689 } finally { mFileLock.unlock()690 mFileLock.unlock(); 691 } 692 return newHighWaterMark; 693 } 694 695 /** 696 * @return The threshold to decide if a given association should be dumped into metrics. 697 */ 698 @Override 699 public long getMinAssociationDumpDuration() { 700 return mAm.mConstants.MIN_ASSOC_LOG_DURATION; 701 } 702 703 private static ParcelFileDescriptor protoToParcelFileDescriptor(ProcessStats stats, int section) 704 throws IOException { 705 final ParcelFileDescriptor[] fds = ParcelFileDescriptor.createPipe(); 706 Thread thr = new Thread("ProcessStats pipe output") { 707 public void run() { 708 try { 709 FileOutputStream fout = new ParcelFileDescriptor.AutoCloseOutputStream(fds[1]); 710 final ProtoOutputStream proto = new ProtoOutputStream(fout); 711 stats.dumpDebug(proto, stats.mTimePeriodEndRealtime, section); 712 proto.flush(); 713 fout.close(); 714 } catch (IOException e) { 715 Slog.w(TAG, "Failure writing pipe", e); 716 } 717 } 718 }; 719 thr.start(); 720 return fds[0]; 721 } 722 723 @Override 724 public ParcelFileDescriptor getStatsOverTime(long minTime) { 725 mAm.mContext.enforceCallingOrSelfPermission( 726 android.Manifest.permission.PACKAGE_USAGE_STATS, null); 727 Parcel current = Parcel.obtain(); 728 long curTime; 729 synchronized (mLock) { 730 long now = SystemClock.uptimeMillis(); 731 mProcessStats.mTimePeriodEndRealtime = SystemClock.elapsedRealtime(); 732 mProcessStats.mTimePeriodEndUptime = now; 733 mProcessStats.writeToParcel(current, now, 0); 734 curTime = mProcessStats.mTimePeriodEndRealtime 735 - mProcessStats.mTimePeriodStartRealtime; 736 } 737 mFileLock.lock(); 738 try { 739 if (curTime < minTime) { 740 // Need to add in older stats to reach desired time. 741 ArrayList<String> files = getCommittedFilesLF(0, false, true); 742 if (files != null && files.size() > 0) { 743 current.setDataPosition(0); 744 ProcessStats stats = ProcessStats.CREATOR.createFromParcel(current); 745 current.recycle(); 746 int i = files.size()-1; 747 while (i >= 0 && (stats.mTimePeriodEndRealtime 748 - stats.mTimePeriodStartRealtime) < minTime) { 749 AtomicFile file = new AtomicFile(new File(files.get(i))); 750 i--; 751 ProcessStats moreStats = new ProcessStats(false); 752 readLF(moreStats, file); 753 if (moreStats.mReadError == null) { 754 stats.add(moreStats); 755 StringBuilder sb = new StringBuilder(); 756 sb.append("Added stats: "); 757 sb.append(moreStats.mTimePeriodStartClockStr); 758 sb.append(", over "); 759 TimeUtils.formatDuration(moreStats.mTimePeriodEndRealtime 760 - moreStats.mTimePeriodStartRealtime, sb); 761 Slog.i(TAG, sb.toString()); 762 } else { 763 Slog.w(TAG, "Failure reading " + files.get(i+1) + "; " 764 + moreStats.mReadError); 765 continue; 766 } 767 } 768 current = Parcel.obtain(); 769 stats.writeToParcel(current, 0); 770 } 771 } 772 final byte[] outData = current.marshall(); 773 current.recycle(); 774 final ParcelFileDescriptor[] fds = ParcelFileDescriptor.createPipe(); 775 Thread thr = new Thread("ProcessStats pipe output") { 776 public void run() { 777 FileOutputStream fout = new ParcelFileDescriptor.AutoCloseOutputStream(fds[1]); 778 try { 779 fout.write(outData); 780 fout.close(); 781 } catch (IOException e) { 782 Slog.w(TAG, "Failure writing pipe", e); 783 } 784 } 785 }; 786 thr.start(); 787 return fds[0]; 788 } catch (IOException e) { 789 Slog.w(TAG, "Failed building output pipe", e); 790 } finally { 791 mFileLock.unlock(); 792 } 793 return null; 794 } 795 796 @Override 797 public int getCurrentMemoryState() { 798 synchronized (mLock) { 799 return mLastMemOnlyState; 800 } 801 } 802 803 private SparseArray<long[]> getUidProcStateStatsOverTime(long minTime) { 804 final ProcessStats stats = new ProcessStats(); 805 long curTime; 806 synchronized (mLock) { 807 final long now = SystemClock.uptimeMillis(); 808 mProcessStats.mTimePeriodEndRealtime = SystemClock.elapsedRealtime(); 809 mProcessStats.mTimePeriodEndUptime = now; 810 stats.add(mProcessStats); 811 curTime = mProcessStats.mTimePeriodEndRealtime - mProcessStats.mTimePeriodStartRealtime; 812 } 813 if (curTime < minTime) { 814 try { 815 mFileLock.lock(); 816 // Need to add in older stats to reach desired time. 817 ArrayList<String> files = getCommittedFilesLF(0, false, true); 818 if (files != null && files.size() > 0) { 819 int i = files.size() - 1; 820 while (i >= 0 && (stats.mTimePeriodEndRealtime 821 - stats.mTimePeriodStartRealtime) < minTime) { 822 AtomicFile file = new AtomicFile(new File(files.get(i))); 823 i--; 824 ProcessStats moreStats = new ProcessStats(false); 825 readLF(moreStats, file); 826 if (moreStats.mReadError == null) { 827 stats.add(moreStats); 828 } else { 829 Slog.w(TAG, "Failure reading " + files.get(i + 1) + "; " 830 + moreStats.mReadError); 831 continue; 832 } 833 } 834 } 835 } finally { 836 mFileLock.unlock(); 837 } 838 } 839 final SparseArray<UidState> uidStates = stats.mUidStates; 840 final SparseArray<long[]> results = new SparseArray<>(); 841 for (int i = 0, size = uidStates.size(); i < size; i++) { 842 final int uid = uidStates.keyAt(i); 843 final UidState uidState = uidStates.valueAt(i); 844 results.put(uid, uidState.getAggregatedDurationsInStates()); 845 } 846 return results; 847 } 848 849 void publish() { 850 LocalServices.addService(ProcessStatsInternal.class, new LocalService()); 851 } 852 853 private final class LocalService extends ProcessStatsInternal { 854 @Override 855 public SparseArray<long[]> getUidProcStateStatsOverTime(long minTime) { 856 return ProcessStatsService.this.getUidProcStateStatsOverTime(minTime); 857 } 858 } 859 860 private void dumpAggregatedStats(PrintWriter pw, long aggregateHours, long now, 861 String reqPackage, boolean isCompact, boolean dumpDetails, boolean dumpFullDetails, 862 boolean dumpAll, boolean activeOnly, int section) { 863 ParcelFileDescriptor pfd = getStatsOverTime(aggregateHours*60*60*1000 864 - (ProcessStats.COMMIT_PERIOD/2)); 865 if (pfd == null) { 866 pw.println("Unable to build stats!"); 867 return; 868 } 869 ProcessStats stats = new ProcessStats(false); 870 InputStream stream = new ParcelFileDescriptor.AutoCloseInputStream(pfd); 871 stats.read(stream); 872 if (stats.mReadError != null) { 873 pw.print("Failure reading: "); pw.println(stats.mReadError); 874 return; 875 } 876 if (isCompact) { 877 stats.dumpCheckinLocked(pw, reqPackage, section); 878 } else { 879 if (dumpDetails || dumpFullDetails) { 880 stats.dumpLocked(pw, reqPackage, now, !dumpFullDetails, dumpDetails, dumpAll, 881 activeOnly, section); 882 } else { 883 stats.dumpSummaryLocked(pw, reqPackage, now, activeOnly); 884 } 885 } 886 } 887 888 static private void dumpHelp(PrintWriter pw) { 889 pw.println("Process stats (procstats) dump options:"); 890 pw.println(" [--checkin|-c|--csv] [--csv-screen] [--csv-proc] [--csv-mem]"); 891 pw.println(" [--details] [--full-details] [--current] [--hours N] [--last N]"); 892 pw.println(" [--max N] --active] [--commit] [--reset] [--clear] [--write] [-h]"); 893 pw.println(" [--start-testing] [--stop-testing] "); 894 pw.println(" [--pretend-screen-on] [--pretend-screen-off] [--stop-pretend-screen]"); 895 pw.println(" [<package.name>]"); 896 pw.println(" --checkin: perform a checkin: print and delete old committed states."); 897 pw.println(" -c: print only state in checkin format."); 898 pw.println(" --csv: output data suitable for putting in a spreadsheet."); 899 pw.println(" --csv-screen: on, off."); 900 pw.println(" --csv-mem: norm, mod, low, crit."); 901 pw.println(" --csv-proc: pers, top, fore, vis, precept, backup,"); 902 pw.println(" service, home, prev, cached"); 903 pw.println(" --details: dump per-package details, not just summary."); 904 pw.println(" --full-details: dump all timing and active state details."); 905 pw.println(" --current: only dump current state."); 906 pw.println(" --hours: aggregate over about N last hours."); 907 pw.println(" --last: only show the last committed stats at index N (starting at 1)."); 908 pw.println(" --max: for -a, max num of historical batches to print."); 909 pw.println(" --active: only show currently active processes/services."); 910 pw.println(" --commit: commit current stats to disk and reset to start new stats."); 911 pw.println(" --section: proc|pkg-proc|pkg-svc|pkg-asc|pkg-all|all "); 912 pw.println(" options can be combined to select desired stats"); 913 pw.println(" --reset: reset current stats, without committing."); 914 pw.println(" --clear: clear all stats; does both --reset and deletes old stats."); 915 pw.println(" --write: write current in-memory stats to disk."); 916 pw.println(" --read: replace current stats with last-written stats."); 917 pw.println(" --start-testing: clear all stats and starting high frequency pss sampling."); 918 pw.println(" --stop-testing: stop high frequency pss sampling."); 919 pw.println(" --pretend-screen-on: pretend screen is on."); 920 pw.println(" --pretend-screen-off: pretend screen is off."); 921 pw.println(" --stop-pretend-screen: forget \"pretend screen\" and use the real state."); 922 pw.println(" -a: print everything."); 923 pw.println(" -h: print this help text."); 924 pw.println(" <package.name>: optional name of package to filter output by."); 925 } 926 927 @Override 928 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 929 if (!com.android.internal.util.DumpUtils.checkDumpAndUsageStatsPermission(mAm.mContext, 930 TAG, pw)) return; 931 932 final long ident = Binder.clearCallingIdentity(); 933 try { 934 if (args.length > 0) { 935 if ("--proto".equals(args[0])) { 936 dumpProto(fd); 937 return; 938 } else if ("--statsd".equals(args[0])) { 939 dumpProtoForStatsd(fd); 940 return; 941 } 942 } 943 dumpInner(pw, args); 944 } finally { 945 Binder.restoreCallingIdentity(ident); 946 } 947 } 948 949 @NeverCompile // Avoid size overhead of debugging code. 950 private void dumpInner(PrintWriter pw, String[] args) { 951 final long now = SystemClock.uptimeMillis(); 952 953 boolean isCheckin = false; 954 boolean isCompact = false; 955 boolean isCsv = false; 956 boolean currentOnly = false; 957 boolean dumpDetails = false; 958 boolean dumpFullDetails = false; 959 boolean dumpAll = false; 960 boolean quit = false; 961 int aggregateHours = 0; 962 int lastIndex = 0; 963 int maxNum = 2; 964 boolean activeOnly = false; 965 String reqPackage = null; 966 boolean csvSepScreenStats = false; 967 int[] csvScreenStats = new int[] { ProcessStats.ADJ_SCREEN_OFF, ProcessStats.ADJ_SCREEN_ON}; 968 boolean csvSepMemStats = false; 969 int[] csvMemStats = new int[] { ProcessStats.ADJ_MEM_FACTOR_CRITICAL}; 970 boolean csvSepProcStats = true; 971 int[] csvProcStats = ProcessStats.ALL_PROC_STATES; 972 int section = ProcessStats.REPORT_ALL; 973 if (args != null) { 974 for (int i=0; i<args.length; i++) { 975 String arg = args[i]; 976 if ("--checkin".equals(arg)) { 977 isCheckin = true; 978 } else if ("-c".equals(arg)) { 979 isCompact = true; 980 } else if ("--csv".equals(arg)) { 981 isCsv = true; 982 } else if ("--csv-screen".equals(arg)) { 983 i++; 984 if (i >= args.length) { 985 pw.println("Error: argument required for --csv-screen"); 986 dumpHelp(pw); 987 return; 988 } 989 boolean[] sep = new boolean[1]; 990 String[] error = new String[1]; 991 csvScreenStats = parseStateList(DumpUtils.ADJ_SCREEN_NAMES_CSV, 992 ProcessStats.ADJ_SCREEN_MOD, args[i], sep, error); 993 if (csvScreenStats == null) { 994 pw.println("Error in \"" + args[i] + "\": " + error[0]); 995 dumpHelp(pw); 996 return; 997 } 998 csvSepScreenStats = sep[0]; 999 } else if ("--csv-mem".equals(arg)) { 1000 i++; 1001 if (i >= args.length) { 1002 pw.println("Error: argument required for --csv-mem"); 1003 dumpHelp(pw); 1004 return; 1005 } 1006 boolean[] sep = new boolean[1]; 1007 String[] error = new String[1]; 1008 csvMemStats = parseStateList(DumpUtils.ADJ_MEM_NAMES_CSV, 1, args[i], 1009 sep, error); 1010 if (csvMemStats == null) { 1011 pw.println("Error in \"" + args[i] + "\": " + error[0]); 1012 dumpHelp(pw); 1013 return; 1014 } 1015 csvSepMemStats = sep[0]; 1016 } else if ("--csv-proc".equals(arg)) { 1017 i++; 1018 if (i >= args.length) { 1019 pw.println("Error: argument required for --csv-proc"); 1020 dumpHelp(pw); 1021 return; 1022 } 1023 boolean[] sep = new boolean[1]; 1024 String[] error = new String[1]; 1025 csvProcStats = parseStateList(DumpUtils.STATE_NAMES_CSV, 1, args[i], 1026 sep, error); 1027 if (csvProcStats == null) { 1028 pw.println("Error in \"" + args[i] + "\": " + error[0]); 1029 dumpHelp(pw); 1030 return; 1031 } 1032 csvSepProcStats = sep[0]; 1033 } else if ("--details".equals(arg)) { 1034 dumpDetails = true; 1035 } else if ("--full-details".equals(arg)) { 1036 dumpFullDetails = true; 1037 } else if ("--hours".equals(arg)) { 1038 i++; 1039 if (i >= args.length) { 1040 pw.println("Error: argument required for --hours"); 1041 dumpHelp(pw); 1042 return; 1043 } 1044 try { 1045 aggregateHours = Integer.parseInt(args[i]); 1046 } catch (NumberFormatException e) { 1047 pw.println("Error: --hours argument not an int -- " + args[i]); 1048 dumpHelp(pw); 1049 return; 1050 } 1051 } else if ("--last".equals(arg)) { 1052 i++; 1053 if (i >= args.length) { 1054 pw.println("Error: argument required for --last"); 1055 dumpHelp(pw); 1056 return; 1057 } 1058 try { 1059 lastIndex = Integer.parseInt(args[i]); 1060 } catch (NumberFormatException e) { 1061 pw.println("Error: --last argument not an int -- " + args[i]); 1062 dumpHelp(pw); 1063 return; 1064 } 1065 } else if ("--max".equals(arg)) { 1066 i++; 1067 if (i >= args.length) { 1068 pw.println("Error: argument required for --max"); 1069 dumpHelp(pw); 1070 return; 1071 } 1072 try { 1073 maxNum = Integer.parseInt(args[i]); 1074 } catch (NumberFormatException e) { 1075 pw.println("Error: --max argument not an int -- " + args[i]); 1076 dumpHelp(pw); 1077 return; 1078 } 1079 } else if ("--active".equals(arg)) { 1080 activeOnly = true; 1081 currentOnly = true; 1082 } else if ("--current".equals(arg)) { 1083 currentOnly = true; 1084 } else if ("--commit".equals(arg)) { 1085 synchronized (mLock) { 1086 mProcessStats.mFlags |= ProcessStats.FLAG_COMPLETE; 1087 writeStateLocked(true, true); 1088 pw.println("Process stats committed."); 1089 quit = true; 1090 } 1091 } else if ("--section".equals(arg)) { 1092 i++; 1093 if (i >= args.length) { 1094 pw.println("Error: argument required for --section"); 1095 dumpHelp(pw); 1096 return; 1097 } 1098 section = parseSectionOptions(args[i]); 1099 } else if ("--clear".equals(arg)) { 1100 synchronized (mLock) { 1101 mProcessStats.resetSafely(); 1102 scheduleRequestPssAllProcs(true, false); 1103 mFileLock.lock(); 1104 try { 1105 ArrayList<String> files = getCommittedFilesLF(0, true, true); 1106 if (files != null) { 1107 for (int fi = files.size() - 1; fi >= 0; fi--) { 1108 (new File(files.get(fi))).delete(); 1109 } 1110 } 1111 } finally { 1112 mFileLock.unlock(); 1113 } 1114 pw.println("All process stats cleared."); 1115 quit = true; 1116 } 1117 } else if ("--write".equals(arg)) { 1118 synchronized (mLock) { 1119 writeStateSyncLocked(); 1120 pw.println("Process stats written."); 1121 quit = true; 1122 } 1123 } else if ("--read".equals(arg)) { 1124 synchronized (mLock) { 1125 mFileLock.lock(); 1126 try { 1127 readLF(mProcessStats, mFile); 1128 pw.println("Process stats read."); 1129 quit = true; 1130 } finally { 1131 mFileLock.unlock(); 1132 } 1133 } 1134 } else if ("--start-testing".equals(arg)) { 1135 mAm.mAppProfiler.setTestPssMode(true); 1136 pw.println("Started high frequency sampling."); 1137 quit = true; 1138 } else if ("--stop-testing".equals(arg)) { 1139 mAm.mAppProfiler.setTestPssMode(false); 1140 pw.println("Stopped high frequency sampling."); 1141 quit = true; 1142 } else if ("--pretend-screen-on".equals(arg)) { 1143 synchronized (mLock) { 1144 mInjectedScreenState = true; 1145 } 1146 quit = true; 1147 } else if ("--pretend-screen-off".equals(arg)) { 1148 synchronized (mLock) { 1149 mInjectedScreenState = false; 1150 } 1151 quit = true; 1152 } else if ("--stop-pretend-screen".equals(arg)) { 1153 synchronized (mLock) { 1154 mInjectedScreenState = null; 1155 } 1156 quit = true; 1157 } else if ("-h".equals(arg)) { 1158 dumpHelp(pw); 1159 return; 1160 } else if ("-a".equals(arg)) { 1161 dumpDetails = true; 1162 dumpAll = true; 1163 } else if (arg.length() > 0 && arg.charAt(0) == '-'){ 1164 pw.println("Unknown option: " + arg); 1165 dumpHelp(pw); 1166 return; 1167 } else { 1168 // Not an option, last argument must be a package name. 1169 reqPackage = arg; 1170 // Include all details, since we know we are only going to 1171 // be dumping a smaller set of data. In fact only the details 1172 // contain per-package data, so this is needed to be able 1173 // to dump anything at all when filtering by package. 1174 dumpDetails = true; 1175 } 1176 } 1177 } 1178 1179 if (quit) { 1180 return; 1181 } 1182 1183 if (isCsv) { 1184 pw.print("Processes running summed over"); 1185 if (!csvSepScreenStats) { 1186 for (int i=0; i<csvScreenStats.length; i++) { 1187 pw.print(" "); 1188 DumpUtils.printScreenLabelCsv(pw, csvScreenStats[i]); 1189 } 1190 } 1191 if (!csvSepMemStats) { 1192 for (int i=0; i<csvMemStats.length; i++) { 1193 pw.print(" "); 1194 DumpUtils.printMemLabelCsv(pw, csvMemStats[i]); 1195 } 1196 } 1197 if (!csvSepProcStats) { 1198 for (int i=0; i<csvProcStats.length; i++) { 1199 pw.print(" "); 1200 pw.print(DumpUtils.STATE_NAMES_CSV[csvProcStats[i]]); 1201 } 1202 } 1203 pw.println(); 1204 synchronized (mLock) { 1205 dumpFilteredProcessesCsvLocked(pw, null, 1206 csvSepScreenStats, csvScreenStats, csvSepMemStats, csvMemStats, 1207 csvSepProcStats, csvProcStats, now, reqPackage); 1208 /* 1209 dumpFilteredProcessesCsvLocked(pw, "Processes running while critical mem:", 1210 false, new int[] {ADJ_SCREEN_OFF, ADJ_SCREEN_ON}, 1211 true, new int[] {ADJ_MEM_FACTOR_CRITICAL}, 1212 true, new int[] {STATE_PERSISTENT, STATE_TOP, STATE_FOREGROUND, STATE_VISIBLE, 1213 STATE_PERCEPTIBLE, STATE_BACKUP, STATE_SERVICE, STATE_HOME, 1214 STATE_PREVIOUS, STATE_CACHED}, 1215 now, reqPackage); 1216 dumpFilteredProcessesCsvLocked(pw, "Processes running over all mem:", 1217 false, new int[] {ADJ_SCREEN_OFF, ADJ_SCREEN_ON}, 1218 false, new int[] {ADJ_MEM_FACTOR_CRITICAL, ADJ_MEM_FACTOR_LOW, 1219 ADJ_MEM_FACTOR_MODERATE, ADJ_MEM_FACTOR_MODERATE}, 1220 true, new int[] {STATE_PERSISTENT, STATE_TOP, STATE_FOREGROUND, STATE_VISIBLE, 1221 STATE_PERCEPTIBLE, STATE_BACKUP, STATE_SERVICE, STATE_HOME, 1222 STATE_PREVIOUS, STATE_CACHED}, 1223 now, reqPackage); 1224 */ 1225 } 1226 return; 1227 } else if (aggregateHours != 0) { 1228 pw.print("AGGREGATED OVER LAST "); pw.print(aggregateHours); pw.println(" HOURS:"); 1229 dumpAggregatedStats(pw, aggregateHours, now, reqPackage, isCompact, 1230 dumpDetails, dumpFullDetails, dumpAll, activeOnly, section); 1231 return; 1232 } else if (lastIndex > 0) { 1233 pw.print("LAST STATS AT INDEX "); pw.print(lastIndex); pw.println(":"); 1234 1235 ArrayList<String> files; 1236 AtomicFile file; 1237 ProcessStats processStats; 1238 1239 mFileLock.lock(); 1240 try { 1241 files = getCommittedFilesLF(0, false, true); 1242 if (lastIndex >= files.size()) { 1243 pw.print("Only have "); pw.print(files.size()); pw.println(" data sets"); 1244 return; 1245 } 1246 file = new AtomicFile(new File(files.get(lastIndex))); 1247 processStats = new ProcessStats(false); 1248 readLF(processStats, file); 1249 } finally { 1250 mFileLock.unlock(); 1251 } 1252 1253 // No lock is needed now, since only us have the access to the 'processStats'. 1254 if (processStats.mReadError != null) { 1255 if (isCheckin || isCompact) pw.print("err,"); 1256 pw.print("Failure reading "); pw.print(files.get(lastIndex)); 1257 pw.print("; "); pw.println(processStats.mReadError); 1258 return; 1259 } 1260 String fileStr = file.getBaseFile().getPath(); 1261 boolean checkedIn = fileStr.endsWith(STATE_FILE_CHECKIN_SUFFIX); 1262 if (isCheckin || isCompact) { 1263 // Don't really need to lock because we uniquely own this object. 1264 processStats.dumpCheckinLocked(pw, reqPackage, section); 1265 } else { 1266 pw.print("COMMITTED STATS FROM "); 1267 pw.print(processStats.mTimePeriodStartClockStr); 1268 if (checkedIn) pw.print(" (checked in)"); 1269 pw.println(":"); 1270 if (dumpDetails || dumpFullDetails) { 1271 processStats.dumpLocked(pw, reqPackage, now, !dumpFullDetails, dumpDetails, 1272 dumpAll, activeOnly, section); 1273 if (dumpAll) { 1274 pw.print(" mFile="); pw.println(getCurrentFile()); 1275 } 1276 } else { 1277 processStats.dumpSummaryLocked(pw, reqPackage, now, activeOnly); 1278 } 1279 } 1280 return; 1281 } 1282 1283 boolean sepNeeded = false; 1284 if ((dumpAll || isCheckin) && !currentOnly) { 1285 mFileLock.lock(); 1286 try { 1287 ArrayList<String> files = getCommittedFilesLF(0, false, !isCheckin); 1288 if (files != null) { 1289 int start = isCheckin ? 0 : (files.size() - maxNum); 1290 if (start < 0) { 1291 start = 0; 1292 } 1293 for (int i=start; i<files.size(); i++) { 1294 if (DEBUG) Slog.d(TAG, "Retrieving state: " + files.get(i)); 1295 try { 1296 AtomicFile file = new AtomicFile(new File(files.get(i))); 1297 ProcessStats processStats = new ProcessStats(false); 1298 readLF(processStats, file); 1299 if (processStats.mReadError != null) { 1300 if (isCheckin || isCompact) pw.print("err,"); 1301 pw.print("Failure reading "); pw.print(files.get(i)); 1302 pw.print("; "); pw.println(processStats.mReadError); 1303 if (DEBUG) Slog.d(TAG, "Deleting state: " + files.get(i)); 1304 (new File(files.get(i))).delete(); 1305 continue; 1306 } 1307 String fileStr = file.getBaseFile().getPath(); 1308 boolean checkedIn = fileStr.endsWith(STATE_FILE_CHECKIN_SUFFIX); 1309 if (isCheckin || isCompact) { 1310 // Don't really need to lock because we uniquely own this object. 1311 processStats.dumpCheckinLocked(pw, reqPackage, section); 1312 } else { 1313 if (sepNeeded) { 1314 pw.println(); 1315 } else { 1316 sepNeeded = true; 1317 } 1318 pw.print("COMMITTED STATS FROM "); 1319 pw.print(processStats.mTimePeriodStartClockStr); 1320 if (checkedIn) pw.print(" (checked in)"); 1321 pw.println(":"); 1322 // Don't really need to lock because we uniquely own this object. 1323 // Always dump summary here, dumping all details is just too 1324 // much crud. 1325 if (dumpFullDetails) { 1326 processStats.dumpLocked(pw, reqPackage, now, false, false, 1327 false, activeOnly, section); 1328 } else { 1329 processStats.dumpSummaryLocked(pw, reqPackage, now, activeOnly); 1330 } 1331 } 1332 if (isCheckin) { 1333 // Rename file suffix to mark that it has checked in. 1334 file.getBaseFile().renameTo(new File( 1335 fileStr + STATE_FILE_CHECKIN_SUFFIX)); 1336 } 1337 } catch (Throwable e) { 1338 pw.print("**** FAILURE DUMPING STATE: "); pw.println(files.get(i)); 1339 e.printStackTrace(pw); 1340 } 1341 } 1342 } 1343 } finally { 1344 mFileLock.unlock(); 1345 } 1346 } 1347 if (!isCheckin) { 1348 synchronized (mLock) { 1349 if (isCompact) { 1350 mProcessStats.dumpCheckinLocked(pw, reqPackage, section); 1351 } else { 1352 if (sepNeeded) { 1353 pw.println(); 1354 } 1355 pw.println("CURRENT STATS:"); 1356 if (dumpDetails || dumpFullDetails) { 1357 mProcessStats.dumpLocked(pw, reqPackage, now, !dumpFullDetails, dumpDetails, 1358 dumpAll, activeOnly, section); 1359 if (dumpAll) { 1360 pw.print(" mFile="); pw.println(getCurrentFile()); 1361 } 1362 } else { 1363 mProcessStats.dumpSummaryLocked(pw, reqPackage, now, activeOnly); 1364 } 1365 sepNeeded = true; 1366 } 1367 } 1368 if (!currentOnly) { 1369 if (sepNeeded) { 1370 pw.println(); 1371 } 1372 pw.println("AGGREGATED OVER LAST 24 HOURS:"); 1373 dumpAggregatedStats(pw, 24, now, reqPackage, isCompact, 1374 dumpDetails, dumpFullDetails, dumpAll, activeOnly, section); 1375 pw.println(); 1376 pw.println("AGGREGATED OVER LAST 3 HOURS:"); 1377 dumpAggregatedStats(pw, 3, now, reqPackage, isCompact, 1378 dumpDetails, dumpFullDetails, dumpAll, activeOnly, section); 1379 } 1380 } 1381 } 1382 1383 private void dumpAggregatedStats(ProtoOutputStream proto, long fieldId, int aggregateHours, long now) { 1384 ParcelFileDescriptor pfd = getStatsOverTime(aggregateHours*60*60*1000 1385 - (ProcessStats.COMMIT_PERIOD/2)); 1386 if (pfd == null) { 1387 return; 1388 } 1389 ProcessStats stats = new ProcessStats(false); 1390 InputStream stream = new ParcelFileDescriptor.AutoCloseInputStream(pfd); 1391 stats.read(stream); 1392 if (stats.mReadError != null) { 1393 return; 1394 } 1395 final long token = proto.start(fieldId); 1396 stats.dumpDebug(proto, now, ProcessStats.REPORT_ALL); 1397 proto.end(token); 1398 } 1399 1400 private void dumpProto(FileDescriptor fd) { 1401 final ProtoOutputStream proto = new ProtoOutputStream(fd); 1402 1403 // dump current procstats 1404 long now; 1405 synchronized (mLock) { 1406 now = SystemClock.uptimeMillis(); 1407 final long token = proto.start(ProcessStatsServiceDumpProto.PROCSTATS_NOW); 1408 mProcessStats.dumpDebug(proto, now, ProcessStats.REPORT_ALL); 1409 proto.end(token); 1410 } 1411 1412 // aggregated over last 3 hours procstats 1413 dumpAggregatedStats(proto, ProcessStatsServiceDumpProto.PROCSTATS_OVER_3HRS, 3, now); 1414 1415 // aggregated over last 24 hours procstats 1416 dumpAggregatedStats(proto, ProcessStatsServiceDumpProto.PROCSTATS_OVER_24HRS, 24, now); 1417 1418 proto.flush(); 1419 } 1420 1421 /** 1422 * Dump proto for the statsd, mainly for testing. 1423 */ 1424 private void dumpProtoForStatsd(FileDescriptor fd) { 1425 final ProtoOutputStream[] protos = {new ProtoOutputStream(fd)}; 1426 1427 ProcessStats procStats = new ProcessStats(false); 1428 getCommittedStatsMerged(0, 0, true, null, procStats); 1429 procStats.dumpAggregatedProtoForStatsd(protos, 999999 /* max bytes per shard */); 1430 1431 protos[0].flush(); 1432 } 1433 } 1434