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