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