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