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