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