blob: 6ffd8a9180ba386cd5d29e95deb1348182d37d26 [file] [log] [blame]
Dianne Hackbornd2932242013-08-05 18:18:42 -07001/*
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
17package com.android.server.am;
18
Dianne Hackborn8a0de582013-08-07 15:22:07 -070019import android.os.Binder;
Dianne Hackbornd2932242013-08-05 18:18:42 -070020import android.os.Parcel;
Dianne Hackborn23fb6e82013-08-07 10:08:22 -070021import android.os.ParcelFileDescriptor;
Dianne Hackbornd2932242013-08-05 18:18:42 -070022import android.os.RemoteException;
23import android.os.SystemClock;
24import android.os.SystemProperties;
Yi Jin9680cfa2017-09-15 15:14:43 -070025import android.service.procstats.ProcessStatsServiceDumpProto;
Chenjie Yu4e028d02018-09-14 16:24:26 -070026import android.text.format.DateFormat;
Dianne Hackbornd2932242013-08-05 18:18:42 -070027import android.util.ArrayMap;
28import android.util.AtomicFile;
Chenjie Yu4e028d02018-09-14 16:24:26 -070029import android.util.Log;
Dianne Hackborn3accca02013-09-20 09:32:11 -070030import android.util.LongSparseArray;
Dianne Hackbornd2932242013-08-05 18:18:42 -070031import android.util.Slog;
32import android.util.SparseArray;
Dianne Hackborn53459a72013-09-17 17:14:57 -070033import android.util.TimeUtils;
Yi Jin9680cfa2017-09-15 15:14:43 -070034import android.util.proto.ProtoOutputStream;
Makoto Onuki3ed5be32017-02-01 14:04:47 -080035
36import com.android.internal.annotations.GuardedBy;
Joe Onorato4eb64fd2016-03-21 15:30:09 -070037import com.android.internal.app.procstats.DumpUtils;
38import com.android.internal.app.procstats.IProcessStats;
39import com.android.internal.app.procstats.ProcessState;
40import com.android.internal.app.procstats.ProcessStats;
41import com.android.internal.app.procstats.ServiceState;
Dianne Hackbornd2932242013-08-05 18:18:42 -070042import com.android.internal.os.BackgroundThread;
43
44import java.io.File;
45import java.io.FileDescriptor;
46import java.io.FileInputStream;
47import java.io.FileOutputStream;
48import java.io.IOException;
Dianne Hackborn53459a72013-09-17 17:14:57 -070049import java.io.InputStream;
Dianne Hackbornd2932242013-08-05 18:18:42 -070050import java.io.PrintWriter;
51import java.util.ArrayList;
Chenjie Yu4e028d02018-09-14 16:24:26 -070052import java.util.Arrays;
Dianne Hackbornd2932242013-08-05 18:18:42 -070053import java.util.Collections;
Dianne Hackborn23fb6e82013-08-07 10:08:22 -070054import java.util.List;
Dianne Hackbornd2932242013-08-05 18:18:42 -070055import java.util.concurrent.locks.ReentrantLock;
56
Dianne Hackborn23fb6e82013-08-07 10:08:22 -070057public final class ProcessStatsService extends IProcessStats.Stub {
Dianne Hackbornd2932242013-08-05 18:18:42 -070058 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
Dianne Hackborn6d9ef382013-09-23 14:39:23 -070066 static final int MAX_HISTORIC_STATES = 8; // Maximum number of historic states we will keep.
Dianne Hackbornd2932242013-08-05 18:18:42 -070067 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.
Dianne Hackbornd2932242013-08-05 18:18:42 -070071
Dianne Hackborn8a0de582013-08-07 15:22:07 -070072 final ActivityManagerService mAm;
Dianne Hackbornd2932242013-08-05 18:18:42 -070073 final File mBaseDir;
74 ProcessStats mProcessStats;
75 AtomicFile mFile;
76 boolean mCommitPending;
77 boolean mShuttingDown;
78 int mLastMemOnlyState = -1;
79 boolean mMemFactorLowered;
80
81 final ReentrantLock mWriteLock = new ReentrantLock();
82 final Object mPendingWriteLock = new Object();
83 AtomicFile mPendingWriteFile;
84 Parcel mPendingWrite;
85 boolean mPendingWriteCommitted;
86 long mLastWriteTime;
87
Makoto Onuki3ed5be32017-02-01 14:04:47 -080088 /** For CTS to inject the screen state. */
89 @GuardedBy("mAm")
90 Boolean mInjectedScreenState;
91
Dianne Hackborn8a0de582013-08-07 15:22:07 -070092 public ProcessStatsService(ActivityManagerService am, File file) {
93 mAm = am;
Dianne Hackbornd2932242013-08-05 18:18:42 -070094 mBaseDir = file;
95 mBaseDir.mkdirs();
96 mProcessStats = new ProcessStats(true);
97 updateFile();
98 SystemProperties.addChangeCallback(new Runnable() {
99 @Override public void run() {
Dianne Hackborn8a0de582013-08-07 15:22:07 -0700100 synchronized (mAm) {
Dianne Hackbornd2932242013-08-05 18:18:42 -0700101 if (mProcessStats.evaluateSystemProperties(false)) {
102 mProcessStats.mFlags |= ProcessStats.FLAG_SYSPROPS;
103 writeStateLocked(true, true);
104 mProcessStats.evaluateSystemProperties(true);
105 }
106 }
107 }
108 });
109 }
110
Dianne Hackbornd94d5332013-10-03 17:32:19 -0700111 @Override
112 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
113 throws RemoteException {
114 try {
115 return super.onTransact(code, data, reply, flags);
116 } catch (RuntimeException e) {
117 if (!(e instanceof SecurityException)) {
118 Slog.wtf(TAG, "Process Stats Crash", e);
119 }
120 throw e;
121 }
122 }
123
Dianne Hackborn2aec55a2018-06-26 10:35:35 -0700124 @GuardedBy("mAm")
125 public void updateProcessStateHolderLocked(ProcessStats.ProcessStateHolder holder,
126 String packageName, int uid, long versionCode, String processName) {
127 holder.pkg = mProcessStats.getPackageStateLocked(packageName, uid, versionCode);
128 holder.state = mProcessStats.getProcessStateLocked(holder.pkg, processName);
129 }
130
131 @GuardedBy("mAm")
Joe Onorato4eb64fd2016-03-21 15:30:09 -0700132 public ProcessState getProcessStateLocked(String packageName,
Dianne Hackborn3accca02013-09-20 09:32:11 -0700133 int uid, long versionCode, String processName) {
Dianne Hackborn8472e612014-01-23 17:57:20 -0800134 return mProcessStats.getProcessStateLocked(packageName, uid, versionCode, processName);
Dianne Hackbornd2932242013-08-05 18:18:42 -0700135 }
136
Dianne Hackborn2aec55a2018-06-26 10:35:35 -0700137 @GuardedBy("mAm")
Joe Onorato4eb64fd2016-03-21 15:30:09 -0700138 public ServiceState getServiceStateLocked(String packageName, int uid,
Dianne Hackborn3accca02013-09-20 09:32:11 -0700139 long versionCode, String processName, String className) {
Dianne Hackborn8472e612014-01-23 17:57:20 -0800140 return mProcessStats.getServiceStateLocked(packageName, uid, versionCode, processName,
141 className);
Dianne Hackbornd2932242013-08-05 18:18:42 -0700142 }
143
144 public boolean isMemFactorLowered() {
145 return mMemFactorLowered;
146 }
147
Andreas Gampea36dc622018-02-05 17:19:22 -0800148 @GuardedBy("mAm")
Dianne Hackbornd2932242013-08-05 18:18:42 -0700149 public boolean setMemFactorLocked(int memFactor, boolean screenOn, long now) {
150 mMemFactorLowered = memFactor < mLastMemOnlyState;
151 mLastMemOnlyState = memFactor;
Makoto Onuki3ed5be32017-02-01 14:04:47 -0800152 if (mInjectedScreenState != null) {
153 screenOn = mInjectedScreenState;
154 }
Dianne Hackbornd2932242013-08-05 18:18:42 -0700155 if (screenOn) {
156 memFactor += ProcessStats.ADJ_SCREEN_ON;
157 }
158 if (memFactor != mProcessStats.mMemFactor) {
159 if (mProcessStats.mMemFactor != ProcessStats.STATE_NOTHING) {
160 mProcessStats.mMemFactorDurations[mProcessStats.mMemFactor]
161 += now - mProcessStats.mStartTime;
162 }
163 mProcessStats.mMemFactor = memFactor;
164 mProcessStats.mStartTime = now;
Dianne Hackborn3accca02013-09-20 09:32:11 -0700165 final ArrayMap<String, SparseArray<LongSparseArray<ProcessStats.PackageState>>> pmap
Dianne Hackbornd2932242013-08-05 18:18:42 -0700166 = mProcessStats.mPackages.getMap();
Dianne Hackborn8472e612014-01-23 17:57:20 -0800167 for (int ipkg=pmap.size()-1; ipkg>=0; ipkg--) {
Dianne Hackborn3accca02013-09-20 09:32:11 -0700168 final SparseArray<LongSparseArray<ProcessStats.PackageState>> uids =
169 pmap.valueAt(ipkg);
Dianne Hackborn8472e612014-01-23 17:57:20 -0800170 for (int iuid=uids.size()-1; iuid>=0; iuid--) {
Dianne Hackborn3accca02013-09-20 09:32:11 -0700171 final LongSparseArray<ProcessStats.PackageState> vers = uids.valueAt(iuid);
Dianne Hackborn8472e612014-01-23 17:57:20 -0800172 for (int iver=vers.size()-1; iver>=0; iver--) {
173 final ProcessStats.PackageState pkg = vers.valueAt(iver);
Joe Onorato4eb64fd2016-03-21 15:30:09 -0700174 final ArrayMap<String, ServiceState> services = pkg.mServices;
Dianne Hackborn8472e612014-01-23 17:57:20 -0800175 for (int isvc=services.size()-1; isvc>=0; isvc--) {
Joe Onorato4eb64fd2016-03-21 15:30:09 -0700176 final ServiceState service = services.valueAt(isvc);
177 service.setMemFactor(memFactor, now);
Dianne Hackbornd2932242013-08-05 18:18:42 -0700178 }
179 }
180 }
181 }
182 return true;
183 }
184 return false;
185 }
186
Dianne Hackborn2aec55a2018-06-26 10:35:35 -0700187 @GuardedBy("mAm")
Dianne Hackbornd2932242013-08-05 18:18:42 -0700188 public int getMemFactorLocked() {
189 return mProcessStats.mMemFactor != ProcessStats.STATE_NOTHING ? mProcessStats.mMemFactor : 0;
190 }
191
Dianne Hackborn2aec55a2018-06-26 10:35:35 -0700192 @GuardedBy("mAm")
Dianne Hackbornf7097a52014-05-13 09:56:14 -0700193 public void addSysMemUsageLocked(long cachedMem, long freeMem, long zramMem, long kernelMem,
194 long nativeMem) {
195 mProcessStats.addSysMemUsage(cachedMem, freeMem, zramMem, kernelMem, nativeMem);
196 }
197
Dianne Hackborn2aec55a2018-06-26 10:35:35 -0700198 @GuardedBy("mAm")
Dianne Hackborn95031ef2018-07-09 09:09:05 -0700199 public void updateTrackingAssociationsLocked(int curSeq, long now) {
200 mProcessStats.updateTrackingAssociationsLocked(curSeq, now);
201 }
202
203 @GuardedBy("mAm")
Dianne Hackbornd2932242013-08-05 18:18:42 -0700204 public boolean shouldWriteNowLocked(long now) {
205 if (now > (mLastWriteTime+WRITE_PERIOD)) {
206 if (SystemClock.elapsedRealtime()
Dianne Hackbornf7097a52014-05-13 09:56:14 -0700207 > (mProcessStats.mTimePeriodStartRealtime+ProcessStats.COMMIT_PERIOD) &&
208 SystemClock.uptimeMillis()
209 > (mProcessStats.mTimePeriodStartUptime+ProcessStats.COMMIT_UPTIME_PERIOD)) {
Dianne Hackbornd2932242013-08-05 18:18:42 -0700210 mCommitPending = true;
211 }
212 return true;
213 }
214 return false;
215 }
216
Dianne Hackborn2aec55a2018-06-26 10:35:35 -0700217 @GuardedBy("mAm")
Dianne Hackbornd2932242013-08-05 18:18:42 -0700218 public void shutdownLocked() {
219 Slog.w(TAG, "Writing process stats before shutdown...");
220 mProcessStats.mFlags |= ProcessStats.FLAG_SHUTDOWN;
221 writeStateSyncLocked();
222 mShuttingDown = true;
223 }
224
Dianne Hackborn2aec55a2018-06-26 10:35:35 -0700225 @GuardedBy("mAm")
Dianne Hackbornd2932242013-08-05 18:18:42 -0700226 public void writeStateAsyncLocked() {
227 writeStateLocked(false);
228 }
229
Dianne Hackborn2aec55a2018-06-26 10:35:35 -0700230 @GuardedBy("mAm")
Dianne Hackbornd2932242013-08-05 18:18:42 -0700231 public void writeStateSyncLocked() {
232 writeStateLocked(true);
233 }
234
Dianne Hackborn2aec55a2018-06-26 10:35:35 -0700235 @GuardedBy("mAm")
Dianne Hackbornd2932242013-08-05 18:18:42 -0700236 private void writeStateLocked(boolean sync) {
237 if (mShuttingDown) {
238 return;
239 }
240 boolean commitPending = mCommitPending;
241 mCommitPending = false;
242 writeStateLocked(sync, commitPending);
243 }
244
Dianne Hackborn2aec55a2018-06-26 10:35:35 -0700245 @GuardedBy("mAm")
Dianne Hackbornd2932242013-08-05 18:18:42 -0700246 public void writeStateLocked(boolean sync, final boolean commit) {
Dianne Hackborne17b4452018-01-10 13:15:40 -0800247 final long totalTime;
Dianne Hackbornd2932242013-08-05 18:18:42 -0700248 synchronized (mPendingWriteLock) {
Dianne Hackborne17b4452018-01-10 13:15:40 -0800249 final long now = SystemClock.uptimeMillis();
Dianne Hackbornd2932242013-08-05 18:18:42 -0700250 if (mPendingWrite == null || !mPendingWriteCommitted) {
251 mPendingWrite = Parcel.obtain();
252 mProcessStats.mTimePeriodEndRealtime = SystemClock.elapsedRealtime();
Dianne Hackbornf7097a52014-05-13 09:56:14 -0700253 mProcessStats.mTimePeriodEndUptime = now;
Dianne Hackbornd2932242013-08-05 18:18:42 -0700254 if (commit) {
255 mProcessStats.mFlags |= ProcessStats.FLAG_COMPLETE;
256 }
Dianne Hackborn23fb6e82013-08-07 10:08:22 -0700257 mProcessStats.writeToParcel(mPendingWrite, 0);
Dianne Hackbornd2932242013-08-05 18:18:42 -0700258 mPendingWriteFile = new AtomicFile(mFile.getBaseFile());
259 mPendingWriteCommitted = commit;
260 }
261 if (commit) {
262 mProcessStats.resetSafely();
263 updateFile();
Dianne Hackborned0a3222018-02-06 16:01:23 -0800264 mAm.requestPssAllProcsLocked(SystemClock.uptimeMillis(), true, false);
Dianne Hackbornd2932242013-08-05 18:18:42 -0700265 }
266 mLastWriteTime = SystemClock.uptimeMillis();
Dianne Hackborne17b4452018-01-10 13:15:40 -0800267 totalTime = SystemClock.uptimeMillis() - now;
268 if (DEBUG) Slog.d(TAG, "Prepared write state in " + now + "ms");
Dianne Hackbornd2932242013-08-05 18:18:42 -0700269 if (!sync) {
270 BackgroundThread.getHandler().post(new Runnable() {
271 @Override public void run() {
Dianne Hackborne17b4452018-01-10 13:15:40 -0800272 performWriteState(totalTime);
Dianne Hackbornd2932242013-08-05 18:18:42 -0700273 }
274 });
275 return;
276 }
277 }
278
Dianne Hackborne17b4452018-01-10 13:15:40 -0800279 performWriteState(totalTime);
Dianne Hackbornd2932242013-08-05 18:18:42 -0700280 }
281
282 private void updateFile() {
283 mFile = new AtomicFile(new File(mBaseDir, STATE_FILE_PREFIX
284 + mProcessStats.mTimePeriodStartClockStr + STATE_FILE_SUFFIX));
285 mLastWriteTime = SystemClock.uptimeMillis();
286 }
287
Dianne Hackborne17b4452018-01-10 13:15:40 -0800288 void performWriteState(long initialTime) {
Dianne Hackbornd2932242013-08-05 18:18:42 -0700289 if (DEBUG) Slog.d(TAG, "Performing write to " + mFile.getBaseFile());
290 Parcel data;
291 AtomicFile file;
292 synchronized (mPendingWriteLock) {
293 data = mPendingWrite;
294 file = mPendingWriteFile;
295 mPendingWriteCommitted = false;
296 if (data == null) {
297 return;
298 }
299 mPendingWrite = null;
300 mPendingWriteFile = null;
301 mWriteLock.lock();
302 }
303
Dianne Hackborne17b4452018-01-10 13:15:40 -0800304 final long startTime = SystemClock.uptimeMillis();
Dianne Hackbornd2932242013-08-05 18:18:42 -0700305 FileOutputStream stream = null;
306 try {
307 stream = file.startWrite();
308 stream.write(data.marshall());
309 stream.flush();
310 file.finishWrite(stream);
Dianne Hackborne17b4452018-01-10 13:15:40 -0800311 com.android.internal.logging.EventLogTags.writeCommitSysConfigFile(
312 "procstats", SystemClock.uptimeMillis() - startTime + initialTime);
Dianne Hackbornd2932242013-08-05 18:18:42 -0700313 if (DEBUG) Slog.d(TAG, "Write completed successfully!");
314 } catch (IOException e) {
315 Slog.w(TAG, "Error writing process statistics", e);
316 file.failWrite(stream);
317 } finally {
318 data.recycle();
319 trimHistoricStatesWriteLocked();
320 mWriteLock.unlock();
321 }
322 }
323
Dianne Hackborn2aec55a2018-06-26 10:35:35 -0700324 @GuardedBy("mAm")
Dianne Hackbornd2932242013-08-05 18:18:42 -0700325 boolean readLocked(ProcessStats stats, AtomicFile file) {
326 try {
327 FileInputStream stream = file.openRead();
Dianne Hackborn60444fd2013-08-08 21:57:14 -0700328 stats.read(stream);
Dianne Hackbornd2932242013-08-05 18:18:42 -0700329 stream.close();
Dianne Hackbornd2932242013-08-05 18:18:42 -0700330 if (stats.mReadError != null) {
331 Slog.w(TAG, "Ignoring existing stats; " + stats.mReadError);
332 if (DEBUG) {
Joe Onorato4eb64fd2016-03-21 15:30:09 -0700333 ArrayMap<String, SparseArray<ProcessState>> procMap = stats.mProcesses.getMap();
Dianne Hackbornd2932242013-08-05 18:18:42 -0700334 final int NPROC = procMap.size();
335 for (int ip=0; ip<NPROC; ip++) {
336 Slog.w(TAG, "Process: " + procMap.keyAt(ip));
Joe Onorato4eb64fd2016-03-21 15:30:09 -0700337 SparseArray<ProcessState> uids = procMap.valueAt(ip);
Dianne Hackbornd2932242013-08-05 18:18:42 -0700338 final int NUID = uids.size();
339 for (int iu=0; iu<NUID; iu++) {
340 Slog.w(TAG, " Uid " + uids.keyAt(iu) + ": " + uids.valueAt(iu));
341 }
342 }
Dianne Hackborn3accca02013-09-20 09:32:11 -0700343 ArrayMap<String, SparseArray<LongSparseArray<ProcessStats.PackageState>>> pkgMap
Dianne Hackbornd2932242013-08-05 18:18:42 -0700344 = stats.mPackages.getMap();
345 final int NPKG = pkgMap.size();
346 for (int ip=0; ip<NPKG; ip++) {
347 Slog.w(TAG, "Package: " + pkgMap.keyAt(ip));
Dianne Hackborn3accca02013-09-20 09:32:11 -0700348 SparseArray<LongSparseArray<ProcessStats.PackageState>> uids
Dianne Hackborn8472e612014-01-23 17:57:20 -0800349 = pkgMap.valueAt(ip);
Dianne Hackbornd2932242013-08-05 18:18:42 -0700350 final int NUID = uids.size();
351 for (int iu=0; iu<NUID; iu++) {
352 Slog.w(TAG, " Uid: " + uids.keyAt(iu));
Dianne Hackborn3accca02013-09-20 09:32:11 -0700353 LongSparseArray<ProcessStats.PackageState> vers = uids.valueAt(iu);
Dianne Hackborn8472e612014-01-23 17:57:20 -0800354 final int NVERS = vers.size();
355 for (int iv=0; iv<NVERS; iv++) {
356 Slog.w(TAG, " Vers: " + vers.keyAt(iv));
357 ProcessStats.PackageState pkgState = vers.valueAt(iv);
358 final int NPROCS = pkgState.mProcesses.size();
359 for (int iproc=0; iproc<NPROCS; iproc++) {
360 Slog.w(TAG, " Process " + pkgState.mProcesses.keyAt(iproc)
361 + ": " + pkgState.mProcesses.valueAt(iproc));
362 }
363 final int NSRVS = pkgState.mServices.size();
364 for (int isvc=0; isvc<NSRVS; isvc++) {
365 Slog.w(TAG, " Service " + pkgState.mServices.keyAt(isvc)
366 + ": " + pkgState.mServices.valueAt(isvc));
367
368 }
Dianne Hackborn2aec55a2018-06-26 10:35:35 -0700369 final int NASCS = pkgState.mAssociations.size();
370 for (int iasc=0; iasc<NASCS; iasc++) {
371 Slog.w(TAG, " Association "
372 + pkgState.mServices.keyAt(iasc)
373 + ": " + pkgState.mAssociations.valueAt(iasc));
374
375 }
Dianne Hackbornd2932242013-08-05 18:18:42 -0700376 }
377 }
378 }
379 }
380 return false;
381 }
382 } catch (Throwable e) {
383 stats.mReadError = "caught exception: " + e;
384 Slog.e(TAG, "Error reading process statistics", e);
385 return false;
386 }
387 return true;
388 }
389
Dianne Hackborn53459a72013-09-17 17:14:57 -0700390 private ArrayList<String> getCommittedFiles(int minNum, boolean inclCurrent,
391 boolean inclCheckedIn) {
Dianne Hackbornd2932242013-08-05 18:18:42 -0700392 File[] files = mBaseDir.listFiles();
393 if (files == null || files.length <= minNum) {
394 return null;
395 }
396 ArrayList<String> filesArray = new ArrayList<String>(files.length);
397 String currentFile = mFile.getBaseFile().getPath();
398 if (DEBUG) Slog.d(TAG, "Collecting " + files.length + " files except: " + currentFile);
399 for (int i=0; i<files.length; i++) {
400 File file = files[i];
401 String fileStr = file.getPath();
402 if (DEBUG) Slog.d(TAG, "Collecting: " + fileStr);
Dianne Hackborn53459a72013-09-17 17:14:57 -0700403 if (!inclCheckedIn && fileStr.endsWith(STATE_FILE_CHECKIN_SUFFIX)) {
Dianne Hackbornd2932242013-08-05 18:18:42 -0700404 if (DEBUG) Slog.d(TAG, "Skipping: already checked in");
405 continue;
406 }
Dianne Hackborn53459a72013-09-17 17:14:57 -0700407 if (!inclCurrent && fileStr.equals(currentFile)) {
Dianne Hackbornd2932242013-08-05 18:18:42 -0700408 if (DEBUG) Slog.d(TAG, "Skipping: current stats");
409 continue;
410 }
411 filesArray.add(fileStr);
412 }
413 Collections.sort(filesArray);
414 return filesArray;
415 }
416
Dianne Hackborn2aec55a2018-06-26 10:35:35 -0700417 @GuardedBy("mAm")
Dianne Hackbornd2932242013-08-05 18:18:42 -0700418 public void trimHistoricStatesWriteLocked() {
Dianne Hackborn53459a72013-09-17 17:14:57 -0700419 ArrayList<String> filesArray = getCommittedFiles(MAX_HISTORIC_STATES, false, true);
Dianne Hackbornd2932242013-08-05 18:18:42 -0700420 if (filesArray == null) {
421 return;
422 }
423 while (filesArray.size() > MAX_HISTORIC_STATES) {
424 String file = filesArray.remove(0);
425 Slog.i(TAG, "Pruning old procstats: " + file);
426 (new File(file)).delete();
427 }
428 }
429
Dianne Hackborn2aec55a2018-06-26 10:35:35 -0700430 @GuardedBy("mAm")
Dianne Hackbornd2932242013-08-05 18:18:42 -0700431 boolean dumpFilteredProcessesCsvLocked(PrintWriter pw, String header,
432 boolean sepScreenStates, int[] screenStates, boolean sepMemStates, int[] memStates,
433 boolean sepProcStates, int[] procStates, long now, String reqPackage) {
Joe Onorato4eb64fd2016-03-21 15:30:09 -0700434 ArrayList<ProcessState> procs = mProcessStats.collectProcessesLocked(
Dianne Hackborn164371f2013-10-01 19:10:13 -0700435 screenStates, memStates, procStates, procStates, now, reqPackage, false);
Dianne Hackbornd2932242013-08-05 18:18:42 -0700436 if (procs.size() > 0) {
437 if (header != null) {
438 pw.println(header);
439 }
Joe Onorato4eb64fd2016-03-21 15:30:09 -0700440 DumpUtils.dumpProcessListCsv(pw, procs, sepScreenStates, screenStates,
Dianne Hackbornd2932242013-08-05 18:18:42 -0700441 sepMemStates, memStates, sepProcStates, procStates, now);
442 return true;
443 }
444 return false;
445 }
446
447 static int[] parseStateList(String[] states, int mult, String arg, boolean[] outSep,
448 String[] outError) {
449 ArrayList<Integer> res = new ArrayList<Integer>();
450 int lastPos = 0;
451 for (int i=0; i<=arg.length(); i++) {
452 char c = i < arg.length() ? arg.charAt(i) : 0;
453 if (c != ',' && c != '+' && c != ' ' && c != 0) {
454 continue;
455 }
456 boolean isSep = c == ',';
457 if (lastPos == 0) {
458 // We now know the type of op.
459 outSep[0] = isSep;
460 } else if (c != 0 && outSep[0] != isSep) {
461 outError[0] = "inconsistent separators (can't mix ',' with '+')";
462 return null;
463 }
464 if (lastPos < (i-1)) {
465 String str = arg.substring(lastPos, i);
466 for (int j=0; j<states.length; j++) {
467 if (str.equals(states[j])) {
468 res.add(j);
469 str = null;
470 break;
471 }
472 }
473 if (str != null) {
474 outError[0] = "invalid word \"" + str + "\"";
475 return null;
476 }
477 }
478 lastPos = i + 1;
479 }
480
481 int[] finalRes = new int[res.size()];
482 for (int i=0; i<res.size(); i++) {
483 finalRes[i] = res.get(i) * mult;
484 }
485 return finalRes;
486 }
487
Chenjie Yu4e028d02018-09-14 16:24:26 -0700488 static int parseSectionOptions(String optionsStr) {
489 final String sep = ",";
490 String[] sectionsStr = optionsStr.split(sep);
491 if (sectionsStr.length == 0) {
492 return ProcessStats.REPORT_ALL;
493 }
494 int res = 0;
495 List<String> optionStrList = Arrays.asList(ProcessStats.OPTIONS_STR);
496 for (String sectionStr : sectionsStr) {
497 int optionIndex = optionStrList.indexOf(sectionStr);
498 if (optionIndex != -1) {
499 res |= ProcessStats.OPTIONS[optionIndex];
500 }
501 }
502 return res;
503 }
504
Dianne Hackborn23fb6e82013-08-07 10:08:22 -0700505 public byte[] getCurrentStats(List<ParcelFileDescriptor> historic) {
Dianne Hackborn53459a72013-09-17 17:14:57 -0700506 mAm.mContext.enforceCallingOrSelfPermission(
507 android.Manifest.permission.PACKAGE_USAGE_STATS, null);
Dianne Hackborn23fb6e82013-08-07 10:08:22 -0700508 Parcel current = Parcel.obtain();
riddle_hsu61231a52014-11-15 18:40:08 +0800509 synchronized (mAm) {
510 long now = SystemClock.uptimeMillis();
511 mProcessStats.mTimePeriodEndRealtime = SystemClock.elapsedRealtime();
512 mProcessStats.mTimePeriodEndUptime = now;
513 mProcessStats.writeToParcel(current, now, 0);
514 }
Dianne Hackborn23fb6e82013-08-07 10:08:22 -0700515 mWriteLock.lock();
516 try {
Dianne Hackborn23fb6e82013-08-07 10:08:22 -0700517 if (historic != null) {
Dianne Hackborn53459a72013-09-17 17:14:57 -0700518 ArrayList<String> files = getCommittedFiles(0, false, true);
Dianne Hackborn23fb6e82013-08-07 10:08:22 -0700519 if (files != null) {
520 for (int i=files.size()-1; i>=0; i--) {
521 try {
522 ParcelFileDescriptor pfd = ParcelFileDescriptor.open(
523 new File(files.get(i)), ParcelFileDescriptor.MODE_READ_ONLY);
524 historic.add(pfd);
525 } catch (IOException e) {
526 Slog.w(TAG, "Failure opening procstat file " + files.get(i), e);
527 }
528 }
529 }
530 }
531 } finally {
532 mWriteLock.unlock();
533 }
534 return current.marshall();
535 }
536
Chenjie Yu4e028d02018-09-14 16:24:26 -0700537 /**
538 * Get stats committed after highWaterMarkMs
539 * @param highWaterMarkMs Report stats committed after this time.
540 * @param section Integer mask to indicage which sections to include in the stats.
541 * @param doAggregate Whether to aggregate the stats or keep them separated.
542 * @return List of proto binary of individual commit files or one that is merged from them.
543 */
544 @Override
545 public long getCommittedStats(long highWaterMarkMs, int section, boolean doAggregate,
546 List<ParcelFileDescriptor> committedStats) {
547 mAm.mContext.enforceCallingOrSelfPermission(
548 android.Manifest.permission.PACKAGE_USAGE_STATS, null);
549
550 ProcessStats mergedStats = new ProcessStats(false);
551 long newHighWaterMark = highWaterMarkMs;
552 mWriteLock.lock();
553 try {
554 ArrayList<String> files = getCommittedFiles(0, false, true);
555 if (files != null) {
556 String highWaterMarkStr =
557 DateFormat.format("yyyy-MM-dd-HH-mm-ss", highWaterMarkMs).toString();
558 ProcessStats stats = new ProcessStats(false);
559 for (int i = files.size() - 1; i >= 0; i--) {
560 String fileName = files.get(i);
561 try {
562 String startTimeStr = fileName.substring(
563 fileName.lastIndexOf(STATE_FILE_PREFIX)
564 + STATE_FILE_PREFIX.length(),
565 fileName.lastIndexOf(STATE_FILE_SUFFIX));
566 if (startTimeStr.compareToIgnoreCase(highWaterMarkStr) > 0) {
567 ParcelFileDescriptor pfd = ParcelFileDescriptor.open(
568 new File(fileName),
569 ParcelFileDescriptor.MODE_READ_ONLY);
570 InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(pfd);
571 stats.reset();
572 stats.read(is);
573 is.close();
574 if (stats.mTimePeriodStartClock > newHighWaterMark) {
575 newHighWaterMark = stats.mTimePeriodStartClock;
576 }
577 if (doAggregate) {
578 mergedStats.add(stats);
579 } else {
580 committedStats.add(protoToParcelFileDescriptor(stats, section));
581 }
582 if (stats.mReadError != null) {
583 Log.w(TAG, "Failure reading process stats: " + stats.mReadError);
584 continue;
585 }
586 }
587 } catch (IOException e) {
588 Slog.w(TAG, "Failure opening procstat file " + fileName, e);
589 } catch (IndexOutOfBoundsException e) {
590 Slog.w(TAG, "Failure to read and parse commit file " + fileName, e);
591 }
592 }
593 if (doAggregate) {
594 committedStats.add(protoToParcelFileDescriptor(mergedStats, section));
595 }
596 return newHighWaterMark;
597 }
598 } catch (IOException e) {
599 Slog.w(TAG, "Failure opening procstat file", e);
600 } finally {
601 mWriteLock.unlock();
602 }
603 return newHighWaterMark;
604 }
605
606 private ParcelFileDescriptor protoToParcelFileDescriptor(ProcessStats stats, int section)
607 throws IOException {
608 final ParcelFileDescriptor[] fds = ParcelFileDescriptor.createPipe();
609 Thread thr = new Thread("ProcessStats pipe output") {
610 public void run() {
611 try {
612 FileOutputStream fout = new ParcelFileDescriptor.AutoCloseOutputStream(fds[1]);
613 final ProtoOutputStream proto = new ProtoOutputStream(fout);
614 stats.writeToProto(proto, stats.mTimePeriodEndRealtime, section);
615 proto.flush();
616 fout.close();
617 } catch (IOException e) {
618 Slog.w(TAG, "Failure writing pipe", e);
619 }
620 }
621 };
622 thr.start();
623 return fds[0];
624 }
625
Dianne Hackborn53459a72013-09-17 17:14:57 -0700626 public ParcelFileDescriptor getStatsOverTime(long minTime) {
627 mAm.mContext.enforceCallingOrSelfPermission(
628 android.Manifest.permission.PACKAGE_USAGE_STATS, null);
riddle_hsu61231a52014-11-15 18:40:08 +0800629 Parcel current = Parcel.obtain();
630 long curTime;
631 synchronized (mAm) {
632 long now = SystemClock.uptimeMillis();
633 mProcessStats.mTimePeriodEndRealtime = SystemClock.elapsedRealtime();
634 mProcessStats.mTimePeriodEndUptime = now;
635 mProcessStats.writeToParcel(current, now, 0);
636 curTime = mProcessStats.mTimePeriodEndRealtime
637 - mProcessStats.mTimePeriodStartRealtime;
638 }
Dianne Hackborn53459a72013-09-17 17:14:57 -0700639 mWriteLock.lock();
640 try {
Dianne Hackborn53459a72013-09-17 17:14:57 -0700641 if (curTime < minTime) {
642 // Need to add in older stats to reach desired time.
643 ArrayList<String> files = getCommittedFiles(0, false, true);
Dianne Hackborncb428552013-09-26 11:07:17 -0700644 if (files != null && files.size() > 0) {
Dianne Hackborn53459a72013-09-17 17:14:57 -0700645 current.setDataPosition(0);
646 ProcessStats stats = ProcessStats.CREATOR.createFromParcel(current);
647 current.recycle();
Dianne Hackborn59da6792013-10-10 18:27:24 -0700648 int i = files.size()-1;
649 while (i >= 0 && (stats.mTimePeriodEndRealtime
Dianne Hackborn53459a72013-09-17 17:14:57 -0700650 - stats.mTimePeriodStartRealtime) < minTime) {
651 AtomicFile file = new AtomicFile(new File(files.get(i)));
Dianne Hackborn59da6792013-10-10 18:27:24 -0700652 i--;
Dianne Hackborn53459a72013-09-17 17:14:57 -0700653 ProcessStats moreStats = new ProcessStats(false);
654 readLocked(moreStats, file);
655 if (moreStats.mReadError == null) {
656 stats.add(moreStats);
657 StringBuilder sb = new StringBuilder();
658 sb.append("Added stats: ");
659 sb.append(moreStats.mTimePeriodStartClockStr);
660 sb.append(", over ");
661 TimeUtils.formatDuration(moreStats.mTimePeriodEndRealtime
662 - moreStats.mTimePeriodStartRealtime, sb);
663 Slog.i(TAG, sb.toString());
664 } else {
Dianne Hackborn59da6792013-10-10 18:27:24 -0700665 Slog.w(TAG, "Failure reading " + files.get(i+1) + "; "
Dianne Hackborn53459a72013-09-17 17:14:57 -0700666 + moreStats.mReadError);
667 continue;
668 }
669 }
670 current = Parcel.obtain();
671 stats.writeToParcel(current, 0);
672 }
673 }
674 final byte[] outData = current.marshall();
675 current.recycle();
676 final ParcelFileDescriptor[] fds = ParcelFileDescriptor.createPipe();
677 Thread thr = new Thread("ProcessStats pipe output") {
678 public void run() {
679 FileOutputStream fout = new ParcelFileDescriptor.AutoCloseOutputStream(fds[1]);
680 try {
681 fout.write(outData);
682 fout.close();
683 } catch (IOException e) {
684 Slog.w(TAG, "Failure writing pipe", e);
685 }
686 }
687 };
688 thr.start();
689 return fds[0];
690 } catch (IOException e) {
691 Slog.w(TAG, "Failed building output pipe", e);
692 } finally {
693 mWriteLock.unlock();
694 }
695 return null;
696 }
697
Dianne Hackborn69cb00b2013-08-09 16:16:56 -0700698 public int getCurrentMemoryState() {
699 synchronized (mAm) {
700 return mLastMemOnlyState;
701 }
702 }
703
Dianne Hackborn237cefb2013-10-22 18:45:27 -0700704 private void dumpAggregatedStats(PrintWriter pw, long aggregateHours, long now,
705 String reqPackage, boolean isCompact, boolean dumpDetails, boolean dumpFullDetails,
Chenjie Yu4e028d02018-09-14 16:24:26 -0700706 boolean dumpAll, boolean activeOnly, int section) {
Dianne Hackborn237cefb2013-10-22 18:45:27 -0700707 ParcelFileDescriptor pfd = getStatsOverTime(aggregateHours*60*60*1000
708 - (ProcessStats.COMMIT_PERIOD/2));
709 if (pfd == null) {
710 pw.println("Unable to build stats!");
711 return;
712 }
713 ProcessStats stats = new ProcessStats(false);
714 InputStream stream = new ParcelFileDescriptor.AutoCloseInputStream(pfd);
715 stats.read(stream);
716 if (stats.mReadError != null) {
717 pw.print("Failure reading: "); pw.println(stats.mReadError);
718 return;
719 }
720 if (isCompact) {
Chenjie Yu4e028d02018-09-14 16:24:26 -0700721 stats.dumpCheckinLocked(pw, reqPackage, section);
Dianne Hackborn237cefb2013-10-22 18:45:27 -0700722 } else {
723 if (dumpDetails || dumpFullDetails) {
Dianne Hackborn7aea7a42018-07-25 08:58:47 -0700724 stats.dumpLocked(pw, reqPackage, now, !dumpFullDetails, dumpDetails, dumpAll,
Chenjie Yu4e028d02018-09-14 16:24:26 -0700725 activeOnly, section);
Dianne Hackborn237cefb2013-10-22 18:45:27 -0700726 } else {
727 stats.dumpSummaryLocked(pw, reqPackage, now, activeOnly);
728 }
729 }
730 }
731
Dianne Hackbornd2932242013-08-05 18:18:42 -0700732 static private void dumpHelp(PrintWriter pw) {
733 pw.println("Process stats (procstats) dump options:");
734 pw.println(" [--checkin|-c|--csv] [--csv-screen] [--csv-proc] [--csv-mem]");
Dianne Hackbornf7097a52014-05-13 09:56:14 -0700735 pw.println(" [--details] [--full-details] [--current] [--hours N] [--last N]");
Dianne Hackbornd052a942014-11-21 15:23:13 -0800736 pw.println(" [--max N] --active] [--commit] [--reset] [--clear] [--write] [-h]");
Makoto Onuki3ed5be32017-02-01 14:04:47 -0800737 pw.println(" [--start-testing] [--stop-testing] ");
738 pw.println(" [--pretend-screen-on] [--pretend-screen-off] [--stop-pretend-screen]");
739 pw.println(" [<package.name>]");
Dianne Hackbornd2932242013-08-05 18:18:42 -0700740 pw.println(" --checkin: perform a checkin: print and delete old committed states.");
Dianne Hackbornd052a942014-11-21 15:23:13 -0800741 pw.println(" -c: print only state in checkin format.");
Dianne Hackbornd2932242013-08-05 18:18:42 -0700742 pw.println(" --csv: output data suitable for putting in a spreadsheet.");
743 pw.println(" --csv-screen: on, off.");
744 pw.println(" --csv-mem: norm, mod, low, crit.");
745 pw.println(" --csv-proc: pers, top, fore, vis, precept, backup,");
746 pw.println(" service, home, prev, cached");
Dianne Hackborn164371f2013-10-01 19:10:13 -0700747 pw.println(" --details: dump per-package details, not just summary.");
748 pw.println(" --full-details: dump all timing and active state details.");
Dianne Hackbornd2932242013-08-05 18:18:42 -0700749 pw.println(" --current: only dump current state.");
Dianne Hackborncb428552013-09-26 11:07:17 -0700750 pw.println(" --hours: aggregate over about N last hours.");
Dianne Hackbornf7097a52014-05-13 09:56:14 -0700751 pw.println(" --last: only show the last committed stats at index N (starting at 1).");
Dianne Hackbornd052a942014-11-21 15:23:13 -0800752 pw.println(" --max: for -a, max num of historical batches to print.");
Dianne Hackborn164371f2013-10-01 19:10:13 -0700753 pw.println(" --active: only show currently active processes/services.");
Dianne Hackbornd2932242013-08-05 18:18:42 -0700754 pw.println(" --commit: commit current stats to disk and reset to start new stats.");
Chenjie Yu4e028d02018-09-14 16:24:26 -0700755 pw.println(" --section: proc|pkg-proc|pkg-svc|pkg-asc|pkg-all|all ");
756 pw.println(" options can be combined to select desired stats");
Dianne Hackborn0d97cd12013-09-16 19:02:52 -0700757 pw.println(" --reset: reset current stats, without committing.");
Dianne Hackborn53459a72013-09-17 17:14:57 -0700758 pw.println(" --clear: clear all stats; does both --reset and deletes old stats.");
Dianne Hackbornd2932242013-08-05 18:18:42 -0700759 pw.println(" --write: write current in-memory stats to disk.");
760 pw.println(" --read: replace current stats with last-written stats.");
Dianne Hackborn1a4b5a42014-12-08 17:43:31 -0800761 pw.println(" --start-testing: clear all stats and starting high frequency pss sampling.");
762 pw.println(" --stop-testing: stop high frequency pss sampling.");
Makoto Onuki3ed5be32017-02-01 14:04:47 -0800763 pw.println(" --pretend-screen-on: pretend screen is on.");
764 pw.println(" --pretend-screen-off: pretend screen is off.");
765 pw.println(" --stop-pretend-screen: forget \"pretend screen\" and use the real state.");
Dianne Hackbornd2932242013-08-05 18:18:42 -0700766 pw.println(" -a: print everything.");
767 pw.println(" -h: print this help text.");
768 pw.println(" <package.name>: optional name of package to filter output by.");
769 }
770
Dianne Hackborn8a0de582013-08-07 15:22:07 -0700771 @Override
772 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkey6df866a2017-03-31 14:08:23 -0600773 if (!com.android.internal.util.DumpUtils.checkDumpAndUsageStatsPermission(mAm.mContext,
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -0600774 TAG, pw)) return;
Dianne Hackborn8a0de582013-08-07 15:22:07 -0700775
Dianne Hackborn08b36a42013-10-09 12:14:11 -0700776 long ident = Binder.clearCallingIdentity();
777 try {
Yi Jin9680cfa2017-09-15 15:14:43 -0700778 if (args.length > 0 && "--proto".equals(args[0])) {
779 dumpProto(fd);
780 } else {
781 dumpInner(pw, args);
782 }
Dianne Hackborn08b36a42013-10-09 12:14:11 -0700783 } finally {
784 Binder.restoreCallingIdentity(ident);
785 }
786 }
787
Yi Jin9680cfa2017-09-15 15:14:43 -0700788 private void dumpInner(PrintWriter pw, String[] args) {
Dianne Hackbornd2932242013-08-05 18:18:42 -0700789 final long now = SystemClock.uptimeMillis();
790
791 boolean isCheckin = false;
792 boolean isCompact = false;
793 boolean isCsv = false;
794 boolean currentOnly = false;
795 boolean dumpDetails = false;
Dianne Hackborn53459a72013-09-17 17:14:57 -0700796 boolean dumpFullDetails = false;
Dianne Hackbornd2932242013-08-05 18:18:42 -0700797 boolean dumpAll = false;
Dianne Hackborn1a4b5a42014-12-08 17:43:31 -0800798 boolean quit = false;
Dianne Hackborncb428552013-09-26 11:07:17 -0700799 int aggregateHours = 0;
Dianne Hackbornf7097a52014-05-13 09:56:14 -0700800 int lastIndex = 0;
Dianne Hackbornd052a942014-11-21 15:23:13 -0800801 int maxNum = 2;
Dianne Hackborn164371f2013-10-01 19:10:13 -0700802 boolean activeOnly = false;
Dianne Hackbornd2932242013-08-05 18:18:42 -0700803 String reqPackage = null;
804 boolean csvSepScreenStats = false;
805 int[] csvScreenStats = new int[] { ProcessStats.ADJ_SCREEN_OFF, ProcessStats.ADJ_SCREEN_ON};
806 boolean csvSepMemStats = false;
807 int[] csvMemStats = new int[] { ProcessStats.ADJ_MEM_FACTOR_CRITICAL};
808 boolean csvSepProcStats = true;
809 int[] csvProcStats = ProcessStats.ALL_PROC_STATES;
Chenjie Yu4e028d02018-09-14 16:24:26 -0700810 int section = ProcessStats.REPORT_ALL;
Dianne Hackbornd2932242013-08-05 18:18:42 -0700811 if (args != null) {
812 for (int i=0; i<args.length; i++) {
813 String arg = args[i];
814 if ("--checkin".equals(arg)) {
815 isCheckin = true;
816 } else if ("-c".equals(arg)) {
817 isCompact = true;
818 } else if ("--csv".equals(arg)) {
819 isCsv = true;
820 } else if ("--csv-screen".equals(arg)) {
821 i++;
822 if (i >= args.length) {
823 pw.println("Error: argument required for --csv-screen");
824 dumpHelp(pw);
825 return;
826 }
827 boolean[] sep = new boolean[1];
828 String[] error = new String[1];
Joe Onorato4eb64fd2016-03-21 15:30:09 -0700829 csvScreenStats = parseStateList(DumpUtils.ADJ_SCREEN_NAMES_CSV,
830 ProcessStats.ADJ_SCREEN_MOD, args[i], sep, error);
Dianne Hackbornd2932242013-08-05 18:18:42 -0700831 if (csvScreenStats == null) {
832 pw.println("Error in \"" + args[i] + "\": " + error[0]);
833 dumpHelp(pw);
834 return;
835 }
836 csvSepScreenStats = sep[0];
837 } else if ("--csv-mem".equals(arg)) {
838 i++;
839 if (i >= args.length) {
840 pw.println("Error: argument required for --csv-mem");
841 dumpHelp(pw);
842 return;
843 }
844 boolean[] sep = new boolean[1];
845 String[] error = new String[1];
Joe Onorato4eb64fd2016-03-21 15:30:09 -0700846 csvMemStats = parseStateList(DumpUtils.ADJ_MEM_NAMES_CSV, 1, args[i],
847 sep, error);
Dianne Hackbornd2932242013-08-05 18:18:42 -0700848 if (csvMemStats == null) {
849 pw.println("Error in \"" + args[i] + "\": " + error[0]);
850 dumpHelp(pw);
851 return;
852 }
853 csvSepMemStats = sep[0];
854 } else if ("--csv-proc".equals(arg)) {
855 i++;
856 if (i >= args.length) {
857 pw.println("Error: argument required for --csv-proc");
858 dumpHelp(pw);
859 return;
860 }
861 boolean[] sep = new boolean[1];
862 String[] error = new String[1];
Joe Onorato4eb64fd2016-03-21 15:30:09 -0700863 csvProcStats = parseStateList(DumpUtils.STATE_NAMES_CSV, 1, args[i],
864 sep, error);
Dianne Hackbornd2932242013-08-05 18:18:42 -0700865 if (csvProcStats == null) {
866 pw.println("Error in \"" + args[i] + "\": " + error[0]);
867 dumpHelp(pw);
868 return;
869 }
870 csvSepProcStats = sep[0];
871 } else if ("--details".equals(arg)) {
872 dumpDetails = true;
Dianne Hackborn53459a72013-09-17 17:14:57 -0700873 } else if ("--full-details".equals(arg)) {
874 dumpFullDetails = true;
Dianne Hackborncb428552013-09-26 11:07:17 -0700875 } else if ("--hours".equals(arg)) {
876 i++;
877 if (i >= args.length) {
878 pw.println("Error: argument required for --hours");
879 dumpHelp(pw);
880 return;
881 }
882 try {
883 aggregateHours = Integer.parseInt(args[i]);
884 } catch (NumberFormatException e) {
885 pw.println("Error: --hours argument not an int -- " + args[i]);
886 dumpHelp(pw);
887 return;
888 }
Dianne Hackbornf7097a52014-05-13 09:56:14 -0700889 } else if ("--last".equals(arg)) {
890 i++;
891 if (i >= args.length) {
892 pw.println("Error: argument required for --last");
893 dumpHelp(pw);
894 return;
895 }
896 try {
897 lastIndex = Integer.parseInt(args[i]);
898 } catch (NumberFormatException e) {
899 pw.println("Error: --last argument not an int -- " + args[i]);
900 dumpHelp(pw);
901 return;
902 }
Dianne Hackbornd052a942014-11-21 15:23:13 -0800903 } else if ("--max".equals(arg)) {
904 i++;
905 if (i >= args.length) {
906 pw.println("Error: argument required for --max");
907 dumpHelp(pw);
908 return;
909 }
910 try {
911 maxNum = Integer.parseInt(args[i]);
912 } catch (NumberFormatException e) {
913 pw.println("Error: --max argument not an int -- " + args[i]);
914 dumpHelp(pw);
915 return;
916 }
Dianne Hackborn164371f2013-10-01 19:10:13 -0700917 } else if ("--active".equals(arg)) {
918 activeOnly = true;
919 currentOnly = true;
Dianne Hackbornd2932242013-08-05 18:18:42 -0700920 } else if ("--current".equals(arg)) {
921 currentOnly = true;
922 } else if ("--commit".equals(arg)) {
Dianne Hackborn50ef0b62013-09-16 17:40:27 -0700923 synchronized (mAm) {
924 mProcessStats.mFlags |= ProcessStats.FLAG_COMPLETE;
925 writeStateLocked(true, true);
926 pw.println("Process stats committed.");
Dianne Hackborn1a4b5a42014-12-08 17:43:31 -0800927 quit = true;
Dianne Hackborn50ef0b62013-09-16 17:40:27 -0700928 }
Chenjie Yu4e028d02018-09-14 16:24:26 -0700929 } else if ("--section".equals(arg)) {
930 i++;
931 if (i >= args.length) {
932 pw.println("Error: argument required for --section");
933 dumpHelp(pw);
934 return;
Dianne Hackborn0d97cd12013-09-16 19:02:52 -0700935 }
Chenjie Yu4e028d02018-09-14 16:24:26 -0700936 section = parseSectionOptions(args[i]);
Dianne Hackborn53459a72013-09-17 17:14:57 -0700937 } else if ("--clear".equals(arg)) {
938 synchronized (mAm) {
939 mProcessStats.resetSafely();
Dianne Hackborned0a3222018-02-06 16:01:23 -0800940 mAm.requestPssAllProcsLocked(SystemClock.uptimeMillis(), true, false);
Dianne Hackborn53459a72013-09-17 17:14:57 -0700941 ArrayList<String> files = getCommittedFiles(0, true, true);
942 if (files != null) {
943 for (int fi=0; fi<files.size(); fi++) {
944 (new File(files.get(fi))).delete();
945 }
946 }
947 pw.println("All process stats cleared.");
Dianne Hackborn1a4b5a42014-12-08 17:43:31 -0800948 quit = true;
Dianne Hackborn53459a72013-09-17 17:14:57 -0700949 }
Dianne Hackbornd2932242013-08-05 18:18:42 -0700950 } else if ("--write".equals(arg)) {
Dianne Hackborn50ef0b62013-09-16 17:40:27 -0700951 synchronized (mAm) {
952 writeStateSyncLocked();
953 pw.println("Process stats written.");
Dianne Hackborn1a4b5a42014-12-08 17:43:31 -0800954 quit = true;
Dianne Hackborn50ef0b62013-09-16 17:40:27 -0700955 }
Dianne Hackbornd2932242013-08-05 18:18:42 -0700956 } else if ("--read".equals(arg)) {
Dianne Hackborn50ef0b62013-09-16 17:40:27 -0700957 synchronized (mAm) {
958 readLocked(mProcessStats, mFile);
959 pw.println("Process stats read.");
Dianne Hackborn1a4b5a42014-12-08 17:43:31 -0800960 quit = true;
Dianne Hackborn50ef0b62013-09-16 17:40:27 -0700961 }
Dianne Hackborn1a4b5a42014-12-08 17:43:31 -0800962 } else if ("--start-testing".equals(arg)) {
963 synchronized (mAm) {
964 mAm.setTestPssMode(true);
965 pw.println("Started high frequency sampling.");
966 quit = true;
967 }
968 } else if ("--stop-testing".equals(arg)) {
969 synchronized (mAm) {
970 mAm.setTestPssMode(false);
971 pw.println("Stopped high frequency sampling.");
972 quit = true;
973 }
Makoto Onuki3ed5be32017-02-01 14:04:47 -0800974 } else if ("--pretend-screen-on".equals(arg)) {
975 synchronized (mAm) {
976 mInjectedScreenState = true;
977 }
978 quit = true;
979 } else if ("--pretend-screen-off".equals(arg)) {
980 synchronized (mAm) {
981 mInjectedScreenState = false;
982 }
983 quit = true;
984 } else if ("--stop-pretend-screen".equals(arg)) {
985 synchronized (mAm) {
986 mInjectedScreenState = null;
987 }
988 quit = true;
Dianne Hackbornd2932242013-08-05 18:18:42 -0700989 } else if ("-h".equals(arg)) {
990 dumpHelp(pw);
991 return;
992 } else if ("-a".equals(arg)) {
993 dumpDetails = true;
994 dumpAll = true;
995 } else if (arg.length() > 0 && arg.charAt(0) == '-'){
996 pw.println("Unknown option: " + arg);
997 dumpHelp(pw);
998 return;
999 } else {
1000 // Not an option, last argument must be a package name.
Dianne Hackborndaa0d5c2013-11-06 16:30:29 -08001001 reqPackage = arg;
1002 // Include all details, since we know we are only going to
1003 // be dumping a smaller set of data. In fact only the details
Dianne Hackbornab4a81b2014-10-09 17:59:38 -07001004 // contain per-package data, so this is needed to be able
Dianne Hackborndaa0d5c2013-11-06 16:30:29 -08001005 // to dump anything at all when filtering by package.
1006 dumpDetails = true;
Dianne Hackbornd2932242013-08-05 18:18:42 -07001007 }
1008 }
1009 }
1010
Dianne Hackborn1a4b5a42014-12-08 17:43:31 -08001011 if (quit) {
1012 return;
1013 }
1014
Dianne Hackbornd2932242013-08-05 18:18:42 -07001015 if (isCsv) {
1016 pw.print("Processes running summed over");
1017 if (!csvSepScreenStats) {
1018 for (int i=0; i<csvScreenStats.length; i++) {
1019 pw.print(" ");
Joe Onorato4eb64fd2016-03-21 15:30:09 -07001020 DumpUtils.printScreenLabelCsv(pw, csvScreenStats[i]);
Dianne Hackbornd2932242013-08-05 18:18:42 -07001021 }
1022 }
1023 if (!csvSepMemStats) {
1024 for (int i=0; i<csvMemStats.length; i++) {
1025 pw.print(" ");
Joe Onorato4eb64fd2016-03-21 15:30:09 -07001026 DumpUtils.printMemLabelCsv(pw, csvMemStats[i]);
Dianne Hackbornd2932242013-08-05 18:18:42 -07001027 }
1028 }
1029 if (!csvSepProcStats) {
1030 for (int i=0; i<csvProcStats.length; i++) {
1031 pw.print(" ");
Joe Onorato4eb64fd2016-03-21 15:30:09 -07001032 pw.print(DumpUtils.STATE_NAMES_CSV[csvProcStats[i]]);
Dianne Hackbornd2932242013-08-05 18:18:42 -07001033 }
1034 }
1035 pw.println();
Dianne Hackborn8a0de582013-08-07 15:22:07 -07001036 synchronized (mAm) {
Dianne Hackbornd2932242013-08-05 18:18:42 -07001037 dumpFilteredProcessesCsvLocked(pw, null,
1038 csvSepScreenStats, csvScreenStats, csvSepMemStats, csvMemStats,
1039 csvSepProcStats, csvProcStats, now, reqPackage);
1040 /*
1041 dumpFilteredProcessesCsvLocked(pw, "Processes running while critical mem:",
1042 false, new int[] {ADJ_SCREEN_OFF, ADJ_SCREEN_ON},
1043 true, new int[] {ADJ_MEM_FACTOR_CRITICAL},
1044 true, new int[] {STATE_PERSISTENT, STATE_TOP, STATE_FOREGROUND, STATE_VISIBLE,
1045 STATE_PERCEPTIBLE, STATE_BACKUP, STATE_SERVICE, STATE_HOME,
1046 STATE_PREVIOUS, STATE_CACHED},
1047 now, reqPackage);
1048 dumpFilteredProcessesCsvLocked(pw, "Processes running over all mem:",
1049 false, new int[] {ADJ_SCREEN_OFF, ADJ_SCREEN_ON},
1050 false, new int[] {ADJ_MEM_FACTOR_CRITICAL, ADJ_MEM_FACTOR_LOW,
1051 ADJ_MEM_FACTOR_MODERATE, ADJ_MEM_FACTOR_MODERATE},
1052 true, new int[] {STATE_PERSISTENT, STATE_TOP, STATE_FOREGROUND, STATE_VISIBLE,
1053 STATE_PERCEPTIBLE, STATE_BACKUP, STATE_SERVICE, STATE_HOME,
1054 STATE_PREVIOUS, STATE_CACHED},
1055 now, reqPackage);
1056 */
1057 }
1058 return;
Dianne Hackborncb428552013-09-26 11:07:17 -07001059 } else if (aggregateHours != 0) {
Dianne Hackborndaa0d5c2013-11-06 16:30:29 -08001060 pw.print("AGGREGATED OVER LAST "); pw.print(aggregateHours); pw.println(" HOURS:");
Dianne Hackborn237cefb2013-10-22 18:45:27 -07001061 dumpAggregatedStats(pw, aggregateHours, now, reqPackage, isCompact,
Chenjie Yu4e028d02018-09-14 16:24:26 -07001062 dumpDetails, dumpFullDetails, dumpAll, activeOnly, section);
Dianne Hackborn53459a72013-09-17 17:14:57 -07001063 return;
Dianne Hackbornf7097a52014-05-13 09:56:14 -07001064 } else if (lastIndex > 0) {
1065 pw.print("LAST STATS AT INDEX "); pw.print(lastIndex); pw.println(":");
1066 ArrayList<String> files = getCommittedFiles(0, false, true);
1067 if (lastIndex >= files.size()) {
1068 pw.print("Only have "); pw.print(files.size()); pw.println(" data sets");
1069 return;
1070 }
1071 AtomicFile file = new AtomicFile(new File(files.get(lastIndex)));
1072 ProcessStats processStats = new ProcessStats(false);
1073 readLocked(processStats, file);
1074 if (processStats.mReadError != null) {
1075 if (isCheckin || isCompact) pw.print("err,");
1076 pw.print("Failure reading "); pw.print(files.get(lastIndex));
1077 pw.print("; "); pw.println(processStats.mReadError);
1078 return;
1079 }
1080 String fileStr = file.getBaseFile().getPath();
1081 boolean checkedIn = fileStr.endsWith(STATE_FILE_CHECKIN_SUFFIX);
1082 if (isCheckin || isCompact) {
1083 // Don't really need to lock because we uniquely own this object.
Chenjie Yu4e028d02018-09-14 16:24:26 -07001084 processStats.dumpCheckinLocked(pw, reqPackage, section);
Dianne Hackbornf7097a52014-05-13 09:56:14 -07001085 } else {
1086 pw.print("COMMITTED STATS FROM ");
1087 pw.print(processStats.mTimePeriodStartClockStr);
1088 if (checkedIn) pw.print(" (checked in)");
1089 pw.println(":");
1090 if (dumpDetails || dumpFullDetails) {
Dianne Hackborn7aea7a42018-07-25 08:58:47 -07001091 processStats.dumpLocked(pw, reqPackage, now, !dumpFullDetails, dumpDetails,
Chenjie Yu4e028d02018-09-14 16:24:26 -07001092 dumpAll, activeOnly, section);
Dianne Hackbornf7097a52014-05-13 09:56:14 -07001093 if (dumpAll) {
1094 pw.print(" mFile="); pw.println(mFile.getBaseFile());
1095 }
1096 } else {
1097 processStats.dumpSummaryLocked(pw, reqPackage, now, activeOnly);
1098 }
1099 }
1100 return;
Dianne Hackbornd2932242013-08-05 18:18:42 -07001101 }
1102
1103 boolean sepNeeded = false;
Dianne Hackborndaa0d5c2013-11-06 16:30:29 -08001104 if (dumpAll || isCheckin) {
Dianne Hackbornd2932242013-08-05 18:18:42 -07001105 mWriteLock.lock();
1106 try {
Dianne Hackborn53459a72013-09-17 17:14:57 -07001107 ArrayList<String> files = getCommittedFiles(0, false, !isCheckin);
Dianne Hackbornd2932242013-08-05 18:18:42 -07001108 if (files != null) {
Dianne Hackbornd052a942014-11-21 15:23:13 -08001109 int start = isCheckin ? 0 : (files.size() - maxNum);
1110 if (start < 0) {
1111 start = 0;
1112 }
1113 for (int i=start; i<files.size(); i++) {
Dianne Hackbornd2932242013-08-05 18:18:42 -07001114 if (DEBUG) Slog.d(TAG, "Retrieving state: " + files.get(i));
1115 try {
1116 AtomicFile file = new AtomicFile(new File(files.get(i)));
1117 ProcessStats processStats = new ProcessStats(false);
1118 readLocked(processStats, file);
1119 if (processStats.mReadError != null) {
1120 if (isCheckin || isCompact) pw.print("err,");
1121 pw.print("Failure reading "); pw.print(files.get(i));
1122 pw.print("; "); pw.println(processStats.mReadError);
1123 if (DEBUG) Slog.d(TAG, "Deleting state: " + files.get(i));
1124 (new File(files.get(i))).delete();
1125 continue;
1126 }
1127 String fileStr = file.getBaseFile().getPath();
1128 boolean checkedIn = fileStr.endsWith(STATE_FILE_CHECKIN_SUFFIX);
1129 if (isCheckin || isCompact) {
1130 // Don't really need to lock because we uniquely own this object.
Chenjie Yu4e028d02018-09-14 16:24:26 -07001131 processStats.dumpCheckinLocked(pw, reqPackage, section);
Dianne Hackbornd2932242013-08-05 18:18:42 -07001132 } else {
1133 if (sepNeeded) {
1134 pw.println();
1135 } else {
1136 sepNeeded = true;
1137 }
1138 pw.print("COMMITTED STATS FROM ");
1139 pw.print(processStats.mTimePeriodStartClockStr);
1140 if (checkedIn) pw.print(" (checked in)");
1141 pw.println(":");
1142 // Don't really need to lock because we uniquely own this object.
Dianne Hackbornae36b232013-09-03 18:12:53 -07001143 // Always dump summary here, dumping all details is just too
1144 // much crud.
Dianne Hackborn53459a72013-09-17 17:14:57 -07001145 if (dumpFullDetails) {
Dianne Hackbornf7097a52014-05-13 09:56:14 -07001146 processStats.dumpLocked(pw, reqPackage, now, false, false,
Chenjie Yu4e028d02018-09-14 16:24:26 -07001147 false, activeOnly, section);
Dianne Hackborn53459a72013-09-17 17:14:57 -07001148 } else {
Dianne Hackborn164371f2013-10-01 19:10:13 -07001149 processStats.dumpSummaryLocked(pw, reqPackage, now, activeOnly);
Dianne Hackborn53459a72013-09-17 17:14:57 -07001150 }
Dianne Hackbornd2932242013-08-05 18:18:42 -07001151 }
1152 if (isCheckin) {
1153 // Rename file suffix to mark that it has checked in.
1154 file.getBaseFile().renameTo(new File(
1155 fileStr + STATE_FILE_CHECKIN_SUFFIX));
1156 }
1157 } catch (Throwable e) {
1158 pw.print("**** FAILURE DUMPING STATE: "); pw.println(files.get(i));
1159 e.printStackTrace(pw);
1160 }
1161 }
1162 }
1163 } finally {
1164 mWriteLock.unlock();
1165 }
1166 }
1167 if (!isCheckin) {
Dianne Hackborn8a0de582013-08-07 15:22:07 -07001168 synchronized (mAm) {
Dianne Hackbornd2932242013-08-05 18:18:42 -07001169 if (isCompact) {
Chenjie Yu4e028d02018-09-14 16:24:26 -07001170 mProcessStats.dumpCheckinLocked(pw, reqPackage, section);
Dianne Hackbornd2932242013-08-05 18:18:42 -07001171 } else {
1172 if (sepNeeded) {
1173 pw.println();
Dianne Hackbornd2932242013-08-05 18:18:42 -07001174 }
Dianne Hackborndaa0d5c2013-11-06 16:30:29 -08001175 pw.println("CURRENT STATS:");
Dianne Hackborn53459a72013-09-17 17:14:57 -07001176 if (dumpDetails || dumpFullDetails) {
Dianne Hackborn7aea7a42018-07-25 08:58:47 -07001177 mProcessStats.dumpLocked(pw, reqPackage, now, !dumpFullDetails, dumpDetails,
Chenjie Yu4e028d02018-09-14 16:24:26 -07001178 dumpAll, activeOnly, section);
Dianne Hackbornd2932242013-08-05 18:18:42 -07001179 if (dumpAll) {
1180 pw.print(" mFile="); pw.println(mFile.getBaseFile());
1181 }
1182 } else {
Dianne Hackborn164371f2013-10-01 19:10:13 -07001183 mProcessStats.dumpSummaryLocked(pw, reqPackage, now, activeOnly);
Dianne Hackbornd2932242013-08-05 18:18:42 -07001184 }
Dianne Hackbornd052a942014-11-21 15:23:13 -08001185 sepNeeded = true;
Dianne Hackbornd2932242013-08-05 18:18:42 -07001186 }
1187 }
Dianne Hackbornd052a942014-11-21 15:23:13 -08001188 if (!currentOnly) {
1189 if (sepNeeded) {
1190 pw.println();
1191 }
1192 pw.println("AGGREGATED OVER LAST 24 HOURS:");
1193 dumpAggregatedStats(pw, 24, now, reqPackage, isCompact,
Chenjie Yu4e028d02018-09-14 16:24:26 -07001194 dumpDetails, dumpFullDetails, dumpAll, activeOnly, section);
Dianne Hackbornd052a942014-11-21 15:23:13 -08001195 pw.println();
1196 pw.println("AGGREGATED OVER LAST 3 HOURS:");
1197 dumpAggregatedStats(pw, 3, now, reqPackage, isCompact,
Chenjie Yu4e028d02018-09-14 16:24:26 -07001198 dumpDetails, dumpFullDetails, dumpAll, activeOnly, section);
Dianne Hackbornd052a942014-11-21 15:23:13 -08001199 }
Dianne Hackbornd2932242013-08-05 18:18:42 -07001200 }
1201 }
Yi Jin9680cfa2017-09-15 15:14:43 -07001202
Yi Jin676d1ac2018-01-25 15:40:28 -08001203 private void dumpAggregatedStats(ProtoOutputStream proto, long fieldId, int aggregateHours, long now) {
Yi Jin9680cfa2017-09-15 15:14:43 -07001204 ParcelFileDescriptor pfd = getStatsOverTime(aggregateHours*60*60*1000
1205 - (ProcessStats.COMMIT_PERIOD/2));
1206 if (pfd == null) {
1207 return;
1208 }
1209 ProcessStats stats = new ProcessStats(false);
1210 InputStream stream = new ParcelFileDescriptor.AutoCloseInputStream(pfd);
1211 stats.read(stream);
1212 if (stats.mReadError != null) {
1213 return;
1214 }
Chenjie Yu4e028d02018-09-14 16:24:26 -07001215 final long token = proto.start(fieldId);
1216 stats.writeToProto(proto, now, ProcessStats.REPORT_ALL);
1217 proto.end(token);
Yi Jin9680cfa2017-09-15 15:14:43 -07001218 }
1219
1220 private void dumpProto(FileDescriptor fd) {
1221 final ProtoOutputStream proto = new ProtoOutputStream(fd);
1222
1223 // dump current procstats
Yi Jin9680cfa2017-09-15 15:14:43 -07001224 long now;
1225 synchronized (mAm) {
1226 now = SystemClock.uptimeMillis();
Chenjie Yu4e028d02018-09-14 16:24:26 -07001227 final long token = proto.start(ProcessStatsServiceDumpProto.PROCSTATS_NOW);
1228 mProcessStats.writeToProto(proto, now, ProcessStats.REPORT_ALL);
1229 proto.end(token);
Yi Jin9680cfa2017-09-15 15:14:43 -07001230 }
Yi Jin9680cfa2017-09-15 15:14:43 -07001231
1232 // aggregated over last 3 hours procstats
Yi Jin676d1ac2018-01-25 15:40:28 -08001233 dumpAggregatedStats(proto, ProcessStatsServiceDumpProto.PROCSTATS_OVER_3HRS, 3, now);
Yi Jin9680cfa2017-09-15 15:14:43 -07001234
1235 // aggregated over last 24 hours procstats
Yi Jin676d1ac2018-01-25 15:40:28 -08001236 dumpAggregatedStats(proto, ProcessStatsServiceDumpProto.PROCSTATS_OVER_24HRS, 24, now);
Yi Jin9680cfa2017-09-15 15:14:43 -07001237
1238 proto.flush();
1239 }
Dianne Hackbornd2932242013-08-05 18:18:42 -07001240}