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