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