Home | History | Annotate | Download | only in procstats
      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.procstats;
     18 
     19 import android.os.Parcel;
     20 import android.os.SystemClock;
     21 import android.os.UserHandle;
     22 import android.service.procstats.ProcessStatsProto;
     23 import android.util.ArrayMap;
     24 import android.util.DebugUtils;
     25 import android.util.Log;
     26 import android.util.LongSparseArray;
     27 import android.util.Slog;
     28 import android.util.TimeUtils;
     29 import android.util.proto.ProtoOutputStream;
     30 import android.util.proto.ProtoUtils;
     31 
     32 import com.android.internal.app.procstats.ProcessStats.PackageState;
     33 import com.android.internal.app.procstats.ProcessStats.ProcessStateHolder;
     34 import com.android.internal.app.procstats.ProcessStats.TotalMemoryUseCollection;
     35 import static com.android.internal.app.procstats.ProcessStats.PSS_SAMPLE_COUNT;
     36 import static com.android.internal.app.procstats.ProcessStats.PSS_MINIMUM;
     37 import static com.android.internal.app.procstats.ProcessStats.PSS_AVERAGE;
     38 import static com.android.internal.app.procstats.ProcessStats.PSS_MAXIMUM;
     39 import static com.android.internal.app.procstats.ProcessStats.PSS_RSS_MINIMUM;
     40 import static com.android.internal.app.procstats.ProcessStats.PSS_RSS_AVERAGE;
     41 import static com.android.internal.app.procstats.ProcessStats.PSS_RSS_MAXIMUM;
     42 import static com.android.internal.app.procstats.ProcessStats.PSS_USS_MINIMUM;
     43 import static com.android.internal.app.procstats.ProcessStats.PSS_USS_AVERAGE;
     44 import static com.android.internal.app.procstats.ProcessStats.PSS_USS_MAXIMUM;
     45 import static com.android.internal.app.procstats.ProcessStats.PSS_COUNT;
     46 import static com.android.internal.app.procstats.ProcessStats.STATE_NOTHING;
     47 import static com.android.internal.app.procstats.ProcessStats.STATE_PERSISTENT;
     48 import static com.android.internal.app.procstats.ProcessStats.STATE_TOP;
     49 import static com.android.internal.app.procstats.ProcessStats.STATE_IMPORTANT_FOREGROUND;
     50 import static com.android.internal.app.procstats.ProcessStats.STATE_IMPORTANT_BACKGROUND;
     51 import static com.android.internal.app.procstats.ProcessStats.STATE_BACKUP;
     52 import static com.android.internal.app.procstats.ProcessStats.STATE_HEAVY_WEIGHT;
     53 import static com.android.internal.app.procstats.ProcessStats.STATE_SERVICE;
     54 import static com.android.internal.app.procstats.ProcessStats.STATE_SERVICE_RESTARTING;
     55 import static com.android.internal.app.procstats.ProcessStats.STATE_RECEIVER;
     56 import static com.android.internal.app.procstats.ProcessStats.STATE_HOME;
     57 import static com.android.internal.app.procstats.ProcessStats.STATE_LAST_ACTIVITY;
     58 import static com.android.internal.app.procstats.ProcessStats.STATE_CACHED_ACTIVITY;
     59 import static com.android.internal.app.procstats.ProcessStats.STATE_CACHED_ACTIVITY_CLIENT;
     60 import static com.android.internal.app.procstats.ProcessStats.STATE_CACHED_EMPTY;
     61 import static com.android.internal.app.procstats.ProcessStats.STATE_COUNT;
     62 
     63 import java.io.PrintWriter;
     64 import java.util.Comparator;
     65 import java.util.HashMap;
     66 import java.util.Map;
     67 
     68 public final class ProcessState {
     69     private static final String TAG = "ProcessStats";
     70     private static final boolean DEBUG = false;
     71     private static final boolean DEBUG_PARCEL = false;
     72 
     73     // Map from process states to the states we track.
     74     private static final int[] PROCESS_STATE_TO_STATE = new int[] {
     75         STATE_PERSISTENT,               // ActivityManager.PROCESS_STATE_PERSISTENT
     76         STATE_PERSISTENT,               // ActivityManager.PROCESS_STATE_PERSISTENT_UI
     77         STATE_TOP,                      // ActivityManager.PROCESS_STATE_TOP
     78         STATE_IMPORTANT_FOREGROUND,     // ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE
     79         STATE_IMPORTANT_FOREGROUND,     // ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE
     80         STATE_IMPORTANT_FOREGROUND,     // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
     81         STATE_IMPORTANT_BACKGROUND,     // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
     82         STATE_IMPORTANT_BACKGROUND,     // ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND
     83         STATE_BACKUP,                   // ActivityManager.PROCESS_STATE_BACKUP
     84         STATE_SERVICE,                  // ActivityManager.PROCESS_STATE_SERVICE
     85         STATE_RECEIVER,                 // ActivityManager.PROCESS_STATE_RECEIVER
     86         STATE_TOP,                      // ActivityManager.PROCESS_STATE_TOP_SLEEPING
     87         STATE_HEAVY_WEIGHT,             // ActivityManager.PROCESS_STATE_HEAVY_WEIGHT
     88         STATE_HOME,                     // ActivityManager.PROCESS_STATE_HOME
     89         STATE_LAST_ACTIVITY,            // ActivityManager.PROCESS_STATE_LAST_ACTIVITY
     90         STATE_CACHED_ACTIVITY,          // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY
     91         STATE_CACHED_ACTIVITY_CLIENT,   // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT
     92         STATE_CACHED_ACTIVITY,          // ActivityManager.PROCESS_STATE_CACHED_RECENT
     93         STATE_CACHED_EMPTY,             // ActivityManager.PROCESS_STATE_CACHED_EMPTY
     94     };
     95 
     96     public static final Comparator<ProcessState> COMPARATOR = new Comparator<ProcessState>() {
     97             @Override
     98             public int compare(ProcessState lhs, ProcessState rhs) {
     99                 if (lhs.mTmpTotalTime < rhs.mTmpTotalTime) {
    100                     return -1;
    101                 } else if (lhs.mTmpTotalTime > rhs.mTmpTotalTime) {
    102                     return 1;
    103                 }
    104                 return 0;
    105             }
    106         };
    107 
    108     static class PssAggr {
    109         long pss = 0;
    110         long samples = 0;
    111 
    112         void add(long newPss, long newSamples) {
    113             pss = (long)( (pss*(double)samples) + (newPss*(double)newSamples) )
    114                     / (samples+newSamples);
    115             samples += newSamples;
    116         }
    117     }
    118 
    119     // Used by reset to count rather than storing extra maps. Be careful.
    120     public int tmpNumInUse;
    121     public ProcessState tmpFoundSubProc;
    122 
    123     private final ProcessStats mStats;
    124     private final String mName;
    125     private final String mPackage;
    126     private final int mUid;
    127     private final long mVersion;
    128     private final DurationsTable mDurations;
    129     private final PssTable mPssTable;
    130 
    131     private ProcessState mCommonProcess;
    132     private int mCurState = STATE_NOTHING;
    133     private long mStartTime;
    134 
    135     private int mLastPssState = STATE_NOTHING;
    136     private long mLastPssTime;
    137 
    138     private boolean mActive;
    139     private int mNumActiveServices;
    140     private int mNumStartedServices;
    141 
    142     private int mNumExcessiveCpu;
    143 
    144     private int mNumCachedKill;
    145     private long mMinCachedKillPss;
    146     private long mAvgCachedKillPss;
    147     private long mMaxCachedKillPss;
    148 
    149     private boolean mMultiPackage;
    150     private boolean mDead;
    151 
    152     // Set in computeProcessTimeLocked and used by COMPARATOR to sort. Be careful.
    153     private long mTmpTotalTime;
    154 
    155     /**
    156      * Create a new top-level process state, for the initial case where there is only
    157      * a single package running in a process.  The initial state is not running.
    158      */
    159     public ProcessState(ProcessStats processStats, String pkg, int uid, long vers, String name) {
    160         mStats = processStats;
    161         mName = name;
    162         mCommonProcess = this;
    163         mPackage = pkg;
    164         mUid = uid;
    165         mVersion = vers;
    166         mDurations = new DurationsTable(processStats.mTableData);
    167         mPssTable = new PssTable(processStats.mTableData);
    168     }
    169 
    170     /**
    171      * Create a new per-package process state for an existing top-level process
    172      * state.  The current running state of the top-level process is also copied,
    173      * marked as started running at 'now'.
    174      */
    175     public ProcessState(ProcessState commonProcess, String pkg, int uid, long vers, String name,
    176             long now) {
    177         mStats = commonProcess.mStats;
    178         mName = name;
    179         mCommonProcess = commonProcess;
    180         mPackage = pkg;
    181         mUid = uid;
    182         mVersion = vers;
    183         mCurState = commonProcess.mCurState;
    184         mStartTime = now;
    185         mDurations = new DurationsTable(commonProcess.mStats.mTableData);
    186         mPssTable = new PssTable(commonProcess.mStats.mTableData);
    187     }
    188 
    189     public ProcessState clone(long now) {
    190         ProcessState pnew = new ProcessState(this, mPackage, mUid, mVersion, mName, now);
    191         pnew.mDurations.addDurations(mDurations);
    192         pnew.mPssTable.copyFrom(mPssTable, PSS_COUNT);
    193         pnew.mNumExcessiveCpu = mNumExcessiveCpu;
    194         pnew.mNumCachedKill = mNumCachedKill;
    195         pnew.mMinCachedKillPss = mMinCachedKillPss;
    196         pnew.mAvgCachedKillPss = mAvgCachedKillPss;
    197         pnew.mMaxCachedKillPss = mMaxCachedKillPss;
    198         pnew.mActive = mActive;
    199         pnew.mNumActiveServices = mNumActiveServices;
    200         pnew.mNumStartedServices = mNumStartedServices;
    201         return pnew;
    202     }
    203 
    204     public String getName() {
    205         return mName;
    206     }
    207 
    208     public ProcessState getCommonProcess() {
    209         return mCommonProcess;
    210     }
    211 
    212     /**
    213      * Say that we are not part of a shared process, so mCommonProcess = this.
    214      */
    215     public void makeStandalone() {
    216         mCommonProcess = this;
    217     }
    218 
    219     public String getPackage() {
    220         return mPackage;
    221     }
    222 
    223     public int getUid() {
    224         return mUid;
    225     }
    226 
    227     public long getVersion() {
    228         return mVersion;
    229     }
    230 
    231     public boolean isMultiPackage() {
    232         return mMultiPackage;
    233     }
    234 
    235     public void setMultiPackage(boolean val) {
    236         mMultiPackage = val;
    237     }
    238 
    239     public int getDurationsBucketCount() {
    240         return mDurations.getKeyCount();
    241     }
    242 
    243     public void add(ProcessState other) {
    244         mDurations.addDurations(other.mDurations);
    245         mPssTable.mergeStats(other.mPssTable);
    246         mNumExcessiveCpu += other.mNumExcessiveCpu;
    247         if (other.mNumCachedKill > 0) {
    248             addCachedKill(other.mNumCachedKill, other.mMinCachedKillPss,
    249                     other.mAvgCachedKillPss, other.mMaxCachedKillPss);
    250         }
    251     }
    252 
    253     public void resetSafely(long now) {
    254         mDurations.resetTable();
    255         mPssTable.resetTable();
    256         mStartTime = now;
    257         mLastPssState = STATE_NOTHING;
    258         mLastPssTime = 0;
    259         mNumExcessiveCpu = 0;
    260         mNumCachedKill = 0;
    261         mMinCachedKillPss = mAvgCachedKillPss = mMaxCachedKillPss = 0;
    262     }
    263 
    264     public void makeDead() {
    265         mDead = true;
    266     }
    267 
    268     private void ensureNotDead() {
    269         if (!mDead) {
    270             return;
    271         }
    272         Slog.w(TAG, "ProcessState dead: name=" + mName
    273                 + " pkg=" + mPackage + " uid=" + mUid + " common.name=" + mCommonProcess.mName);
    274     }
    275 
    276     public void writeToParcel(Parcel out, long now) {
    277         out.writeInt(mMultiPackage ? 1 : 0);
    278         mDurations.writeToParcel(out);
    279         mPssTable.writeToParcel(out);
    280         out.writeInt(0);  // was mNumExcessiveWake
    281         out.writeInt(mNumExcessiveCpu);
    282         out.writeInt(mNumCachedKill);
    283         if (mNumCachedKill > 0) {
    284             out.writeLong(mMinCachedKillPss);
    285             out.writeLong(mAvgCachedKillPss);
    286             out.writeLong(mMaxCachedKillPss);
    287         }
    288     }
    289 
    290     public boolean readFromParcel(Parcel in, boolean fully) {
    291         boolean multiPackage = in.readInt() != 0;
    292         if (fully) {
    293             mMultiPackage = multiPackage;
    294         }
    295         if (DEBUG_PARCEL) Slog.d(TAG, "Reading durations table...");
    296         if (!mDurations.readFromParcel(in)) {
    297             return false;
    298         }
    299         if (DEBUG_PARCEL) Slog.d(TAG, "Reading pss table...");
    300         if (!mPssTable.readFromParcel(in)) {
    301             return false;
    302         }
    303         in.readInt(); // was mNumExcessiveWake
    304         mNumExcessiveCpu = in.readInt();
    305         mNumCachedKill = in.readInt();
    306         if (mNumCachedKill > 0) {
    307             mMinCachedKillPss = in.readLong();
    308             mAvgCachedKillPss = in.readLong();
    309             mMaxCachedKillPss = in.readLong();
    310         } else {
    311             mMinCachedKillPss = mAvgCachedKillPss = mMaxCachedKillPss = 0;
    312         }
    313         return true;
    314     }
    315 
    316     public void makeActive() {
    317         ensureNotDead();
    318         mActive = true;
    319     }
    320 
    321     public void makeInactive() {
    322         mActive = false;
    323     }
    324 
    325     public boolean isInUse() {
    326         return mActive || mNumActiveServices > 0 || mNumStartedServices > 0
    327                 || mCurState != STATE_NOTHING;
    328     }
    329 
    330     public boolean isActive() {
    331         return mActive;
    332     }
    333 
    334     public boolean hasAnyData() {
    335         return !(mDurations.getKeyCount() == 0
    336                 && mCurState == STATE_NOTHING
    337                 && mPssTable.getKeyCount() == 0);
    338     }
    339 
    340     /**
    341      * Update the current state of the given list of processes.
    342      *
    343      * @param state Current ActivityManager.PROCESS_STATE_*
    344      * @param memFactor Current mem factor constant.
    345      * @param now Current time.
    346      * @param pkgList Processes to update.
    347      */
    348     public void setState(int state, int memFactor, long now,
    349             ArrayMap<String, ProcessStateHolder> pkgList) {
    350         if (state < 0) {
    351             state = mNumStartedServices > 0
    352                     ? (STATE_SERVICE_RESTARTING+(memFactor*STATE_COUNT)) : STATE_NOTHING;
    353         } else {
    354             state = PROCESS_STATE_TO_STATE[state] + (memFactor*STATE_COUNT);
    355         }
    356 
    357         // First update the common process.
    358         mCommonProcess.setState(state, now);
    359 
    360         // If the common process is not multi-package, there is nothing else to do.
    361         if (!mCommonProcess.mMultiPackage) {
    362             return;
    363         }
    364 
    365         if (pkgList != null) {
    366             for (int ip=pkgList.size()-1; ip>=0; ip--) {
    367                 pullFixedProc(pkgList, ip).setState(state, now);
    368             }
    369         }
    370     }
    371 
    372     public void setState(int state, long now) {
    373         ensureNotDead();
    374         if (!mDead && (mCurState != state)) {
    375             //Slog.i(TAG, "Setting state in " + mName + "/" + mPackage + ": " + state);
    376             commitStateTime(now);
    377             mCurState = state;
    378         }
    379     }
    380 
    381     public void commitStateTime(long now) {
    382         if (mCurState != STATE_NOTHING) {
    383             long dur = now - mStartTime;
    384             if (dur > 0) {
    385                 mDurations.addDuration(mCurState, dur);
    386             }
    387         }
    388         mStartTime = now;
    389     }
    390 
    391     public void incActiveServices(String serviceName) {
    392         if (DEBUG && "".equals(mName)) {
    393             RuntimeException here = new RuntimeException("here");
    394             here.fillInStackTrace();
    395             Slog.d(TAG, "incActiveServices: " + this + " service=" + serviceName
    396                     + " to " + (mNumActiveServices+1), here);
    397         }
    398         if (mCommonProcess != this) {
    399             mCommonProcess.incActiveServices(serviceName);
    400         }
    401         mNumActiveServices++;
    402     }
    403 
    404     public void decActiveServices(String serviceName) {
    405         if (DEBUG && "".equals(mName)) {
    406             RuntimeException here = new RuntimeException("here");
    407             here.fillInStackTrace();
    408             Slog.d(TAG, "decActiveServices: " + this + " service=" + serviceName
    409                     + " to " + (mNumActiveServices-1), here);
    410         }
    411         if (mCommonProcess != this) {
    412             mCommonProcess.decActiveServices(serviceName);
    413         }
    414         mNumActiveServices--;
    415         if (mNumActiveServices < 0) {
    416             Slog.wtfStack(TAG, "Proc active services underrun: pkg=" + mPackage
    417                     + " uid=" + mUid + " proc=" + mName + " service=" + serviceName);
    418             mNumActiveServices = 0;
    419         }
    420     }
    421 
    422     public void incStartedServices(int memFactor, long now, String serviceName) {
    423         if (false) {
    424             RuntimeException here = new RuntimeException("here");
    425             here.fillInStackTrace();
    426             Slog.d(TAG, "incStartedServices: " + this + " service=" + serviceName
    427                     + " to " + (mNumStartedServices+1), here);
    428         }
    429         if (mCommonProcess != this) {
    430             mCommonProcess.incStartedServices(memFactor, now, serviceName);
    431         }
    432         mNumStartedServices++;
    433         if (mNumStartedServices == 1 && mCurState == STATE_NOTHING) {
    434             setState(STATE_SERVICE_RESTARTING + (memFactor*STATE_COUNT), now);
    435         }
    436     }
    437 
    438     public void decStartedServices(int memFactor, long now, String serviceName) {
    439         if (false) {
    440             RuntimeException here = new RuntimeException("here");
    441             here.fillInStackTrace();
    442             Slog.d(TAG, "decActiveServices: " + this + " service=" + serviceName
    443                     + " to " + (mNumStartedServices-1), here);
    444         }
    445         if (mCommonProcess != this) {
    446             mCommonProcess.decStartedServices(memFactor, now, serviceName);
    447         }
    448         mNumStartedServices--;
    449         if (mNumStartedServices == 0 && (mCurState%STATE_COUNT) == STATE_SERVICE_RESTARTING) {
    450             setState(STATE_NOTHING, now);
    451         } else if (mNumStartedServices < 0) {
    452             Slog.wtfStack(TAG, "Proc started services underrun: pkg="
    453                     + mPackage + " uid=" + mUid + " name=" + mName);
    454             mNumStartedServices = 0;
    455         }
    456     }
    457 
    458     public void addPss(long pss, long uss, long rss, boolean always, int type, long duration,
    459             ArrayMap<String, ProcessStateHolder> pkgList) {
    460         ensureNotDead();
    461         switch (type) {
    462             case ProcessStats.ADD_PSS_INTERNAL_SINGLE:
    463                 mStats.mInternalSinglePssCount++;
    464                 mStats.mInternalSinglePssTime += duration;
    465                 break;
    466             case ProcessStats.ADD_PSS_INTERNAL_ALL_MEM:
    467                 mStats.mInternalAllMemPssCount++;
    468                 mStats.mInternalAllMemPssTime += duration;
    469                 break;
    470             case ProcessStats.ADD_PSS_INTERNAL_ALL_POLL:
    471                 mStats.mInternalAllPollPssCount++;
    472                 mStats.mInternalAllPollPssTime += duration;
    473                 break;
    474             case ProcessStats.ADD_PSS_EXTERNAL:
    475                 mStats.mExternalPssCount++;
    476                 mStats.mExternalPssTime += duration;
    477                 break;
    478             case ProcessStats.ADD_PSS_EXTERNAL_SLOW:
    479                 mStats.mExternalSlowPssCount++;
    480                 mStats.mExternalSlowPssTime += duration;
    481                 break;
    482         }
    483         if (!always) {
    484             if (mLastPssState == mCurState && SystemClock.uptimeMillis()
    485                     < (mLastPssTime+(30*1000))) {
    486                 return;
    487             }
    488         }
    489         mLastPssState = mCurState;
    490         mLastPssTime = SystemClock.uptimeMillis();
    491         if (mCurState != STATE_NOTHING) {
    492             // First update the common process.
    493             mCommonProcess.mPssTable.mergeStats(mCurState, 1, pss, pss, pss, uss, uss, uss,
    494                     rss, rss, rss);
    495 
    496             // If the common process is not multi-package, there is nothing else to do.
    497             if (!mCommonProcess.mMultiPackage) {
    498                 return;
    499             }
    500 
    501             if (pkgList != null) {
    502                 for (int ip=pkgList.size()-1; ip>=0; ip--) {
    503                     pullFixedProc(pkgList, ip).mPssTable.mergeStats(mCurState, 1,
    504                             pss, pss, pss, uss, uss, uss, rss, rss, rss);
    505                 }
    506             }
    507         }
    508     }
    509 
    510     public void reportExcessiveCpu(ArrayMap<String, ProcessStateHolder> pkgList) {
    511         ensureNotDead();
    512         mCommonProcess.mNumExcessiveCpu++;
    513         if (!mCommonProcess.mMultiPackage) {
    514             return;
    515         }
    516 
    517         for (int ip=pkgList.size()-1; ip>=0; ip--) {
    518             pullFixedProc(pkgList, ip).mNumExcessiveCpu++;
    519         }
    520     }
    521 
    522     private void addCachedKill(int num, long minPss, long avgPss, long maxPss) {
    523         if (mNumCachedKill <= 0) {
    524             mNumCachedKill = num;
    525             mMinCachedKillPss = minPss;
    526             mAvgCachedKillPss = avgPss;
    527             mMaxCachedKillPss = maxPss;
    528         } else {
    529             if (minPss < mMinCachedKillPss) {
    530                 mMinCachedKillPss = minPss;
    531             }
    532             if (maxPss > mMaxCachedKillPss) {
    533                 mMaxCachedKillPss = maxPss;
    534             }
    535             mAvgCachedKillPss = (long)( ((mAvgCachedKillPss*(double)mNumCachedKill) + avgPss)
    536                     / (mNumCachedKill+num) );
    537             mNumCachedKill += num;
    538         }
    539     }
    540 
    541     public void reportCachedKill(ArrayMap<String, ProcessStateHolder> pkgList, long pss) {
    542         ensureNotDead();
    543         mCommonProcess.addCachedKill(1, pss, pss, pss);
    544         if (!mCommonProcess.mMultiPackage) {
    545             return;
    546         }
    547 
    548         for (int ip=pkgList.size()-1; ip>=0; ip--) {
    549             pullFixedProc(pkgList, ip).addCachedKill(1, pss, pss, pss);
    550         }
    551     }
    552 
    553     public ProcessState pullFixedProc(String pkgName) {
    554         if (mMultiPackage) {
    555             // The array map is still pointing to a common process state
    556             // that is now shared across packages.  Update it to point to
    557             // the new per-package state.
    558             LongSparseArray<PackageState> vpkg = mStats.mPackages.get(pkgName, mUid);
    559             if (vpkg == null) {
    560                 throw new IllegalStateException("Didn't find package " + pkgName
    561                         + " / " + mUid);
    562             }
    563             PackageState pkg = vpkg.get(mVersion);
    564             if (pkg == null) {
    565                 throw new IllegalStateException("Didn't find package " + pkgName
    566                         + " / " + mUid + " vers " + mVersion);
    567             }
    568             ProcessState proc = pkg.mProcesses.get(mName);
    569             if (proc == null) {
    570                 throw new IllegalStateException("Didn't create per-package process "
    571                         + mName + " in pkg " + pkgName + " / " + mUid + " vers " + mVersion);
    572             }
    573             return proc;
    574         }
    575         return this;
    576     }
    577 
    578     private ProcessState pullFixedProc(ArrayMap<String, ProcessStateHolder> pkgList,
    579             int index) {
    580         ProcessStateHolder holder = pkgList.valueAt(index);
    581         ProcessState proc = holder.state;
    582         if (mDead && proc.mCommonProcess != proc) {
    583             // Somehow we are contining to use a process state that is dead, because
    584             // it was not being told it was active during the last commit.  We can recover
    585             // from this by generating a fresh new state, but this is bad because we
    586             // are losing whatever data we had in the old process state.
    587             Log.wtf(TAG, "Pulling dead proc: name=" + mName + " pkg=" + mPackage
    588                     + " uid=" + mUid + " common.name=" + mCommonProcess.mName);
    589             proc = mStats.getProcessStateLocked(proc.mPackage, proc.mUid, proc.mVersion,
    590                     proc.mName);
    591         }
    592         if (proc.mMultiPackage) {
    593             // The array map is still pointing to a common process state
    594             // that is now shared across packages.  Update it to point to
    595             // the new per-package state.
    596             LongSparseArray<PackageState> vpkg = mStats.mPackages.get(pkgList.keyAt(index),
    597                     proc.mUid);
    598             if (vpkg == null) {
    599                 throw new IllegalStateException("No existing package "
    600                         + pkgList.keyAt(index) + "/" + proc.mUid
    601                         + " for multi-proc " + proc.mName);
    602             }
    603             PackageState pkg = vpkg.get(proc.mVersion);
    604             if (pkg == null) {
    605                 throw new IllegalStateException("No existing package "
    606                         + pkgList.keyAt(index) + "/" + proc.mUid
    607                         + " for multi-proc " + proc.mName + " version " + proc.mVersion);
    608             }
    609             String savedName = proc.mName;
    610             proc = pkg.mProcesses.get(proc.mName);
    611             if (proc == null) {
    612                 throw new IllegalStateException("Didn't create per-package process "
    613                         + savedName + " in pkg " + pkg.mPackageName + "/" + pkg.mUid);
    614             }
    615             holder.state = proc;
    616         }
    617         return proc;
    618     }
    619 
    620     public long getDuration(int state, long now) {
    621         long time = mDurations.getValueForId((byte)state);
    622         if (mCurState == state) {
    623             time += now - mStartTime;
    624         }
    625         return time;
    626     }
    627 
    628     public long getPssSampleCount(int state) {
    629         return mPssTable.getValueForId((byte)state, PSS_SAMPLE_COUNT);
    630     }
    631 
    632     public long getPssMinimum(int state) {
    633         return mPssTable.getValueForId((byte)state, PSS_MINIMUM);
    634     }
    635 
    636     public long getPssAverage(int state) {
    637         return mPssTable.getValueForId((byte)state, PSS_AVERAGE);
    638     }
    639 
    640     public long getPssMaximum(int state) {
    641         return mPssTable.getValueForId((byte)state, PSS_MAXIMUM);
    642     }
    643 
    644     public long getPssUssMinimum(int state) {
    645         return mPssTable.getValueForId((byte)state, PSS_USS_MINIMUM);
    646     }
    647 
    648     public long getPssUssAverage(int state) {
    649         return mPssTable.getValueForId((byte)state, PSS_USS_AVERAGE);
    650     }
    651 
    652     public long getPssUssMaximum(int state) {
    653         return mPssTable.getValueForId((byte)state, PSS_USS_MAXIMUM);
    654     }
    655 
    656     public long getPssRssMinimum(int state) {
    657         return mPssTable.getValueForId((byte)state, PSS_RSS_MINIMUM);
    658     }
    659 
    660     public long getPssRssAverage(int state) {
    661         return mPssTable.getValueForId((byte)state, PSS_RSS_AVERAGE);
    662     }
    663 
    664     public long getPssRssMaximum(int state) {
    665         return mPssTable.getValueForId((byte)state, PSS_RSS_MAXIMUM);
    666     }
    667 
    668     /**
    669      * Sums up the PSS data and adds it to 'data'.
    670      *
    671      * @param data The aggregate data is added here.
    672      * @param now SystemClock.uptimeMillis()
    673      */
    674     public void aggregatePss(TotalMemoryUseCollection data, long now) {
    675         final PssAggr fgPss = new PssAggr();
    676         final PssAggr bgPss = new PssAggr();
    677         final PssAggr cachedPss = new PssAggr();
    678         boolean havePss = false;
    679         for (int i=0; i<mDurations.getKeyCount(); i++) {
    680             final int key = mDurations.getKeyAt(i);
    681             int type = SparseMappingTable.getIdFromKey(key);
    682             int procState = type % STATE_COUNT;
    683             long samples = getPssSampleCount(type);
    684             if (samples > 0) {
    685                 long avg = getPssAverage(type);
    686                 havePss = true;
    687                 if (procState <= STATE_IMPORTANT_FOREGROUND) {
    688                     fgPss.add(avg, samples);
    689                 } else if (procState <= STATE_RECEIVER) {
    690                     bgPss.add(avg, samples);
    691                 } else {
    692                     cachedPss.add(avg, samples);
    693                 }
    694             }
    695         }
    696         if (!havePss) {
    697             return;
    698         }
    699         boolean fgHasBg = false;
    700         boolean fgHasCached = false;
    701         boolean bgHasCached = false;
    702         if (fgPss.samples < 3 && bgPss.samples > 0) {
    703             fgHasBg = true;
    704             fgPss.add(bgPss.pss, bgPss.samples);
    705         }
    706         if (fgPss.samples < 3 && cachedPss.samples > 0) {
    707             fgHasCached = true;
    708             fgPss.add(cachedPss.pss, cachedPss.samples);
    709         }
    710         if (bgPss.samples < 3 && cachedPss.samples > 0) {
    711             bgHasCached = true;
    712             bgPss.add(cachedPss.pss, cachedPss.samples);
    713         }
    714         if (bgPss.samples < 3 && !fgHasBg && fgPss.samples > 0) {
    715             bgPss.add(fgPss.pss, fgPss.samples);
    716         }
    717         if (cachedPss.samples < 3 && !bgHasCached && bgPss.samples > 0) {
    718             cachedPss.add(bgPss.pss, bgPss.samples);
    719         }
    720         if (cachedPss.samples < 3 && !fgHasCached && fgPss.samples > 0) {
    721             cachedPss.add(fgPss.pss, fgPss.samples);
    722         }
    723         for (int i=0; i<mDurations.getKeyCount(); i++) {
    724             final int key = mDurations.getKeyAt(i);
    725             final int type = SparseMappingTable.getIdFromKey(key);
    726             long time = mDurations.getValue(key);
    727             if (mCurState == type) {
    728                 time += now - mStartTime;
    729             }
    730             final int procState = type % STATE_COUNT;
    731             data.processStateTime[procState] += time;
    732             long samples = getPssSampleCount(type);
    733             long avg;
    734             if (samples > 0) {
    735                 avg = getPssAverage(type);
    736             } else if (procState <= STATE_IMPORTANT_FOREGROUND) {
    737                 samples = fgPss.samples;
    738                 avg = fgPss.pss;
    739             } else if (procState <= STATE_RECEIVER) {
    740                 samples = bgPss.samples;
    741                 avg = bgPss.pss;
    742             } else {
    743                 samples = cachedPss.samples;
    744                 avg = cachedPss.pss;
    745             }
    746             double newAvg = ( (data.processStatePss[procState]
    747                     * (double)data.processStateSamples[procState])
    748                         + (avg*(double)samples)
    749                     ) / (data.processStateSamples[procState]+samples);
    750             data.processStatePss[procState] = (long)newAvg;
    751             data.processStateSamples[procState] += samples;
    752             data.processStateWeight[procState] += avg * (double)time;
    753         }
    754     }
    755 
    756     public long computeProcessTimeLocked(int[] screenStates, int[] memStates,
    757                 int[] procStates, long now) {
    758         long totalTime = 0;
    759         for (int is=0; is<screenStates.length; is++) {
    760             for (int im=0; im<memStates.length; im++) {
    761                 for (int ip=0; ip<procStates.length; ip++) {
    762                     int bucket = ((screenStates[is] + memStates[im]) * STATE_COUNT)
    763                             + procStates[ip];
    764                     totalTime += getDuration(bucket, now);
    765                 }
    766             }
    767         }
    768         mTmpTotalTime = totalTime;
    769         return totalTime;
    770     }
    771 
    772     public void dumpSummary(PrintWriter pw, String prefix,
    773             int[] screenStates, int[] memStates, int[] procStates,
    774             long now, long totalTime) {
    775         pw.print(prefix);
    776         pw.print("* ");
    777         pw.print(mName);
    778         pw.print(" / ");
    779         UserHandle.formatUid(pw, mUid);
    780         pw.print(" / v");
    781         pw.print(mVersion);
    782         pw.println(":");
    783         dumpProcessSummaryDetails(pw, prefix, "         TOTAL: ", screenStates, memStates,
    784                 procStates, now, totalTime, true);
    785         dumpProcessSummaryDetails(pw, prefix, "    Persistent: ", screenStates, memStates,
    786                 new int[] { STATE_PERSISTENT }, now, totalTime, true);
    787         dumpProcessSummaryDetails(pw, prefix, "           Top: ", screenStates, memStates,
    788                 new int[] {STATE_TOP}, now, totalTime, true);
    789         dumpProcessSummaryDetails(pw, prefix, "        Imp Fg: ", screenStates, memStates,
    790                 new int[] { STATE_IMPORTANT_FOREGROUND }, now, totalTime, true);
    791         dumpProcessSummaryDetails(pw, prefix, "        Imp Bg: ", screenStates, memStates,
    792                 new int[] {STATE_IMPORTANT_BACKGROUND}, now, totalTime, true);
    793         dumpProcessSummaryDetails(pw, prefix, "        Backup: ", screenStates, memStates,
    794                 new int[] {STATE_BACKUP}, now, totalTime, true);
    795         dumpProcessSummaryDetails(pw, prefix, "     Heavy Wgt: ", screenStates, memStates,
    796                 new int[] {STATE_HEAVY_WEIGHT}, now, totalTime, true);
    797         dumpProcessSummaryDetails(pw, prefix, "       Service: ", screenStates, memStates,
    798                 new int[] {STATE_SERVICE}, now, totalTime, true);
    799         dumpProcessSummaryDetails(pw, prefix, "    Service Rs: ", screenStates, memStates,
    800                 new int[] {STATE_SERVICE_RESTARTING}, now, totalTime, true);
    801         dumpProcessSummaryDetails(pw, prefix, "      Receiver: ", screenStates, memStates,
    802                 new int[] {STATE_RECEIVER}, now, totalTime, true);
    803         dumpProcessSummaryDetails(pw, prefix, "         Heavy: ", screenStates, memStates,
    804                 new int[] {STATE_HOME}, now, totalTime, true);
    805         dumpProcessSummaryDetails(pw, prefix, "        (Home): ", screenStates, memStates,
    806                 new int[] {STATE_HOME}, now, totalTime, true);
    807         dumpProcessSummaryDetails(pw, prefix, "    (Last Act): ", screenStates, memStates,
    808                 new int[] {STATE_LAST_ACTIVITY}, now, totalTime, true);
    809         dumpProcessSummaryDetails(pw, prefix, "      (Cached): ", screenStates, memStates,
    810                 new int[] {STATE_CACHED_ACTIVITY, STATE_CACHED_ACTIVITY_CLIENT,
    811                         STATE_CACHED_EMPTY}, now, totalTime, true);
    812     }
    813 
    814     public void dumpProcessState(PrintWriter pw, String prefix,
    815             int[] screenStates, int[] memStates, int[] procStates, long now) {
    816         long totalTime = 0;
    817         int printedScreen = -1;
    818         for (int is=0; is<screenStates.length; is++) {
    819             int printedMem = -1;
    820             for (int im=0; im<memStates.length; im++) {
    821                 for (int ip=0; ip<procStates.length; ip++) {
    822                     final int iscreen = screenStates[is];
    823                     final int imem = memStates[im];
    824                     final int bucket = ((iscreen + imem) * STATE_COUNT) + procStates[ip];
    825                     long time = mDurations.getValueForId((byte)bucket);
    826                     String running = "";
    827                     if (mCurState == bucket) {
    828                         running = " (running)";
    829                     }
    830                     if (time != 0) {
    831                         pw.print(prefix);
    832                         if (screenStates.length > 1) {
    833                             DumpUtils.printScreenLabel(pw, printedScreen != iscreen
    834                                     ? iscreen : STATE_NOTHING);
    835                             printedScreen = iscreen;
    836                         }
    837                         if (memStates.length > 1) {
    838                             DumpUtils.printMemLabel(pw,
    839                                     printedMem != imem ? imem : STATE_NOTHING, '/');
    840                             printedMem = imem;
    841                         }
    842                         pw.print(DumpUtils.STATE_NAMES[procStates[ip]]); pw.print(": ");
    843                         TimeUtils.formatDuration(time, pw); pw.println(running);
    844                         totalTime += time;
    845                     }
    846                 }
    847             }
    848         }
    849         if (totalTime != 0) {
    850             pw.print(prefix);
    851             if (screenStates.length > 1) {
    852                 DumpUtils.printScreenLabel(pw, STATE_NOTHING);
    853             }
    854             if (memStates.length > 1) {
    855                 DumpUtils.printMemLabel(pw, STATE_NOTHING, '/');
    856             }
    857             pw.print("TOTAL  : ");
    858             TimeUtils.formatDuration(totalTime, pw);
    859             pw.println();
    860         }
    861     }
    862 
    863     public void dumpPss(PrintWriter pw, String prefix,
    864             int[] screenStates, int[] memStates, int[] procStates) {
    865         boolean printedHeader = false;
    866         int printedScreen = -1;
    867         for (int is=0; is<screenStates.length; is++) {
    868             int printedMem = -1;
    869             for (int im=0; im<memStates.length; im++) {
    870                 for (int ip=0; ip<procStates.length; ip++) {
    871                     final int iscreen = screenStates[is];
    872                     final int imem = memStates[im];
    873                     final int bucket = ((iscreen + imem) * STATE_COUNT) + procStates[ip];
    874                     long count = getPssSampleCount(bucket);
    875                     if (count > 0) {
    876                         if (!printedHeader) {
    877                             pw.print(prefix);
    878                             pw.print("PSS/USS (");
    879                             pw.print(mPssTable.getKeyCount());
    880                             pw.println(" entries):");
    881                             printedHeader = true;
    882                         }
    883                         pw.print(prefix);
    884                         pw.print("  ");
    885                         if (screenStates.length > 1) {
    886                             DumpUtils.printScreenLabel(pw,
    887                                     printedScreen != iscreen ? iscreen : STATE_NOTHING);
    888                             printedScreen = iscreen;
    889                         }
    890                         if (memStates.length > 1) {
    891                             DumpUtils.printMemLabel(pw,
    892                                     printedMem != imem ? imem : STATE_NOTHING, '/');
    893                             printedMem = imem;
    894                         }
    895                         pw.print(DumpUtils.STATE_NAMES[procStates[ip]]); pw.print(": ");
    896                         pw.print(count);
    897                         pw.print(" samples ");
    898                         DebugUtils.printSizeValue(pw, getPssMinimum(bucket) * 1024);
    899                         pw.print(" ");
    900                         DebugUtils.printSizeValue(pw, getPssAverage(bucket) * 1024);
    901                         pw.print(" ");
    902                         DebugUtils.printSizeValue(pw, getPssMaximum(bucket) * 1024);
    903                         pw.print(" / ");
    904                         DebugUtils.printSizeValue(pw, getPssUssMinimum(bucket) * 1024);
    905                         pw.print(" ");
    906                         DebugUtils.printSizeValue(pw, getPssUssAverage(bucket) * 1024);
    907                         pw.print(" ");
    908                         DebugUtils.printSizeValue(pw, getPssUssMaximum(bucket) * 1024);
    909                         pw.print(" / ");
    910                         DebugUtils.printSizeValue(pw, getPssRssMinimum(bucket) * 1024);
    911                         pw.print(" ");
    912                         DebugUtils.printSizeValue(pw, getPssRssAverage(bucket) * 1024);
    913                         pw.print(" ");
    914                         DebugUtils.printSizeValue(pw, getPssRssMaximum(bucket) * 1024);
    915                         pw.println();
    916                     }
    917                 }
    918             }
    919         }
    920         if (mNumExcessiveCpu != 0) {
    921             pw.print(prefix); pw.print("Killed for excessive CPU use: ");
    922                     pw.print(mNumExcessiveCpu); pw.println(" times");
    923         }
    924         if (mNumCachedKill != 0) {
    925             pw.print(prefix); pw.print("Killed from cached state: ");
    926                     pw.print(mNumCachedKill); pw.print(" times from pss ");
    927                     DebugUtils.printSizeValue(pw, mMinCachedKillPss * 1024); pw.print("-");
    928                     DebugUtils.printSizeValue(pw, mAvgCachedKillPss * 1024); pw.print("-");
    929                     DebugUtils.printSizeValue(pw, mMaxCachedKillPss * 1024); pw.println();
    930         }
    931     }
    932 
    933     private void dumpProcessSummaryDetails(PrintWriter pw, String prefix,
    934             String label, int[] screenStates, int[] memStates, int[] procStates,
    935             long now, long totalTime, boolean full) {
    936         ProcessStats.ProcessDataCollection totals = new ProcessStats.ProcessDataCollection(
    937                 screenStates, memStates, procStates);
    938         computeProcessData(totals, now);
    939         final double percentage = (double) totals.totalTime / (double) totalTime * 100;
    940         // We don't print percentages < .01, so just drop those.
    941         if (percentage >= 0.005 || totals.numPss != 0) {
    942             if (prefix != null) {
    943                 pw.print(prefix);
    944             }
    945             if (label != null) {
    946                 pw.print(label);
    947             }
    948             totals.print(pw, totalTime, full);
    949             if (prefix != null) {
    950                 pw.println();
    951             }
    952         }
    953     }
    954 
    955     public void dumpInternalLocked(PrintWriter pw, String prefix, boolean dumpAll) {
    956         if (dumpAll) {
    957             pw.print(prefix); pw.print("myID=");
    958                     pw.print(Integer.toHexString(System.identityHashCode(this)));
    959                     pw.print(" mCommonProcess=");
    960                     pw.print(Integer.toHexString(System.identityHashCode(mCommonProcess)));
    961                     pw.print(" mPackage="); pw.println(mPackage);
    962             if (mMultiPackage) {
    963                 pw.print(prefix); pw.print("mMultiPackage="); pw.println(mMultiPackage);
    964             }
    965             if (this != mCommonProcess) {
    966                 pw.print(prefix); pw.print("Common Proc: "); pw.print(mCommonProcess.mName);
    967                         pw.print("/"); pw.print(mCommonProcess.mUid);
    968                         pw.print(" pkg="); pw.println(mCommonProcess.mPackage);
    969             }
    970         }
    971         if (mActive) {
    972             pw.print(prefix); pw.print("mActive="); pw.println(mActive);
    973         }
    974         if (mDead) {
    975             pw.print(prefix); pw.print("mDead="); pw.println(mDead);
    976         }
    977         if (mNumActiveServices != 0 || mNumStartedServices != 0) {
    978             pw.print(prefix); pw.print("mNumActiveServices="); pw.print(mNumActiveServices);
    979                     pw.print(" mNumStartedServices=");
    980                     pw.println(mNumStartedServices);
    981         }
    982     }
    983 
    984     public void computeProcessData(ProcessStats.ProcessDataCollection data, long now) {
    985         data.totalTime = 0;
    986         data.numPss = data.minPss = data.avgPss = data.maxPss =
    987                 data.minUss = data.avgUss = data.maxUss =
    988                 data.minRss = data.avgRss = data.maxRss = 0;
    989         for (int is=0; is<data.screenStates.length; is++) {
    990             for (int im=0; im<data.memStates.length; im++) {
    991                 for (int ip=0; ip<data.procStates.length; ip++) {
    992                     int bucket = ((data.screenStates[is] + data.memStates[im]) * STATE_COUNT)
    993                             + data.procStates[ip];
    994                     data.totalTime += getDuration(bucket, now);
    995                     long samples = getPssSampleCount(bucket);
    996                     if (samples > 0) {
    997                         long minPss = getPssMinimum(bucket);
    998                         long avgPss = getPssAverage(bucket);
    999                         long maxPss = getPssMaximum(bucket);
   1000                         long minUss = getPssUssMinimum(bucket);
   1001                         long avgUss = getPssUssAverage(bucket);
   1002                         long maxUss = getPssUssMaximum(bucket);
   1003                         long minRss = getPssRssMinimum(bucket);
   1004                         long avgRss = getPssRssAverage(bucket);
   1005                         long maxRss = getPssRssMaximum(bucket);
   1006                         if (data.numPss == 0) {
   1007                             data.minPss = minPss;
   1008                             data.avgPss = avgPss;
   1009                             data.maxPss = maxPss;
   1010                             data.minUss = minUss;
   1011                             data.avgUss = avgUss;
   1012                             data.maxUss = maxUss;
   1013                             data.minRss = minRss;
   1014                             data.avgRss = avgRss;
   1015                             data.maxRss = maxRss;
   1016                         } else {
   1017                             if (minPss < data.minPss) {
   1018                                 data.minPss = minPss;
   1019                             }
   1020                             data.avgPss = (long)( ((data.avgPss*(double)data.numPss)
   1021                                     + (avgPss*(double)samples)) / (data.numPss+samples) );
   1022                             if (maxPss > data.maxPss) {
   1023                                 data.maxPss = maxPss;
   1024                             }
   1025                             if (minUss < data.minUss) {
   1026                                 data.minUss = minUss;
   1027                             }
   1028                             data.avgUss = (long)( ((data.avgUss*(double)data.numPss)
   1029                                     + (avgUss*(double)samples)) / (data.numPss+samples) );
   1030                             if (maxUss > data.maxUss) {
   1031                                 data.maxUss = maxUss;
   1032                             }
   1033                             if (minRss < data.minRss) {
   1034                                 data.minRss = minRss;
   1035                             }
   1036                             data.avgRss = (long)( ((data.avgRss*(double)data.numPss)
   1037                                     + (avgRss*(double)samples)) / (data.numPss+samples) );
   1038                             if (maxRss > data.maxRss) {
   1039                                 data.maxRss = maxRss;
   1040                             }
   1041                         }
   1042                         data.numPss += samples;
   1043                     }
   1044                 }
   1045             }
   1046         }
   1047     }
   1048 
   1049     public void dumpCsv(PrintWriter pw,
   1050             boolean sepScreenStates, int[] screenStates, boolean sepMemStates,
   1051             int[] memStates, boolean sepProcStates, int[] procStates, long now) {
   1052         final int NSS = sepScreenStates ? screenStates.length : 1;
   1053         final int NMS = sepMemStates ? memStates.length : 1;
   1054         final int NPS = sepProcStates ? procStates.length : 1;
   1055         for (int iss=0; iss<NSS; iss++) {
   1056             for (int ims=0; ims<NMS; ims++) {
   1057                 for (int ips=0; ips<NPS; ips++) {
   1058                     final int vsscreen = sepScreenStates ? screenStates[iss] : 0;
   1059                     final int vsmem = sepMemStates ? memStates[ims] : 0;
   1060                     final int vsproc = sepProcStates ? procStates[ips] : 0;
   1061                     final int NSA = sepScreenStates ? 1 : screenStates.length;
   1062                     final int NMA = sepMemStates ? 1 : memStates.length;
   1063                     final int NPA = sepProcStates ? 1 : procStates.length;
   1064                     long totalTime = 0;
   1065                     for (int isa=0; isa<NSA; isa++) {
   1066                         for (int ima=0; ima<NMA; ima++) {
   1067                             for (int ipa=0; ipa<NPA; ipa++) {
   1068                                 final int vascreen = sepScreenStates ? 0 : screenStates[isa];
   1069                                 final int vamem = sepMemStates ? 0 : memStates[ima];
   1070                                 final int vaproc = sepProcStates ? 0 : procStates[ipa];
   1071                                 final int bucket = ((vsscreen + vascreen + vsmem + vamem)
   1072                                         * STATE_COUNT) + vsproc + vaproc;
   1073                                 totalTime += getDuration(bucket, now);
   1074                             }
   1075                         }
   1076                     }
   1077                     pw.print(DumpUtils.CSV_SEP);
   1078                     pw.print(totalTime);
   1079                 }
   1080             }
   1081         }
   1082     }
   1083 
   1084     public void dumpPackageProcCheckin(PrintWriter pw, String pkgName, int uid, long vers,
   1085             String itemName, long now) {
   1086         pw.print("pkgproc,");
   1087         pw.print(pkgName);
   1088         pw.print(",");
   1089         pw.print(uid);
   1090         pw.print(",");
   1091         pw.print(vers);
   1092         pw.print(",");
   1093         pw.print(DumpUtils.collapseString(pkgName, itemName));
   1094         dumpAllStateCheckin(pw, now);
   1095         pw.println();
   1096         if (mPssTable.getKeyCount() > 0) {
   1097             pw.print("pkgpss,");
   1098             pw.print(pkgName);
   1099             pw.print(",");
   1100             pw.print(uid);
   1101             pw.print(",");
   1102             pw.print(vers);
   1103             pw.print(",");
   1104             pw.print(DumpUtils.collapseString(pkgName, itemName));
   1105             dumpAllPssCheckin(pw);
   1106             pw.println();
   1107         }
   1108         if (mNumExcessiveCpu > 0 || mNumCachedKill > 0) {
   1109             pw.print("pkgkills,");
   1110             pw.print(pkgName);
   1111             pw.print(",");
   1112             pw.print(uid);
   1113             pw.print(",");
   1114             pw.print(vers);
   1115             pw.print(",");
   1116             pw.print(DumpUtils.collapseString(pkgName, itemName));
   1117             pw.print(",");
   1118             pw.print("0"); // was mNumExcessiveWake
   1119             pw.print(",");
   1120             pw.print(mNumExcessiveCpu);
   1121             pw.print(",");
   1122             pw.print(mNumCachedKill);
   1123             pw.print(",");
   1124             pw.print(mMinCachedKillPss);
   1125             pw.print(":");
   1126             pw.print(mAvgCachedKillPss);
   1127             pw.print(":");
   1128             pw.print(mMaxCachedKillPss);
   1129             pw.println();
   1130         }
   1131     }
   1132 
   1133     public void dumpProcCheckin(PrintWriter pw, String procName, int uid, long now) {
   1134         if (mDurations.getKeyCount() > 0) {
   1135             pw.print("proc,");
   1136             pw.print(procName);
   1137             pw.print(",");
   1138             pw.print(uid);
   1139             dumpAllStateCheckin(pw, now);
   1140             pw.println();
   1141         }
   1142         if (mPssTable.getKeyCount() > 0) {
   1143             pw.print("pss,");
   1144             pw.print(procName);
   1145             pw.print(",");
   1146             pw.print(uid);
   1147             dumpAllPssCheckin(pw);
   1148             pw.println();
   1149         }
   1150         if (mNumExcessiveCpu > 0 || mNumCachedKill > 0) {
   1151             pw.print("kills,");
   1152             pw.print(procName);
   1153             pw.print(",");
   1154             pw.print(uid);
   1155             pw.print(",");
   1156             pw.print("0"); // was mNumExcessiveWake
   1157             pw.print(",");
   1158             pw.print(mNumExcessiveCpu);
   1159             pw.print(",");
   1160             pw.print(mNumCachedKill);
   1161             pw.print(",");
   1162             pw.print(mMinCachedKillPss);
   1163             pw.print(":");
   1164             pw.print(mAvgCachedKillPss);
   1165             pw.print(":");
   1166             pw.print(mMaxCachedKillPss);
   1167             pw.println();
   1168         }
   1169     }
   1170 
   1171     public void dumpAllStateCheckin(PrintWriter pw, long now) {
   1172         boolean didCurState = false;
   1173         for (int i=0; i<mDurations.getKeyCount(); i++) {
   1174             final int key = mDurations.getKeyAt(i);
   1175             final int type = SparseMappingTable.getIdFromKey(key);
   1176             long time = mDurations.getValue(key);
   1177             if (mCurState == type) {
   1178                 didCurState = true;
   1179                 time += now - mStartTime;
   1180             }
   1181             DumpUtils.printProcStateTagAndValue(pw, type, time);
   1182         }
   1183         if (!didCurState && mCurState != STATE_NOTHING) {
   1184             DumpUtils.printProcStateTagAndValue(pw, mCurState, now - mStartTime);
   1185         }
   1186     }
   1187 
   1188     public void dumpAllPssCheckin(PrintWriter pw) {
   1189         final int N = mPssTable.getKeyCount();
   1190         for (int i=0; i<N; i++) {
   1191             final int key = mPssTable.getKeyAt(i);
   1192             final int type = SparseMappingTable.getIdFromKey(key);
   1193             pw.print(',');
   1194             DumpUtils.printProcStateTag(pw, type);
   1195             pw.print(':');
   1196             pw.print(mPssTable.getValue(key, PSS_SAMPLE_COUNT));
   1197             pw.print(':');
   1198             pw.print(mPssTable.getValue(key, PSS_MINIMUM));
   1199             pw.print(':');
   1200             pw.print(mPssTable.getValue(key, PSS_AVERAGE));
   1201             pw.print(':');
   1202             pw.print(mPssTable.getValue(key, PSS_MAXIMUM));
   1203             pw.print(':');
   1204             pw.print(mPssTable.getValue(key, PSS_USS_MINIMUM));
   1205             pw.print(':');
   1206             pw.print(mPssTable.getValue(key, PSS_USS_AVERAGE));
   1207             pw.print(':');
   1208             pw.print(mPssTable.getValue(key, PSS_USS_MAXIMUM));
   1209             pw.print(':');
   1210             pw.print(mPssTable.getValue(key, PSS_RSS_MINIMUM));
   1211             pw.print(':');
   1212             pw.print(mPssTable.getValue(key, PSS_RSS_AVERAGE));
   1213             pw.print(':');
   1214             pw.print(mPssTable.getValue(key, PSS_RSS_MAXIMUM));
   1215         }
   1216     }
   1217 
   1218     @Override
   1219     public String toString() {
   1220         StringBuilder sb = new StringBuilder(128);
   1221         sb.append("ProcessState{").append(Integer.toHexString(System.identityHashCode(this)))
   1222                 .append(" ").append(mName).append("/").append(mUid)
   1223                 .append(" pkg=").append(mPackage);
   1224         if (mMultiPackage) sb.append(" (multi)");
   1225         if (mCommonProcess != this) sb.append(" (sub)");
   1226         sb.append("}");
   1227         return sb.toString();
   1228     }
   1229 
   1230     public void writeToProto(ProtoOutputStream proto, long fieldId,
   1231             String procName, int uid, long now) {
   1232         final long token = proto.start(fieldId);
   1233         proto.write(ProcessStatsProto.PROCESS, procName);
   1234         proto.write(ProcessStatsProto.UID, uid);
   1235         if (mNumExcessiveCpu > 0 || mNumCachedKill > 0 ) {
   1236             final long killToken = proto.start(ProcessStatsProto.KILL);
   1237             proto.write(ProcessStatsProto.Kill.CPU, mNumExcessiveCpu);
   1238             proto.write(ProcessStatsProto.Kill.CACHED, mNumCachedKill);
   1239             ProtoUtils.toAggStatsProto(proto, ProcessStatsProto.Kill.CACHED_PSS,
   1240                     mMinCachedKillPss, mAvgCachedKillPss, mMaxCachedKillPss);
   1241             proto.end(killToken);
   1242         }
   1243 
   1244         // Group proc stats by type (screen state + mem state + process state)
   1245         Map<Integer, Long> durationByState = new HashMap<>();
   1246         boolean didCurState = false;
   1247         for (int i=0; i<mDurations.getKeyCount(); i++) {
   1248             final int key = mDurations.getKeyAt(i);
   1249             final int type = SparseMappingTable.getIdFromKey(key);
   1250             long time = mDurations.getValue(key);
   1251             if (mCurState == type) {
   1252                 didCurState = true;
   1253                 time += now - mStartTime;
   1254             }
   1255             durationByState.put(type, time);
   1256         }
   1257         if (!didCurState && mCurState != STATE_NOTHING) {
   1258             durationByState.put(mCurState, now - mStartTime);
   1259         }
   1260 
   1261         for (int i=0; i<mPssTable.getKeyCount(); i++) {
   1262             final int key = mPssTable.getKeyAt(i);
   1263             final int type = SparseMappingTable.getIdFromKey(key);
   1264             if (!durationByState.containsKey(type)) {
   1265                 // state without duration should not have stats!
   1266                 continue;
   1267             }
   1268             final long stateToken = proto.start(ProcessStatsProto.STATES);
   1269             DumpUtils.printProcStateTagProto(proto,
   1270                     ProcessStatsProto.State.SCREEN_STATE,
   1271                     ProcessStatsProto.State.MEMORY_STATE,
   1272                     ProcessStatsProto.State.PROCESS_STATE,
   1273                     type);
   1274 
   1275             long duration = durationByState.get(type);
   1276             durationByState.remove(type); // remove the key since it is already being dumped.
   1277             proto.write(ProcessStatsProto.State.DURATION_MS, duration);
   1278 
   1279             proto.write(ProcessStatsProto.State.SAMPLE_SIZE, mPssTable.getValue(key, PSS_SAMPLE_COUNT));
   1280             ProtoUtils.toAggStatsProto(proto, ProcessStatsProto.State.PSS,
   1281                     mPssTable.getValue(key, PSS_MINIMUM),
   1282                     mPssTable.getValue(key, PSS_AVERAGE),
   1283                     mPssTable.getValue(key, PSS_MAXIMUM));
   1284             ProtoUtils.toAggStatsProto(proto, ProcessStatsProto.State.USS,
   1285                     mPssTable.getValue(key, PSS_USS_MINIMUM),
   1286                     mPssTable.getValue(key, PSS_USS_AVERAGE),
   1287                     mPssTable.getValue(key, PSS_USS_MAXIMUM));
   1288             ProtoUtils.toAggStatsProto(proto, ProcessStatsProto.State.RSS,
   1289                     mPssTable.getValue(key, PSS_RSS_MINIMUM),
   1290                     mPssTable.getValue(key, PSS_RSS_AVERAGE),
   1291                     mPssTable.getValue(key, PSS_RSS_MAXIMUM));
   1292 
   1293             proto.end(stateToken);
   1294         }
   1295 
   1296         for (Map.Entry<Integer, Long> entry : durationByState.entrySet()) {
   1297             final long stateToken = proto.start(ProcessStatsProto.STATES);
   1298             DumpUtils.printProcStateTagProto(proto,
   1299                     ProcessStatsProto.State.SCREEN_STATE,
   1300                     ProcessStatsProto.State.MEMORY_STATE,
   1301                     ProcessStatsProto.State.PROCESS_STATE,
   1302                     entry.getKey());
   1303             proto.write(ProcessStatsProto.State.DURATION_MS, entry.getValue());
   1304             proto.end(stateToken);
   1305         }
   1306         proto.end(token);
   1307     }
   1308 }
   1309