/services/java/com/android/server/am/ProcessStatsService.java

https://github.com/aizuzi/platform_frameworks_base · Java · 909 lines · 819 code · 42 blank · 48 comment · 202 complexity · 0655dca0ac59d0d9e4524bec1e68e571 MD5 · raw file

  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. package com.android.server.am;
  17. import android.app.AppGlobals;
  18. import android.content.pm.IPackageManager;
  19. import android.content.pm.PackageManager;
  20. import android.os.Binder;
  21. import android.os.Parcel;
  22. import android.os.ParcelFileDescriptor;
  23. import android.os.RemoteException;
  24. import android.os.SystemClock;
  25. import android.os.SystemProperties;
  26. import android.os.UserHandle;
  27. import android.util.ArrayMap;
  28. import android.util.AtomicFile;
  29. import android.util.Slog;
  30. import android.util.SparseArray;
  31. import android.util.TimeUtils;
  32. import com.android.internal.app.IProcessStats;
  33. import com.android.internal.app.ProcessStats;
  34. import com.android.internal.os.BackgroundThread;
  35. import java.io.File;
  36. import java.io.FileDescriptor;
  37. import java.io.FileInputStream;
  38. import java.io.FileOutputStream;
  39. import java.io.IOException;
  40. import java.io.InputStream;
  41. import java.io.PrintWriter;
  42. import java.util.ArrayList;
  43. import java.util.Collections;
  44. import java.util.List;
  45. import java.util.concurrent.locks.ReentrantLock;
  46. public final class ProcessStatsService extends IProcessStats.Stub {
  47. static final String TAG = "ProcessStatsService";
  48. static final boolean DEBUG = false;
  49. // Most data is kept in a sparse data structure: an integer array which integer
  50. // holds the type of the entry, and the identifier for a long array that data
  51. // exists in and the offset into the array to find it. The constants below
  52. // define the encoding of that data in an integer.
  53. static final int MAX_HISTORIC_STATES = 8; // Maximum number of historic states we will keep.
  54. static final String STATE_FILE_PREFIX = "state-"; // Prefix to use for state filenames.
  55. static final String STATE_FILE_SUFFIX = ".bin"; // Suffix to use for state filenames.
  56. static final String STATE_FILE_CHECKIN_SUFFIX = ".ci"; // State files that have checked in.
  57. static long WRITE_PERIOD = 30*60*1000; // Write file every 30 minutes or so.
  58. final ActivityManagerService mAm;
  59. final File mBaseDir;
  60. ProcessStats mProcessStats;
  61. AtomicFile mFile;
  62. boolean mCommitPending;
  63. boolean mShuttingDown;
  64. int mLastMemOnlyState = -1;
  65. boolean mMemFactorLowered;
  66. final ReentrantLock mWriteLock = new ReentrantLock();
  67. final Object mPendingWriteLock = new Object();
  68. AtomicFile mPendingWriteFile;
  69. Parcel mPendingWrite;
  70. boolean mPendingWriteCommitted;
  71. long mLastWriteTime;
  72. public ProcessStatsService(ActivityManagerService am, File file) {
  73. mAm = am;
  74. mBaseDir = file;
  75. mBaseDir.mkdirs();
  76. mProcessStats = new ProcessStats(true);
  77. updateFile();
  78. SystemProperties.addChangeCallback(new Runnable() {
  79. @Override public void run() {
  80. synchronized (mAm) {
  81. if (mProcessStats.evaluateSystemProperties(false)) {
  82. mProcessStats.mFlags |= ProcessStats.FLAG_SYSPROPS;
  83. writeStateLocked(true, true);
  84. mProcessStats.evaluateSystemProperties(true);
  85. }
  86. }
  87. }
  88. });
  89. }
  90. @Override
  91. public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
  92. throws RemoteException {
  93. try {
  94. return super.onTransact(code, data, reply, flags);
  95. } catch (RuntimeException e) {
  96. if (!(e instanceof SecurityException)) {
  97. Slog.wtf(TAG, "Process Stats Crash", e);
  98. }
  99. throw e;
  100. }
  101. }
  102. public ProcessStats.ProcessState getProcessStateLocked(String packageName,
  103. int uid, String processName) {
  104. return mProcessStats.getProcessStateLocked(packageName, uid, processName);
  105. }
  106. public ProcessStats.ServiceState getServiceStateLocked(String packageName, int uid,
  107. String processName, String className) {
  108. return mProcessStats.getServiceStateLocked(packageName, uid, processName, className);
  109. }
  110. public boolean isMemFactorLowered() {
  111. return mMemFactorLowered;
  112. }
  113. public boolean setMemFactorLocked(int memFactor, boolean screenOn, long now) {
  114. mMemFactorLowered = memFactor < mLastMemOnlyState;
  115. mLastMemOnlyState = memFactor;
  116. if (screenOn) {
  117. memFactor += ProcessStats.ADJ_SCREEN_ON;
  118. }
  119. if (memFactor != mProcessStats.mMemFactor) {
  120. if (mProcessStats.mMemFactor != ProcessStats.STATE_NOTHING) {
  121. mProcessStats.mMemFactorDurations[mProcessStats.mMemFactor]
  122. += now - mProcessStats.mStartTime;
  123. }
  124. mProcessStats.mMemFactor = memFactor;
  125. mProcessStats.mStartTime = now;
  126. ArrayMap<String, SparseArray<ProcessStats.PackageState>> pmap
  127. = mProcessStats.mPackages.getMap();
  128. for (int i=0; i<pmap.size(); i++) {
  129. SparseArray<ProcessStats.PackageState> uids = pmap.valueAt(i);
  130. for (int j=0; j<uids.size(); j++) {
  131. ProcessStats.PackageState pkg = uids.valueAt(j);
  132. ArrayMap<String, ProcessStats.ServiceState> services = pkg.mServices;
  133. for (int k=0; k<services.size(); k++) {
  134. ProcessStats.ServiceState service = services.valueAt(k);
  135. if (service.isInUse()) {
  136. if (service.mStartedState != ProcessStats.STATE_NOTHING) {
  137. service.setStarted(true, memFactor, now);
  138. }
  139. if (service.mBoundState != ProcessStats.STATE_NOTHING) {
  140. service.setBound(true, memFactor, now);
  141. }
  142. if (service.mExecState != ProcessStats.STATE_NOTHING) {
  143. service.setExecuting(true, memFactor, now);
  144. }
  145. }
  146. }
  147. }
  148. }
  149. return true;
  150. }
  151. return false;
  152. }
  153. public int getMemFactorLocked() {
  154. return mProcessStats.mMemFactor != ProcessStats.STATE_NOTHING ? mProcessStats.mMemFactor : 0;
  155. }
  156. public boolean shouldWriteNowLocked(long now) {
  157. if (now > (mLastWriteTime+WRITE_PERIOD)) {
  158. if (SystemClock.elapsedRealtime()
  159. > (mProcessStats.mTimePeriodStartRealtime+ProcessStats.COMMIT_PERIOD)) {
  160. mCommitPending = true;
  161. }
  162. return true;
  163. }
  164. return false;
  165. }
  166. public void shutdownLocked() {
  167. Slog.w(TAG, "Writing process stats before shutdown...");
  168. mProcessStats.mFlags |= ProcessStats.FLAG_SHUTDOWN;
  169. writeStateSyncLocked();
  170. mShuttingDown = true;
  171. }
  172. public void writeStateAsyncLocked() {
  173. writeStateLocked(false);
  174. }
  175. public void writeStateSyncLocked() {
  176. writeStateLocked(true);
  177. }
  178. private void writeStateLocked(boolean sync) {
  179. if (mShuttingDown) {
  180. return;
  181. }
  182. boolean commitPending = mCommitPending;
  183. mCommitPending = false;
  184. writeStateLocked(sync, commitPending);
  185. }
  186. public void writeStateLocked(boolean sync, final boolean commit) {
  187. synchronized (mPendingWriteLock) {
  188. long now = SystemClock.uptimeMillis();
  189. if (mPendingWrite == null || !mPendingWriteCommitted) {
  190. mPendingWrite = Parcel.obtain();
  191. mProcessStats.mTimePeriodEndRealtime = SystemClock.elapsedRealtime();
  192. if (commit) {
  193. mProcessStats.mFlags |= ProcessStats.FLAG_COMPLETE;
  194. }
  195. mProcessStats.writeToParcel(mPendingWrite, 0);
  196. mPendingWriteFile = new AtomicFile(mFile.getBaseFile());
  197. mPendingWriteCommitted = commit;
  198. }
  199. if (commit) {
  200. mProcessStats.resetSafely();
  201. updateFile();
  202. }
  203. mLastWriteTime = SystemClock.uptimeMillis();
  204. Slog.i(TAG, "Prepared write state in " + (SystemClock.uptimeMillis()-now) + "ms");
  205. if (!sync) {
  206. BackgroundThread.getHandler().post(new Runnable() {
  207. @Override public void run() {
  208. performWriteState();
  209. }
  210. });
  211. return;
  212. }
  213. }
  214. performWriteState();
  215. }
  216. private void updateFile() {
  217. mFile = new AtomicFile(new File(mBaseDir, STATE_FILE_PREFIX
  218. + mProcessStats.mTimePeriodStartClockStr + STATE_FILE_SUFFIX));
  219. mLastWriteTime = SystemClock.uptimeMillis();
  220. }
  221. void performWriteState() {
  222. if (DEBUG) Slog.d(TAG, "Performing write to " + mFile.getBaseFile());
  223. Parcel data;
  224. AtomicFile file;
  225. synchronized (mPendingWriteLock) {
  226. data = mPendingWrite;
  227. file = mPendingWriteFile;
  228. mPendingWriteCommitted = false;
  229. if (data == null) {
  230. return;
  231. }
  232. mPendingWrite = null;
  233. mPendingWriteFile = null;
  234. mWriteLock.lock();
  235. }
  236. FileOutputStream stream = null;
  237. try {
  238. stream = file.startWrite();
  239. stream.write(data.marshall());
  240. stream.flush();
  241. file.finishWrite(stream);
  242. if (DEBUG) Slog.d(TAG, "Write completed successfully!");
  243. } catch (IOException e) {
  244. Slog.w(TAG, "Error writing process statistics", e);
  245. file.failWrite(stream);
  246. } finally {
  247. data.recycle();
  248. trimHistoricStatesWriteLocked();
  249. mWriteLock.unlock();
  250. }
  251. }
  252. boolean readLocked(ProcessStats stats, AtomicFile file) {
  253. try {
  254. FileInputStream stream = file.openRead();
  255. stats.read(stream);
  256. stream.close();
  257. if (stats.mReadError != null) {
  258. Slog.w(TAG, "Ignoring existing stats; " + stats.mReadError);
  259. if (DEBUG) {
  260. ArrayMap<String, SparseArray<ProcessStats.ProcessState>> procMap
  261. = stats.mProcesses.getMap();
  262. final int NPROC = procMap.size();
  263. for (int ip=0; ip<NPROC; ip++) {
  264. Slog.w(TAG, "Process: " + procMap.keyAt(ip));
  265. SparseArray<ProcessStats.ProcessState> uids = procMap.valueAt(ip);
  266. final int NUID = uids.size();
  267. for (int iu=0; iu<NUID; iu++) {
  268. Slog.w(TAG, " Uid " + uids.keyAt(iu) + ": " + uids.valueAt(iu));
  269. }
  270. }
  271. ArrayMap<String, SparseArray<ProcessStats.PackageState>> pkgMap
  272. = stats.mPackages.getMap();
  273. final int NPKG = pkgMap.size();
  274. for (int ip=0; ip<NPKG; ip++) {
  275. Slog.w(TAG, "Package: " + pkgMap.keyAt(ip));
  276. SparseArray<ProcessStats.PackageState> uids = pkgMap.valueAt(ip);
  277. final int NUID = uids.size();
  278. for (int iu=0; iu<NUID; iu++) {
  279. Slog.w(TAG, " Uid: " + uids.keyAt(iu));
  280. ProcessStats.PackageState pkgState = uids.valueAt(iu);
  281. final int NPROCS = pkgState.mProcesses.size();
  282. for (int iproc=0; iproc<NPROCS; iproc++) {
  283. Slog.w(TAG, " Process " + pkgState.mProcesses.keyAt(iproc)
  284. + ": " + pkgState.mProcesses.valueAt(iproc));
  285. }
  286. final int NSRVS = pkgState.mServices.size();
  287. for (int isvc=0; isvc<NSRVS; isvc++) {
  288. Slog.w(TAG, " Service " + pkgState.mServices.keyAt(isvc)
  289. + ": " + pkgState.mServices.valueAt(isvc));
  290. }
  291. }
  292. }
  293. }
  294. return false;
  295. }
  296. } catch (Throwable e) {
  297. stats.mReadError = "caught exception: " + e;
  298. Slog.e(TAG, "Error reading process statistics", e);
  299. return false;
  300. }
  301. return true;
  302. }
  303. private ArrayList<String> getCommittedFiles(int minNum, boolean inclCurrent,
  304. boolean inclCheckedIn) {
  305. File[] files = mBaseDir.listFiles();
  306. if (files == null || files.length <= minNum) {
  307. return null;
  308. }
  309. ArrayList<String> filesArray = new ArrayList<String>(files.length);
  310. String currentFile = mFile.getBaseFile().getPath();
  311. if (DEBUG) Slog.d(TAG, "Collecting " + files.length + " files except: " + currentFile);
  312. for (int i=0; i<files.length; i++) {
  313. File file = files[i];
  314. String fileStr = file.getPath();
  315. if (DEBUG) Slog.d(TAG, "Collecting: " + fileStr);
  316. if (!inclCheckedIn && fileStr.endsWith(STATE_FILE_CHECKIN_SUFFIX)) {
  317. if (DEBUG) Slog.d(TAG, "Skipping: already checked in");
  318. continue;
  319. }
  320. if (!inclCurrent && fileStr.equals(currentFile)) {
  321. if (DEBUG) Slog.d(TAG, "Skipping: current stats");
  322. continue;
  323. }
  324. filesArray.add(fileStr);
  325. }
  326. Collections.sort(filesArray);
  327. return filesArray;
  328. }
  329. public void trimHistoricStatesWriteLocked() {
  330. ArrayList<String> filesArray = getCommittedFiles(MAX_HISTORIC_STATES, false, true);
  331. if (filesArray == null) {
  332. return;
  333. }
  334. while (filesArray.size() > MAX_HISTORIC_STATES) {
  335. String file = filesArray.remove(0);
  336. Slog.i(TAG, "Pruning old procstats: " + file);
  337. (new File(file)).delete();
  338. }
  339. }
  340. boolean dumpFilteredProcessesCsvLocked(PrintWriter pw, String header,
  341. boolean sepScreenStates, int[] screenStates, boolean sepMemStates, int[] memStates,
  342. boolean sepProcStates, int[] procStates, long now, String reqPackage) {
  343. ArrayList<ProcessStats.ProcessState> procs = mProcessStats.collectProcessesLocked(
  344. screenStates, memStates, procStates, procStates, now, reqPackage, false);
  345. if (procs.size() > 0) {
  346. if (header != null) {
  347. pw.println(header);
  348. }
  349. ProcessStats.dumpProcessListCsv(pw, procs, sepScreenStates, screenStates,
  350. sepMemStates, memStates, sepProcStates, procStates, now);
  351. return true;
  352. }
  353. return false;
  354. }
  355. static int[] parseStateList(String[] states, int mult, String arg, boolean[] outSep,
  356. String[] outError) {
  357. ArrayList<Integer> res = new ArrayList<Integer>();
  358. int lastPos = 0;
  359. for (int i=0; i<=arg.length(); i++) {
  360. char c = i < arg.length() ? arg.charAt(i) : 0;
  361. if (c != ',' && c != '+' && c != ' ' && c != 0) {
  362. continue;
  363. }
  364. boolean isSep = c == ',';
  365. if (lastPos == 0) {
  366. // We now know the type of op.
  367. outSep[0] = isSep;
  368. } else if (c != 0 && outSep[0] != isSep) {
  369. outError[0] = "inconsistent separators (can't mix ',' with '+')";
  370. return null;
  371. }
  372. if (lastPos < (i-1)) {
  373. String str = arg.substring(lastPos, i);
  374. for (int j=0; j<states.length; j++) {
  375. if (str.equals(states[j])) {
  376. res.add(j);
  377. str = null;
  378. break;
  379. }
  380. }
  381. if (str != null) {
  382. outError[0] = "invalid word \"" + str + "\"";
  383. return null;
  384. }
  385. }
  386. lastPos = i + 1;
  387. }
  388. int[] finalRes = new int[res.size()];
  389. for (int i=0; i<res.size(); i++) {
  390. finalRes[i] = res.get(i) * mult;
  391. }
  392. return finalRes;
  393. }
  394. public byte[] getCurrentStats(List<ParcelFileDescriptor> historic) {
  395. mAm.mContext.enforceCallingOrSelfPermission(
  396. android.Manifest.permission.PACKAGE_USAGE_STATS, null);
  397. Parcel current = Parcel.obtain();
  398. mWriteLock.lock();
  399. try {
  400. synchronized (mAm) {
  401. mProcessStats.mTimePeriodEndRealtime = SystemClock.elapsedRealtime();
  402. mProcessStats.writeToParcel(current, 0);
  403. }
  404. if (historic != null) {
  405. ArrayList<String> files = getCommittedFiles(0, false, true);
  406. if (files != null) {
  407. for (int i=files.size()-1; i>=0; i--) {
  408. try {
  409. ParcelFileDescriptor pfd = ParcelFileDescriptor.open(
  410. new File(files.get(i)), ParcelFileDescriptor.MODE_READ_ONLY);
  411. historic.add(pfd);
  412. } catch (IOException e) {
  413. Slog.w(TAG, "Failure opening procstat file " + files.get(i), e);
  414. }
  415. }
  416. }
  417. }
  418. } finally {
  419. mWriteLock.unlock();
  420. }
  421. return current.marshall();
  422. }
  423. public ParcelFileDescriptor getStatsOverTime(long minTime) {
  424. mAm.mContext.enforceCallingOrSelfPermission(
  425. android.Manifest.permission.PACKAGE_USAGE_STATS, null);
  426. mWriteLock.lock();
  427. try {
  428. Parcel current = Parcel.obtain();
  429. long curTime;
  430. synchronized (mAm) {
  431. mProcessStats.mTimePeriodEndRealtime = SystemClock.elapsedRealtime();
  432. mProcessStats.writeToParcel(current, 0);
  433. curTime = mProcessStats.mTimePeriodEndRealtime
  434. - mProcessStats.mTimePeriodStartRealtime;
  435. }
  436. if (curTime < minTime) {
  437. // Need to add in older stats to reach desired time.
  438. ArrayList<String> files = getCommittedFiles(0, false, true);
  439. if (files != null && files.size() > 0) {
  440. current.setDataPosition(0);
  441. ProcessStats stats = ProcessStats.CREATOR.createFromParcel(current);
  442. current.recycle();
  443. int i = files.size()-1;
  444. while (i >= 0 && (stats.mTimePeriodEndRealtime
  445. - stats.mTimePeriodStartRealtime) < minTime) {
  446. AtomicFile file = new AtomicFile(new File(files.get(i)));
  447. i--;
  448. ProcessStats moreStats = new ProcessStats(false);
  449. readLocked(moreStats, file);
  450. if (moreStats.mReadError == null) {
  451. stats.add(moreStats);
  452. StringBuilder sb = new StringBuilder();
  453. sb.append("Added stats: ");
  454. sb.append(moreStats.mTimePeriodStartClockStr);
  455. sb.append(", over ");
  456. TimeUtils.formatDuration(moreStats.mTimePeriodEndRealtime
  457. - moreStats.mTimePeriodStartRealtime, sb);
  458. Slog.i(TAG, sb.toString());
  459. } else {
  460. Slog.w(TAG, "Failure reading " + files.get(i+1) + "; "
  461. + moreStats.mReadError);
  462. continue;
  463. }
  464. }
  465. current = Parcel.obtain();
  466. stats.writeToParcel(current, 0);
  467. }
  468. }
  469. final byte[] outData = current.marshall();
  470. current.recycle();
  471. final ParcelFileDescriptor[] fds = ParcelFileDescriptor.createPipe();
  472. Thread thr = new Thread("ProcessStats pipe output") {
  473. public void run() {
  474. FileOutputStream fout = new ParcelFileDescriptor.AutoCloseOutputStream(fds[1]);
  475. try {
  476. fout.write(outData);
  477. fout.close();
  478. } catch (IOException e) {
  479. Slog.w(TAG, "Failure writing pipe", e);
  480. }
  481. }
  482. };
  483. thr.start();
  484. return fds[0];
  485. } catch (IOException e) {
  486. Slog.w(TAG, "Failed building output pipe", e);
  487. } finally {
  488. mWriteLock.unlock();
  489. }
  490. return null;
  491. }
  492. public int getCurrentMemoryState() {
  493. synchronized (mAm) {
  494. return mLastMemOnlyState;
  495. }
  496. }
  497. private void dumpAggregatedStats(PrintWriter pw, long aggregateHours, long now,
  498. String reqPackage, boolean isCompact, boolean dumpDetails, boolean dumpFullDetails,
  499. boolean dumpAll, boolean activeOnly) {
  500. ParcelFileDescriptor pfd = getStatsOverTime(aggregateHours*60*60*1000
  501. - (ProcessStats.COMMIT_PERIOD/2));
  502. if (pfd == null) {
  503. pw.println("Unable to build stats!");
  504. return;
  505. }
  506. ProcessStats stats = new ProcessStats(false);
  507. InputStream stream = new ParcelFileDescriptor.AutoCloseInputStream(pfd);
  508. stats.read(stream);
  509. if (stats.mReadError != null) {
  510. pw.print("Failure reading: "); pw.println(stats.mReadError);
  511. return;
  512. }
  513. if (isCompact) {
  514. stats.dumpCheckinLocked(pw, reqPackage);
  515. } else {
  516. if (dumpDetails || dumpFullDetails) {
  517. stats.dumpLocked(pw, reqPackage, now, !dumpFullDetails, dumpAll, activeOnly);
  518. } else {
  519. stats.dumpSummaryLocked(pw, reqPackage, now, activeOnly);
  520. }
  521. }
  522. }
  523. static private void dumpHelp(PrintWriter pw) {
  524. pw.println("Process stats (procstats) dump options:");
  525. pw.println(" [--checkin|-c|--csv] [--csv-screen] [--csv-proc] [--csv-mem]");
  526. pw.println(" [--details] [--full-details] [--current] [--hours] [--active]");
  527. pw.println(" [--commit] [--reset] [--clear] [--write] [-h] [<package.name>]");
  528. pw.println(" --checkin: perform a checkin: print and delete old committed states.");
  529. pw.println(" --c: print only state in checkin format.");
  530. pw.println(" --csv: output data suitable for putting in a spreadsheet.");
  531. pw.println(" --csv-screen: on, off.");
  532. pw.println(" --csv-mem: norm, mod, low, crit.");
  533. pw.println(" --csv-proc: pers, top, fore, vis, precept, backup,");
  534. pw.println(" service, home, prev, cached");
  535. pw.println(" --details: dump per-package details, not just summary.");
  536. pw.println(" --full-details: dump all timing and active state details.");
  537. pw.println(" --current: only dump current state.");
  538. pw.println(" --hours: aggregate over about N last hours.");
  539. pw.println(" --active: only show currently active processes/services.");
  540. pw.println(" --commit: commit current stats to disk and reset to start new stats.");
  541. pw.println(" --reset: reset current stats, without committing.");
  542. pw.println(" --clear: clear all stats; does both --reset and deletes old stats.");
  543. pw.println(" --write: write current in-memory stats to disk.");
  544. pw.println(" --read: replace current stats with last-written stats.");
  545. pw.println(" -a: print everything.");
  546. pw.println(" -h: print this help text.");
  547. pw.println(" <package.name>: optional name of package to filter output by.");
  548. }
  549. @Override
  550. protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
  551. if (mAm.checkCallingPermission(android.Manifest.permission.DUMP)
  552. != PackageManager.PERMISSION_GRANTED) {
  553. pw.println("Permission Denial: can't dump procstats from from pid="
  554. + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
  555. + " without permission " + android.Manifest.permission.DUMP);
  556. return;
  557. }
  558. long ident = Binder.clearCallingIdentity();
  559. try {
  560. dumpInner(fd, pw, args);
  561. } finally {
  562. Binder.restoreCallingIdentity(ident);
  563. }
  564. }
  565. private void dumpInner(FileDescriptor fd, PrintWriter pw, String[] args) {
  566. final long now = SystemClock.uptimeMillis();
  567. boolean isCheckin = false;
  568. boolean isCompact = false;
  569. boolean isCsv = false;
  570. boolean currentOnly = false;
  571. boolean dumpDetails = false;
  572. boolean dumpFullDetails = false;
  573. boolean dumpAll = false;
  574. int aggregateHours = 0;
  575. boolean activeOnly = false;
  576. String reqPackage = null;
  577. boolean csvSepScreenStats = false;
  578. int[] csvScreenStats = new int[] { ProcessStats.ADJ_SCREEN_OFF, ProcessStats.ADJ_SCREEN_ON};
  579. boolean csvSepMemStats = false;
  580. int[] csvMemStats = new int[] { ProcessStats.ADJ_MEM_FACTOR_CRITICAL};
  581. boolean csvSepProcStats = true;
  582. int[] csvProcStats = ProcessStats.ALL_PROC_STATES;
  583. if (args != null) {
  584. for (int i=0; i<args.length; i++) {
  585. String arg = args[i];
  586. if ("--checkin".equals(arg)) {
  587. isCheckin = true;
  588. } else if ("-c".equals(arg)) {
  589. isCompact = true;
  590. } else if ("--csv".equals(arg)) {
  591. isCsv = true;
  592. } else if ("--csv-screen".equals(arg)) {
  593. i++;
  594. if (i >= args.length) {
  595. pw.println("Error: argument required for --csv-screen");
  596. dumpHelp(pw);
  597. return;
  598. }
  599. boolean[] sep = new boolean[1];
  600. String[] error = new String[1];
  601. csvScreenStats = parseStateList(ProcessStats.ADJ_SCREEN_NAMES_CSV, ProcessStats.ADJ_SCREEN_MOD,
  602. args[i], sep, error);
  603. if (csvScreenStats == null) {
  604. pw.println("Error in \"" + args[i] + "\": " + error[0]);
  605. dumpHelp(pw);
  606. return;
  607. }
  608. csvSepScreenStats = sep[0];
  609. } else if ("--csv-mem".equals(arg)) {
  610. i++;
  611. if (i >= args.length) {
  612. pw.println("Error: argument required for --csv-mem");
  613. dumpHelp(pw);
  614. return;
  615. }
  616. boolean[] sep = new boolean[1];
  617. String[] error = new String[1];
  618. csvMemStats = parseStateList(ProcessStats.ADJ_MEM_NAMES_CSV, 1, args[i], sep, error);
  619. if (csvMemStats == null) {
  620. pw.println("Error in \"" + args[i] + "\": " + error[0]);
  621. dumpHelp(pw);
  622. return;
  623. }
  624. csvSepMemStats = sep[0];
  625. } else if ("--csv-proc".equals(arg)) {
  626. i++;
  627. if (i >= args.length) {
  628. pw.println("Error: argument required for --csv-proc");
  629. dumpHelp(pw);
  630. return;
  631. }
  632. boolean[] sep = new boolean[1];
  633. String[] error = new String[1];
  634. csvProcStats = parseStateList(ProcessStats.STATE_NAMES_CSV, 1, args[i], sep, error);
  635. if (csvProcStats == null) {
  636. pw.println("Error in \"" + args[i] + "\": " + error[0]);
  637. dumpHelp(pw);
  638. return;
  639. }
  640. csvSepProcStats = sep[0];
  641. } else if ("--details".equals(arg)) {
  642. dumpDetails = true;
  643. } else if ("--full-details".equals(arg)) {
  644. dumpFullDetails = true;
  645. } else if ("--hours".equals(arg)) {
  646. i++;
  647. if (i >= args.length) {
  648. pw.println("Error: argument required for --hours");
  649. dumpHelp(pw);
  650. return;
  651. }
  652. try {
  653. aggregateHours = Integer.parseInt(args[i]);
  654. } catch (NumberFormatException e) {
  655. pw.println("Error: --hours argument not an int -- " + args[i]);
  656. dumpHelp(pw);
  657. return;
  658. }
  659. } else if ("--active".equals(arg)) {
  660. activeOnly = true;
  661. currentOnly = true;
  662. } else if ("--current".equals(arg)) {
  663. currentOnly = true;
  664. } else if ("--commit".equals(arg)) {
  665. synchronized (mAm) {
  666. mProcessStats.mFlags |= ProcessStats.FLAG_COMPLETE;
  667. writeStateLocked(true, true);
  668. pw.println("Process stats committed.");
  669. }
  670. return;
  671. } else if ("--reset".equals(arg)) {
  672. synchronized (mAm) {
  673. mProcessStats.resetSafely();
  674. pw.println("Process stats reset.");
  675. }
  676. return;
  677. } else if ("--clear".equals(arg)) {
  678. synchronized (mAm) {
  679. mProcessStats.resetSafely();
  680. ArrayList<String> files = getCommittedFiles(0, true, true);
  681. if (files != null) {
  682. for (int fi=0; fi<files.size(); fi++) {
  683. (new File(files.get(fi))).delete();
  684. }
  685. }
  686. pw.println("All process stats cleared.");
  687. }
  688. return;
  689. } else if ("--write".equals(arg)) {
  690. synchronized (mAm) {
  691. writeStateSyncLocked();
  692. pw.println("Process stats written.");
  693. }
  694. return;
  695. } else if ("--read".equals(arg)) {
  696. synchronized (mAm) {
  697. readLocked(mProcessStats, mFile);
  698. pw.println("Process stats read.");
  699. }
  700. return;
  701. } else if ("-h".equals(arg)) {
  702. dumpHelp(pw);
  703. return;
  704. } else if ("-a".equals(arg)) {
  705. dumpDetails = true;
  706. dumpAll = true;
  707. } else if (arg.length() > 0 && arg.charAt(0) == '-'){
  708. pw.println("Unknown option: " + arg);
  709. dumpHelp(pw);
  710. return;
  711. } else {
  712. // Not an option, last argument must be a package name.
  713. reqPackage = arg;
  714. // Include all details, since we know we are only going to
  715. // be dumping a smaller set of data. In fact only the details
  716. // container per-package data, so that are needed to be able
  717. // to dump anything at all when filtering by package.
  718. dumpDetails = true;
  719. }
  720. }
  721. }
  722. if (isCsv) {
  723. pw.print("Processes running summed over");
  724. if (!csvSepScreenStats) {
  725. for (int i=0; i<csvScreenStats.length; i++) {
  726. pw.print(" ");
  727. ProcessStats.printScreenLabelCsv(pw, csvScreenStats[i]);
  728. }
  729. }
  730. if (!csvSepMemStats) {
  731. for (int i=0; i<csvMemStats.length; i++) {
  732. pw.print(" ");
  733. ProcessStats.printMemLabelCsv(pw, csvMemStats[i]);
  734. }
  735. }
  736. if (!csvSepProcStats) {
  737. for (int i=0; i<csvProcStats.length; i++) {
  738. pw.print(" ");
  739. pw.print(ProcessStats.STATE_NAMES_CSV[csvProcStats[i]]);
  740. }
  741. }
  742. pw.println();
  743. synchronized (mAm) {
  744. dumpFilteredProcessesCsvLocked(pw, null,
  745. csvSepScreenStats, csvScreenStats, csvSepMemStats, csvMemStats,
  746. csvSepProcStats, csvProcStats, now, reqPackage);
  747. /*
  748. dumpFilteredProcessesCsvLocked(pw, "Processes running while critical mem:",
  749. false, new int[] {ADJ_SCREEN_OFF, ADJ_SCREEN_ON},
  750. true, new int[] {ADJ_MEM_FACTOR_CRITICAL},
  751. true, new int[] {STATE_PERSISTENT, STATE_TOP, STATE_FOREGROUND, STATE_VISIBLE,
  752. STATE_PERCEPTIBLE, STATE_BACKUP, STATE_SERVICE, STATE_HOME,
  753. STATE_PREVIOUS, STATE_CACHED},
  754. now, reqPackage);
  755. dumpFilteredProcessesCsvLocked(pw, "Processes running over all mem:",
  756. false, new int[] {ADJ_SCREEN_OFF, ADJ_SCREEN_ON},
  757. false, new int[] {ADJ_MEM_FACTOR_CRITICAL, ADJ_MEM_FACTOR_LOW,
  758. ADJ_MEM_FACTOR_MODERATE, ADJ_MEM_FACTOR_MODERATE},
  759. true, new int[] {STATE_PERSISTENT, STATE_TOP, STATE_FOREGROUND, STATE_VISIBLE,
  760. STATE_PERCEPTIBLE, STATE_BACKUP, STATE_SERVICE, STATE_HOME,
  761. STATE_PREVIOUS, STATE_CACHED},
  762. now, reqPackage);
  763. */
  764. }
  765. return;
  766. } else if (aggregateHours != 0) {
  767. pw.print("AGGREGATED OVER LAST "); pw.print(aggregateHours); pw.println(" HOURS:");
  768. dumpAggregatedStats(pw, aggregateHours, now, reqPackage, isCompact,
  769. dumpDetails, dumpFullDetails, dumpAll, activeOnly);
  770. return;
  771. }
  772. boolean sepNeeded = false;
  773. if (dumpAll || isCheckin) {
  774. mWriteLock.lock();
  775. try {
  776. ArrayList<String> files = getCommittedFiles(0, false, !isCheckin);
  777. if (files != null) {
  778. for (int i=0; i<files.size(); i++) {
  779. if (DEBUG) Slog.d(TAG, "Retrieving state: " + files.get(i));
  780. try {
  781. AtomicFile file = new AtomicFile(new File(files.get(i)));
  782. ProcessStats processStats = new ProcessStats(false);
  783. readLocked(processStats, file);
  784. if (processStats.mReadError != null) {
  785. if (isCheckin || isCompact) pw.print("err,");
  786. pw.print("Failure reading "); pw.print(files.get(i));
  787. pw.print("; "); pw.println(processStats.mReadError);
  788. if (DEBUG) Slog.d(TAG, "Deleting state: " + files.get(i));
  789. (new File(files.get(i))).delete();
  790. continue;
  791. }
  792. String fileStr = file.getBaseFile().getPath();
  793. boolean checkedIn = fileStr.endsWith(STATE_FILE_CHECKIN_SUFFIX);
  794. if (isCheckin || isCompact) {
  795. // Don't really need to lock because we uniquely own this object.
  796. processStats.dumpCheckinLocked(pw, reqPackage);
  797. } else {
  798. if (sepNeeded) {
  799. pw.println();
  800. } else {
  801. sepNeeded = true;
  802. }
  803. pw.print("COMMITTED STATS FROM ");
  804. pw.print(processStats.mTimePeriodStartClockStr);
  805. if (checkedIn) pw.print(" (checked in)");
  806. pw.println(":");
  807. // Don't really need to lock because we uniquely own this object.
  808. // Always dump summary here, dumping all details is just too
  809. // much crud.
  810. if (dumpFullDetails) {
  811. mProcessStats.dumpLocked(pw, reqPackage, now, false, false,
  812. activeOnly);
  813. } else {
  814. processStats.dumpSummaryLocked(pw, reqPackage, now, activeOnly);
  815. }
  816. }
  817. if (isCheckin) {
  818. // Rename file suffix to mark that it has checked in.
  819. file.getBaseFile().renameTo(new File(
  820. fileStr + STATE_FILE_CHECKIN_SUFFIX));
  821. }
  822. } catch (Throwable e) {
  823. pw.print("**** FAILURE DUMPING STATE: "); pw.println(files.get(i));
  824. e.printStackTrace(pw);
  825. }
  826. }
  827. }
  828. } finally {
  829. mWriteLock.unlock();
  830. }
  831. }
  832. if (!isCheckin) {
  833. if (!currentOnly) {
  834. if (sepNeeded) {
  835. pw.println();
  836. }
  837. pw.println("AGGREGATED OVER LAST 24 HOURS:");
  838. dumpAggregatedStats(pw, 24, now, reqPackage, isCompact,
  839. dumpDetails, dumpFullDetails, dumpAll, activeOnly);
  840. pw.println();
  841. pw.println("AGGREGATED OVER LAST 3 HOURS:");
  842. dumpAggregatedStats(pw, 3, now, reqPackage, isCompact,
  843. dumpDetails, dumpFullDetails, dumpAll, activeOnly);
  844. sepNeeded = true;
  845. }
  846. synchronized (mAm) {
  847. if (isCompact) {
  848. mProcessStats.dumpCheckinLocked(pw, reqPackage);
  849. } else {
  850. if (sepNeeded) {
  851. pw.println();
  852. }
  853. pw.println("CURRENT STATS:");
  854. if (dumpDetails || dumpFullDetails) {
  855. mProcessStats.dumpLocked(pw, reqPackage, now, !dumpFullDetails, dumpAll,
  856. activeOnly);
  857. if (dumpAll) {
  858. pw.print(" mFile="); pw.println(mFile.getBaseFile());
  859. }
  860. } else {
  861. mProcessStats.dumpSummaryLocked(pw, reqPackage, now, activeOnly);
  862. }
  863. }
  864. }
  865. }
  866. }
  867. }