1 /*
2  * Copyright (C) 2007 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.internal.os;
18 
19 import static android.os.Process.*;
20 
21 import android.os.FileUtils;
22 import android.os.Process;
23 import android.os.StrictMode;
24 import android.os.SystemClock;
25 import android.system.OsConstants;
26 import android.util.Slog;
27 
28 import com.android.internal.util.FastPrintWriter;
29 
30 import libcore.io.IoUtils;
31 import libcore.io.Libcore;
32 
33 import java.io.File;
34 import java.io.FileInputStream;
35 import java.io.PrintWriter;
36 import java.io.StringWriter;
37 import java.text.SimpleDateFormat;
38 import java.util.ArrayList;
39 import java.util.Collections;
40 import java.util.Comparator;
41 import java.util.Date;
42 import java.util.List;
43 import java.util.StringTokenizer;
44 
45 public class ProcessCpuTracker {
46     private static final String TAG = "ProcessCpuTracker";
47     private static final boolean DEBUG = false;
48     private static final boolean localLOGV = DEBUG || false;
49 
50     private static final int[] PROCESS_STATS_FORMAT = new int[] {
51         PROC_SPACE_TERM,
52         PROC_SPACE_TERM|PROC_PARENS,
53         PROC_SPACE_TERM,
54         PROC_SPACE_TERM,
55         PROC_SPACE_TERM,
56         PROC_SPACE_TERM,
57         PROC_SPACE_TERM,
58         PROC_SPACE_TERM,
59         PROC_SPACE_TERM,
60         PROC_SPACE_TERM|PROC_OUT_LONG,                  // 10: minor faults
61         PROC_SPACE_TERM,
62         PROC_SPACE_TERM|PROC_OUT_LONG,                  // 12: major faults
63         PROC_SPACE_TERM,
64         PROC_SPACE_TERM|PROC_OUT_LONG,                  // 14: utime
65         PROC_SPACE_TERM|PROC_OUT_LONG,                  // 15: stime
66     };
67 
68     static final int PROCESS_STAT_MINOR_FAULTS = 0;
69     static final int PROCESS_STAT_MAJOR_FAULTS = 1;
70     static final int PROCESS_STAT_UTIME = 2;
71     static final int PROCESS_STAT_STIME = 3;
72 
73     /** Stores user time and system time in jiffies. */
74     private final long[] mProcessStatsData = new long[4];
75 
76     /** Stores user time and system time in jiffies.  Used for
77      * public API to retrieve CPU use for a process.  Must lock while in use. */
78     private final long[] mSinglePidStatsData = new long[4];
79 
80     private static final int[] PROCESS_FULL_STATS_FORMAT = new int[] {
81         PROC_SPACE_TERM,
82         PROC_SPACE_TERM|PROC_PARENS|PROC_OUT_STRING,    // 2: name
83         PROC_SPACE_TERM,
84         PROC_SPACE_TERM,
85         PROC_SPACE_TERM,
86         PROC_SPACE_TERM,
87         PROC_SPACE_TERM,
88         PROC_SPACE_TERM,
89         PROC_SPACE_TERM,
90         PROC_SPACE_TERM|PROC_OUT_LONG,                  // 10: minor faults
91         PROC_SPACE_TERM,
92         PROC_SPACE_TERM|PROC_OUT_LONG,                  // 12: major faults
93         PROC_SPACE_TERM,
94         PROC_SPACE_TERM|PROC_OUT_LONG,                  // 14: utime
95         PROC_SPACE_TERM|PROC_OUT_LONG,                  // 15: stime
96         PROC_SPACE_TERM,
97         PROC_SPACE_TERM,
98         PROC_SPACE_TERM,
99         PROC_SPACE_TERM,
100         PROC_SPACE_TERM,
101         PROC_SPACE_TERM,
102         PROC_SPACE_TERM,
103         PROC_SPACE_TERM|PROC_OUT_LONG,                  // 23: vsize
104     };
105 
106     static final int PROCESS_FULL_STAT_MINOR_FAULTS = 1;
107     static final int PROCESS_FULL_STAT_MAJOR_FAULTS = 2;
108     static final int PROCESS_FULL_STAT_UTIME = 3;
109     static final int PROCESS_FULL_STAT_STIME = 4;
110     static final int PROCESS_FULL_STAT_VSIZE = 5;
111 
112     private final String[] mProcessFullStatsStringData = new String[6];
113     private final long[] mProcessFullStatsData = new long[6];
114 
115     private static final int[] SYSTEM_CPU_FORMAT = new int[] {
116         PROC_SPACE_TERM|PROC_COMBINE,
117         PROC_SPACE_TERM|PROC_OUT_LONG,                  // 1: user time
118         PROC_SPACE_TERM|PROC_OUT_LONG,                  // 2: nice time
119         PROC_SPACE_TERM|PROC_OUT_LONG,                  // 3: sys time
120         PROC_SPACE_TERM|PROC_OUT_LONG,                  // 4: idle time
121         PROC_SPACE_TERM|PROC_OUT_LONG,                  // 5: iowait time
122         PROC_SPACE_TERM|PROC_OUT_LONG,                  // 6: irq time
123         PROC_SPACE_TERM|PROC_OUT_LONG                   // 7: softirq time
124     };
125 
126     private final long[] mSystemCpuData = new long[7];
127 
128     private static final int[] LOAD_AVERAGE_FORMAT = new int[] {
129         PROC_SPACE_TERM|PROC_OUT_FLOAT,                 // 0: 1 min
130         PROC_SPACE_TERM|PROC_OUT_FLOAT,                 // 1: 5 mins
131         PROC_SPACE_TERM|PROC_OUT_FLOAT                  // 2: 15 mins
132     };
133 
134     private final float[] mLoadAverageData = new float[3];
135 
136     private final boolean mIncludeThreads;
137 
138     // How long a CPU jiffy is in milliseconds.
139     private final long mJiffyMillis;
140 
141     private float mLoad1 = 0;
142     private float mLoad5 = 0;
143     private float mLoad15 = 0;
144 
145     // All times are in milliseconds. They are converted from jiffies to milliseconds
146     // when extracted from the kernel.
147     private long mCurrentSampleTime;
148     private long mLastSampleTime;
149 
150     private long mCurrentSampleRealTime;
151     private long mLastSampleRealTime;
152 
153     private long mCurrentSampleWallTime;
154     private long mLastSampleWallTime;
155 
156     private long mBaseUserTime;
157     private long mBaseSystemTime;
158     private long mBaseIoWaitTime;
159     private long mBaseIrqTime;
160     private long mBaseSoftIrqTime;
161     private long mBaseIdleTime;
162     private int mRelUserTime;
163     private int mRelSystemTime;
164     private int mRelIoWaitTime;
165     private int mRelIrqTime;
166     private int mRelSoftIrqTime;
167     private int mRelIdleTime;
168     private boolean mRelStatsAreGood;
169 
170     private int[] mCurPids;
171     private int[] mCurThreadPids;
172 
173     private final ArrayList<Stats> mProcStats = new ArrayList<Stats>();
174     private final ArrayList<Stats> mWorkingProcs = new ArrayList<Stats>();
175     private boolean mWorkingProcsSorted;
176 
177     private boolean mFirst = true;
178 
179     private byte[] mBuffer = new byte[4096];
180 
181     public interface FilterStats {
182         /** Which stats to pick when filtering */
needed(Stats stats)183         boolean needed(Stats stats);
184     }
185 
186     public static class Stats {
187         public final int pid;
188         public final int uid;
189         final String statFile;
190         final String cmdlineFile;
191         final String threadsDir;
192         final ArrayList<Stats> threadStats;
193         final ArrayList<Stats> workingThreads;
194 
195         public BatteryStatsImpl.Uid.Proc batteryStats;
196 
197         public boolean interesting;
198 
199         public String baseName;
200         public String name;
201         public int nameWidth;
202 
203         // vsize capture when process first detected; can be used to
204         // filter out kernel processes.
205         public long vsize;
206 
207         /**
208          * Time in milliseconds.
209          */
210         public long base_uptime;
211 
212         /**
213          * Time in milliseconds.
214          */
215         public long rel_uptime;
216 
217         /**
218          * Time in milliseconds.
219          */
220         public long base_utime;
221 
222         /**
223          * Time in milliseconds.
224          */
225         public long base_stime;
226 
227         /**
228          * Time in milliseconds.
229          */
230         public int rel_utime;
231 
232         /**
233          * Time in milliseconds.
234          */
235         public int rel_stime;
236 
237         public long base_minfaults;
238         public long base_majfaults;
239         public int rel_minfaults;
240         public int rel_majfaults;
241 
242         public boolean active;
243         public boolean working;
244         public boolean added;
245         public boolean removed;
246 
Stats(int _pid, int parentPid, boolean includeThreads)247         Stats(int _pid, int parentPid, boolean includeThreads) {
248             pid = _pid;
249             if (parentPid < 0) {
250                 final File procDir = new File("/proc", Integer.toString(pid));
251                 statFile = new File(procDir, "stat").toString();
252                 cmdlineFile = new File(procDir, "cmdline").toString();
253                 threadsDir = (new File(procDir, "task")).toString();
254                 if (includeThreads) {
255                     threadStats = new ArrayList<Stats>();
256                     workingThreads = new ArrayList<Stats>();
257                 } else {
258                     threadStats = null;
259                     workingThreads = null;
260                 }
261             } else {
262                 final File procDir = new File("/proc", Integer.toString(
263                         parentPid));
264                 final File taskDir = new File(
265                         new File(procDir, "task"), Integer.toString(pid));
266                 statFile = new File(taskDir, "stat").toString();
267                 cmdlineFile = null;
268                 threadsDir = null;
269                 threadStats = null;
270                 workingThreads = null;
271             }
272             uid = FileUtils.getUid(statFile.toString());
273         }
274     }
275 
276     private final static Comparator<Stats> sLoadComparator = new Comparator<Stats>() {
277         public final int
278         compare(Stats sta, Stats stb) {
279             int ta = sta.rel_utime + sta.rel_stime;
280             int tb = stb.rel_utime + stb.rel_stime;
281             if (ta != tb) {
282                 return ta > tb ? -1 : 1;
283             }
284             if (sta.added != stb.added) {
285                 return sta.added ? -1 : 1;
286             }
287             if (sta.removed != stb.removed) {
288                 return sta.added ? -1 : 1;
289             }
290             return 0;
291         }
292     };
293 
294 
ProcessCpuTracker(boolean includeThreads)295     public ProcessCpuTracker(boolean includeThreads) {
296         mIncludeThreads = includeThreads;
297         long jiffyHz = Libcore.os.sysconf(OsConstants._SC_CLK_TCK);
298         mJiffyMillis = 1000/jiffyHz;
299     }
300 
onLoadChanged(float load1, float load5, float load15)301     public void onLoadChanged(float load1, float load5, float load15) {
302     }
303 
onMeasureProcessName(String name)304     public int onMeasureProcessName(String name) {
305         return 0;
306     }
307 
init()308     public void init() {
309         if (DEBUG) Slog.v(TAG, "Init: " + this);
310         mFirst = true;
311         update();
312     }
313 
update()314     public void update() {
315         if (DEBUG) Slog.v(TAG, "Update: " + this);
316 
317         final long nowUptime = SystemClock.uptimeMillis();
318         final long nowRealtime = SystemClock.elapsedRealtime();
319         final long nowWallTime = System.currentTimeMillis();
320 
321         final long[] sysCpu = mSystemCpuData;
322         if (Process.readProcFile("/proc/stat", SYSTEM_CPU_FORMAT,
323                 null, sysCpu, null)) {
324             // Total user time is user + nice time.
325             final long usertime = (sysCpu[0]+sysCpu[1]) * mJiffyMillis;
326             // Total system time is simply system time.
327             final long systemtime = sysCpu[2] * mJiffyMillis;
328             // Total idle time is simply idle time.
329             final long idletime = sysCpu[3] * mJiffyMillis;
330             // Total irq time is iowait + irq + softirq time.
331             final long iowaittime = sysCpu[4] * mJiffyMillis;
332             final long irqtime = sysCpu[5] * mJiffyMillis;
333             final long softirqtime = sysCpu[6] * mJiffyMillis;
334 
335             // This code is trying to avoid issues with idle time going backwards,
336             // but currently it gets into situations where it triggers most of the time. :(
337             if (true || (usertime >= mBaseUserTime && systemtime >= mBaseSystemTime
338                     && iowaittime >= mBaseIoWaitTime && irqtime >= mBaseIrqTime
339                     && softirqtime >= mBaseSoftIrqTime && idletime >= mBaseIdleTime)) {
340                 mRelUserTime = (int)(usertime - mBaseUserTime);
341                 mRelSystemTime = (int)(systemtime - mBaseSystemTime);
342                 mRelIoWaitTime = (int)(iowaittime - mBaseIoWaitTime);
343                 mRelIrqTime = (int)(irqtime - mBaseIrqTime);
344                 mRelSoftIrqTime = (int)(softirqtime - mBaseSoftIrqTime);
345                 mRelIdleTime = (int)(idletime - mBaseIdleTime);
346                 mRelStatsAreGood = true;
347 
348                 if (DEBUG) {
349                     Slog.i("Load", "Total U:" + (sysCpu[0]*mJiffyMillis)
350                           + " N:" + (sysCpu[1]*mJiffyMillis)
351                           + " S:" + (sysCpu[2]*mJiffyMillis) + " I:" + (sysCpu[3]*mJiffyMillis)
352                           + " W:" + (sysCpu[4]*mJiffyMillis) + " Q:" + (sysCpu[5]*mJiffyMillis)
353                           + " O:" + (sysCpu[6]*mJiffyMillis));
354                     Slog.i("Load", "Rel U:" + mRelUserTime + " S:" + mRelSystemTime
355                           + " I:" + mRelIdleTime + " Q:" + mRelIrqTime);
356                 }
357 
358                 mBaseUserTime = usertime;
359                 mBaseSystemTime = systemtime;
360                 mBaseIoWaitTime = iowaittime;
361                 mBaseIrqTime = irqtime;
362                 mBaseSoftIrqTime = softirqtime;
363                 mBaseIdleTime = idletime;
364 
365             } else {
366                 mRelUserTime = 0;
367                 mRelSystemTime = 0;
368                 mRelIoWaitTime = 0;
369                 mRelIrqTime = 0;
370                 mRelSoftIrqTime = 0;
371                 mRelIdleTime = 0;
372                 mRelStatsAreGood = false;
373                 Slog.w(TAG, "/proc/stats has gone backwards; skipping CPU update");
374                 return;
375             }
376         }
377 
378         mLastSampleTime = mCurrentSampleTime;
379         mCurrentSampleTime = nowUptime;
380         mLastSampleRealTime = mCurrentSampleRealTime;
381         mCurrentSampleRealTime = nowRealtime;
382         mLastSampleWallTime = mCurrentSampleWallTime;
383         mCurrentSampleWallTime = nowWallTime;
384 
385         final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads();
386         try {
387             mCurPids = collectStats("/proc", -1, mFirst, mCurPids, mProcStats);
388         } finally {
389             StrictMode.setThreadPolicy(savedPolicy);
390         }
391 
392         final float[] loadAverages = mLoadAverageData;
393         if (Process.readProcFile("/proc/loadavg", LOAD_AVERAGE_FORMAT,
394                 null, null, loadAverages)) {
395             float load1 = loadAverages[0];
396             float load5 = loadAverages[1];
397             float load15 = loadAverages[2];
398             if (load1 != mLoad1 || load5 != mLoad5 || load15 != mLoad15) {
399                 mLoad1 = load1;
400                 mLoad5 = load5;
401                 mLoad15 = load15;
402                 onLoadChanged(load1, load5, load15);
403             }
404         }
405 
406         if (DEBUG) Slog.i(TAG, "*** TIME TO COLLECT STATS: "
407                 + (SystemClock.uptimeMillis()-mCurrentSampleTime));
408 
409         mWorkingProcsSorted = false;
410         mFirst = false;
411     }
412 
collectStats(String statsFile, int parentPid, boolean first, int[] curPids, ArrayList<Stats> allProcs)413     private int[] collectStats(String statsFile, int parentPid, boolean first,
414             int[] curPids, ArrayList<Stats> allProcs) {
415 
416         int[] pids = Process.getPids(statsFile, curPids);
417         int NP = (pids == null) ? 0 : pids.length;
418         int NS = allProcs.size();
419         int curStatsIndex = 0;
420         for (int i=0; i<NP; i++) {
421             int pid = pids[i];
422             if (pid < 0) {
423                 NP = pid;
424                 break;
425             }
426             Stats st = curStatsIndex < NS ? allProcs.get(curStatsIndex) : null;
427 
428             if (st != null && st.pid == pid) {
429                 // Update an existing process...
430                 st.added = false;
431                 st.working = false;
432                 curStatsIndex++;
433                 if (DEBUG) Slog.v(TAG, "Existing "
434                         + (parentPid < 0 ? "process" : "thread")
435                         + " pid " + pid + ": " + st);
436 
437                 if (st.interesting) {
438                     final long uptime = SystemClock.uptimeMillis();
439 
440                     final long[] procStats = mProcessStatsData;
441                     if (!Process.readProcFile(st.statFile.toString(),
442                             PROCESS_STATS_FORMAT, null, procStats, null)) {
443                         continue;
444                     }
445 
446                     final long minfaults = procStats[PROCESS_STAT_MINOR_FAULTS];
447                     final long majfaults = procStats[PROCESS_STAT_MAJOR_FAULTS];
448                     final long utime = procStats[PROCESS_STAT_UTIME] * mJiffyMillis;
449                     final long stime = procStats[PROCESS_STAT_STIME] * mJiffyMillis;
450 
451                     if (utime == st.base_utime && stime == st.base_stime) {
452                         st.rel_utime = 0;
453                         st.rel_stime = 0;
454                         st.rel_minfaults = 0;
455                         st.rel_majfaults = 0;
456                         if (st.active) {
457                             st.active = false;
458                         }
459                         continue;
460                     }
461 
462                     if (!st.active) {
463                         st.active = true;
464                     }
465 
466                     if (parentPid < 0) {
467                         getName(st, st.cmdlineFile);
468                         if (st.threadStats != null) {
469                             mCurThreadPids = collectStats(st.threadsDir, pid, false,
470                                     mCurThreadPids, st.threadStats);
471                         }
472                     }
473 
474                     if (DEBUG) Slog.v("Load", "Stats changed " + st.name + " pid=" + st.pid
475                             + " utime=" + utime + "-" + st.base_utime
476                             + " stime=" + stime + "-" + st.base_stime
477                             + " minfaults=" + minfaults + "-" + st.base_minfaults
478                             + " majfaults=" + majfaults + "-" + st.base_majfaults);
479 
480                     st.rel_uptime = uptime - st.base_uptime;
481                     st.base_uptime = uptime;
482                     st.rel_utime = (int)(utime - st.base_utime);
483                     st.rel_stime = (int)(stime - st.base_stime);
484                     st.base_utime = utime;
485                     st.base_stime = stime;
486                     st.rel_minfaults = (int)(minfaults - st.base_minfaults);
487                     st.rel_majfaults = (int)(majfaults - st.base_majfaults);
488                     st.base_minfaults = minfaults;
489                     st.base_majfaults = majfaults;
490                     st.working = true;
491                 }
492 
493                 continue;
494             }
495 
496             if (st == null || st.pid > pid) {
497                 // We have a new process!
498                 st = new Stats(pid, parentPid, mIncludeThreads);
499                 allProcs.add(curStatsIndex, st);
500                 curStatsIndex++;
501                 NS++;
502                 if (DEBUG) Slog.v(TAG, "New "
503                         + (parentPid < 0 ? "process" : "thread")
504                         + " pid " + pid + ": " + st);
505 
506                 final String[] procStatsString = mProcessFullStatsStringData;
507                 final long[] procStats = mProcessFullStatsData;
508                 st.base_uptime = SystemClock.uptimeMillis();
509                 String path = st.statFile.toString();
510                 //Slog.d(TAG, "Reading proc file: " + path);
511                 if (Process.readProcFile(path, PROCESS_FULL_STATS_FORMAT, procStatsString,
512                         procStats, null)) {
513                     // This is a possible way to filter out processes that
514                     // are actually kernel threads...  do we want to?  Some
515                     // of them do use CPU, but there can be a *lot* that are
516                     // not doing anything.
517                     st.vsize = procStats[PROCESS_FULL_STAT_VSIZE];
518                     if (true || procStats[PROCESS_FULL_STAT_VSIZE] != 0) {
519                         st.interesting = true;
520                         st.baseName = procStatsString[0];
521                         st.base_minfaults = procStats[PROCESS_FULL_STAT_MINOR_FAULTS];
522                         st.base_majfaults = procStats[PROCESS_FULL_STAT_MAJOR_FAULTS];
523                         st.base_utime = procStats[PROCESS_FULL_STAT_UTIME] * mJiffyMillis;
524                         st.base_stime = procStats[PROCESS_FULL_STAT_STIME] * mJiffyMillis;
525                     } else {
526                         Slog.i(TAG, "Skipping kernel process pid " + pid
527                                 + " name " + procStatsString[0]);
528                         st.baseName = procStatsString[0];
529                     }
530                 } else {
531                     Slog.w(TAG, "Skipping unknown process pid " + pid);
532                     st.baseName = "<unknown>";
533                     st.base_utime = st.base_stime = 0;
534                     st.base_minfaults = st.base_majfaults = 0;
535                 }
536 
537                 if (parentPid < 0) {
538                     getName(st, st.cmdlineFile);
539                     if (st.threadStats != null) {
540                         mCurThreadPids = collectStats(st.threadsDir, pid, true,
541                                 mCurThreadPids, st.threadStats);
542                     }
543                 } else if (st.interesting) {
544                     st.name = st.baseName;
545                     st.nameWidth = onMeasureProcessName(st.name);
546                 }
547 
548                 if (DEBUG) Slog.v("Load", "Stats added " + st.name + " pid=" + st.pid
549                         + " utime=" + st.base_utime + " stime=" + st.base_stime
550                         + " minfaults=" + st.base_minfaults + " majfaults=" + st.base_majfaults);
551 
552                 st.rel_utime = 0;
553                 st.rel_stime = 0;
554                 st.rel_minfaults = 0;
555                 st.rel_majfaults = 0;
556                 st.added = true;
557                 if (!first && st.interesting) {
558                     st.working = true;
559                 }
560                 continue;
561             }
562 
563             // This process has gone away!
564             st.rel_utime = 0;
565             st.rel_stime = 0;
566             st.rel_minfaults = 0;
567             st.rel_majfaults = 0;
568             st.removed = true;
569             st.working = true;
570             allProcs.remove(curStatsIndex);
571             NS--;
572             if (DEBUG) Slog.v(TAG, "Removed "
573                     + (parentPid < 0 ? "process" : "thread")
574                     + " pid " + pid + ": " + st);
575             // Decrement the loop counter so that we process the current pid
576             // again the next time through the loop.
577             i--;
578             continue;
579         }
580 
581         while (curStatsIndex < NS) {
582             // This process has gone away!
583             final Stats st = allProcs.get(curStatsIndex);
584             st.rel_utime = 0;
585             st.rel_stime = 0;
586             st.rel_minfaults = 0;
587             st.rel_majfaults = 0;
588             st.removed = true;
589             st.working = true;
590             allProcs.remove(curStatsIndex);
591             NS--;
592             if (localLOGV) Slog.v(TAG, "Removed pid " + st.pid + ": " + st);
593         }
594 
595         return pids;
596     }
597 
598     /**
599      * Returns the total time (in milliseconds) spent executing in
600      * both user and system code.  Safe to call without lock held.
601      */
602     public long getCpuTimeForPid(int pid) {
603         synchronized (mSinglePidStatsData) {
604             final String statFile = "/proc/" + pid + "/stat";
605             final long[] statsData = mSinglePidStatsData;
606             if (Process.readProcFile(statFile, PROCESS_STATS_FORMAT,
607                     null, statsData, null)) {
608                 long time = statsData[PROCESS_STAT_UTIME]
609                         + statsData[PROCESS_STAT_STIME];
610                 return time * mJiffyMillis;
611             }
612             return 0;
613         }
614     }
615 
616     /**
617      * @return time in milliseconds.
618      */
619     final public int getLastUserTime() {
620         return mRelUserTime;
621     }
622 
623     /**
624      * @return time in milliseconds.
625      */
626     final public int getLastSystemTime() {
627         return mRelSystemTime;
628     }
629 
630     /**
631      * @return time in milliseconds.
632      */
633     final public int getLastIoWaitTime() {
634         return mRelIoWaitTime;
635     }
636 
637     /**
638      * @return time in milliseconds.
639      */
640     final public int getLastIrqTime() {
641         return mRelIrqTime;
642     }
643 
644     /**
645      * @return time in milliseconds.
646      */
647     final public int getLastSoftIrqTime() {
648         return mRelSoftIrqTime;
649     }
650 
651     /**
652      * @return time in milliseconds.
653      */
654     final public int getLastIdleTime() {
655         return mRelIdleTime;
656     }
657 
658     final public boolean hasGoodLastStats() {
659         return mRelStatsAreGood;
660     }
661 
662     final public float getTotalCpuPercent() {
663         int denom = mRelUserTime+mRelSystemTime+mRelIrqTime+mRelIdleTime;
664         if (denom <= 0) {
665             return 0;
666         }
667         return ((float)(mRelUserTime+mRelSystemTime+mRelIrqTime)*100) / denom;
668     }
669 
670     final void buildWorkingProcs() {
671         if (!mWorkingProcsSorted) {
672             mWorkingProcs.clear();
673             final int N = mProcStats.size();
674             for (int i=0; i<N; i++) {
675                 Stats stats = mProcStats.get(i);
676                 if (stats.working) {
677                     mWorkingProcs.add(stats);
678                     if (stats.threadStats != null && stats.threadStats.size() > 1) {
679                         stats.workingThreads.clear();
680                         final int M = stats.threadStats.size();
681                         for (int j=0; j<M; j++) {
682                             Stats tstats = stats.threadStats.get(j);
683                             if (tstats.working) {
684                                 stats.workingThreads.add(tstats);
685                             }
686                         }
687                         Collections.sort(stats.workingThreads, sLoadComparator);
688                     }
689                 }
690             }
691             Collections.sort(mWorkingProcs, sLoadComparator);
692             mWorkingProcsSorted = true;
693         }
694     }
695 
696     final public int countStats() {
697         return mProcStats.size();
698     }
699 
700     final public Stats getStats(int index) {
701         return mProcStats.get(index);
702     }
703 
704     final public List<Stats> getStats(FilterStats filter) {
705         final ArrayList<Stats> statses = new ArrayList<>(mProcStats.size());
706         final int N = mProcStats.size();
707         for (int p = 0; p < N; p++) {
708             Stats stats = mProcStats.get(p);
709             if (filter.needed(stats)) {
710                 statses.add(stats);
711             }
712         }
713         return statses;
714     }
715 
716     final public int countWorkingStats() {
717         buildWorkingProcs();
718         return mWorkingProcs.size();
719     }
720 
721     final public Stats getWorkingStats(int index) {
722         return mWorkingProcs.get(index);
723     }
724 
725     final public String printCurrentLoad() {
726         StringWriter sw = new StringWriter();
727         PrintWriter pw = new FastPrintWriter(sw, false, 128);
728         pw.print("Load: ");
729         pw.print(mLoad1);
730         pw.print(" / ");
731         pw.print(mLoad5);
732         pw.print(" / ");
733         pw.println(mLoad15);
734         pw.flush();
735         return sw.toString();
736     }
737 
738     final public String printCurrentState(long now) {
739         final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
740 
741         buildWorkingProcs();
742 
743         StringWriter sw = new StringWriter();
744         PrintWriter pw = new FastPrintWriter(sw, false, 1024);
745 
746         pw.print("CPU usage from ");
747         if (now > mLastSampleTime) {
748             pw.print(now-mLastSampleTime);
749             pw.print("ms to ");
750             pw.print(now-mCurrentSampleTime);
751             pw.print("ms ago");
752         } else {
753             pw.print(mLastSampleTime-now);
754             pw.print("ms to ");
755             pw.print(mCurrentSampleTime-now);
756             pw.print("ms later");
757         }
758         pw.print(" (");
759         pw.print(sdf.format(new Date(mLastSampleWallTime)));
760         pw.print(" to ");
761         pw.print(sdf.format(new Date(mCurrentSampleWallTime)));
762         pw.print(")");
763 
764         long sampleTime = mCurrentSampleTime - mLastSampleTime;
765         long sampleRealTime = mCurrentSampleRealTime - mLastSampleRealTime;
766         long percAwake = sampleRealTime > 0 ? ((sampleTime*100) / sampleRealTime) : 0;
767         if (percAwake != 100) {
768             pw.print(" with ");
769             pw.print(percAwake);
770             pw.print("% awake");
771         }
772         pw.println(":");
773 
774         final int totalTime = mRelUserTime + mRelSystemTime + mRelIoWaitTime
775                 + mRelIrqTime + mRelSoftIrqTime + mRelIdleTime;
776 
777         if (DEBUG) Slog.i(TAG, "totalTime " + totalTime + " over sample time "
778                 + (mCurrentSampleTime-mLastSampleTime));
779 
780         int N = mWorkingProcs.size();
781         for (int i=0; i<N; i++) {
782             Stats st = mWorkingProcs.get(i);
783             printProcessCPU(pw, st.added ? " +" : (st.removed ? " -": "  "),
784                     st.pid, st.name, (int)st.rel_uptime,
785                     st.rel_utime, st.rel_stime, 0, 0, 0, st.rel_minfaults, st.rel_majfaults);
786             if (!st.removed && st.workingThreads != null) {
787                 int M = st.workingThreads.size();
788                 for (int j=0; j<M; j++) {
789                     Stats tst = st.workingThreads.get(j);
790                     printProcessCPU(pw,
791                             tst.added ? "   +" : (tst.removed ? "   -": "    "),
792                             tst.pid, tst.name, (int)st.rel_uptime,
793                             tst.rel_utime, tst.rel_stime, 0, 0, 0, 0, 0);
794                 }
795             }
796         }
797 
798         printProcessCPU(pw, "", -1, "TOTAL", totalTime, mRelUserTime, mRelSystemTime,
799                 mRelIoWaitTime, mRelIrqTime, mRelSoftIrqTime, 0, 0);
800 
801         pw.flush();
802         return sw.toString();
803     }
804 
805     private void printRatio(PrintWriter pw, long numerator, long denominator) {
806         long thousands = (numerator*1000)/denominator;
807         long hundreds = thousands/10;
808         pw.print(hundreds);
809         if (hundreds < 10) {
810             long remainder = thousands - (hundreds*10);
811             if (remainder != 0) {
812                 pw.print('.');
813                 pw.print(remainder);
814             }
815         }
816     }
817 
818     private void printProcessCPU(PrintWriter pw, String prefix, int pid, String label,
819             int totalTime, int user, int system, int iowait, int irq, int softIrq,
820             int minFaults, int majFaults) {
821         pw.print(prefix);
822         if (totalTime == 0) totalTime = 1;
823         printRatio(pw, user+system+iowait+irq+softIrq, totalTime);
824         pw.print("% ");
825         if (pid >= 0) {
826             pw.print(pid);
827             pw.print("/");
828         }
829         pw.print(label);
830         pw.print(": ");
831         printRatio(pw, user, totalTime);
832         pw.print("% user + ");
833         printRatio(pw, system, totalTime);
834         pw.print("% kernel");
835         if (iowait > 0) {
836             pw.print(" + ");
837             printRatio(pw, iowait, totalTime);
838             pw.print("% iowait");
839         }
840         if (irq > 0) {
841             pw.print(" + ");
842             printRatio(pw, irq, totalTime);
843             pw.print("% irq");
844         }
845         if (softIrq > 0) {
846             pw.print(" + ");
847             printRatio(pw, softIrq, totalTime);
848             pw.print("% softirq");
849         }
850         if (minFaults > 0 || majFaults > 0) {
851             pw.print(" / faults:");
852             if (minFaults > 0) {
853                 pw.print(" ");
854                 pw.print(minFaults);
855                 pw.print(" minor");
856             }
857             if (majFaults > 0) {
858                 pw.print(" ");
859                 pw.print(majFaults);
860                 pw.print(" major");
861             }
862         }
863         pw.println();
864     }
865 
866     private String readFile(String file, char endChar) {
867         // Permit disk reads here, as /proc/meminfo isn't really "on
868         // disk" and should be fast.  TODO: make BlockGuard ignore
869         // /proc/ and /sys/ files perhaps?
870         StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads();
871         FileInputStream is = null;
872         try {
873             is = new FileInputStream(file);
874             int len = is.read(mBuffer);
875             is.close();
876 
877             if (len > 0) {
878                 int i;
879                 for (i=0; i<len; i++) {
880                     if (mBuffer[i] == endChar) {
881                         break;
882                     }
883                 }
884                 return new String(mBuffer, 0, i);
885             }
886         } catch (java.io.FileNotFoundException e) {
887         } catch (java.io.IOException e) {
888         } finally {
889             IoUtils.closeQuietly(is);
890             StrictMode.setThreadPolicy(savedPolicy);
891         }
892         return null;
893     }
894 
895     private void getName(Stats st, String cmdlineFile) {
896         String newName = st.name;
897         if (st.name == null || st.name.equals("app_process")
898                 || st.name.equals("<pre-initialized>")) {
899             String cmdName = readFile(cmdlineFile, '\0');
900             if (cmdName != null && cmdName.length() > 1) {
901                 newName = cmdName;
902                 int i = newName.lastIndexOf("/");
903                 if (i > 0 && i < newName.length()-1) {
904                     newName = newName.substring(i+1);
905                 }
906             }
907             if (newName == null) {
908                 newName = st.baseName;
909             }
910         }
911         if (st.name == null || !newName.equals(st.name)) {
912             st.name = newName;
913             st.nameWidth = onMeasureProcessName(st.name);
914         }
915     }
916 }
917