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