ProcessStats.java revision cb4285537b1bf67b5a248e509d5fe41a6f49282e
1/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.internal.app;
18
19import android.os.Parcel;
20import android.os.Parcelable;
21import android.os.SystemClock;
22import android.os.SystemProperties;
23import android.os.UserHandle;
24import android.text.format.DateFormat;
25import android.util.ArrayMap;
26import android.util.ArraySet;
27import android.util.Log;
28import android.util.Slog;
29import android.util.SparseArray;
30import android.util.TimeUtils;
31import android.webkit.WebViewFactory;
32import com.android.internal.util.ArrayUtils;
33import dalvik.system.VMRuntime;
34
35import java.io.IOException;
36import java.io.InputStream;
37import java.io.PrintWriter;
38import java.util.ArrayList;
39import java.util.Arrays;
40import java.util.Collections;
41import java.util.Comparator;
42import java.util.Objects;
43
44public final class ProcessStats implements Parcelable {
45    static final String TAG = "ProcessStats";
46    static final boolean DEBUG = false;
47
48    public static final String SERVICE_NAME = "procstats";
49
50    // How often the service commits its data, giving the minimum batching
51    // that is done.
52    public static long COMMIT_PERIOD = 3*60*60*1000;  // Commit current stats every 3 hours
53
54    public static final int STATE_NOTHING = -1;
55    public static final int STATE_PERSISTENT = 0;
56    public static final int STATE_TOP = 1;
57    public static final int STATE_IMPORTANT_FOREGROUND = 2;
58    public static final int STATE_IMPORTANT_BACKGROUND = 3;
59    public static final int STATE_BACKUP = 4;
60    public static final int STATE_HEAVY_WEIGHT = 5;
61    public static final int STATE_SERVICE = 6;
62    public static final int STATE_SERVICE_RESTARTING = 7;
63    public static final int STATE_RECEIVER = 8;
64    public static final int STATE_HOME = 9;
65    public static final int STATE_LAST_ACTIVITY = 10;
66    public static final int STATE_CACHED_ACTIVITY = 11;
67    public static final int STATE_CACHED_ACTIVITY_CLIENT = 12;
68    public static final int STATE_CACHED_EMPTY = 13;
69    public static final int STATE_COUNT = STATE_CACHED_EMPTY+1;
70
71    public static final int PSS_SAMPLE_COUNT = 0;
72    public static final int PSS_MINIMUM = 1;
73    public static final int PSS_AVERAGE = 2;
74    public static final int PSS_MAXIMUM = 3;
75    public static final int PSS_USS_MINIMUM = 4;
76    public static final int PSS_USS_AVERAGE = 5;
77    public static final int PSS_USS_MAXIMUM = 6;
78    public static final int PSS_COUNT = PSS_USS_MAXIMUM+1;
79
80    public static final int ADJ_NOTHING = -1;
81    public static final int ADJ_MEM_FACTOR_NORMAL = 0;
82    public static final int ADJ_MEM_FACTOR_MODERATE = 1;
83    public static final int ADJ_MEM_FACTOR_LOW = 2;
84    public static final int ADJ_MEM_FACTOR_CRITICAL = 3;
85    public static final int ADJ_MEM_FACTOR_COUNT = ADJ_MEM_FACTOR_CRITICAL+1;
86    public static final int ADJ_SCREEN_MOD = ADJ_MEM_FACTOR_COUNT;
87    public static final int ADJ_SCREEN_OFF = 0;
88    public static final int ADJ_SCREEN_ON = ADJ_SCREEN_MOD;
89    public static final int ADJ_COUNT = ADJ_SCREEN_ON*2;
90
91    public static final int FLAG_COMPLETE = 1<<0;
92    public static final int FLAG_SHUTDOWN = 1<<1;
93    public static final int FLAG_SYSPROPS = 1<<2;
94
95    public static final int[] ALL_MEM_ADJ = new int[] { ADJ_MEM_FACTOR_NORMAL,
96            ADJ_MEM_FACTOR_MODERATE, ADJ_MEM_FACTOR_LOW, ADJ_MEM_FACTOR_CRITICAL };
97
98    public static final int[] ALL_SCREEN_ADJ = new int[] { ADJ_SCREEN_OFF, ADJ_SCREEN_ON };
99
100    public static final int[] NON_CACHED_PROC_STATES = new int[] {
101            STATE_PERSISTENT, STATE_TOP, STATE_IMPORTANT_FOREGROUND,
102            STATE_IMPORTANT_BACKGROUND, STATE_BACKUP, STATE_HEAVY_WEIGHT,
103            STATE_SERVICE, STATE_SERVICE_RESTARTING, STATE_RECEIVER
104    };
105
106    public static final int[] BACKGROUND_PROC_STATES = new int[] {
107            STATE_IMPORTANT_FOREGROUND, STATE_IMPORTANT_BACKGROUND, STATE_BACKUP,
108            STATE_HEAVY_WEIGHT, STATE_SERVICE, STATE_SERVICE_RESTARTING, STATE_RECEIVER
109    };
110
111    // Map from process states to the states we track.
112    static final int[] PROCESS_STATE_TO_STATE = new int[] {
113            STATE_PERSISTENT,               // ActivityManager.PROCESS_STATE_PERSISTENT
114            STATE_PERSISTENT,               // ActivityManager.PROCESS_STATE_PERSISTENT_UI
115            STATE_TOP,                      // ActivityManager.PROCESS_STATE_TOP
116            STATE_IMPORTANT_FOREGROUND,     // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
117            STATE_IMPORTANT_BACKGROUND,     // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
118            STATE_BACKUP,                   // ActivityManager.PROCESS_STATE_BACKUP
119            STATE_HEAVY_WEIGHT,             // ActivityManager.PROCESS_STATE_HEAVY_WEIGHT
120            STATE_SERVICE,                  // ActivityManager.PROCESS_STATE_SERVICE
121            STATE_RECEIVER,                 // ActivityManager.PROCESS_STATE_RECEIVER
122            STATE_HOME,                     // ActivityManager.PROCESS_STATE_HOME
123            STATE_LAST_ACTIVITY,            // ActivityManager.PROCESS_STATE_LAST_ACTIVITY
124            STATE_CACHED_ACTIVITY,          // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY
125            STATE_CACHED_ACTIVITY_CLIENT,   // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT
126            STATE_CACHED_EMPTY,             // ActivityManager.PROCESS_STATE_CACHED_EMPTY
127    };
128
129    public static final int[] ALL_PROC_STATES = new int[] { STATE_PERSISTENT,
130            STATE_TOP, STATE_IMPORTANT_FOREGROUND, STATE_IMPORTANT_BACKGROUND, STATE_BACKUP,
131            STATE_HEAVY_WEIGHT, STATE_SERVICE, STATE_SERVICE_RESTARTING, STATE_RECEIVER,
132            STATE_HOME, STATE_LAST_ACTIVITY, STATE_CACHED_ACTIVITY,
133            STATE_CACHED_ACTIVITY_CLIENT, STATE_CACHED_EMPTY
134    };
135
136    static final String[] STATE_NAMES = new String[] {
137            "Persistent", "Top       ", "Imp Fg    ", "Imp Bg    ",
138            "Backup    ", "Heavy Wght", "Service   ", "Service Rs",
139            "Receiver  ", "Home      ",
140            "Last Act  ", "Cch Act   ", "Cch CliAct", "Cch Empty "
141    };
142
143    public static final String[] ADJ_SCREEN_NAMES_CSV = new String[] {
144            "off", "on"
145    };
146
147    public static final String[] ADJ_MEM_NAMES_CSV = new String[] {
148            "norm", "mod",  "low", "crit"
149    };
150
151    public static final String[] STATE_NAMES_CSV = new String[] {
152            "pers", "top", "impfg", "impbg", "backup", "heavy",
153            "service", "service-rs", "receiver", "home", "lastact",
154            "cch-activity", "cch-aclient", "cch-empty"
155    };
156
157    static final String[] ADJ_SCREEN_TAGS = new String[] {
158            "0", "1"
159    };
160
161    static final String[] ADJ_MEM_TAGS = new String[] {
162            "n", "m",  "l", "c"
163    };
164
165    static final String[] STATE_TAGS = new String[] {
166            "p", "t", "f", "b", "u", "w",
167            "s", "x", "r", "h", "l", "a", "c", "e"
168    };
169
170    static final String CSV_SEP = "\t";
171
172    // Current version of the parcel format.
173    private static final int PARCEL_VERSION = 13;
174    // In-memory Parcel magic number, used to detect attempts to unmarshall bad data
175    private static final int MAGIC = 0x50535453;
176
177    // Where the "type"/"state" part of the data appears in an offset integer.
178    static int OFFSET_TYPE_SHIFT = 0;
179    static int OFFSET_TYPE_MASK = 0xff;
180    // Where the "which array" part of the data appears in an offset integer.
181    static int OFFSET_ARRAY_SHIFT = 8;
182    static int OFFSET_ARRAY_MASK = 0xff;
183    // Where the "index into array" part of the data appears in an offset integer.
184    static int OFFSET_INDEX_SHIFT = 16;
185    static int OFFSET_INDEX_MASK = 0xffff;
186
187    public String mReadError;
188    public String mTimePeriodStartClockStr;
189    public int mFlags;
190
191    public final ProcessMap<PackageState> mPackages = new ProcessMap<PackageState>();
192    public final ProcessMap<ProcessState> mProcesses = new ProcessMap<ProcessState>();
193
194    public final long[] mMemFactorDurations = new long[ADJ_COUNT];
195    public int mMemFactor = STATE_NOTHING;
196    public long mStartTime;
197
198    public long mTimePeriodStartClock;
199    public long mTimePeriodStartRealtime;
200    public long mTimePeriodEndRealtime;
201    String mRuntime;
202    String mWebView;
203    boolean mRunning;
204
205    static final int LONGS_SIZE = 4096;
206    final ArrayList<long[]> mLongs = new ArrayList<long[]>();
207    int mNextLong;
208
209    int[] mAddLongTable;
210    int mAddLongTableSize;
211
212    // For writing parcels.
213    ArrayMap<String, Integer> mCommonStringToIndex;
214
215    // For reading parcels.
216    ArrayList<String> mIndexToCommonString;
217
218    public ProcessStats(boolean running) {
219        mRunning = running;
220        reset();
221    }
222
223    public ProcessStats(Parcel in) {
224        reset();
225        readFromParcel(in);
226    }
227
228    public void add(ProcessStats other) {
229        ArrayMap<String, SparseArray<PackageState>> pkgMap = other.mPackages.getMap();
230        for (int ip=0; ip<pkgMap.size(); ip++) {
231            String pkgName = pkgMap.keyAt(ip);
232            SparseArray<PackageState> uids = pkgMap.valueAt(ip);
233            for (int iu=0; iu<uids.size(); iu++) {
234                int uid = uids.keyAt(iu);
235                PackageState otherState = uids.valueAt(iu);
236                final int NPROCS = otherState.mProcesses.size();
237                final int NSRVS = otherState.mServices.size();
238                for (int iproc=0; iproc<NPROCS; iproc++) {
239                    ProcessState otherProc = otherState.mProcesses.valueAt(iproc);
240                    if (otherProc.mCommonProcess != otherProc) {
241                        if (DEBUG) Slog.d(TAG, "Adding pkg " + pkgName + " uid " + uid
242                                + " proc " + otherProc.mName);
243                        ProcessState thisProc = getProcessStateLocked(pkgName, uid,
244                                otherProc.mName);
245                        if (thisProc.mCommonProcess == thisProc) {
246                            if (DEBUG) Slog.d(TAG, "Existing process is single-package, splitting");
247                            thisProc.mMultiPackage = true;
248                            long now = SystemClock.uptimeMillis();
249                            final PackageState pkgState = getPackageStateLocked(pkgName, uid);
250                            thisProc = thisProc.clone(thisProc.mPackage, now);
251                            pkgState.mProcesses.put(thisProc.mName, thisProc);
252                        }
253                        thisProc.add(otherProc);
254                    }
255                }
256                for (int isvc=0; isvc<NSRVS; isvc++) {
257                    ServiceState otherSvc = otherState.mServices.valueAt(isvc);
258                    if (DEBUG) Slog.d(TAG, "Adding pkg " + pkgName + " uid " + uid
259                            + " service " + otherSvc.mName);
260                    ServiceState thisSvc = getServiceStateLocked(pkgName, uid,
261                            otherSvc.mProcessName, otherSvc.mName);
262                    thisSvc.add(otherSvc);
263                }
264            }
265        }
266
267        ArrayMap<String, SparseArray<ProcessState>> procMap = other.mProcesses.getMap();
268        for (int ip=0; ip<procMap.size(); ip++) {
269            SparseArray<ProcessState> uids = procMap.valueAt(ip);
270            for (int iu=0; iu<uids.size(); iu++) {
271                int uid = uids.keyAt(iu);
272                ProcessState otherProc = uids.valueAt(iu);
273                ProcessState thisProc = mProcesses.get(otherProc.mName, uid);
274                if (DEBUG) Slog.d(TAG, "Adding uid " + uid + " proc " + otherProc.mName);
275                if (thisProc == null) {
276                    if (DEBUG) Slog.d(TAG, "Creating new process!");
277                    thisProc = new ProcessState(this, otherProc.mPackage, uid, otherProc.mName);
278                    mProcesses.put(otherProc.mName, uid, thisProc);
279                    PackageState thisState = getPackageStateLocked(otherProc.mPackage, uid);
280                    if (!thisState.mProcesses.containsKey(otherProc.mName)) {
281                        thisState.mProcesses.put(otherProc.mName, thisProc);
282                    }
283                }
284                thisProc.add(otherProc);
285            }
286        }
287
288        for (int i=0; i<ADJ_COUNT; i++) {
289            if (DEBUG) Slog.d(TAG, "Total duration #" + i + " inc by "
290                    + other.mMemFactorDurations[i] + " from "
291                    + mMemFactorDurations[i]);
292            mMemFactorDurations[i] += other.mMemFactorDurations[i];
293        }
294
295        if (other.mTimePeriodStartClock < mTimePeriodStartClock) {
296            mTimePeriodStartClock = other.mTimePeriodStartClock;
297            mTimePeriodStartClockStr = other.mTimePeriodStartClockStr;
298        }
299        mTimePeriodEndRealtime += other.mTimePeriodEndRealtime - other.mTimePeriodStartRealtime;
300    }
301
302    public static final Parcelable.Creator<ProcessStats> CREATOR
303            = new Parcelable.Creator<ProcessStats>() {
304        public ProcessStats createFromParcel(Parcel in) {
305            return new ProcessStats(in);
306        }
307
308        public ProcessStats[] newArray(int size) {
309            return new ProcessStats[size];
310        }
311    };
312
313    private static void printScreenLabel(PrintWriter pw, int offset) {
314        switch (offset) {
315            case ADJ_NOTHING:
316                pw.print("             ");
317                break;
318            case ADJ_SCREEN_OFF:
319                pw.print("Screen Off / ");
320                break;
321            case ADJ_SCREEN_ON:
322                pw.print("Screen On  / ");
323                break;
324            default:
325                pw.print("?????????? / ");
326                break;
327        }
328    }
329
330    public static void printScreenLabelCsv(PrintWriter pw, int offset) {
331        switch (offset) {
332            case ADJ_NOTHING:
333                break;
334            case ADJ_SCREEN_OFF:
335                pw.print(ADJ_SCREEN_NAMES_CSV[0]);
336                break;
337            case ADJ_SCREEN_ON:
338                pw.print(ADJ_SCREEN_NAMES_CSV[1]);
339                break;
340            default:
341                pw.print("???");
342                break;
343        }
344    }
345
346    private static void printMemLabel(PrintWriter pw, int offset) {
347        switch (offset) {
348            case ADJ_NOTHING:
349                pw.print("       ");
350                break;
351            case ADJ_MEM_FACTOR_NORMAL:
352                pw.print("Norm / ");
353                break;
354            case ADJ_MEM_FACTOR_MODERATE:
355                pw.print("Mod  / ");
356                break;
357            case ADJ_MEM_FACTOR_LOW:
358                pw.print("Low  / ");
359                break;
360            case ADJ_MEM_FACTOR_CRITICAL:
361                pw.print("Crit / ");
362                break;
363            default:
364                pw.print("???? / ");
365                break;
366        }
367    }
368
369    public static void printMemLabelCsv(PrintWriter pw, int offset) {
370        if (offset >= ADJ_MEM_FACTOR_NORMAL) {
371            if (offset <= ADJ_MEM_FACTOR_CRITICAL) {
372                pw.print(ADJ_MEM_NAMES_CSV[offset]);
373            } else {
374                pw.print("???");
375            }
376        }
377    }
378
379    public static long dumpSingleTime(PrintWriter pw, String prefix, long[] durations,
380            int curState, long curStartTime, long now) {
381        long totalTime = 0;
382        int printedScreen = -1;
383        for (int iscreen=0; iscreen<ADJ_COUNT; iscreen+=ADJ_SCREEN_MOD) {
384            int printedMem = -1;
385            for (int imem=0; imem<ADJ_MEM_FACTOR_COUNT; imem++) {
386                int state = imem+iscreen;
387                long time = durations[state];
388                String running = "";
389                if (curState == state) {
390                    time += now - curStartTime;
391                    if (pw != null) {
392                        running = " (running)";
393                    }
394                }
395                if (time != 0) {
396                    if (pw != null) {
397                        pw.print(prefix);
398                        printScreenLabel(pw, printedScreen != iscreen
399                                ? iscreen : STATE_NOTHING);
400                        printedScreen = iscreen;
401                        printMemLabel(pw, printedMem != imem ? imem : STATE_NOTHING);
402                        printedMem = imem;
403                        TimeUtils.formatDuration(time, pw); pw.println(running);
404                    }
405                    totalTime += time;
406                }
407            }
408        }
409        if (totalTime != 0 && pw != null) {
410            pw.print(prefix);
411            printScreenLabel(pw, STATE_NOTHING);
412            pw.print("TOTAL: ");
413            TimeUtils.formatDuration(totalTime, pw);
414            pw.println();
415        }
416        return totalTime;
417    }
418
419    static void dumpAdjTimesCheckin(PrintWriter pw, String sep, long[] durations,
420            int curState, long curStartTime, long now) {
421        for (int iscreen=0; iscreen<ADJ_COUNT; iscreen+=ADJ_SCREEN_MOD) {
422            for (int imem=0; imem<ADJ_MEM_FACTOR_COUNT; imem++) {
423                int state = imem+iscreen;
424                long time = durations[state];
425                if (curState == state) {
426                    time += now - curStartTime;
427                }
428                if (time != 0) {
429                    printAdjTagAndValue(pw, state, time);
430                }
431            }
432        }
433    }
434
435    static void dumpServiceTimeCheckin(PrintWriter pw, String label, String packageName,
436            int uid, String serviceName, ServiceState svc, int serviceType, int opCount,
437            int curState, long curStartTime, long now) {
438        if (opCount <= 0) {
439            return;
440        }
441        pw.print(label);
442        pw.print(",");
443        pw.print(packageName);
444        pw.print(",");
445        pw.print(uid);
446        pw.print(",");
447        pw.print(serviceName);
448        pw.print(",");
449        pw.print(opCount);
450        boolean didCurState = false;
451        for (int i=0; i<svc.mDurationsTableSize; i++) {
452            int off = svc.mDurationsTable[i];
453            int type = (off>>OFFSET_TYPE_SHIFT)&OFFSET_TYPE_MASK;
454            int memFactor = type / ServiceState.SERVICE_COUNT;
455            type %= ServiceState.SERVICE_COUNT;
456            if (type != serviceType) {
457                continue;
458            }
459            long time = svc.mStats.getLong(off, 0);
460            if (curState == memFactor) {
461                didCurState = true;
462                time += now - curStartTime;
463            }
464            printAdjTagAndValue(pw, memFactor, time);
465        }
466        if (!didCurState && curState != STATE_NOTHING) {
467            printAdjTagAndValue(pw, curState, now - curStartTime);
468        }
469        pw.println();
470    }
471
472    public static void computeProcessData(ProcessState proc, ProcessDataCollection data, long now) {
473        data.totalTime = 0;
474        data.numPss = data.minPss = data.avgPss = data.maxPss =
475                data.minUss = data.avgUss = data.maxUss = 0;
476        for (int is=0; is<data.screenStates.length; is++) {
477            for (int im=0; im<data.memStates.length; im++) {
478                for (int ip=0; ip<data.procStates.length; ip++) {
479                    int bucket = ((data.screenStates[is] + data.memStates[im]) * STATE_COUNT)
480                            + data.procStates[ip];
481                    data.totalTime += proc.getDuration(bucket, now);
482                    long samples = proc.getPssSampleCount(bucket);
483                    if (samples > 0) {
484                        long minPss = proc.getPssMinimum(bucket);
485                        long avgPss = proc.getPssAverage(bucket);
486                        long maxPss = proc.getPssMaximum(bucket);
487                        long minUss = proc.getPssUssMinimum(bucket);
488                        long avgUss = proc.getPssUssAverage(bucket);
489                        long maxUss = proc.getPssUssMaximum(bucket);
490                        if (data.numPss == 0) {
491                            data.minPss = minPss;
492                            data.avgPss = avgPss;
493                            data.maxPss = maxPss;
494                            data.minUss = minUss;
495                            data.avgUss = avgUss;
496                            data.maxUss = maxUss;
497                        } else {
498                            if (minPss < data.minPss) {
499                                data.minPss = minPss;
500                            }
501                            data.avgPss = (long)( ((data.avgPss*(double)data.numPss)
502                                    + (avgPss*(double)samples)) / (data.numPss+samples) );
503                            if (maxPss > data.maxPss) {
504                                data.maxPss = maxPss;
505                            }
506                            if (minUss < data.minUss) {
507                                data.minUss = minUss;
508                            }
509                            data.avgUss = (long)( ((data.avgUss*(double)data.numPss)
510                                    + (avgUss*(double)samples)) / (data.numPss+samples) );
511                            if (maxUss > data.maxUss) {
512                                data.maxUss = maxUss;
513                            }
514                        }
515                        data.numPss += samples;
516                    }
517                }
518            }
519        }
520    }
521
522    static long computeProcessTimeLocked(ProcessState proc, int[] screenStates, int[] memStates,
523                int[] procStates, long now) {
524        long totalTime = 0;
525        /*
526        for (int i=0; i<proc.mDurationsTableSize; i++) {
527            int val = proc.mDurationsTable[i];
528            totalTime += proc.mState.getLong(val, 0);
529            if ((val&0xff) == proc.mCurState) {
530                totalTime += now - proc.mStartTime;
531            }
532        }
533        */
534        for (int is=0; is<screenStates.length; is++) {
535            for (int im=0; im<memStates.length; im++) {
536                for (int ip=0; ip<procStates.length; ip++) {
537                    int bucket = ((screenStates[is] + memStates[im]) * STATE_COUNT)
538                            + procStates[ip];
539                    totalTime += proc.getDuration(bucket, now);
540                }
541            }
542        }
543        proc.mTmpTotalTime = totalTime;
544        return totalTime;
545    }
546
547    static void dumpProcessState(PrintWriter pw, String prefix, ProcessState proc,
548            int[] screenStates, int[] memStates, int[] procStates, long now) {
549        long totalTime = 0;
550        int printedScreen = -1;
551        for (int is=0; is<screenStates.length; is++) {
552            int printedMem = -1;
553            for (int im=0; im<memStates.length; im++) {
554                for (int ip=0; ip<procStates.length; ip++) {
555                    final int iscreen = screenStates[is];
556                    final int imem = memStates[im];
557                    final int bucket = ((iscreen + imem) * STATE_COUNT) + procStates[ip];
558                    long time = proc.getDuration(bucket, now);
559                    String running = "";
560                    if (proc.mCurState == bucket) {
561                        running = " (running)";
562                    }
563                    if (time != 0) {
564                        pw.print(prefix);
565                        if (screenStates.length > 1) {
566                            printScreenLabel(pw, printedScreen != iscreen
567                                    ? iscreen : STATE_NOTHING);
568                            printedScreen = iscreen;
569                        }
570                        if (memStates.length > 1) {
571                            printMemLabel(pw, printedMem != imem ? imem : STATE_NOTHING);
572                            printedMem = imem;
573                        }
574                        pw.print(STATE_NAMES[procStates[ip]]); pw.print(": ");
575                        TimeUtils.formatDuration(time, pw); pw.println(running);
576                        totalTime += time;
577                    }
578                }
579            }
580        }
581        if (totalTime != 0) {
582            pw.print(prefix);
583            if (screenStates.length > 1) {
584                printScreenLabel(pw, STATE_NOTHING);
585            }
586            if (memStates.length > 1) {
587                printMemLabel(pw, STATE_NOTHING);
588            }
589            pw.print("TOTAL     : ");
590            TimeUtils.formatDuration(totalTime, pw);
591            pw.println();
592        }
593    }
594
595    static void dumpProcessPss(PrintWriter pw, String prefix, ProcessState proc, int[] screenStates,
596            int[] memStates, int[] procStates) {
597        boolean printedHeader = false;
598        int printedScreen = -1;
599        for (int is=0; is<screenStates.length; is++) {
600            int printedMem = -1;
601            for (int im=0; im<memStates.length; im++) {
602                for (int ip=0; ip<procStates.length; ip++) {
603                    final int iscreen = screenStates[is];
604                    final int imem = memStates[im];
605                    final int bucket = ((iscreen + imem) * STATE_COUNT) + procStates[ip];
606                    long count = proc.getPssSampleCount(bucket);
607                    if (count > 0) {
608                        if (!printedHeader) {
609                            pw.print(prefix);
610                            pw.print("PSS/USS (");
611                            pw.print(proc.mPssTableSize);
612                            pw.println(" entries):");
613                            printedHeader = true;
614                        }
615                        pw.print(prefix);
616                        pw.print("  ");
617                        if (screenStates.length > 1) {
618                            printScreenLabel(pw, printedScreen != iscreen
619                                    ? iscreen : STATE_NOTHING);
620                            printedScreen = iscreen;
621                        }
622                        if (memStates.length > 1) {
623                            printMemLabel(pw, printedMem != imem ? imem : STATE_NOTHING);
624                            printedMem = imem;
625                        }
626                        pw.print(STATE_NAMES[procStates[ip]]); pw.print(": ");
627                        pw.print(count);
628                        pw.print(" samples ");
629                        printSizeValue(pw, proc.getPssMinimum(bucket) * 1024);
630                        pw.print(" ");
631                        printSizeValue(pw, proc.getPssAverage(bucket) * 1024);
632                        pw.print(" ");
633                        printSizeValue(pw, proc.getPssMaximum(bucket) * 1024);
634                        pw.print(" / ");
635                        printSizeValue(pw, proc.getPssUssMinimum(bucket) * 1024);
636                        pw.print(" ");
637                        printSizeValue(pw, proc.getPssUssAverage(bucket) * 1024);
638                        pw.print(" ");
639                        printSizeValue(pw, proc.getPssUssMaximum(bucket) * 1024);
640                        pw.println();
641                    }
642                }
643            }
644        }
645        if (proc.mNumExcessiveWake != 0) {
646            pw.print(prefix); pw.print("Killed for excessive wake locks: ");
647                    pw.print(proc.mNumExcessiveWake); pw.println(" times");
648        }
649        if (proc.mNumExcessiveCpu != 0) {
650            pw.print(prefix); pw.print("Killed for excessive CPU use: ");
651                    pw.print(proc.mNumExcessiveCpu); pw.println(" times");
652        }
653        if (proc.mNumCachedKill != 0) {
654            pw.print(prefix); pw.print("Killed from cached state: ");
655                    pw.print(proc.mNumCachedKill); pw.print(" times from pss ");
656                    printSizeValue(pw, proc.mMinCachedKillPss * 1024); pw.print("-");
657                    printSizeValue(pw, proc.mAvgCachedKillPss * 1024); pw.print("-");
658                    printSizeValue(pw, proc.mMaxCachedKillPss * 1024); pw.println();
659        }
660    }
661
662    static void dumpStateHeadersCsv(PrintWriter pw, String sep, int[] screenStates,
663            int[] memStates, int[] procStates) {
664        final int NS = screenStates != null ? screenStates.length : 1;
665        final int NM = memStates != null ? memStates.length : 1;
666        final int NP = procStates != null ? procStates.length : 1;
667        for (int is=0; is<NS; is++) {
668            for (int im=0; im<NM; im++) {
669                for (int ip=0; ip<NP; ip++) {
670                    pw.print(sep);
671                    boolean printed = false;
672                    if (screenStates != null && screenStates.length > 1) {
673                        printScreenLabelCsv(pw, screenStates[is]);
674                        printed = true;
675                    }
676                    if (memStates != null && memStates.length > 1) {
677                        if (printed) {
678                            pw.print("-");
679                        }
680                        printMemLabelCsv(pw, memStates[im]);
681                        printed = true;
682                    }
683                    if (procStates != null && procStates.length > 1) {
684                        if (printed) {
685                            pw.print("-");
686                        }
687                        pw.print(STATE_NAMES_CSV[procStates[ip]]);
688                    }
689                }
690            }
691        }
692    }
693
694    static void dumpProcessStateCsv(PrintWriter pw, ProcessState proc,
695            boolean sepScreenStates, int[] screenStates, boolean sepMemStates, int[] memStates,
696            boolean sepProcStates, int[] procStates, long now) {
697        final int NSS = sepScreenStates ? screenStates.length : 1;
698        final int NMS = sepMemStates ? memStates.length : 1;
699        final int NPS = sepProcStates ? procStates.length : 1;
700        for (int iss=0; iss<NSS; iss++) {
701            for (int ims=0; ims<NMS; ims++) {
702                for (int ips=0; ips<NPS; ips++) {
703                    final int vsscreen = sepScreenStates ? screenStates[iss] : 0;
704                    final int vsmem = sepMemStates ? memStates[ims] : 0;
705                    final int vsproc = sepProcStates ? procStates[ips] : 0;
706                    final int NSA = sepScreenStates ? 1 : screenStates.length;
707                    final int NMA = sepMemStates ? 1 : memStates.length;
708                    final int NPA = sepProcStates ? 1 : procStates.length;
709                    long totalTime = 0;
710                    for (int isa=0; isa<NSA; isa++) {
711                        for (int ima=0; ima<NMA; ima++) {
712                            for (int ipa=0; ipa<NPA; ipa++) {
713                                final int vascreen = sepScreenStates ? 0 : screenStates[isa];
714                                final int vamem = sepMemStates ? 0 : memStates[ima];
715                                final int vaproc = sepProcStates ? 0 : procStates[ipa];
716                                final int bucket = ((vsscreen + vascreen + vsmem + vamem)
717                                        * STATE_COUNT) + vsproc + vaproc;
718                                totalTime += proc.getDuration(bucket, now);
719                            }
720                        }
721                    }
722                    pw.print(CSV_SEP);
723                    pw.print(totalTime);
724                }
725            }
726        }
727    }
728
729    static void dumpProcessList(PrintWriter pw, String prefix, ArrayList<ProcessState> procs,
730            int[] screenStates, int[] memStates, int[] procStates, long now) {
731        String innerPrefix = prefix + "  ";
732        for (int i=procs.size()-1; i>=0; i--) {
733            ProcessState proc = procs.get(i);
734            pw.print(prefix);
735            pw.print(proc.mName);
736            pw.print(" / ");
737            UserHandle.formatUid(pw, proc.mUid);
738            pw.print(" (");
739            pw.print(proc.mDurationsTableSize);
740            pw.print(" entries)");
741            pw.println(":");
742            dumpProcessState(pw, innerPrefix, proc, screenStates, memStates, procStates, now);
743            if (proc.mPssTableSize > 0) {
744                dumpProcessPss(pw, innerPrefix, proc, screenStates, memStates, procStates);
745            }
746        }
747    }
748
749    static void dumpProcessSummaryDetails(PrintWriter pw, ProcessState proc, String prefix,
750            String label, int[] screenStates, int[] memStates, int[] procStates,
751            long now, long totalTime, boolean full) {
752        ProcessDataCollection totals = new ProcessDataCollection(screenStates,
753                memStates, procStates);
754        computeProcessData(proc, totals, now);
755        if (totals.totalTime != 0 || totals.numPss != 0) {
756            if (prefix != null) {
757                pw.print(prefix);
758            }
759            if (label != null) {
760                pw.print(label);
761            }
762            totals.print(pw, totalTime, full);
763            if (prefix != null) {
764                pw.println();
765            }
766        }
767    }
768
769    static void dumpProcessSummaryLocked(PrintWriter pw, String prefix,
770            ArrayList<ProcessState> procs, int[] screenStates, int[] memStates, int[] procStates,
771            long now, long totalTime) {
772        for (int i=procs.size()-1; i>=0; i--) {
773            ProcessState proc = procs.get(i);
774            pw.print(prefix);
775            pw.print("* ");
776            pw.print(proc.mName);
777            pw.print(" / ");
778            UserHandle.formatUid(pw, proc.mUid);
779            pw.println(":");
780            dumpProcessSummaryDetails(pw, proc, prefix, "         TOTAL: ", screenStates, memStates,
781                    procStates, now, totalTime, true);
782            dumpProcessSummaryDetails(pw, proc, prefix, "    Persistent: ", screenStates, memStates,
783                    new int[] { STATE_PERSISTENT }, now, totalTime, true);
784            dumpProcessSummaryDetails(pw, proc, prefix, "           Top: ", screenStates, memStates,
785                    new int[] {STATE_TOP}, now, totalTime, true);
786            dumpProcessSummaryDetails(pw, proc, prefix, "        Imp Fg: ", screenStates, memStates,
787                    new int[] { STATE_IMPORTANT_FOREGROUND }, now, totalTime, true);
788            dumpProcessSummaryDetails(pw, proc, prefix, "        Imp Bg: ", screenStates, memStates,
789                    new int[] {STATE_IMPORTANT_BACKGROUND}, now, totalTime, true);
790            dumpProcessSummaryDetails(pw, proc, prefix, "        Backup: ", screenStates, memStates,
791                    new int[] {STATE_BACKUP}, now, totalTime, true);
792            dumpProcessSummaryDetails(pw, proc, prefix, "     Heavy Wgt: ", screenStates, memStates,
793                    new int[] {STATE_HEAVY_WEIGHT}, now, totalTime, true);
794            dumpProcessSummaryDetails(pw, proc, prefix, "       Service: ", screenStates, memStates,
795                    new int[] {STATE_SERVICE}, now, totalTime, true);
796            dumpProcessSummaryDetails(pw, proc, prefix, "    Service Rs: ", screenStates, memStates,
797                    new int[] {STATE_SERVICE_RESTARTING}, now, totalTime, true);
798            dumpProcessSummaryDetails(pw, proc, prefix, "      Receiver: ", screenStates, memStates,
799                    new int[] {STATE_RECEIVER}, now, totalTime, true);
800            dumpProcessSummaryDetails(pw, proc, prefix, "          Home: ", screenStates, memStates,
801                    new int[] {STATE_HOME}, now, totalTime, true);
802            dumpProcessSummaryDetails(pw, proc, prefix, "    (Last Act): ", screenStates, memStates,
803                    new int[] {STATE_LAST_ACTIVITY}, now, totalTime, true);
804            dumpProcessSummaryDetails(pw, proc, prefix, "      (Cached): ", screenStates, memStates,
805                    new int[] {STATE_CACHED_ACTIVITY, STATE_CACHED_ACTIVITY_CLIENT,
806                            STATE_CACHED_EMPTY}, now, totalTime, true);
807        }
808    }
809
810    static void printPercent(PrintWriter pw, double fraction) {
811        fraction *= 100;
812        if (fraction < 1) {
813            pw.print(String.format("%.2f", fraction));
814        } else if (fraction < 10) {
815            pw.print(String.format("%.1f", fraction));
816        } else {
817            pw.print(String.format("%.0f", fraction));
818        }
819        pw.print("%");
820    }
821
822    static void printSizeValue(PrintWriter pw, long number) {
823        float result = number;
824        String suffix = "";
825        if (result > 900) {
826            suffix = "KB";
827            result = result / 1024;
828        }
829        if (result > 900) {
830            suffix = "MB";
831            result = result / 1024;
832        }
833        if (result > 900) {
834            suffix = "GB";
835            result = result / 1024;
836        }
837        if (result > 900) {
838            suffix = "TB";
839            result = result / 1024;
840        }
841        if (result > 900) {
842            suffix = "PB";
843            result = result / 1024;
844        }
845        String value;
846        if (result < 1) {
847            value = String.format("%.2f", result);
848        } else if (result < 10) {
849            value = String.format("%.1f", result);
850        } else if (result < 100) {
851            value = String.format("%.0f", result);
852        } else {
853            value = String.format("%.0f", result);
854        }
855        pw.print(value);
856        pw.print(suffix);
857    }
858
859    public static void dumpProcessListCsv(PrintWriter pw, ArrayList<ProcessState> procs,
860            boolean sepScreenStates, int[] screenStates, boolean sepMemStates, int[] memStates,
861            boolean sepProcStates, int[] procStates, long now) {
862        pw.print("process");
863        pw.print(CSV_SEP);
864        pw.print("uid");
865        dumpStateHeadersCsv(pw, CSV_SEP, sepScreenStates ? screenStates : null,
866                sepMemStates ? memStates : null,
867                sepProcStates ? procStates : null);
868        pw.println();
869        for (int i=procs.size()-1; i>=0; i--) {
870            ProcessState proc = procs.get(i);
871            pw.print(proc.mName);
872            pw.print(CSV_SEP);
873            UserHandle.formatUid(pw, proc.mUid);
874            dumpProcessStateCsv(pw, proc, sepScreenStates, screenStates,
875                    sepMemStates, memStates, sepProcStates, procStates, now);
876            pw.println();
877        }
878    }
879
880    static int printArrayEntry(PrintWriter pw, String[] array, int value, int mod) {
881        int index = value/mod;
882        if (index >= 0 && index < array.length) {
883            pw.print(array[index]);
884        } else {
885            pw.print('?');
886        }
887        return value - index*mod;
888    }
889
890    static void printProcStateTag(PrintWriter pw, int state) {
891        state = printArrayEntry(pw, ADJ_SCREEN_TAGS,  state, ADJ_SCREEN_MOD*STATE_COUNT);
892        state = printArrayEntry(pw, ADJ_MEM_TAGS,  state, STATE_COUNT);
893        printArrayEntry(pw, STATE_TAGS,  state, 1);
894    }
895
896    static void printAdjTag(PrintWriter pw, int state) {
897        state = printArrayEntry(pw, ADJ_SCREEN_TAGS,  state, ADJ_SCREEN_MOD);
898        printArrayEntry(pw, ADJ_MEM_TAGS, state, 1);
899    }
900
901    static void printProcStateTagAndValue(PrintWriter pw, int state, long value) {
902        pw.print(',');
903        printProcStateTag(pw, state);
904        pw.print(':');
905        pw.print(value);
906    }
907
908    static void printAdjTagAndValue(PrintWriter pw, int state, long value) {
909        pw.print(',');
910        printAdjTag(pw, state);
911        pw.print(':');
912        pw.print(value);
913    }
914
915    static void dumpAllProcessStateCheckin(PrintWriter pw, ProcessState proc, long now) {
916        boolean didCurState = false;
917        for (int i=0; i<proc.mDurationsTableSize; i++) {
918            int off = proc.mDurationsTable[i];
919            int type = (off>>OFFSET_TYPE_SHIFT)&OFFSET_TYPE_MASK;
920            long time = proc.mStats.getLong(off, 0);
921            if (proc.mCurState == type) {
922                didCurState = true;
923                time += now - proc.mStartTime;
924            }
925            printProcStateTagAndValue(pw, type, time);
926        }
927        if (!didCurState && proc.mCurState != STATE_NOTHING) {
928            printProcStateTagAndValue(pw, proc.mCurState, now - proc.mStartTime);
929        }
930    }
931
932    static void dumpAllProcessPssCheckin(PrintWriter pw, ProcessState proc) {
933        for (int i=0; i<proc.mPssTableSize; i++) {
934            int off = proc.mPssTable[i];
935            int type = (off>>OFFSET_TYPE_SHIFT)&OFFSET_TYPE_MASK;
936            long count = proc.mStats.getLong(off, PSS_SAMPLE_COUNT);
937            long min = proc.mStats.getLong(off, PSS_MINIMUM);
938            long avg = proc.mStats.getLong(off, PSS_AVERAGE);
939            long max = proc.mStats.getLong(off, PSS_MAXIMUM);
940            long umin = proc.mStats.getLong(off, PSS_USS_MINIMUM);
941            long uavg = proc.mStats.getLong(off, PSS_USS_AVERAGE);
942            long umax = proc.mStats.getLong(off, PSS_USS_MAXIMUM);
943            pw.print(',');
944            printProcStateTag(pw, type);
945            pw.print(':');
946            pw.print(count);
947            pw.print(':');
948            pw.print(min);
949            pw.print(':');
950            pw.print(avg);
951            pw.print(':');
952            pw.print(max);
953            pw.print(':');
954            pw.print(umin);
955            pw.print(':');
956            pw.print(uavg);
957            pw.print(':');
958            pw.print(umax);
959        }
960    }
961
962    public void reset() {
963        if (DEBUG) Slog.d(TAG, "Resetting state of " + mTimePeriodStartClockStr);
964        resetCommon();
965        mPackages.getMap().clear();
966        mProcesses.getMap().clear();
967        mMemFactor = STATE_NOTHING;
968        mStartTime = 0;
969        if (DEBUG) Slog.d(TAG, "State reset; now " + mTimePeriodStartClockStr);
970    }
971
972    public void resetSafely() {
973        if (DEBUG) Slog.d(TAG, "Safely resetting state of " + mTimePeriodStartClockStr);
974        resetCommon();
975        long now = SystemClock.uptimeMillis();
976        ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap();
977        for (int ip=procMap.size()-1; ip>=0; ip--) {
978            SparseArray<ProcessState> uids = procMap.valueAt(ip);
979            for (int iu=uids.size()-1; iu>=0; iu--) {
980                ProcessState ps = uids.valueAt(iu);
981                if (ps.isInUse()) {
982                    uids.valueAt(iu).resetSafely(now);
983                } else {
984                    uids.valueAt(iu).makeDead();
985                    uids.removeAt(iu);
986                }
987            }
988            if (uids.size() <= 0) {
989                procMap.removeAt(ip);
990            }
991        }
992        ArrayMap<String, SparseArray<PackageState>> pkgMap = mPackages.getMap();
993        for (int ip=pkgMap.size()-1; ip>=0; ip--) {
994            SparseArray<PackageState> uids = pkgMap.valueAt(ip);
995            for (int iu=uids.size()-1; iu>=0; iu--) {
996                PackageState pkgState = uids.valueAt(iu);
997                for (int iproc=pkgState.mProcesses.size()-1; iproc>=0; iproc--) {
998                    ProcessState ps = pkgState.mProcesses.valueAt(iproc);
999                    if (ps.isInUse() || ps.mCommonProcess.isInUse()) {
1000                        pkgState.mProcesses.valueAt(iproc).resetSafely(now);
1001                    } else {
1002                        pkgState.mProcesses.valueAt(iproc).makeDead();
1003                        pkgState.mProcesses.removeAt(iproc);
1004                    }
1005                }
1006                for (int isvc=pkgState.mServices.size()-1; isvc>=0; isvc--) {
1007                    ServiceState ss = pkgState.mServices.valueAt(isvc);
1008                    if (ss.isInUse()) {
1009                        pkgState.mServices.valueAt(isvc).resetSafely(now);
1010                    } else {
1011                        pkgState.mServices.removeAt(isvc);
1012                    }
1013                }
1014                if (pkgState.mProcesses.size() <= 0 && pkgState.mServices.size() <= 0) {
1015                    uids.removeAt(iu);
1016                }
1017            }
1018            if (uids.size() <= 0) {
1019                pkgMap.removeAt(ip);
1020            }
1021        }
1022        mStartTime = now;
1023        if (DEBUG) Slog.d(TAG, "State reset; now " + mTimePeriodStartClockStr);
1024    }
1025
1026    private void resetCommon() {
1027        mTimePeriodStartClock = System.currentTimeMillis();
1028        buildTimePeriodStartClockStr();
1029        mTimePeriodStartRealtime = mTimePeriodEndRealtime = SystemClock.elapsedRealtime();
1030        mLongs.clear();
1031        mLongs.add(new long[LONGS_SIZE]);
1032        mNextLong = 0;
1033        Arrays.fill(mMemFactorDurations, 0);
1034        mStartTime = 0;
1035        mReadError = null;
1036        mFlags = 0;
1037        evaluateSystemProperties(true);
1038    }
1039
1040    public boolean evaluateSystemProperties(boolean update) {
1041        boolean changed = false;
1042        String runtime = SystemProperties.get("persist.sys.dalvik.vm.lib",
1043                VMRuntime.getRuntime().vmLibrary());
1044        if (!Objects.equals(runtime, mRuntime)) {
1045            changed = true;
1046            if (update) {
1047                mRuntime = runtime;
1048            }
1049        }
1050        String webview = WebViewFactory.useExperimentalWebView() ? "chromeview" : "webview";
1051        if (!Objects.equals(webview, mWebView)) {
1052            changed = true;
1053            if (update) {
1054                mWebView = webview;
1055            }
1056        }
1057        return changed;
1058    }
1059
1060    private void buildTimePeriodStartClockStr() {
1061        mTimePeriodStartClockStr = DateFormat.format("yyyy-MM-dd-HH-mm-ss",
1062                mTimePeriodStartClock).toString();
1063    }
1064
1065    static final int[] BAD_TABLE = new int[0];
1066
1067    private int[] readTableFromParcel(Parcel in, String name, String what) {
1068        final int size = in.readInt();
1069        if (size < 0) {
1070            Slog.w(TAG, "Ignoring existing stats; bad " + what + " table size: " + size);
1071            return BAD_TABLE;
1072        }
1073        if (size == 0) {
1074            return null;
1075        }
1076        final int[] table = new int[size];
1077        for (int i=0; i<size; i++) {
1078            table[i] = in.readInt();
1079            if (DEBUG) Slog.i(TAG, "Reading in " + name + " table #" + i + ": "
1080                    + ProcessStats.printLongOffset(table[i]));
1081            if (!validateLongOffset(table[i])) {
1082                Slog.w(TAG, "Ignoring existing stats; bad " + what + " table entry: "
1083                        + ProcessStats.printLongOffset(table[i]));
1084                return null;
1085            }
1086        }
1087        return table;
1088    }
1089
1090    private void writeCompactedLongArray(Parcel out, long[] array, int num) {
1091        for (int i=0; i<num; i++) {
1092            long val = array[i];
1093            if (val < 0) {
1094                Slog.w(TAG, "Time val negative: " + val);
1095                val = 0;
1096            }
1097            if (val <= Integer.MAX_VALUE) {
1098                out.writeInt((int)val);
1099            } else {
1100                int top = ~((int)((val>>32)&0x7fffffff));
1101                int bottom = (int)(val&0xfffffff);
1102                out.writeInt(top);
1103                out.writeInt(bottom);
1104            }
1105        }
1106    }
1107
1108    private void readCompactedLongArray(Parcel in, int version, long[] array, int num) {
1109        if (version <= 10) {
1110            in.readLongArray(array);
1111            return;
1112        }
1113        final int alen = array.length;
1114        if (num > alen) {
1115            throw new RuntimeException("bad array lengths: got " + num + " array is " + alen);
1116        }
1117        int i;
1118        for (i=0; i<num; i++) {
1119            int val = in.readInt();
1120            if (val >= 0) {
1121                array[i] = val;
1122            } else {
1123                int bottom = in.readInt();
1124                array[i] = (((long)~val)<<32) | bottom;
1125            }
1126        }
1127        while (i < alen) {
1128            array[i] = 0;
1129            i++;
1130        }
1131    }
1132
1133    private void writeCommonString(Parcel out, String name) {
1134        Integer index = mCommonStringToIndex.get(name);
1135        if (index != null) {
1136            out.writeInt(index);
1137            return;
1138        }
1139        index = mCommonStringToIndex.size();
1140        mCommonStringToIndex.put(name, index);
1141        out.writeInt(~index);
1142        out.writeString(name);
1143    }
1144
1145    private String readCommonString(Parcel in, int version) {
1146        if (version <= 9) {
1147            return in.readString();
1148        }
1149        int index = in.readInt();
1150        if (index >= 0) {
1151            return mIndexToCommonString.get(index);
1152        }
1153        index = ~index;
1154        String name = in.readString();
1155        while (mIndexToCommonString.size() <= index) {
1156            mIndexToCommonString.add(null);
1157        }
1158        mIndexToCommonString.set(index, name);
1159        return name;
1160    }
1161
1162    @Override
1163    public int describeContents() {
1164        return 0;
1165    }
1166
1167    @Override
1168    public void writeToParcel(Parcel out, int flags) {
1169        long now = SystemClock.uptimeMillis();
1170        out.writeInt(MAGIC);
1171        out.writeInt(PARCEL_VERSION);
1172        out.writeInt(STATE_COUNT);
1173        out.writeInt(ADJ_COUNT);
1174        out.writeInt(PSS_COUNT);
1175        out.writeInt(LONGS_SIZE);
1176
1177        mCommonStringToIndex = new ArrayMap<String, Integer>(mProcesses.mMap.size());
1178
1179        // First commit all running times.
1180        ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap();
1181        final int NPROC = procMap.size();
1182        for (int ip=0; ip<NPROC; ip++) {
1183            SparseArray<ProcessState> uids = procMap.valueAt(ip);
1184            final int NUID = uids.size();
1185            for (int iu=0; iu<NUID; iu++) {
1186                uids.valueAt(iu).commitStateTime(now);
1187            }
1188        }
1189        ArrayMap<String, SparseArray<PackageState>> pkgMap = mPackages.getMap();
1190        final int NPKG = pkgMap.size();
1191        for (int ip=0; ip<NPKG; ip++) {
1192            SparseArray<PackageState> uids = pkgMap.valueAt(ip);
1193            final int NUID = uids.size();
1194            for (int iu=0; iu<NUID; iu++) {
1195                PackageState pkgState = uids.valueAt(iu);
1196                final int NPROCS = pkgState.mProcesses.size();
1197                for (int iproc=0; iproc<NPROCS; iproc++) {
1198                    ProcessState proc = pkgState.mProcesses.valueAt(iproc);
1199                    if (proc.mCommonProcess != proc) {
1200                        proc.commitStateTime(now);
1201                    }
1202                }
1203                final int NSRVS = pkgState.mServices.size();
1204                for (int isvc=0; isvc<NSRVS; isvc++) {
1205                    pkgState.mServices.valueAt(isvc).commitStateTime(now);
1206                }
1207            }
1208        }
1209
1210        out.writeLong(mTimePeriodStartClock);
1211        out.writeLong(mTimePeriodStartRealtime);
1212        out.writeLong(mTimePeriodEndRealtime);
1213        out.writeString(mRuntime);
1214        out.writeString(mWebView);
1215        out.writeInt(mFlags);
1216
1217        out.writeInt(mLongs.size());
1218        out.writeInt(mNextLong);
1219        for (int i=0; i<(mLongs.size()-1); i++) {
1220            long[] array = mLongs.get(i);
1221            writeCompactedLongArray(out, array, array.length);
1222        }
1223        long[] lastLongs = mLongs.get(mLongs.size() - 1);
1224        writeCompactedLongArray(out, lastLongs, mNextLong);
1225
1226        if (mMemFactor != STATE_NOTHING) {
1227            mMemFactorDurations[mMemFactor] += now - mStartTime;
1228            mStartTime = now;
1229        }
1230        writeCompactedLongArray(out, mMemFactorDurations, mMemFactorDurations.length);
1231
1232        out.writeInt(NPROC);
1233        for (int ip=0; ip<NPROC; ip++) {
1234            writeCommonString(out, procMap.keyAt(ip));
1235            SparseArray<ProcessState> uids = procMap.valueAt(ip);
1236            final int NUID = uids.size();
1237            out.writeInt(NUID);
1238            for (int iu=0; iu<NUID; iu++) {
1239                out.writeInt(uids.keyAt(iu));
1240                ProcessState proc = uids.valueAt(iu);
1241                writeCommonString(out, proc.mPackage);
1242                proc.writeToParcel(out, now);
1243            }
1244        }
1245        out.writeInt(NPKG);
1246        for (int ip=0; ip<NPKG; ip++) {
1247            writeCommonString(out, pkgMap.keyAt(ip));
1248            SparseArray<PackageState> uids = pkgMap.valueAt(ip);
1249            final int NUID = uids.size();
1250            out.writeInt(NUID);
1251            for (int iu=0; iu<NUID; iu++) {
1252                out.writeInt(uids.keyAt(iu));
1253                PackageState pkgState = uids.valueAt(iu);
1254                final int NPROCS = pkgState.mProcesses.size();
1255                out.writeInt(NPROCS);
1256                for (int iproc=0; iproc<NPROCS; iproc++) {
1257                    writeCommonString(out, pkgState.mProcesses.keyAt(iproc));
1258                    ProcessState proc = pkgState.mProcesses.valueAt(iproc);
1259                    if (proc.mCommonProcess == proc) {
1260                        // This is the same as the common process we wrote above.
1261                        out.writeInt(0);
1262                    } else {
1263                        // There is separate data for this package's process.
1264                        out.writeInt(1);
1265                        proc.writeToParcel(out, now);
1266                    }
1267                }
1268                final int NSRVS = pkgState.mServices.size();
1269                out.writeInt(NSRVS);
1270                for (int isvc=0; isvc<NSRVS; isvc++) {
1271                    out.writeString(pkgState.mServices.keyAt(isvc));
1272                    ServiceState svc = pkgState.mServices.valueAt(isvc);
1273                    writeCommonString(out, svc.mProcessName);
1274                    svc.writeToParcel(out, now);
1275                }
1276            }
1277        }
1278
1279        mCommonStringToIndex = null;
1280    }
1281
1282    private boolean readCheckedInt(Parcel in, int val, String what) {
1283        int got;
1284        if ((got=in.readInt()) != val) {
1285            mReadError = "bad " + what + ": " + got;
1286            return false;
1287        }
1288        return true;
1289    }
1290
1291    static byte[] readFully(InputStream stream, int[] outLen) throws IOException {
1292        int pos = 0;
1293        final int initialAvail = stream.available();
1294        byte[] data = new byte[initialAvail > 0 ? (initialAvail+1) : 16384];
1295        while (true) {
1296            int amt = stream.read(data, pos, data.length-pos);
1297            if (DEBUG) Slog.i("foo", "Read " + amt + " bytes at " + pos
1298                    + " of avail " + data.length);
1299            if (amt < 0) {
1300                if (DEBUG) Slog.i("foo", "**** FINISHED READING: pos=" + pos
1301                        + " len=" + data.length);
1302                outLen[0] = pos;
1303                return data;
1304            }
1305            pos += amt;
1306            if (pos >= data.length) {
1307                byte[] newData = new byte[pos+16384];
1308                if (DEBUG) Slog.i(TAG, "Copying " + pos + " bytes to new array len "
1309                        + newData.length);
1310                System.arraycopy(data, 0, newData, 0, pos);
1311                data = newData;
1312            }
1313        }
1314    }
1315
1316    public void read(InputStream stream) {
1317        try {
1318            int[] len = new int[1];
1319            byte[] raw = readFully(stream, len);
1320            Parcel in = Parcel.obtain();
1321            in.unmarshall(raw, 0, len[0]);
1322            in.setDataPosition(0);
1323            stream.close();
1324
1325            readFromParcel(in);
1326        } catch (IOException e) {
1327            mReadError = "caught exception: " + e;
1328        }
1329    }
1330
1331    public void readFromParcel(Parcel in) {
1332        final boolean hadData = mPackages.getMap().size() > 0
1333                || mProcesses.getMap().size() > 0;
1334        if (hadData) {
1335            resetSafely();
1336        }
1337
1338        if (!readCheckedInt(in, MAGIC, "magic number")) {
1339            return;
1340        }
1341        int version = in.readInt();
1342        if (version != PARCEL_VERSION) {
1343            mReadError = "bad version: " + version;
1344            return;
1345        }
1346        if (!readCheckedInt(in, STATE_COUNT, "state count")) {
1347            return;
1348        }
1349        if (!readCheckedInt(in, ADJ_COUNT, "adj count")) {
1350            return;
1351        }
1352        if (!readCheckedInt(in, PSS_COUNT, "pss count")) {
1353            return;
1354        }
1355        if (!readCheckedInt(in, LONGS_SIZE, "longs size")) {
1356            return;
1357        }
1358
1359        mIndexToCommonString = new ArrayList<String>();
1360
1361        mTimePeriodStartClock = in.readLong();
1362        buildTimePeriodStartClockStr();
1363        mTimePeriodStartRealtime = in.readLong();
1364        mTimePeriodEndRealtime = in.readLong();
1365        mRuntime = in.readString();
1366        mWebView = in.readString();
1367        mFlags = in.readInt();
1368
1369        final int NLONGS = in.readInt();
1370        final int NEXTLONG = in.readInt();
1371        mLongs.clear();
1372        for (int i=0; i<(NLONGS-1); i++) {
1373            while (i >= mLongs.size()) {
1374                mLongs.add(new long[LONGS_SIZE]);
1375            }
1376            readCompactedLongArray(in, version, mLongs.get(i), LONGS_SIZE);
1377        }
1378        long[] longs = new long[LONGS_SIZE];
1379        mNextLong = NEXTLONG;
1380        readCompactedLongArray(in, version, longs, NEXTLONG);
1381        mLongs.add(longs);
1382
1383        readCompactedLongArray(in, version, mMemFactorDurations, mMemFactorDurations.length);
1384
1385        int NPROC = in.readInt();
1386        if (NPROC < 0) {
1387            mReadError = "bad process count: " + NPROC;
1388            return;
1389        }
1390        while (NPROC > 0) {
1391            NPROC--;
1392            String procName = readCommonString(in, version);
1393            if (procName == null) {
1394                mReadError = "bad process name";
1395                return;
1396            }
1397            int NUID = in.readInt();
1398            if (NUID < 0) {
1399                mReadError = "bad uid count: " + NUID;
1400                return;
1401            }
1402            while (NUID > 0) {
1403                NUID--;
1404                int uid = in.readInt();
1405                if (uid < 0) {
1406                    mReadError = "bad uid: " + uid;
1407                    return;
1408                }
1409                String pkgName = readCommonString(in, version);
1410                if (pkgName == null) {
1411                    mReadError = "bad process package name";
1412                    return;
1413                }
1414                ProcessState proc = hadData ? mProcesses.get(procName, uid) : null;
1415                if (proc != null) {
1416                    if (!proc.readFromParcel(in, false)) {
1417                        return;
1418                    }
1419                } else {
1420                    proc = new ProcessState(this, pkgName, uid, procName);
1421                    if (!proc.readFromParcel(in, true)) {
1422                        return;
1423                    }
1424                }
1425                if (DEBUG) Slog.d(TAG, "Adding process: " + procName + " " + uid + " " + proc);
1426                mProcesses.put(procName, uid, proc);
1427            }
1428        }
1429
1430        if (DEBUG) Slog.d(TAG, "Read " + mProcesses.getMap().size() + " processes");
1431
1432        int NPKG = in.readInt();
1433        if (NPKG < 0) {
1434            mReadError = "bad package count: " + NPKG;
1435            return;
1436        }
1437        while (NPKG > 0) {
1438            NPKG--;
1439            String pkgName = readCommonString(in, version);
1440            if (pkgName == null) {
1441                mReadError = "bad package name";
1442                return;
1443            }
1444            int NUID = in.readInt();
1445            if (NUID < 0) {
1446                mReadError = "bad uid count: " + NUID;
1447                return;
1448            }
1449            while (NUID > 0) {
1450                NUID--;
1451                int uid = in.readInt();
1452                if (uid < 0) {
1453                    mReadError = "bad uid: " + uid;
1454                    return;
1455                }
1456                PackageState pkgState = new PackageState(pkgName, uid);
1457                mPackages.put(pkgName, uid, pkgState);
1458                int NPROCS = in.readInt();
1459                if (NPROCS < 0) {
1460                    mReadError = "bad package process count: " + NPROCS;
1461                    return;
1462                }
1463                while (NPROCS > 0) {
1464                    NPROCS--;
1465                    String procName = readCommonString(in, version);
1466                    if (procName == null) {
1467                        mReadError = "bad package process name";
1468                        return;
1469                    }
1470                    int hasProc = in.readInt();
1471                    if (DEBUG) Slog.d(TAG, "Reading package " + pkgName + " " + uid
1472                            + " process " + procName + " hasProc=" + hasProc);
1473                    ProcessState commonProc = mProcesses.get(procName, uid);
1474                    if (DEBUG) Slog.d(TAG, "Got common proc " + procName + " " + uid
1475                            + ": " + commonProc);
1476                    if (commonProc == null) {
1477                        mReadError = "no common proc: " + procName;
1478                        return;
1479                    }
1480                    if (hasProc != 0) {
1481                        // The process for this package is unique to the package; we
1482                        // need to load it.  We don't need to do anything about it if
1483                        // it is not unique because if someone later looks for it
1484                        // they will find and use it from the global procs.
1485                        ProcessState proc = hadData ? pkgState.mProcesses.get(procName) : null;
1486                        if (proc != null) {
1487                            if (!proc.readFromParcel(in, false)) {
1488                                return;
1489                            }
1490                        } else {
1491                            proc = new ProcessState(commonProc, pkgName, uid, procName, 0);
1492                            if (!proc.readFromParcel(in, true)) {
1493                                return;
1494                            }
1495                        }
1496                        if (DEBUG) Slog.d(TAG, "Adding package " + pkgName + " process: "
1497                                + procName + " " + uid + " " + proc);
1498                        pkgState.mProcesses.put(procName, proc);
1499                    } else {
1500                        if (DEBUG) Slog.d(TAG, "Adding package " + pkgName + " process: "
1501                                + procName + " " + uid + " " + commonProc);
1502                        pkgState.mProcesses.put(procName, commonProc);
1503                    }
1504                }
1505                int NSRVS = in.readInt();
1506                if (NSRVS < 0) {
1507                    mReadError = "bad package service count: " + NSRVS;
1508                    return;
1509                }
1510                while (NSRVS > 0) {
1511                    NSRVS--;
1512                    String serviceName = in.readString();
1513                    if (serviceName == null) {
1514                        mReadError = "bad package service name";
1515                        return;
1516                    }
1517                    String processName = version > 9 ? readCommonString(in, version) : null;
1518                    ServiceState serv = hadData ? pkgState.mServices.get(serviceName) : null;
1519                    if (serv == null) {
1520                        serv = new ServiceState(this, pkgName, serviceName, processName, null);
1521                    }
1522                    if (!serv.readFromParcel(in)) {
1523                        return;
1524                    }
1525                    if (DEBUG) Slog.d(TAG, "Adding package " + pkgName + " service: "
1526                            + serviceName + " " + uid + " " + serv);
1527                    pkgState.mServices.put(serviceName, serv);
1528                }
1529            }
1530        }
1531
1532        mIndexToCommonString = null;
1533
1534        if (DEBUG) Slog.d(TAG, "Successfully read procstats!");
1535    }
1536
1537    int addLongData(int index, int type, int num) {
1538        int tableLen = mAddLongTable != null ? mAddLongTable.length : 0;
1539        if (mAddLongTableSize >= tableLen) {
1540            int newSize = ArrayUtils.idealIntArraySize(tableLen + 1);
1541            int[] newTable = new int[newSize];
1542            if (tableLen > 0) {
1543                System.arraycopy(mAddLongTable, 0, newTable, 0, tableLen);
1544            }
1545            mAddLongTable = newTable;
1546        }
1547        if (mAddLongTableSize > 0 && mAddLongTableSize - index != 0) {
1548            System.arraycopy(mAddLongTable, index, mAddLongTable, index + 1,
1549                    mAddLongTableSize - index);
1550        }
1551        int off = allocLongData(num);
1552        mAddLongTable[index] = type | off;
1553        mAddLongTableSize++;
1554        return off;
1555    }
1556
1557    int allocLongData(int num) {
1558        int whichLongs = mLongs.size()-1;
1559        long[] longs = mLongs.get(whichLongs);
1560        if (mNextLong + num > longs.length) {
1561            longs = new long[LONGS_SIZE];
1562            mLongs.add(longs);
1563            whichLongs++;
1564            mNextLong = 0;
1565        }
1566        int off = (whichLongs<<OFFSET_ARRAY_SHIFT) | (mNextLong<<OFFSET_INDEX_SHIFT);
1567        mNextLong += num;
1568        return off;
1569    }
1570
1571    boolean validateLongOffset(int off) {
1572        int arr = (off>>OFFSET_ARRAY_SHIFT)&OFFSET_ARRAY_MASK;
1573        if (arr >= mLongs.size()) {
1574            return false;
1575        }
1576        int idx = (off>>OFFSET_INDEX_SHIFT)&OFFSET_INDEX_MASK;
1577        if (idx >= LONGS_SIZE) {
1578            return false;
1579        }
1580        if (DEBUG) Slog.d(TAG, "Validated long " + printLongOffset(off)
1581                + ": " + getLong(off, 0));
1582        return true;
1583    }
1584
1585    static String printLongOffset(int off) {
1586        StringBuilder sb = new StringBuilder(16);
1587        sb.append("a"); sb.append((off>>OFFSET_ARRAY_SHIFT)&OFFSET_ARRAY_MASK);
1588        sb.append("i"); sb.append((off>>OFFSET_INDEX_SHIFT)&OFFSET_INDEX_MASK);
1589        sb.append("t"); sb.append((off>>OFFSET_TYPE_SHIFT)&OFFSET_TYPE_MASK);
1590        return sb.toString();
1591    }
1592
1593    void setLong(int off, int index, long value) {
1594        long[] longs = mLongs.get((off>>OFFSET_ARRAY_SHIFT)&OFFSET_ARRAY_MASK);
1595        longs[index + ((off>>OFFSET_INDEX_SHIFT)&OFFSET_INDEX_MASK)] = value;
1596    }
1597
1598    long getLong(int off, int index) {
1599        long[] longs = mLongs.get((off>>OFFSET_ARRAY_SHIFT)&OFFSET_ARRAY_MASK);
1600        return longs[index + ((off>>OFFSET_INDEX_SHIFT)&OFFSET_INDEX_MASK)];
1601    }
1602
1603    static int binarySearch(int[] array, int size, int value) {
1604        int lo = 0;
1605        int hi = size - 1;
1606
1607        while (lo <= hi) {
1608            int mid = (lo + hi) >>> 1;
1609            int midVal = (array[mid] >> OFFSET_TYPE_SHIFT) & OFFSET_TYPE_MASK;
1610
1611            if (midVal < value) {
1612                lo = mid + 1;
1613            } else if (midVal > value) {
1614                hi = mid - 1;
1615            } else {
1616                return mid;  // value found
1617            }
1618        }
1619        return ~lo;  // value not present
1620    }
1621
1622    public PackageState getPackageStateLocked(String packageName, int uid) {
1623        PackageState as = mPackages.get(packageName, uid);
1624        if (as != null) {
1625            return as;
1626        }
1627        as = new PackageState(packageName, uid);
1628        mPackages.put(packageName, uid, as);
1629        return as;
1630    }
1631
1632    public ProcessState getProcessStateLocked(String packageName, int uid, String processName) {
1633        final PackageState pkgState = getPackageStateLocked(packageName, uid);
1634        ProcessState ps = pkgState.mProcesses.get(processName);
1635        if (ps != null) {
1636            return ps;
1637        }
1638        ProcessState commonProc = mProcesses.get(processName, uid);
1639        if (commonProc == null) {
1640            commonProc = new ProcessState(this, packageName, uid, processName);
1641            mProcesses.put(processName, uid, commonProc);
1642        }
1643        if (!commonProc.mMultiPackage) {
1644            if (packageName.equals(commonProc.mPackage)) {
1645                // This common process is not in use by multiple packages, and
1646                // is for the calling package, so we can just use it directly.
1647                ps = commonProc;
1648            } else {
1649                // This common process has not been in use by multiple packages,
1650                // but it was created for a different package than the caller.
1651                // We need to convert it to a multi-package process.
1652                commonProc.mMultiPackage = true;
1653                // To do this, we need to make two new process states, one a copy
1654                // of the current state for the process under the original package
1655                // name, and the second a free new process state for it as the
1656                // new package name.
1657                long now = SystemClock.uptimeMillis();
1658                // First let's make a copy of the current process state and put
1659                // that under the now unique state for its original package name.
1660                final PackageState commonPkgState = getPackageStateLocked(commonProc.mPackage, uid);
1661                if (commonPkgState != null) {
1662                    commonPkgState.mProcesses.put(commonProc.mName, commonProc.clone(
1663                            commonProc.mPackage, now));
1664                } else {
1665                    Slog.w(TAG, "Cloning proc state: no package state " + commonProc.mPackage
1666                            + "/" + uid + " for proc " + commonProc.mName);
1667                }
1668                // And now make a fresh new process state for the new package name.
1669                ps = new ProcessState(commonProc, packageName, uid, processName, now);
1670            }
1671        } else {
1672            // The common process is for multiple packages, we need to create a
1673            // separate object for the per-package data.
1674            ps = new ProcessState(commonProc, packageName, uid, processName,
1675                    SystemClock.uptimeMillis());
1676        }
1677        pkgState.mProcesses.put(processName, ps);
1678        return ps;
1679    }
1680
1681    public ProcessStats.ServiceState getServiceStateLocked(String packageName, int uid,
1682            String processName, String className) {
1683        final ProcessStats.PackageState as = getPackageStateLocked(packageName, uid);
1684        ProcessStats.ServiceState ss = as.mServices.get(className);
1685        if (ss != null) {
1686            return ss;
1687        }
1688        final ProcessStats.ProcessState ps = processName != null
1689                ? getProcessStateLocked(packageName, uid, processName) : null;
1690        ss = new ProcessStats.ServiceState(this, packageName, className, processName, ps);
1691        as.mServices.put(className, ss);
1692        return ss;
1693    }
1694
1695    private void dumpProcessInternalLocked(PrintWriter pw, String prefix, ProcessState proc,
1696            boolean dumpAll) {
1697        if (dumpAll) {
1698            pw.print(prefix); pw.print("myID=");
1699                    pw.print(Integer.toHexString(System.identityHashCode(proc)));
1700                    pw.print(" mCommonProcess=");
1701                    pw.print(Integer.toHexString(System.identityHashCode(proc.mCommonProcess)));
1702                    pw.print(" mPackage="); pw.println(proc.mPackage);
1703            if (proc.mMultiPackage) {
1704                pw.print(prefix); pw.print("mMultiPackage="); pw.println(proc.mMultiPackage);
1705            }
1706            if (proc != proc.mCommonProcess) {
1707                pw.print(prefix); pw.print("Common Proc: "); pw.print(proc.mCommonProcess.mName);
1708                        pw.print("/"); pw.print(proc.mCommonProcess.mUid);
1709                        pw.print(" pkg="); pw.println(proc.mCommonProcess.mPackage);
1710            }
1711        }
1712        pw.print(prefix); pw.print("mActive="); pw.println(proc.mActive);
1713        if (proc.mDead) {
1714            pw.print(prefix); pw.print("mDead="); pw.println(proc.mDead);
1715        }
1716        pw.print(prefix); pw.print("mNumActiveServices="); pw.print(proc.mNumActiveServices);
1717                pw.print(" mNumStartedServices=");
1718                pw.println(proc.mNumStartedServices);
1719    }
1720
1721    public void dumpLocked(PrintWriter pw, String reqPackage, long now, boolean dumpSummary,
1722            boolean dumpAll) {
1723        long totalTime = dumpSingleTime(null, null, mMemFactorDurations, mMemFactor,
1724                mStartTime, now);
1725        ArrayMap<String, SparseArray<PackageState>> pkgMap = mPackages.getMap();
1726        boolean printedHeader = false;
1727        for (int ip=0; ip<pkgMap.size(); ip++) {
1728            String pkgName = pkgMap.keyAt(ip);
1729            if (reqPackage != null && !reqPackage.equals(pkgName)) {
1730                continue;
1731            }
1732            SparseArray<PackageState> uids = pkgMap.valueAt(ip);
1733            for (int iu=0; iu<uids.size(); iu++) {
1734                int uid = uids.keyAt(iu);
1735                PackageState pkgState = uids.valueAt(iu);
1736                final int NPROCS = pkgState.mProcesses.size();
1737                final int NSRVS = pkgState.mServices.size();
1738                if (NPROCS > 0 || NSRVS > 0) {
1739                    if (!printedHeader) {
1740                        pw.println("Per-Package Stats:");
1741                        printedHeader = true;
1742                    }
1743                    pw.print("  * "); pw.print(pkgName); pw.print(" / ");
1744                            UserHandle.formatUid(pw, uid); pw.println(":");
1745                }
1746                if (!dumpSummary || dumpAll) {
1747                    for (int iproc=0; iproc<NPROCS; iproc++) {
1748                        ProcessState proc = pkgState.mProcesses.valueAt(iproc);
1749                        pw.print("      Process ");
1750                        pw.print(pkgState.mProcesses.keyAt(iproc));
1751                        pw.print(" (");
1752                        pw.print(proc.mDurationsTableSize);
1753                        pw.print(" entries)");
1754                        pw.println(":");
1755                        dumpProcessState(pw, "        ", proc, ALL_SCREEN_ADJ, ALL_MEM_ADJ,
1756                                ALL_PROC_STATES, now);
1757                        dumpProcessPss(pw, "        ", proc, ALL_SCREEN_ADJ, ALL_MEM_ADJ,
1758                                ALL_PROC_STATES);
1759                        dumpProcessInternalLocked(pw, "        ", proc, dumpAll);
1760                    }
1761                } else {
1762                    ArrayList<ProcessState> procs = new ArrayList<ProcessState>();
1763                    for (int iproc=0; iproc<NPROCS; iproc++) {
1764                        procs.add(pkgState.mProcesses.valueAt(iproc));
1765                    }
1766                    dumpProcessSummaryLocked(pw, "      ", procs, ALL_SCREEN_ADJ, ALL_MEM_ADJ,
1767                            NON_CACHED_PROC_STATES, now, totalTime);
1768                }
1769                for (int isvc=0; isvc<NSRVS; isvc++) {
1770                    if (dumpAll) {
1771                        pw.print("      Service ");
1772                    } else {
1773                        pw.print("      * ");
1774                    }
1775                    pw.print(pkgState.mServices.keyAt(isvc));
1776                    pw.println(":");
1777                    ServiceState svc = pkgState.mServices.valueAt(isvc);
1778                    pw.print("        Process: "); pw.println(svc.mProcessName);
1779                    dumpServiceStats(pw, "        ", "          ", "    ", "Running", svc,
1780                            svc.mRunCount, ServiceState.SERVICE_RUN, svc.mRunState,
1781                            svc.mRunStartTime, now, totalTime, !dumpSummary || dumpAll);
1782                    dumpServiceStats(pw, "        ", "          ", "    ", "Started", svc,
1783                            svc.mStartedCount, ServiceState.SERVICE_STARTED, svc.mStartedState,
1784                            svc.mStartedStartTime, now, totalTime, !dumpSummary || dumpAll);
1785                    dumpServiceStats(pw, "        ", "          ", "      ", "Bound", svc,
1786                            svc.mBoundCount, ServiceState.SERVICE_BOUND, svc.mBoundState,
1787                            svc.mBoundStartTime, now, totalTime, !dumpSummary || dumpAll);
1788                    dumpServiceStats(pw, "        ", "          ", "  ", "Executing", svc,
1789                            svc.mExecCount, ServiceState.SERVICE_EXEC, svc.mExecState,
1790                            svc.mExecStartTime, now, totalTime, !dumpSummary || dumpAll);
1791                    if (dumpAll) {
1792                        pw.print("        mActive="); pw.println(svc.mActive);
1793                    }
1794                }
1795            }
1796        }
1797
1798        if (reqPackage == null) {
1799            ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap();
1800            printedHeader = false;
1801            int numShownProcs = 0, numTotalProcs = 0;
1802            for (int ip=0; ip<procMap.size(); ip++) {
1803                String procName = procMap.keyAt(ip);
1804                SparseArray<ProcessState> uids = procMap.valueAt(ip);
1805                for (int iu=0; iu<uids.size(); iu++) {
1806                    int uid = uids.keyAt(iu);
1807                    numTotalProcs++;
1808                    ProcessState proc = uids.valueAt(iu);
1809                    if (proc.mDurationsTableSize == 0 && proc.mCurState == STATE_NOTHING
1810                            && proc.mPssTableSize == 0) {
1811                        continue;
1812                    }
1813                    numShownProcs++;
1814                    if (!printedHeader) {
1815                        pw.println();
1816                        pw.println("Per-Process Stats:");
1817                        printedHeader = true;
1818                    }
1819                    pw.print("  * "); pw.print(procName); pw.print(" / ");
1820                            UserHandle.formatUid(pw, uid);
1821                            pw.print(" ("); pw.print(proc.mDurationsTableSize);
1822                            pw.print(" entries)"); pw.println(":");
1823                    dumpProcessState(pw, "        ", proc, ALL_SCREEN_ADJ, ALL_MEM_ADJ,
1824                            ALL_PROC_STATES, now);
1825                    dumpProcessPss(pw, "        ", proc, ALL_SCREEN_ADJ, ALL_MEM_ADJ,
1826                            ALL_PROC_STATES);
1827                    if (dumpAll) {
1828                        dumpProcessInternalLocked(pw, "        ", proc, dumpAll);
1829                    }
1830                }
1831            }
1832            if (dumpAll) {
1833                pw.println();
1834                pw.print("  Total procs: "); pw.print(numShownProcs);
1835                        pw.print(" shown of "); pw.print(numTotalProcs); pw.println(" total");
1836            }
1837
1838            pw.println();
1839            if (dumpSummary) {
1840                pw.println("Summary:");
1841                dumpSummaryLocked(pw, reqPackage, now);
1842            } else {
1843                dumpTotalsLocked(pw, now);
1844            }
1845        } else {
1846            pw.println();
1847            dumpTotalsLocked(pw, now);
1848        }
1849
1850        if (dumpAll) {
1851            pw.println();
1852            pw.println("Internal state:");
1853            pw.print("  Num long arrays: "); pw.println(mLongs.size());
1854            pw.print("  Next long entry: "); pw.println(mNextLong);
1855            pw.print("  mRunning="); pw.println(mRunning);
1856        }
1857    }
1858
1859    public static long dumpSingleServiceTime(PrintWriter pw, String prefix, ServiceState service,
1860            int serviceType, int curState, long curStartTime, long now) {
1861        long totalTime = 0;
1862        int printedScreen = -1;
1863        for (int iscreen=0; iscreen<ADJ_COUNT; iscreen+=ADJ_SCREEN_MOD) {
1864            int printedMem = -1;
1865            for (int imem=0; imem<ADJ_MEM_FACTOR_COUNT; imem++) {
1866                int state = imem+iscreen;
1867                long time = service.getDuration(serviceType, curState, curStartTime,
1868                        state, now);
1869                String running = "";
1870                if (curState == state && pw != null) {
1871                    running = " (running)";
1872                }
1873                if (time != 0) {
1874                    if (pw != null) {
1875                        pw.print(prefix);
1876                        printScreenLabel(pw, printedScreen != iscreen
1877                                ? iscreen : STATE_NOTHING);
1878                        printedScreen = iscreen;
1879                        printMemLabel(pw, printedMem != imem ? imem : STATE_NOTHING);
1880                        printedMem = imem;
1881                        TimeUtils.formatDuration(time, pw); pw.println(running);
1882                    }
1883                    totalTime += time;
1884                }
1885            }
1886        }
1887        if (totalTime != 0 && pw != null) {
1888            pw.print(prefix);
1889            printScreenLabel(pw, STATE_NOTHING);
1890            pw.print("TOTAL: ");
1891            TimeUtils.formatDuration(totalTime, pw);
1892            pw.println();
1893        }
1894        return totalTime;
1895    }
1896
1897    void dumpServiceStats(PrintWriter pw, String prefix, String prefixInner,
1898            String headerPrefix, String header, ServiceState service,
1899            int count, int serviceType, int state, long startTime, long now, long totalTime,
1900            boolean dumpAll) {
1901        if (count != 0) {
1902            if (dumpAll) {
1903                pw.print(prefix); pw.print(header);
1904                pw.print(" op count "); pw.print(count); pw.println(":");
1905                dumpSingleServiceTime(pw, prefixInner, service, serviceType, state, startTime,
1906                        now);
1907            } else {
1908                long myTime = dumpSingleServiceTime(null, null, service, serviceType, state,
1909                        startTime, now);
1910                pw.print(prefix); pw.print(headerPrefix); pw.print(header);
1911                pw.print(" count "); pw.print(count);
1912                pw.print(" / time ");
1913                printPercent(pw, (double)myTime/(double)totalTime);
1914                pw.println();
1915            }
1916        }
1917    }
1918
1919    public void dumpSummaryLocked(PrintWriter pw, String reqPackage, long now) {
1920        long totalTime = dumpSingleTime(null, null, mMemFactorDurations, mMemFactor,
1921                mStartTime, now);
1922        dumpFilteredSummaryLocked(pw, null, "  ", ALL_SCREEN_ADJ, ALL_MEM_ADJ,
1923                ALL_PROC_STATES, NON_CACHED_PROC_STATES, now, totalTime, reqPackage);
1924        pw.println();
1925        dumpTotalsLocked(pw, now);
1926    }
1927
1928    void dumpTotalsLocked(PrintWriter pw, long now) {
1929        pw.println("Run time Stats:");
1930        dumpSingleTime(pw, "  ", mMemFactorDurations, mMemFactor, mStartTime, now);
1931        pw.println();
1932        pw.print("          Start time: ");
1933        pw.print(DateFormat.format("yyyy-MM-dd HH:mm:ss", mTimePeriodStartClock));
1934        pw.println();
1935        pw.print("  Total elapsed time: ");
1936        TimeUtils.formatDuration(
1937                (mRunning ? SystemClock.elapsedRealtime() : mTimePeriodEndRealtime)
1938                        - mTimePeriodStartRealtime, pw);
1939        boolean partial = true;
1940        if ((mFlags&FLAG_SHUTDOWN) != 0) {
1941            pw.print(" (shutdown)");
1942            partial = false;
1943        }
1944        if ((mFlags&FLAG_SYSPROPS) != 0) {
1945            pw.print(" (sysprops)");
1946            partial = false;
1947        }
1948        if ((mFlags&FLAG_COMPLETE) != 0) {
1949            pw.print(" (complete)");
1950            partial = false;
1951        }
1952        if (partial) {
1953            pw.print(" (partial)");
1954        }
1955        pw.print(' ');
1956        pw.print(mRuntime);
1957        pw.print(' ');
1958        pw.print(mWebView);
1959        pw.println();
1960    }
1961
1962    void dumpFilteredSummaryLocked(PrintWriter pw, String header, String prefix,
1963            int[] screenStates, int[] memStates, int[] procStates,
1964            int[] sortProcStates, long now, long totalTime, String reqPackage) {
1965        ArrayList<ProcessState> procs = collectProcessesLocked(screenStates, memStates,
1966                procStates, sortProcStates, now, reqPackage);
1967        if (procs.size() > 0) {
1968            if (header != null) {
1969                pw.println();
1970                pw.println(header);
1971            }
1972            dumpProcessSummaryLocked(pw, prefix, procs, screenStates, memStates,
1973                    sortProcStates, now, totalTime);
1974        }
1975    }
1976
1977    public ArrayList<ProcessState> collectProcessesLocked(int[] screenStates, int[] memStates,
1978            int[] procStates, int sortProcStates[], long now, String reqPackage) {
1979        ArraySet<ProcessState> foundProcs = new ArraySet<ProcessState>();
1980        ArrayMap<String, SparseArray<PackageState>> pkgMap = mPackages.getMap();
1981        for (int ip=0; ip<pkgMap.size(); ip++) {
1982            if (reqPackage != null && !reqPackage.equals(pkgMap.keyAt(ip))) {
1983                continue;
1984            }
1985            SparseArray<PackageState> procs = pkgMap.valueAt(ip);
1986            for (int iu=0; iu<procs.size(); iu++) {
1987                PackageState state = procs.valueAt(iu);
1988                for (int iproc=0; iproc<state.mProcesses.size(); iproc++) {
1989                    ProcessState proc = state.mProcesses.valueAt(iproc);
1990                    foundProcs.add(proc.mCommonProcess);
1991                }
1992            }
1993        }
1994        ArrayList<ProcessState> outProcs = new ArrayList<ProcessState>(foundProcs.size());
1995        for (int i=0; i<foundProcs.size(); i++) {
1996            ProcessState proc = foundProcs.valueAt(i);
1997            if (computeProcessTimeLocked(proc, screenStates, memStates,
1998                    procStates, now) > 0) {
1999                outProcs.add(proc);
2000                if (procStates != sortProcStates) {
2001                    computeProcessTimeLocked(proc, screenStates, memStates, sortProcStates, now);
2002                }
2003            }
2004        }
2005        Collections.sort(outProcs, new Comparator<ProcessState>() {
2006            @Override
2007            public int compare(ProcessState lhs, ProcessState rhs) {
2008                if (lhs.mTmpTotalTime < rhs.mTmpTotalTime) {
2009                    return -1;
2010                } else if (lhs.mTmpTotalTime > rhs.mTmpTotalTime) {
2011                    return 1;
2012                }
2013                return 0;
2014            }
2015        });
2016        return outProcs;
2017    }
2018
2019    String collapseString(String pkgName, String itemName) {
2020        if (itemName.startsWith(pkgName)) {
2021            final int ITEMLEN = itemName.length();
2022            final int PKGLEN = pkgName.length();
2023            if (ITEMLEN == PKGLEN) {
2024                return "";
2025            } else if (ITEMLEN >= PKGLEN) {
2026                if (itemName.charAt(PKGLEN) == '.') {
2027                    return itemName.substring(PKGLEN);
2028                }
2029            }
2030        }
2031        return itemName;
2032    }
2033
2034    public void dumpCheckinLocked(PrintWriter pw, String reqPackage) {
2035        final long now = SystemClock.uptimeMillis();
2036        ArrayMap<String, SparseArray<PackageState>> pkgMap = mPackages.getMap();
2037        pw.println("vers,3");
2038        pw.print("period,"); pw.print(mTimePeriodStartClockStr);
2039        pw.print(","); pw.print(mTimePeriodStartRealtime); pw.print(",");
2040        pw.print(mRunning ? SystemClock.elapsedRealtime() : mTimePeriodEndRealtime);
2041        boolean partial = true;
2042        if ((mFlags&FLAG_SHUTDOWN) != 0) {
2043            pw.print(",shutdown");
2044            partial = false;
2045        }
2046        if ((mFlags&FLAG_SYSPROPS) != 0) {
2047            pw.print(",sysprops");
2048            partial = false;
2049        }
2050        if ((mFlags&FLAG_COMPLETE) != 0) {
2051            pw.print(",complete");
2052            partial = false;
2053        }
2054        if (partial) {
2055            pw.print(",partial");
2056        }
2057        pw.println();
2058        pw.print("config,"); pw.print(mRuntime); pw.print(','); pw.println(mWebView);
2059        for (int ip=0; ip<pkgMap.size(); ip++) {
2060            String pkgName = pkgMap.keyAt(ip);
2061            if (reqPackage != null && !reqPackage.equals(pkgName)) {
2062                continue;
2063            }
2064            SparseArray<PackageState> uids = pkgMap.valueAt(ip);
2065            for (int iu=0; iu<uids.size(); iu++) {
2066                int uid = uids.keyAt(iu);
2067                PackageState pkgState = uids.valueAt(iu);
2068                final int NPROCS = pkgState.mProcesses.size();
2069                final int NSRVS = pkgState.mServices.size();
2070                for (int iproc=0; iproc<NPROCS; iproc++) {
2071                    ProcessState proc = pkgState.mProcesses.valueAt(iproc);
2072                    pw.print("pkgproc,");
2073                    pw.print(pkgName);
2074                    pw.print(",");
2075                    pw.print(uid);
2076                    pw.print(",");
2077                    pw.print(collapseString(pkgName, pkgState.mProcesses.keyAt(iproc)));
2078                    dumpAllProcessStateCheckin(pw, proc, now);
2079                    pw.println();
2080                    if (proc.mPssTableSize > 0) {
2081                        pw.print("pkgpss,");
2082                        pw.print(pkgName);
2083                        pw.print(",");
2084                        pw.print(uid);
2085                        pw.print(",");
2086                        pw.print(collapseString(pkgName, pkgState.mProcesses.keyAt(iproc)));
2087                        dumpAllProcessPssCheckin(pw, proc);
2088                        pw.println();
2089                    }
2090                    if (proc.mNumExcessiveWake > 0 || proc.mNumExcessiveCpu > 0
2091                            || proc.mNumCachedKill > 0) {
2092                        pw.print("pkgkills,");
2093                        pw.print(pkgName);
2094                        pw.print(",");
2095                        pw.print(uid);
2096                        pw.print(",");
2097                        pw.print(collapseString(pkgName, pkgState.mProcesses.keyAt(iproc)));
2098                        pw.print(",");
2099                        pw.print(proc.mNumExcessiveWake);
2100                        pw.print(",");
2101                        pw.print(proc.mNumExcessiveCpu);
2102                        pw.print(",");
2103                        pw.print(proc.mNumCachedKill);
2104                        pw.print(",");
2105                        pw.print(proc.mMinCachedKillPss);
2106                        pw.print(":");
2107                        pw.print(proc.mAvgCachedKillPss);
2108                        pw.print(":");
2109                        pw.print(proc.mMaxCachedKillPss);
2110                        pw.println();
2111                    }
2112                }
2113                for (int isvc=0; isvc<NSRVS; isvc++) {
2114                    String serviceName = collapseString(pkgName,
2115                            pkgState.mServices.keyAt(isvc));
2116                    ServiceState svc = pkgState.mServices.valueAt(isvc);
2117                    dumpServiceTimeCheckin(pw, "pkgsvc-run", pkgName, uid, serviceName,
2118                            svc, ServiceState.SERVICE_RUN, svc.mRunCount,
2119                            svc.mRunState, svc.mRunStartTime, now);
2120                    dumpServiceTimeCheckin(pw, "pkgsvc-start", pkgName, uid, serviceName,
2121                            svc, ServiceState.SERVICE_STARTED, svc.mStartedCount,
2122                            svc.mStartedState, svc.mStartedStartTime, now);
2123                    dumpServiceTimeCheckin(pw, "pkgsvc-bound", pkgName, uid, serviceName,
2124                            svc, ServiceState.SERVICE_BOUND, svc.mBoundCount,
2125                            svc.mBoundState, svc.mBoundStartTime, now);
2126                    dumpServiceTimeCheckin(pw, "pkgsvc-exec", pkgName, uid, serviceName,
2127                            svc, ServiceState.SERVICE_EXEC, svc.mExecCount,
2128                            svc.mExecState, svc.mExecStartTime, now);
2129                }
2130            }
2131        }
2132
2133        ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap();
2134        for (int ip=0; ip<procMap.size(); ip++) {
2135            String procName = procMap.keyAt(ip);
2136            SparseArray<ProcessState> uids = procMap.valueAt(ip);
2137            for (int iu=0; iu<uids.size(); iu++) {
2138                int uid = uids.keyAt(iu);
2139                ProcessState procState = uids.valueAt(iu);
2140                if (procState.mDurationsTableSize > 0) {
2141                    pw.print("proc,");
2142                    pw.print(procName);
2143                    pw.print(",");
2144                    pw.print(uid);
2145                    dumpAllProcessStateCheckin(pw, procState, now);
2146                    pw.println();
2147                }
2148                if (procState.mPssTableSize > 0) {
2149                    pw.print("pss,");
2150                    pw.print(procName);
2151                    pw.print(",");
2152                    pw.print(uid);
2153                    dumpAllProcessPssCheckin(pw, procState);
2154                    pw.println();
2155                }
2156                if (procState.mNumExcessiveWake > 0 || procState.mNumExcessiveCpu > 0
2157                        || procState.mNumCachedKill > 0) {
2158                    pw.print("kills,");
2159                    pw.print(procName);
2160                    pw.print(",");
2161                    pw.print(uid);
2162                    pw.print(",");
2163                    pw.print(procState.mNumExcessiveWake);
2164                    pw.print(",");
2165                    pw.print(procState.mNumExcessiveCpu);
2166                    pw.print(",");
2167                    pw.print(procState.mNumCachedKill);
2168                    pw.print(",");
2169                    pw.print(procState.mMinCachedKillPss);
2170                    pw.print(":");
2171                    pw.print(procState.mAvgCachedKillPss);
2172                    pw.print(":");
2173                    pw.print(procState.mMaxCachedKillPss);
2174                    pw.println();
2175                }
2176            }
2177        }
2178        pw.print("total");
2179        dumpAdjTimesCheckin(pw, ",", mMemFactorDurations, mMemFactor,
2180                mStartTime, now);
2181        pw.println();
2182    }
2183
2184    public static class DurationsTable {
2185        public final ProcessStats mStats;
2186        public final String mName;
2187        public int[] mDurationsTable;
2188        public int mDurationsTableSize;
2189
2190        public DurationsTable(ProcessStats stats, String name) {
2191            mStats = stats;
2192            mName = name;
2193        }
2194
2195        void copyDurationsTo(DurationsTable other) {
2196            if (mDurationsTable != null) {
2197                mStats.mAddLongTable = new int[mDurationsTable.length];
2198                mStats.mAddLongTableSize = 0;
2199                for (int i=0; i<mDurationsTableSize; i++) {
2200                    int origEnt = mDurationsTable[i];
2201                    int type = (origEnt>>OFFSET_TYPE_SHIFT)&OFFSET_TYPE_MASK;
2202                    int newOff = mStats.addLongData(i, type, 1);
2203                    mStats.mAddLongTable[i] = newOff | type;
2204                    mStats.setLong(newOff, 0, mStats.getLong(origEnt, 0));
2205                }
2206                other.mDurationsTable = mStats.mAddLongTable;
2207                other.mDurationsTableSize = mStats.mAddLongTableSize;
2208            } else {
2209                other.mDurationsTable = null;
2210                other.mDurationsTableSize = 0;
2211            }
2212        }
2213
2214        void addDurations(DurationsTable other) {
2215            for (int i=0; i<other.mDurationsTableSize; i++) {
2216                int ent = other.mDurationsTable[i];
2217                int state = (ent>>OFFSET_TYPE_SHIFT)&OFFSET_TYPE_MASK;
2218                if (DEBUG) Slog.d(TAG, "Adding state " + state + " duration "
2219                        + other.mStats.getLong(ent, 0));
2220                addDuration(state, other.mStats.getLong(ent, 0));
2221            }
2222        }
2223
2224        void resetDurationsSafely() {
2225            mDurationsTable = null;
2226            mDurationsTableSize = 0;
2227        }
2228
2229        void writeDurationsToParcel(Parcel out) {
2230            out.writeInt(mDurationsTableSize);
2231            for (int i=0; i<mDurationsTableSize; i++) {
2232                if (DEBUG) Slog.i(TAG, "Writing in " + mName + " dur #" + i + ": "
2233                        + printLongOffset(mDurationsTable[i]));
2234                out.writeInt(mDurationsTable[i]);
2235            }
2236        }
2237
2238        boolean readDurationsFromParcel(Parcel in) {
2239            mDurationsTable = mStats.readTableFromParcel(in, mName, "durations");
2240            if (mDurationsTable == BAD_TABLE) {
2241                return false;
2242            }
2243            mDurationsTableSize = mDurationsTable != null ? mDurationsTable.length : 0;
2244            return true;
2245        }
2246
2247        void addDuration(int state, long dur) {
2248            int idx = binarySearch(mDurationsTable, mDurationsTableSize, state);
2249            int off;
2250            if (idx >= 0) {
2251                off = mDurationsTable[idx];
2252            } else {
2253                mStats.mAddLongTable = mDurationsTable;
2254                mStats.mAddLongTableSize = mDurationsTableSize;
2255                off = mStats.addLongData(~idx, state, 1);
2256                mDurationsTable = mStats.mAddLongTable;
2257                mDurationsTableSize = mStats.mAddLongTableSize;
2258            }
2259            long[] longs = mStats.mLongs.get((off>>OFFSET_ARRAY_SHIFT)&OFFSET_ARRAY_MASK);
2260            if (DEBUG) Slog.d(TAG, "Duration of " + mName + " state " + state + " inc by " + dur
2261                    + " from " + longs[(off>>OFFSET_INDEX_SHIFT)&OFFSET_INDEX_MASK]);
2262            longs[(off>>OFFSET_INDEX_SHIFT)&OFFSET_INDEX_MASK] += dur;
2263        }
2264
2265        long getDuration(int state, long now) {
2266            int idx = binarySearch(mDurationsTable, mDurationsTableSize, state);
2267            return idx >= 0 ? mStats.getLong(mDurationsTable[idx], 0) : 0;
2268        }
2269    }
2270
2271    public static final class ProcessState extends DurationsTable {
2272        public final ProcessState mCommonProcess;
2273        public final String mPackage;
2274        public final int mUid;
2275
2276        //final long[] mDurations = new long[STATE_COUNT*ADJ_COUNT];
2277        int mCurState = STATE_NOTHING;
2278        long mStartTime;
2279
2280        int mLastPssState = STATE_NOTHING;
2281        long mLastPssTime;
2282        int[] mPssTable;
2283        int mPssTableSize;
2284
2285        boolean mActive;
2286        int mNumActiveServices;
2287        int mNumStartedServices;
2288
2289        int mNumExcessiveWake;
2290        int mNumExcessiveCpu;
2291
2292        int mNumCachedKill;
2293        long mMinCachedKillPss;
2294        long mAvgCachedKillPss;
2295        long mMaxCachedKillPss;
2296
2297        boolean mMultiPackage;
2298        boolean mDead;
2299
2300        public long mTmpTotalTime;
2301
2302        /**
2303         * Create a new top-level process state, for the initial case where there is only
2304         * a single package running in a process.  The initial state is not running.
2305         */
2306        public ProcessState(ProcessStats processStats, String pkg, int uid, String name) {
2307            super(processStats, name);
2308            mCommonProcess = this;
2309            mPackage = pkg;
2310            mUid = uid;
2311        }
2312
2313        /**
2314         * Create a new per-package process state for an existing top-level process
2315         * state.  The current running state of the top-level process is also copied,
2316         * marked as started running at 'now'.
2317         */
2318        public ProcessState(ProcessState commonProcess, String pkg, int uid, String name,
2319                long now) {
2320            super(commonProcess.mStats, name);
2321            mCommonProcess = commonProcess;
2322            mPackage = pkg;
2323            mUid = uid;
2324            mCurState = commonProcess.mCurState;
2325            mStartTime = now;
2326        }
2327
2328        ProcessState clone(String pkg, long now) {
2329            ProcessState pnew = new ProcessState(this, pkg, mUid, mName, now);
2330            copyDurationsTo(pnew);
2331            if (mPssTable != null) {
2332                mStats.mAddLongTable = new int[mPssTable.length];
2333                mStats.mAddLongTableSize = 0;
2334                for (int i=0; i<mPssTableSize; i++) {
2335                    int origEnt = mPssTable[i];
2336                    int type = (origEnt>>OFFSET_TYPE_SHIFT)&OFFSET_TYPE_MASK;
2337                    int newOff = mStats.addLongData(i, type, PSS_COUNT);
2338                    mStats.mAddLongTable[i] = newOff | type;
2339                    for (int j=0; j<PSS_COUNT; j++) {
2340                        mStats.setLong(newOff, j, mStats.getLong(origEnt, j));
2341                    }
2342                }
2343                pnew.mPssTable = mStats.mAddLongTable;
2344                pnew.mPssTableSize = mStats.mAddLongTableSize;
2345            }
2346            pnew.mNumExcessiveWake = mNumExcessiveWake;
2347            pnew.mNumExcessiveCpu = mNumExcessiveCpu;
2348            pnew.mNumCachedKill = mNumCachedKill;
2349            pnew.mMinCachedKillPss = mMinCachedKillPss;
2350            pnew.mAvgCachedKillPss = mAvgCachedKillPss;
2351            pnew.mMaxCachedKillPss = mMaxCachedKillPss;
2352            pnew.mActive = mActive;
2353            pnew.mNumStartedServices = mNumStartedServices;
2354            return pnew;
2355        }
2356
2357        void add(ProcessState other) {
2358            addDurations(other);
2359            for (int i=0; i<other.mPssTableSize; i++) {
2360                int ent = other.mPssTable[i];
2361                int state = (ent>>OFFSET_TYPE_SHIFT)&OFFSET_TYPE_MASK;
2362                addPss(state, (int) other.mStats.getLong(ent, PSS_SAMPLE_COUNT),
2363                        other.mStats.getLong(ent, PSS_MINIMUM),
2364                        other.mStats.getLong(ent, PSS_AVERAGE),
2365                        other.mStats.getLong(ent, PSS_MAXIMUM),
2366                        other.mStats.getLong(ent, PSS_USS_MINIMUM),
2367                        other.mStats.getLong(ent, PSS_USS_AVERAGE),
2368                        other.mStats.getLong(ent, PSS_USS_MAXIMUM));
2369            }
2370            mNumExcessiveWake += other.mNumExcessiveWake;
2371            mNumExcessiveCpu += other.mNumExcessiveCpu;
2372            if (other.mNumCachedKill > 0) {
2373                addCachedKill(other.mNumCachedKill, other.mMinCachedKillPss,
2374                        other.mAvgCachedKillPss, other.mMaxCachedKillPss);
2375            }
2376        }
2377
2378        void resetSafely(long now) {
2379            resetDurationsSafely();
2380            mStartTime = now;
2381            mLastPssState = STATE_NOTHING;
2382            mLastPssTime = 0;
2383            mPssTable = null;
2384            mPssTableSize = 0;
2385            mNumExcessiveWake = 0;
2386            mNumExcessiveCpu = 0;
2387            mNumCachedKill = 0;
2388            mMinCachedKillPss = mAvgCachedKillPss = mMaxCachedKillPss = 0;
2389        }
2390
2391        void makeDead() {
2392            mDead = true;
2393        }
2394
2395        private void ensureNotDead() {
2396            if (!mDead) {
2397                return;
2398            }
2399            throw new IllegalStateException("ProcessState dead: name=" + mName
2400                    + " pkg=" + mPackage + " uid=" + mUid + " common.name=" + mCommonProcess.mName);
2401        }
2402
2403        void writeToParcel(Parcel out, long now) {
2404            out.writeInt(mMultiPackage ? 1 : 0);
2405            writeDurationsToParcel(out);
2406            out.writeInt(mPssTableSize);
2407            for (int i=0; i<mPssTableSize; i++) {
2408                if (DEBUG) Slog.i(TAG, "Writing in " + mName + " pss #" + i + ": "
2409                        + printLongOffset(mPssTable[i]));
2410                out.writeInt(mPssTable[i]);
2411            }
2412            out.writeInt(mNumExcessiveWake);
2413            out.writeInt(mNumExcessiveCpu);
2414            out.writeInt(mNumCachedKill);
2415            if (mNumCachedKill > 0) {
2416                out.writeLong(mMinCachedKillPss);
2417                out.writeLong(mAvgCachedKillPss);
2418                out.writeLong(mMaxCachedKillPss);
2419            }
2420        }
2421
2422        boolean readFromParcel(Parcel in, boolean fully) {
2423            boolean multiPackage = in.readInt() != 0;
2424            if (fully) {
2425                mMultiPackage = multiPackage;
2426            }
2427            if (DEBUG) Slog.d(TAG, "Reading durations table...");
2428            if (!readDurationsFromParcel(in)) {
2429                return false;
2430            }
2431            if (DEBUG) Slog.d(TAG, "Reading pss table...");
2432            mPssTable = mStats.readTableFromParcel(in, mName, "pss");
2433            if (mPssTable == BAD_TABLE) {
2434                return false;
2435            }
2436            mPssTableSize = mPssTable != null ? mPssTable.length : 0;
2437            mNumExcessiveWake = in.readInt();
2438            mNumExcessiveCpu = in.readInt();
2439            mNumCachedKill = in.readInt();
2440            if (mNumCachedKill > 0) {
2441                mMinCachedKillPss = in.readLong();
2442                mAvgCachedKillPss = in.readLong();
2443                mMaxCachedKillPss = in.readLong();
2444            } else {
2445                mMinCachedKillPss = mAvgCachedKillPss = mMaxCachedKillPss = 0;
2446            }
2447            return true;
2448        }
2449
2450        public void makeActive() {
2451            ensureNotDead();
2452            mActive = true;
2453        }
2454
2455        public void makeInactive() {
2456            mActive = false;
2457        }
2458
2459        public boolean isInUse() {
2460            return mActive || mNumActiveServices > 0 || mNumStartedServices > 0
2461                    || mCurState != STATE_NOTHING;
2462        }
2463
2464        /**
2465         * Update the current state of the given list of processes.
2466         *
2467         * @param state Current ActivityManager.PROCESS_STATE_*
2468         * @param memFactor Current mem factor constant.
2469         * @param now Current time.
2470         * @param pkgList Processes to update.
2471         */
2472        public void setState(int state, int memFactor, long now,
2473                ArrayMap<String, ProcessState> pkgList) {
2474            if (state < 0) {
2475                state = mNumStartedServices > 0
2476                        ? (STATE_SERVICE_RESTARTING+(memFactor*STATE_COUNT)) : STATE_NOTHING;
2477            } else {
2478                state = PROCESS_STATE_TO_STATE[state] + (memFactor*STATE_COUNT);
2479            }
2480
2481            // First update the common process.
2482            mCommonProcess.setState(state, now);
2483
2484            // If the common process is not multi-package, there is nothing else to do.
2485            if (!mCommonProcess.mMultiPackage) {
2486                return;
2487            }
2488
2489            if (pkgList != null) {
2490                for (int ip=pkgList.size()-1; ip>=0; ip--) {
2491                    pullFixedProc(pkgList, ip).setState(state, now);
2492                }
2493            }
2494        }
2495
2496        void setState(int state, long now) {
2497            ensureNotDead();
2498            if (mCurState != state) {
2499                //Slog.i(TAG, "Setting state in " + mName + "/" + mPackage + ": " + state);
2500                commitStateTime(now);
2501                mCurState = state;
2502            }
2503        }
2504
2505        void commitStateTime(long now) {
2506            if (mCurState != STATE_NOTHING) {
2507                long dur = now - mStartTime;
2508                if (dur > 0) {
2509                    addDuration(mCurState, dur);
2510                }
2511            }
2512            mStartTime = now;
2513        }
2514
2515        void incActiveServices() {
2516            if (mCommonProcess != this) {
2517                mCommonProcess.incActiveServices();
2518            }
2519            mNumActiveServices++;
2520        }
2521
2522        void decActiveServices() {
2523            if (mCommonProcess != this) {
2524                mCommonProcess.decActiveServices();
2525            }
2526            mNumActiveServices--;
2527            if (mNumActiveServices < 0) {
2528                throw new IllegalStateException("Proc active services underrun: pkg="
2529                        + mPackage + " uid=" + mUid + " name=" + mName);
2530            }
2531        }
2532
2533        void incStartedServices(int memFactor, long now) {
2534            if (mCommonProcess != this) {
2535                mCommonProcess.incStartedServices(memFactor, now);
2536            }
2537            mNumStartedServices++;
2538            if (mNumStartedServices == 1 && mCurState == STATE_NOTHING) {
2539                setState(STATE_NOTHING, memFactor, now, null);
2540            }
2541        }
2542
2543        void decStartedServices(int memFactor, long now) {
2544            if (mCommonProcess != this) {
2545                mCommonProcess.decStartedServices(memFactor, now);
2546            }
2547            mNumStartedServices--;
2548            if (mNumStartedServices == 0 && mCurState == STATE_SERVICE_RESTARTING) {
2549                setState(STATE_NOTHING, memFactor, now, null);
2550            } else if (mNumStartedServices < 0) {
2551                throw new IllegalStateException("Proc started services underrun: pkg="
2552                        + mPackage + " uid=" + mUid + " name=" + mName);
2553            }
2554        }
2555
2556        public void addPss(long pss, long uss, boolean always,
2557                ArrayMap<String, ProcessState> pkgList) {
2558            ensureNotDead();
2559            if (!always) {
2560                if (mLastPssState == mCurState && SystemClock.uptimeMillis()
2561                        < (mLastPssTime+(30*1000))) {
2562                    return;
2563                }
2564            }
2565            mLastPssState = mCurState;
2566            mLastPssTime = SystemClock.uptimeMillis();
2567            if (mCurState != STATE_NOTHING) {
2568                // First update the common process.
2569                mCommonProcess.addPss(mCurState, 1, pss, pss, pss, uss, uss, uss);
2570
2571                // If the common process is not multi-package, there is nothing else to do.
2572                if (!mCommonProcess.mMultiPackage) {
2573                    return;
2574                }
2575
2576                if (pkgList != null) {
2577                    for (int ip=pkgList.size()-1; ip>=0; ip--) {
2578                        pullFixedProc(pkgList, ip).addPss(mCurState, 1,
2579                                pss, pss, pss, uss, uss, uss);
2580                    }
2581                }
2582            }
2583        }
2584
2585        void addPss(int state, int inCount, long minPss, long avgPss, long maxPss, long minUss,
2586                long avgUss, long maxUss) {
2587            int idx = binarySearch(mPssTable, mPssTableSize, state);
2588            int off;
2589            if (idx >= 0) {
2590                off = mPssTable[idx];
2591            } else {
2592                mStats.mAddLongTable = mPssTable;
2593                mStats.mAddLongTableSize = mPssTableSize;
2594                off = mStats.addLongData(~idx, state, PSS_COUNT);
2595                mPssTable = mStats.mAddLongTable;
2596                mPssTableSize = mStats.mAddLongTableSize;
2597            }
2598            long[] longs = mStats.mLongs.get((off>>OFFSET_ARRAY_SHIFT)&OFFSET_ARRAY_MASK);
2599            idx = (off>>OFFSET_INDEX_SHIFT)&OFFSET_INDEX_MASK;
2600            long count = longs[idx+PSS_SAMPLE_COUNT];
2601            if (count == 0) {
2602                longs[idx+PSS_SAMPLE_COUNT] = inCount;
2603                longs[idx+PSS_MINIMUM] = minPss;
2604                longs[idx+PSS_AVERAGE] = avgPss;
2605                longs[idx+PSS_MAXIMUM] = maxPss;
2606                longs[idx+PSS_USS_MINIMUM] = minUss;
2607                longs[idx+PSS_USS_AVERAGE] = avgUss;
2608                longs[idx+PSS_USS_MAXIMUM] = maxUss;
2609            } else {
2610                longs[idx+PSS_SAMPLE_COUNT] = count+inCount;
2611                if (longs[idx+PSS_MINIMUM] > minPss) {
2612                    longs[idx+PSS_MINIMUM] = minPss;
2613                }
2614                longs[idx+PSS_AVERAGE] = (long)(
2615                        ((longs[idx+PSS_AVERAGE]*(double)count)+(avgPss*(double)inCount))
2616                                / (count+inCount) );
2617                if (longs[idx+PSS_MAXIMUM] < maxPss) {
2618                    longs[idx+PSS_MAXIMUM] = maxPss;
2619                }
2620                if (longs[idx+PSS_USS_MINIMUM] > minUss) {
2621                    longs[idx+PSS_USS_MINIMUM] = minUss;
2622                }
2623                longs[idx+PSS_USS_AVERAGE] = (long)(
2624                        ((longs[idx+PSS_USS_AVERAGE]*(double)count)+(avgUss*(double)inCount))
2625                                / (count+inCount) );
2626                if (longs[idx+PSS_USS_MAXIMUM] < maxUss) {
2627                    longs[idx+PSS_USS_MAXIMUM] = maxUss;
2628                }
2629            }
2630        }
2631
2632        public void reportExcessiveWake(ArrayMap<String, ProcessState> pkgList) {
2633            ensureNotDead();
2634            mCommonProcess.mNumExcessiveWake++;
2635            if (!mCommonProcess.mMultiPackage) {
2636                return;
2637            }
2638
2639            for (int ip=pkgList.size()-1; ip>=0; ip--) {
2640                pullFixedProc(pkgList, ip).mNumExcessiveWake++;
2641            }
2642        }
2643
2644        public void reportExcessiveCpu(ArrayMap<String, ProcessState> pkgList) {
2645            ensureNotDead();
2646            mCommonProcess.mNumExcessiveCpu++;
2647            if (!mCommonProcess.mMultiPackage) {
2648                return;
2649            }
2650
2651            for (int ip=pkgList.size()-1; ip>=0; ip--) {
2652                pullFixedProc(pkgList, ip).mNumExcessiveCpu++;
2653            }
2654        }
2655
2656        private void addCachedKill(int num, long minPss, long avgPss, long maxPss) {
2657            if (mNumCachedKill <= 0) {
2658                mNumCachedKill = num;
2659                mMinCachedKillPss = minPss;
2660                mAvgCachedKillPss = avgPss;
2661                mMaxCachedKillPss = maxPss;
2662            } else {
2663                if (minPss < mMinCachedKillPss) {
2664                    mMinCachedKillPss = minPss;
2665                }
2666                if (maxPss > mMaxCachedKillPss) {
2667                    mMaxCachedKillPss = maxPss;
2668                }
2669                mAvgCachedKillPss = (long)( ((mAvgCachedKillPss*(double)mNumCachedKill) + avgPss)
2670                        / (mNumCachedKill+num) );
2671                mNumCachedKill += num;
2672            }
2673        }
2674
2675        public void reportCachedKill(ArrayMap<String, ProcessState> pkgList, long pss) {
2676            ensureNotDead();
2677            mCommonProcess.addCachedKill(1, pss, pss, pss);
2678            if (!mCommonProcess.mMultiPackage) {
2679                return;
2680            }
2681
2682            for (int ip=pkgList.size()-1; ip>=0; ip--) {
2683                pullFixedProc(pkgList, ip).addCachedKill(1, pss, pss, pss);
2684            }
2685        }
2686
2687        ProcessState pullFixedProc(String pkgName) {
2688            if (mMultiPackage) {
2689                // The array map is still pointing to a common process state
2690                // that is now shared across packages.  Update it to point to
2691                // the new per-package state.
2692                ProcessState proc = mStats.mPackages.get(pkgName,
2693                        mUid).mProcesses.get(mName);
2694                if (proc == null) {
2695                    throw new IllegalStateException("Didn't create per-package process");
2696                }
2697                return proc;
2698            }
2699            return this;
2700        }
2701
2702        private ProcessState pullFixedProc(ArrayMap<String, ProcessState> pkgList, int index) {
2703            ProcessState proc = pkgList.valueAt(index);
2704            if (mDead && proc.mCommonProcess != proc) {
2705                // Somehow we are contining to use a process state that is dead, because
2706                // it was not being told it was active during the last commit.  We can recover
2707                // from this by generating a fresh new state, but this is bad because we
2708                // are losing whatever data we had in the old process state.
2709                Log.wtf(TAG, "Pulling dead proc: name=" + mName + " pkg=" + mPackage
2710                        + " uid=" + mUid + " common.name=" + mCommonProcess.mName);
2711                proc = mStats.getProcessStateLocked(proc.mPackage, proc.mUid, proc.mName);
2712            }
2713            if (proc.mMultiPackage) {
2714                // The array map is still pointing to a common process state
2715                // that is now shared across packages.  Update it to point to
2716                // the new per-package state.
2717                PackageState pkg = mStats.mPackages.get(pkgList.keyAt(index), proc.mUid);
2718                if (pkg == null) {
2719                    throw new IllegalStateException("No existing package "
2720                            + pkgList.keyAt(index) + " for multi-proc " + proc.mName);
2721                }
2722                proc = pkg.mProcesses.get(proc.mName);
2723                if (proc == null) {
2724                    throw new IllegalStateException("Didn't create per-package process");
2725                }
2726                pkgList.setValueAt(index, proc);
2727            }
2728            return proc;
2729        }
2730
2731        long getDuration(int state, long now) {
2732            long time = super.getDuration(state, now);
2733            if (mCurState == state) {
2734                time += now - mStartTime;
2735            }
2736            return time;
2737        }
2738
2739        long getPssSampleCount(int state) {
2740            int idx = binarySearch(mPssTable, mPssTableSize, state);
2741            return idx >= 0 ? mStats.getLong(mPssTable[idx], PSS_SAMPLE_COUNT) : 0;
2742        }
2743
2744        long getPssMinimum(int state) {
2745            int idx = binarySearch(mPssTable, mPssTableSize, state);
2746            return idx >= 0 ? mStats.getLong(mPssTable[idx], PSS_MINIMUM) : 0;
2747        }
2748
2749        long getPssAverage(int state) {
2750            int idx = binarySearch(mPssTable, mPssTableSize, state);
2751            return idx >= 0 ? mStats.getLong(mPssTable[idx], PSS_AVERAGE) : 0;
2752        }
2753
2754        long getPssMaximum(int state) {
2755            int idx = binarySearch(mPssTable, mPssTableSize, state);
2756            return idx >= 0 ? mStats.getLong(mPssTable[idx], PSS_MAXIMUM) : 0;
2757        }
2758
2759        long getPssUssMinimum(int state) {
2760            int idx = binarySearch(mPssTable, mPssTableSize, state);
2761            return idx >= 0 ? mStats.getLong(mPssTable[idx], PSS_USS_MINIMUM) : 0;
2762        }
2763
2764        long getPssUssAverage(int state) {
2765            int idx = binarySearch(mPssTable, mPssTableSize, state);
2766            return idx >= 0 ? mStats.getLong(mPssTable[idx], PSS_USS_AVERAGE) : 0;
2767        }
2768
2769        long getPssUssMaximum(int state) {
2770            int idx = binarySearch(mPssTable, mPssTableSize, state);
2771            return idx >= 0 ? mStats.getLong(mPssTable[idx], PSS_USS_MAXIMUM) : 0;
2772        }
2773    }
2774
2775    public static final class ServiceState extends DurationsTable {
2776        public final String mPackage;
2777        public final String mProcessName;
2778        ProcessState mProc;
2779
2780        int mActive = 0;
2781
2782        public static final int SERVICE_RUN = 0;
2783        public static final int SERVICE_STARTED = 1;
2784        public static final int SERVICE_BOUND = 2;
2785        public static final int SERVICE_EXEC = 3;
2786        static final int SERVICE_COUNT = 4;
2787
2788        int mRunCount;
2789        public int mRunState = STATE_NOTHING;
2790        long mRunStartTime;
2791
2792        int mStartedCount;
2793        public int mStartedState = STATE_NOTHING;
2794        long mStartedStartTime;
2795
2796        int mBoundCount;
2797        public int mBoundState = STATE_NOTHING;
2798        long mBoundStartTime;
2799
2800        int mExecCount;
2801        public int mExecState = STATE_NOTHING;
2802        long mExecStartTime;
2803
2804        public ServiceState(ProcessStats processStats, String pkg, String name,
2805                String processName, ProcessState proc) {
2806            super(processStats, name);
2807            mPackage = pkg;
2808            mProcessName = processName;
2809            mProc = proc;
2810        }
2811
2812        public void makeActive() {
2813            if (mActive == 0) {
2814                mProc.incActiveServices();
2815            }
2816            mActive++;
2817        }
2818
2819        public void makeInactive() {
2820            /*
2821            RuntimeException here = new RuntimeException("here");
2822            here.fillInStackTrace();
2823            Slog.i(TAG, "Making " + this + " inactive", here);
2824            */
2825            mActive--;
2826            if (mActive == 0) {
2827                mProc.decActiveServices();
2828            }
2829        }
2830
2831        public boolean isInUse() {
2832            return mActive > 0;
2833        }
2834
2835        void add(ServiceState other) {
2836            addDurations(other);
2837            mRunCount += other.mRunCount;
2838            mStartedCount += other.mStartedCount;
2839            mBoundCount += other.mBoundCount;
2840            mExecCount += other.mExecCount;
2841        }
2842
2843        void resetSafely(long now) {
2844            resetDurationsSafely();
2845            mRunCount = mRunState != STATE_NOTHING ? 1 : 0;
2846            mStartedCount = mStartedState != STATE_NOTHING ? 1 : 0;
2847            mBoundCount = mBoundState != STATE_NOTHING ? 1 : 0;
2848            mExecCount = mExecState != STATE_NOTHING ? 1 : 0;
2849            mRunStartTime = mStartedStartTime = mBoundStartTime = mExecStartTime = now;
2850        }
2851
2852        void writeToParcel(Parcel out, long now) {
2853            writeDurationsToParcel(out);
2854            out.writeInt(mRunCount);
2855            out.writeInt(mStartedCount);
2856            out.writeInt(mBoundCount);
2857            out.writeInt(mExecCount);
2858        }
2859
2860        boolean readFromParcel(Parcel in) {
2861            if (!readDurationsFromParcel(in)) {
2862                return false;
2863            }
2864            mRunCount = in.readInt();
2865            mStartedCount = in.readInt();
2866            mBoundCount = in.readInt();
2867            mExecCount = in.readInt();
2868            return true;
2869        }
2870
2871        void commitStateTime(long now) {
2872            if (mRunState != STATE_NOTHING) {
2873                addDuration(SERVICE_RUN + (mRunState*SERVICE_COUNT), now - mRunStartTime);
2874                mRunStartTime = now;
2875            }
2876            if (mStartedState != STATE_NOTHING) {
2877                addDuration(SERVICE_STARTED + (mStartedState*SERVICE_COUNT),
2878                        now - mStartedStartTime);
2879                mStartedStartTime = now;
2880            }
2881            if (mBoundState != STATE_NOTHING) {
2882                addDuration(SERVICE_BOUND + (mBoundState*SERVICE_COUNT), now - mBoundStartTime);
2883                mBoundStartTime = now;
2884            }
2885            if (mExecState != STATE_NOTHING) {
2886                addDuration(SERVICE_EXEC + (mExecState*SERVICE_COUNT), now - mExecStartTime);
2887                mExecStartTime = now;
2888            }
2889        }
2890
2891        private void updateRunning(int memFactor, long now) {
2892            final int state = (mStartedState != STATE_NOTHING || mBoundState != STATE_NOTHING
2893                    || mExecState != STATE_NOTHING) ? memFactor : STATE_NOTHING;
2894            if (mRunState != state) {
2895                if (mRunState != STATE_NOTHING) {
2896                    addDuration(SERVICE_RUN + (mRunState*SERVICE_COUNT),
2897                            now - mRunStartTime);
2898                } else if (state != STATE_NOTHING) {
2899                    mRunCount++;
2900                }
2901                mRunState = state;
2902                mRunStartTime = now;
2903            }
2904        }
2905
2906        public void setStarted(boolean started, int memFactor, long now) {
2907            if (mActive <= 0) {
2908                throw new IllegalStateException("Service " + this + " has mActive=" + mActive);
2909            }
2910            final boolean wasStarted = mStartedState != STATE_NOTHING;
2911            final int state = started ? memFactor : STATE_NOTHING;
2912            if (mStartedState != state) {
2913                if (mStartedState != STATE_NOTHING) {
2914                    addDuration(SERVICE_STARTED + (mStartedState*SERVICE_COUNT),
2915                            now - mStartedStartTime);
2916                } else if (started) {
2917                    mStartedCount++;
2918                }
2919                mStartedState = state;
2920                mStartedStartTime = now;
2921                mProc = mProc.pullFixedProc(mPackage);
2922                if (wasStarted != started) {
2923                    if (started) {
2924                        mProc.incStartedServices(memFactor, now);
2925                    } else {
2926                        mProc.decStartedServices(memFactor, now);
2927                    }
2928                }
2929                updateRunning(memFactor, now);
2930            }
2931        }
2932
2933        public void setBound(boolean bound, int memFactor, long now) {
2934            if (mActive <= 0) {
2935                throw new IllegalStateException("Service " + this + " has mActive=" + mActive);
2936            }
2937            final int state = bound ? memFactor : STATE_NOTHING;
2938            if (mBoundState != state) {
2939                if (mBoundState != STATE_NOTHING) {
2940                    addDuration(SERVICE_BOUND + (mBoundState*SERVICE_COUNT),
2941                            now - mBoundStartTime);
2942                } else if (bound) {
2943                    mBoundCount++;
2944                }
2945                mBoundState = state;
2946                mBoundStartTime = now;
2947                updateRunning(memFactor, now);
2948            }
2949        }
2950
2951        public void setExecuting(boolean executing, int memFactor, long now) {
2952            if (mActive <= 0) {
2953                throw new IllegalStateException("Service " + this + " has mActive=" + mActive);
2954            }
2955            final int state = executing ? memFactor : STATE_NOTHING;
2956            if (mExecState != state) {
2957                if (mExecState != STATE_NOTHING) {
2958                    addDuration(SERVICE_EXEC + (mExecState*SERVICE_COUNT), now - mExecStartTime);
2959                } else if (executing) {
2960                    mExecCount++;
2961                }
2962                mExecState = state;
2963                mExecStartTime = now;
2964                updateRunning(memFactor, now);
2965            }
2966        }
2967
2968        private long getDuration(int opType, int curState, long startTime, int memFactor,
2969                long now) {
2970            int state = opType + (memFactor*SERVICE_COUNT);
2971            long time = getDuration(state, now);
2972            if (curState == memFactor) {
2973                time += now - startTime;
2974            }
2975            return time;
2976        }
2977    }
2978
2979    public static final class PackageState {
2980        public final ArrayMap<String, ProcessState> mProcesses
2981                = new ArrayMap<String, ProcessState>();
2982        public final ArrayMap<String, ServiceState> mServices
2983                = new ArrayMap<String, ServiceState>();
2984        public final String mPackageName;
2985        public final int mUid;
2986
2987        public PackageState(String packageName, int uid) {
2988            mUid = uid;
2989            mPackageName = packageName;
2990        }
2991    }
2992
2993    public static final class ProcessDataCollection {
2994        final int[] screenStates;
2995        final int[] memStates;
2996        final int[] procStates;
2997
2998        public long totalTime;
2999        public long numPss;
3000        public long minPss;
3001        public long avgPss;
3002        public long maxPss;
3003        public long minUss;
3004        public long avgUss;
3005        public long maxUss;
3006
3007        public ProcessDataCollection(int[] _screenStates, int[] _memStates, int[] _procStates) {
3008            screenStates = _screenStates;
3009            memStates = _memStates;
3010            procStates = _procStates;
3011        }
3012
3013        void print(PrintWriter pw, long overallTime, boolean full) {
3014            if (totalTime > overallTime) {
3015                pw.print("*");
3016            }
3017            printPercent(pw, (double) totalTime / (double) overallTime);
3018            if (numPss > 0) {
3019                pw.print(" (");
3020                printSizeValue(pw, minPss * 1024);
3021                pw.print("-");
3022                printSizeValue(pw, avgPss * 1024);
3023                pw.print("-");
3024                printSizeValue(pw, maxPss * 1024);
3025                pw.print("/");
3026                printSizeValue(pw, minUss * 1024);
3027                pw.print("-");
3028                printSizeValue(pw, avgUss * 1024);
3029                pw.print("-");
3030                printSizeValue(pw, maxUss * 1024);
3031                if (full) {
3032                    pw.print(" over ");
3033                    pw.print(numPss);
3034                }
3035                pw.print(")");
3036            }
3037        }
3038    }
3039}
3040