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