Home | History | Annotate | Download | only in applications
      1 /*
      2  * Copyright (C) 2010 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.settings.applications;
     18 
     19 import com.android.settings.R;
     20 import com.android.settings.Utils;
     21 
     22 import android.app.ActivityManager;
     23 import android.app.ActivityManagerNative;
     24 import android.app.ActivityThread;
     25 import android.content.ComponentName;
     26 import android.content.Context;
     27 import android.content.pm.ApplicationInfo;
     28 import android.content.pm.PackageInfo;
     29 import android.content.pm.PackageItemInfo;
     30 import android.content.pm.PackageManager;
     31 import android.content.pm.ServiceInfo;
     32 import android.content.pm.UserInfo;
     33 import android.content.res.Resources;
     34 import android.graphics.drawable.Drawable;
     35 import android.graphics.drawable.Drawable.ConstantState;
     36 import android.os.Handler;
     37 import android.os.HandlerThread;
     38 import android.os.Looper;
     39 import android.os.Message;
     40 import android.os.RemoteException;
     41 import android.os.UserHandle;
     42 import android.os.UserManager;
     43 import android.text.format.Formatter;
     44 import android.util.Log;
     45 import android.util.SparseArray;
     46 
     47 import java.util.ArrayList;
     48 import java.util.Collections;
     49 import java.util.Comparator;
     50 import java.util.HashMap;
     51 import java.util.Iterator;
     52 import java.util.List;
     53 
     54 /**
     55  * Singleton for retrieving and monitoring the state about all running
     56  * applications/processes/services.
     57  */
     58 public class RunningState {
     59     static final String TAG = "RunningState";
     60     static final boolean DEBUG_COMPARE = false;
     61 
     62     static Object sGlobalLock = new Object();
     63     static RunningState sInstance;
     64 
     65     static final int MSG_RESET_CONTENTS = 1;
     66     static final int MSG_UPDATE_CONTENTS = 2;
     67     static final int MSG_REFRESH_UI = 3;
     68     static final int MSG_UPDATE_TIME = 4;
     69 
     70     static final long TIME_UPDATE_DELAY = 1000;
     71     static final long CONTENTS_UPDATE_DELAY = 2000;
     72 
     73     static final int MAX_SERVICES = 100;
     74 
     75     final Context mApplicationContext;
     76     final ActivityManager mAm;
     77     final PackageManager mPm;
     78     final UserManager mUm;
     79     final int mMyUserId;
     80 
     81     OnRefreshUiListener mRefreshUiListener;
     82 
     83     final InterestingConfigChanges mInterestingConfigChanges = new InterestingConfigChanges();
     84 
     85     // Processes that are hosting a service we are interested in, organized
     86     // by uid and name.  Note that this mapping does not change even across
     87     // service restarts, and during a restart there will still be a process
     88     // entry.
     89     final SparseArray<HashMap<String, ProcessItem>> mServiceProcessesByName
     90             = new SparseArray<HashMap<String, ProcessItem>>();
     91 
     92     // Processes that are hosting a service we are interested in, organized
     93     // by their pid.  These disappear and re-appear as services are restarted.
     94     final SparseArray<ProcessItem> mServiceProcessesByPid
     95             = new SparseArray<ProcessItem>();
     96 
     97     // Used to sort the interesting processes.
     98     final ServiceProcessComparator mServiceProcessComparator
     99             = new ServiceProcessComparator();
    100 
    101     // Additional interesting processes to be shown to the user, even if
    102     // there is no service running in them.
    103     final ArrayList<ProcessItem> mInterestingProcesses = new ArrayList<ProcessItem>();
    104 
    105     // All currently running processes, for finding dependencies etc.
    106     final SparseArray<ProcessItem> mRunningProcesses
    107             = new SparseArray<ProcessItem>();
    108 
    109     // The processes associated with services, in sorted order.
    110     final ArrayList<ProcessItem> mProcessItems = new ArrayList<ProcessItem>();
    111 
    112     // All processes, used for retrieving memory information.
    113     final ArrayList<ProcessItem> mAllProcessItems = new ArrayList<ProcessItem>();
    114 
    115     // If there are other users on the device, these are the merged items
    116     // representing all items that would be put in mMergedItems for that user.
    117     final SparseArray<MergedItem> mOtherUserMergedItems = new SparseArray<MergedItem>();
    118 
    119     // If there are other users on the device, these are the merged items
    120     // representing all items that would be put in mUserBackgroundItems for that user.
    121     final SparseArray<MergedItem> mOtherUserBackgroundItems = new SparseArray<MergedItem>();
    122 
    123     // Tracking of information about users.
    124     final SparseArray<UserState> mUsers = new SparseArray<UserState>();
    125 
    126     static class AppProcessInfo {
    127         final ActivityManager.RunningAppProcessInfo info;
    128         boolean hasServices;
    129         boolean hasForegroundServices;
    130 
    131         AppProcessInfo(ActivityManager.RunningAppProcessInfo _info) {
    132             info = _info;
    133         }
    134     }
    135 
    136     // Temporary structure used when updating above information.
    137     final SparseArray<AppProcessInfo> mTmpAppProcesses = new SparseArray<AppProcessInfo>();
    138 
    139     int mSequence = 0;
    140 
    141     final Comparator<RunningState.MergedItem> mBackgroundComparator
    142         = new Comparator<RunningState.MergedItem>() {
    143             @Override
    144             public int compare(MergedItem lhs, MergedItem rhs) {
    145                 if (DEBUG_COMPARE) {
    146                     Log.i(TAG, "Comparing " + lhs + " with " + rhs);
    147                     Log.i(TAG, "     Proc " + lhs.mProcess + " with " + rhs.mProcess);
    148                     Log.i(TAG, "   UserId " + lhs.mUserId + " with " + rhs.mUserId);
    149                 }
    150                 if (lhs.mUserId != rhs.mUserId) {
    151                     if (lhs.mUserId == mMyUserId) return -1;
    152                     if (rhs.mUserId == mMyUserId) return 1;
    153                     return lhs.mUserId < rhs.mUserId ? -1 : 1;
    154                 }
    155                 if (lhs.mProcess == rhs.mProcess) {
    156                     if (lhs.mLabel == rhs.mLabel) {
    157                         return 0;
    158                     }
    159                     return lhs.mLabel != null ? lhs.mLabel.compareTo(rhs.mLabel) : -1;
    160                 }
    161                 if (lhs.mProcess == null) return -1;
    162                 if (rhs.mProcess == null) return 1;
    163                 if (DEBUG_COMPARE) Log.i(TAG, "    Label " + lhs.mProcess.mLabel
    164                         + " with " + rhs.mProcess.mLabel);
    165                 final ActivityManager.RunningAppProcessInfo lhsInfo
    166                         = lhs.mProcess.mRunningProcessInfo;
    167                 final ActivityManager.RunningAppProcessInfo rhsInfo
    168                         = rhs.mProcess.mRunningProcessInfo;
    169                 final boolean lhsBg = lhsInfo.importance
    170                         >= ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
    171                 final boolean rhsBg = rhsInfo.importance
    172                         >= ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
    173                         if (DEBUG_COMPARE) Log.i(TAG, "       Bg " + lhsBg + " with " + rhsBg);
    174                 if (lhsBg != rhsBg) {
    175                     return lhsBg ? 1 : -1;
    176                 }
    177                 final boolean lhsA = (lhsInfo.flags
    178                         & ActivityManager.RunningAppProcessInfo.FLAG_HAS_ACTIVITIES) != 0;
    179                 final boolean rhsA = (rhsInfo.flags
    180                         & ActivityManager.RunningAppProcessInfo.FLAG_HAS_ACTIVITIES) != 0;
    181                 if (DEBUG_COMPARE) Log.i(TAG, "      Act " + lhsA + " with " + rhsA);
    182                 if (lhsA != rhsA) {
    183                     return lhsA ? -1 : 1;
    184                 }
    185                 if (DEBUG_COMPARE) Log.i(TAG, "      Lru " + lhsInfo.lru + " with " + rhsInfo.lru);
    186                 if (lhsInfo.lru != rhsInfo.lru) {
    187                     return lhsInfo.lru < rhsInfo.lru ? -1 : 1;
    188                 }
    189                 if (lhs.mProcess.mLabel == rhs.mProcess.mLabel) {
    190                     return 0;
    191                 }
    192                 if (lhs.mProcess.mLabel == null) return 1;
    193                 if (rhs.mProcess.mLabel == null) return -1;
    194                 return lhs.mProcess.mLabel.compareTo(rhs.mProcess.mLabel);
    195             }
    196     };
    197 
    198     // ----- following protected by mLock -----
    199 
    200     // Lock for protecting the state that will be shared between the
    201     // background update thread and the UI thread.
    202     final Object mLock = new Object();
    203 
    204     boolean mResumed;
    205     boolean mHaveData;
    206     boolean mWatchingBackgroundItems;
    207 
    208     ArrayList<BaseItem> mItems = new ArrayList<BaseItem>();
    209     ArrayList<MergedItem> mMergedItems = new ArrayList<MergedItem>();
    210     ArrayList<MergedItem> mBackgroundItems = new ArrayList<MergedItem>();
    211     ArrayList<MergedItem> mUserBackgroundItems = new ArrayList<MergedItem>();
    212 
    213     int mNumBackgroundProcesses;
    214     long mBackgroundProcessMemory;
    215     int mNumForegroundProcesses;
    216     long mForegroundProcessMemory;
    217     int mNumServiceProcesses;
    218     long mServiceProcessMemory;
    219 
    220     // ----- BACKGROUND MONITORING THREAD -----
    221 
    222     final HandlerThread mBackgroundThread;
    223     final class BackgroundHandler extends Handler {
    224         public BackgroundHandler(Looper looper) {
    225             super(looper);
    226         }
    227 
    228         @Override
    229         public void handleMessage(Message msg) {
    230             switch (msg.what) {
    231                 case MSG_RESET_CONTENTS:
    232                     reset();
    233                     break;
    234                 case MSG_UPDATE_CONTENTS:
    235                     synchronized (mLock) {
    236                         if (!mResumed) {
    237                             return;
    238                         }
    239                     }
    240                     Message cmd = mHandler.obtainMessage(MSG_REFRESH_UI);
    241                     cmd.arg1 = update(mApplicationContext, mAm) ? 1 : 0;
    242                     mHandler.sendMessage(cmd);
    243                     removeMessages(MSG_UPDATE_CONTENTS);
    244                     msg = obtainMessage(MSG_UPDATE_CONTENTS);
    245                     sendMessageDelayed(msg, CONTENTS_UPDATE_DELAY);
    246                     break;
    247             }
    248         }
    249     };
    250 
    251     final BackgroundHandler mBackgroundHandler;
    252 
    253     final Handler mHandler = new Handler() {
    254         int mNextUpdate = OnRefreshUiListener.REFRESH_TIME;
    255 
    256         @Override
    257         public void handleMessage(Message msg) {
    258             switch (msg.what) {
    259                 case MSG_REFRESH_UI:
    260                     mNextUpdate = msg.arg1 != 0
    261                             ? OnRefreshUiListener.REFRESH_STRUCTURE
    262                             : OnRefreshUiListener.REFRESH_DATA;
    263                     break;
    264                 case MSG_UPDATE_TIME:
    265                     synchronized (mLock) {
    266                         if (!mResumed) {
    267                             return;
    268                         }
    269                     }
    270                     removeMessages(MSG_UPDATE_TIME);
    271                     Message m = obtainMessage(MSG_UPDATE_TIME);
    272                     sendMessageDelayed(m, TIME_UPDATE_DELAY);
    273 
    274                     if (mRefreshUiListener != null) {
    275                         //Log.i("foo", "Refresh UI: " + mNextUpdate
    276                         //        + " @ " + SystemClock.uptimeMillis());
    277                         mRefreshUiListener.onRefreshUi(mNextUpdate);
    278                         mNextUpdate = OnRefreshUiListener.REFRESH_TIME;
    279                     }
    280                     break;
    281             }
    282         }
    283     };
    284 
    285     // ----- DATA STRUCTURES -----
    286 
    287     static interface OnRefreshUiListener {
    288         public static final int REFRESH_TIME = 0;
    289         public static final int REFRESH_DATA = 1;
    290         public static final int REFRESH_STRUCTURE = 2;
    291 
    292         public void onRefreshUi(int what);
    293     }
    294 
    295     static class UserState {
    296         UserInfo mInfo;
    297         String mLabel;
    298         Drawable mIcon;
    299     }
    300 
    301     static class BaseItem {
    302         final boolean mIsProcess;
    303         final int mUserId;
    304 
    305         PackageItemInfo mPackageInfo;
    306         CharSequence mDisplayLabel;
    307         String mLabel;
    308         String mDescription;
    309 
    310         int mCurSeq;
    311 
    312         long mActiveSince;
    313         long mSize;
    314         String mSizeStr;
    315         String mCurSizeStr;
    316         boolean mNeedDivider;
    317         boolean mBackground;
    318 
    319         public BaseItem(boolean isProcess, int userId) {
    320             mIsProcess = isProcess;
    321             mUserId = userId;
    322         }
    323 
    324         public Drawable loadIcon(Context context, RunningState state) {
    325             if (mPackageInfo != null) {
    326                 return mPackageInfo.loadIcon(state.mPm);
    327             }
    328             return null;
    329         }
    330     }
    331 
    332     static class ServiceItem extends BaseItem {
    333         ActivityManager.RunningServiceInfo mRunningService;
    334         ServiceInfo mServiceInfo;
    335         boolean mShownAsStarted;
    336 
    337         MergedItem mMergedItem;
    338 
    339         public ServiceItem(int userId) {
    340             super(false, userId);
    341         }
    342     }
    343 
    344     static class ProcessItem extends BaseItem {
    345         final HashMap<ComponentName, ServiceItem> mServices
    346                 = new HashMap<ComponentName, ServiceItem>();
    347         final SparseArray<ProcessItem> mDependentProcesses
    348                 = new SparseArray<ProcessItem>();
    349 
    350         final int mUid;
    351         final String mProcessName;
    352         int mPid;
    353 
    354         ProcessItem mClient;
    355         int mLastNumDependentProcesses;
    356 
    357         int mRunningSeq;
    358         ActivityManager.RunningAppProcessInfo mRunningProcessInfo;
    359 
    360         MergedItem mMergedItem;
    361 
    362         boolean mInteresting;
    363 
    364         // Purely for sorting.
    365         boolean mIsSystem;
    366         boolean mIsStarted;
    367         long mActiveSince;
    368 
    369         public ProcessItem(Context context, int uid, String processName) {
    370             super(true, UserHandle.getUserId(uid));
    371             mDescription = context.getResources().getString(
    372                     R.string.service_process_name, processName);
    373             mUid = uid;
    374             mProcessName = processName;
    375         }
    376 
    377         void ensureLabel(PackageManager pm) {
    378             if (mLabel != null) {
    379                 return;
    380             }
    381 
    382             try {
    383                 ApplicationInfo ai = pm.getApplicationInfo(mProcessName,
    384                         PackageManager.GET_UNINSTALLED_PACKAGES);
    385                 if (ai.uid == mUid) {
    386                     mDisplayLabel = ai.loadLabel(pm);
    387                     mLabel = mDisplayLabel.toString();
    388                     mPackageInfo = ai;
    389                     return;
    390                 }
    391             } catch (PackageManager.NameNotFoundException e) {
    392             }
    393 
    394             // If we couldn't get information about the overall
    395             // process, try to find something about the uid.
    396             String[] pkgs = pm.getPackagesForUid(mUid);
    397 
    398             // If there is one package with this uid, that is what we want.
    399             if (pkgs.length == 1) {
    400                 try {
    401                     ApplicationInfo ai = pm.getApplicationInfo(pkgs[0],
    402                             PackageManager.GET_UNINSTALLED_PACKAGES);
    403                     mDisplayLabel = ai.loadLabel(pm);
    404                     mLabel = mDisplayLabel.toString();
    405                     mPackageInfo = ai;
    406                     return;
    407                 } catch (PackageManager.NameNotFoundException e) {
    408                 }
    409             }
    410 
    411             // If there are multiple, see if one gives us the official name
    412             // for this uid.
    413             for (String name : pkgs) {
    414                 try {
    415                     PackageInfo pi = pm.getPackageInfo(name, 0);
    416                     if (pi.sharedUserLabel != 0) {
    417                         CharSequence nm = pm.getText(name,
    418                                 pi.sharedUserLabel, pi.applicationInfo);
    419                         if (nm != null) {
    420                             mDisplayLabel = nm;
    421                             mLabel = nm.toString();
    422                             mPackageInfo = pi.applicationInfo;
    423                             return;
    424                         }
    425                     }
    426                 } catch (PackageManager.NameNotFoundException e) {
    427                 }
    428             }
    429 
    430             // If still don't have anything to display, just use the
    431             // service info.
    432             if (mServices.size() > 0) {
    433                 ApplicationInfo ai = mServices.values().iterator().next()
    434                         .mServiceInfo.applicationInfo;
    435                 mPackageInfo = ai;
    436                 mDisplayLabel = mPackageInfo.loadLabel(pm);
    437                 mLabel = mDisplayLabel.toString();
    438                 return;
    439             }
    440 
    441             // Finally... whatever, just pick the first package's name.
    442             try {
    443                 ApplicationInfo ai = pm.getApplicationInfo(pkgs[0],
    444                         PackageManager.GET_UNINSTALLED_PACKAGES);
    445                 mDisplayLabel = ai.loadLabel(pm);
    446                 mLabel = mDisplayLabel.toString();
    447                 mPackageInfo = ai;
    448                 return;
    449             } catch (PackageManager.NameNotFoundException e) {
    450             }
    451         }
    452 
    453         boolean updateService(Context context, ActivityManager.RunningServiceInfo service) {
    454             final PackageManager pm = context.getPackageManager();
    455 
    456             boolean changed = false;
    457             ServiceItem si = mServices.get(service.service);
    458             if (si == null) {
    459                 changed = true;
    460                 si = new ServiceItem(mUserId);
    461                 si.mRunningService = service;
    462                 try {
    463                     si.mServiceInfo = ActivityThread.getPackageManager().getServiceInfo(
    464                             service.service, PackageManager.GET_UNINSTALLED_PACKAGES,
    465                             UserHandle.getUserId(service.uid));
    466 
    467                     if (si.mServiceInfo == null) {
    468                         Log.d("RunningService", "getServiceInfo returned null for: "
    469                                 + service.service);
    470                         return false;
    471                     }
    472                 } catch (RemoteException e) {
    473                 }
    474                 si.mDisplayLabel = makeLabel(pm,
    475                         si.mRunningService.service.getClassName(), si.mServiceInfo);
    476                 mLabel = mDisplayLabel != null ? mDisplayLabel.toString() : null;
    477                 si.mPackageInfo = si.mServiceInfo.applicationInfo;
    478                 mServices.put(service.service, si);
    479             }
    480             si.mCurSeq = mCurSeq;
    481             si.mRunningService = service;
    482             long activeSince = service.restarting == 0 ? service.activeSince : -1;
    483             if (si.mActiveSince != activeSince) {
    484                 si.mActiveSince = activeSince;
    485                 changed = true;
    486             }
    487             if (service.clientPackage != null && service.clientLabel != 0) {
    488                 if (si.mShownAsStarted) {
    489                     si.mShownAsStarted = false;
    490                     changed = true;
    491                 }
    492                 try {
    493                     Resources clientr = pm.getResourcesForApplication(service.clientPackage);
    494                     String label = clientr.getString(service.clientLabel);
    495                     si.mDescription = context.getResources().getString(
    496                             R.string.service_client_name, label);
    497                 } catch (PackageManager.NameNotFoundException e) {
    498                     si.mDescription = null;
    499                 }
    500             } else {
    501                 if (!si.mShownAsStarted) {
    502                     si.mShownAsStarted = true;
    503                     changed = true;
    504                 }
    505                 si.mDescription = context.getResources().getString(
    506                         R.string.service_started_by_app);
    507             }
    508 
    509             return changed;
    510         }
    511 
    512         boolean updateSize(Context context, long pss, int curSeq) {
    513             mSize = pss * 1024;
    514             if (mCurSeq == curSeq) {
    515                 String sizeStr = Formatter.formatShortFileSize(
    516                         context, mSize);
    517                 if (!sizeStr.equals(mSizeStr)){
    518                     mSizeStr = sizeStr;
    519                     // We update this on the second tick where we update just
    520                     // the text in the current items, so no need to say we
    521                     // changed here.
    522                     return false;
    523                 }
    524             }
    525             return false;
    526         }
    527 
    528         boolean buildDependencyChain(Context context, PackageManager pm, int curSeq) {
    529             final int NP = mDependentProcesses.size();
    530             boolean changed = false;
    531             for (int i=0; i<NP; i++) {
    532                 ProcessItem proc = mDependentProcesses.valueAt(i);
    533                 if (proc.mClient != this) {
    534                     changed = true;
    535                     proc.mClient = this;
    536                 }
    537                 proc.mCurSeq = curSeq;
    538                 proc.ensureLabel(pm);
    539                 changed |= proc.buildDependencyChain(context, pm, curSeq);
    540             }
    541 
    542             if (mLastNumDependentProcesses != mDependentProcesses.size()) {
    543                 changed = true;
    544                 mLastNumDependentProcesses = mDependentProcesses.size();
    545             }
    546 
    547             return changed;
    548         }
    549 
    550         void addDependentProcesses(ArrayList<BaseItem> dest,
    551                 ArrayList<ProcessItem> destProc) {
    552             final int NP = mDependentProcesses.size();
    553             for (int i=0; i<NP; i++) {
    554                 ProcessItem proc = mDependentProcesses.valueAt(i);
    555                 proc.addDependentProcesses(dest, destProc);
    556                 dest.add(proc);
    557                 if (proc.mPid > 0) {
    558                     destProc.add(proc);
    559                 }
    560             }
    561         }
    562     }
    563 
    564     static class MergedItem extends BaseItem {
    565         ProcessItem mProcess;
    566         UserState mUser;
    567         final ArrayList<ProcessItem> mOtherProcesses = new ArrayList<ProcessItem>();
    568         final ArrayList<ServiceItem> mServices = new ArrayList<ServiceItem>();
    569         final ArrayList<MergedItem> mChildren = new ArrayList<MergedItem>();
    570 
    571         private int mLastNumProcesses = -1, mLastNumServices = -1;
    572 
    573         MergedItem(int userId) {
    574             super(false, userId);
    575         }
    576 
    577         private void setDescription(Context context, int numProcesses, int numServices) {
    578             if (mLastNumProcesses != numProcesses || mLastNumServices != numServices) {
    579                 mLastNumProcesses = numProcesses;
    580                 mLastNumServices = numServices;
    581                 int resid = R.string.running_processes_item_description_s_s;
    582                 if (numProcesses != 1) {
    583                     resid = numServices != 1
    584                             ? R.string.running_processes_item_description_p_p
    585                             : R.string.running_processes_item_description_p_s;
    586                 } else if (numServices != 1) {
    587                     resid = R.string.running_processes_item_description_s_p;
    588                 }
    589                 mDescription = context.getResources().getString(resid, numProcesses,
    590                         numServices);
    591             }
    592         }
    593 
    594         boolean update(Context context, boolean background) {
    595             mBackground = background;
    596 
    597             if (mUser != null) {
    598                 // This is a merged item that contains a child collection
    599                 // of items...  that is, it is an entire user, containing
    600                 // everything associated with that user.  So set it up as such.
    601                 // For concrete stuff we need about the process of this item,
    602                 // we will just use the info from the first child.
    603                 MergedItem child0 = mChildren.get(0);
    604                 mPackageInfo = child0.mProcess.mPackageInfo;
    605                 mLabel = mUser != null ? mUser.mLabel : null;
    606                 mDisplayLabel = mLabel;
    607                 int numProcesses = 0;
    608                 int numServices = 0;
    609                 mActiveSince = -1;
    610                 for (int i=0; i<mChildren.size(); i++) {
    611                     MergedItem child = mChildren.get(i);
    612                     numProcesses += child.mLastNumProcesses;
    613                     numServices += child.mLastNumServices;
    614                     if (child.mActiveSince >= 0 && mActiveSince < child.mActiveSince) {
    615                         mActiveSince = child.mActiveSince;
    616                     }
    617                 }
    618                 if (!mBackground) {
    619                     setDescription(context, numProcesses, numServices);
    620                 }
    621             } else {
    622                 mPackageInfo = mProcess.mPackageInfo;
    623                 mDisplayLabel = mProcess.mDisplayLabel;
    624                 mLabel = mProcess.mLabel;
    625 
    626                 if (!mBackground) {
    627                     setDescription(context, (mProcess.mPid > 0 ? 1 : 0) + mOtherProcesses.size(),
    628                             mServices.size());
    629                 }
    630 
    631                 mActiveSince = -1;
    632                 for (int i=0; i<mServices.size(); i++) {
    633                     ServiceItem si = mServices.get(i);
    634                     if (si.mActiveSince >= 0 && mActiveSince < si.mActiveSince) {
    635                         mActiveSince = si.mActiveSince;
    636                     }
    637                 }
    638             }
    639 
    640             return false;
    641         }
    642 
    643         boolean updateSize(Context context) {
    644             if (mUser != null) {
    645                 mSize = 0;
    646                 for (int i=0; i<mChildren.size(); i++) {
    647                     MergedItem child = mChildren.get(i);
    648                     child.updateSize(context);
    649                     mSize += child.mSize;
    650                 }
    651             } else {
    652                 mSize = mProcess.mSize;
    653                 for (int i=0; i<mOtherProcesses.size(); i++) {
    654                     mSize += mOtherProcesses.get(i).mSize;
    655                 }
    656             }
    657 
    658             String sizeStr = Formatter.formatShortFileSize(
    659                     context, mSize);
    660             if (!sizeStr.equals(mSizeStr)){
    661                 mSizeStr = sizeStr;
    662                 // We update this on the second tick where we update just
    663                 // the text in the current items, so no need to say we
    664                 // changed here.
    665                 return false;
    666             }
    667             return false;
    668         }
    669 
    670         public Drawable loadIcon(Context context, RunningState state) {
    671             if (mUser == null) {
    672                 return super.loadIcon(context, state);
    673             }
    674             if (mUser.mIcon != null) {
    675                 ConstantState constState = mUser.mIcon.getConstantState();
    676                 if (constState == null) {
    677                     return mUser.mIcon;
    678                 } else {
    679                     return constState.newDrawable();
    680                 }
    681             }
    682             return context.getResources().getDrawable(
    683                     com.android.internal.R.drawable.ic_menu_cc);
    684         }
    685     }
    686 
    687     class ServiceProcessComparator implements Comparator<ProcessItem> {
    688         public int compare(ProcessItem object1, ProcessItem object2) {
    689             if (object1.mUserId != object2.mUserId) {
    690                 if (object1.mUserId == mMyUserId) return -1;
    691                 if (object2.mUserId == mMyUserId) return 1;
    692                 return object1.mUserId < object2.mUserId ? -1 : 1;
    693             }
    694             if (object1.mIsStarted != object2.mIsStarted) {
    695                 // Non-started processes go last.
    696                 return object1.mIsStarted ? -1 : 1;
    697             }
    698             if (object1.mIsSystem != object2.mIsSystem) {
    699                 // System processes go below non-system.
    700                 return object1.mIsSystem ? 1 : -1;
    701             }
    702             if (object1.mActiveSince != object2.mActiveSince) {
    703                 // Remaining ones are sorted with the longest running
    704                 // services last.
    705                 return (object1.mActiveSince > object2.mActiveSince) ? -1 : 1;
    706             }
    707             return 0;
    708         }
    709     }
    710 
    711     static CharSequence makeLabel(PackageManager pm,
    712             String className, PackageItemInfo item) {
    713         if (item != null && (item.labelRes != 0
    714                 || item.nonLocalizedLabel != null)) {
    715             CharSequence label = item.loadLabel(pm);
    716             if (label != null) {
    717                 return label;
    718             }
    719         }
    720 
    721         String label = className;
    722         int tail = label.lastIndexOf('.');
    723         if (tail >= 0) {
    724             label = label.substring(tail+1, label.length());
    725         }
    726         return label;
    727     }
    728 
    729     static RunningState getInstance(Context context) {
    730         synchronized (sGlobalLock) {
    731             if (sInstance == null) {
    732                 sInstance = new RunningState(context);
    733             }
    734             return sInstance;
    735         }
    736     }
    737 
    738     private RunningState(Context context) {
    739         mApplicationContext = context.getApplicationContext();
    740         mAm = (ActivityManager)mApplicationContext.getSystemService(Context.ACTIVITY_SERVICE);
    741         mPm = mApplicationContext.getPackageManager();
    742         mUm = (UserManager)mApplicationContext.getSystemService(Context.USER_SERVICE);
    743         mMyUserId = UserHandle.myUserId();
    744         mResumed = false;
    745         mBackgroundThread = new HandlerThread("RunningState:Background");
    746         mBackgroundThread.start();
    747         mBackgroundHandler = new BackgroundHandler(mBackgroundThread.getLooper());
    748     }
    749 
    750     void resume(OnRefreshUiListener listener) {
    751         synchronized (mLock) {
    752             mResumed = true;
    753             mRefreshUiListener = listener;
    754             if (mInterestingConfigChanges.applyNewConfig(mApplicationContext.getResources())) {
    755                 mHaveData = false;
    756                 mBackgroundHandler.removeMessages(MSG_RESET_CONTENTS);
    757                 mBackgroundHandler.removeMessages(MSG_UPDATE_CONTENTS);
    758                 mBackgroundHandler.sendEmptyMessage(MSG_RESET_CONTENTS);
    759             }
    760             if (!mBackgroundHandler.hasMessages(MSG_UPDATE_CONTENTS)) {
    761                 mBackgroundHandler.sendEmptyMessage(MSG_UPDATE_CONTENTS);
    762             }
    763             mHandler.sendEmptyMessage(MSG_UPDATE_TIME);
    764         }
    765     }
    766 
    767     void updateNow() {
    768         synchronized (mLock) {
    769             mBackgroundHandler.removeMessages(MSG_UPDATE_CONTENTS);
    770             mBackgroundHandler.sendEmptyMessage(MSG_UPDATE_CONTENTS);
    771         }
    772     }
    773 
    774     boolean hasData() {
    775         synchronized (mLock) {
    776             return mHaveData;
    777         }
    778     }
    779 
    780     void waitForData() {
    781         synchronized (mLock) {
    782             while (!mHaveData) {
    783                 try {
    784                     mLock.wait(0);
    785                 } catch (InterruptedException e) {
    786                 }
    787             }
    788         }
    789     }
    790 
    791     void pause() {
    792         synchronized (mLock) {
    793             mResumed = false;
    794             mRefreshUiListener = null;
    795             mHandler.removeMessages(MSG_UPDATE_TIME);
    796         }
    797     }
    798 
    799     private boolean isInterestingProcess(ActivityManager.RunningAppProcessInfo pi) {
    800         if ((pi.flags&ActivityManager.RunningAppProcessInfo.FLAG_CANT_SAVE_STATE) != 0) {
    801             return true;
    802         }
    803         if ((pi.flags&ActivityManager.RunningAppProcessInfo.FLAG_PERSISTENT) == 0
    804                 && pi.importance >= ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND
    805                 && pi.importance < ActivityManager.RunningAppProcessInfo.IMPORTANCE_CANT_SAVE_STATE
    806                 && pi.importanceReasonCode
    807                         == ActivityManager.RunningAppProcessInfo.REASON_UNKNOWN) {
    808             return true;
    809         }
    810         return false;
    811     }
    812 
    813     private void reset() {
    814         mServiceProcessesByName.clear();
    815         mServiceProcessesByPid.clear();
    816         mInterestingProcesses.clear();
    817         mRunningProcesses.clear();
    818         mProcessItems.clear();
    819         mAllProcessItems.clear();
    820         mUsers.clear();
    821     }
    822 
    823     private void addOtherUserItem(Context context, ArrayList<MergedItem> newMergedItems,
    824             SparseArray<MergedItem> userItems, MergedItem newItem) {
    825         MergedItem userItem = userItems.get(newItem.mUserId);
    826         boolean first = userItem == null || userItem.mCurSeq != mSequence;
    827         if (first) {
    828             if (userItem == null) {
    829                 userItem = new MergedItem(newItem.mUserId);
    830                 userItems.put(newItem.mUserId, userItem);
    831             } else {
    832                 userItem.mChildren.clear();
    833             }
    834             userItem.mCurSeq = mSequence;
    835             if ((userItem.mUser=mUsers.get(newItem.mUserId)) == null) {
    836                 userItem.mUser = new UserState();
    837                 UserInfo info = mUm.getUserInfo(newItem.mUserId);
    838                 userItem.mUser.mInfo = info;
    839                 if (info != null) {
    840                     userItem.mUser.mIcon = Utils.getUserIcon(context, mUm, info);
    841                 }
    842                 String name = info != null ? info.name : null;
    843                 if (name == null && info != null) {
    844                     name = Integer.toString(info.id);
    845                 } else if (info == null) {
    846                     name = context.getString(R.string.unknown);
    847                 }
    848                 userItem.mUser.mLabel = context.getResources().getString(
    849                         R.string.running_process_item_user_label, name);
    850             }
    851             newMergedItems.add(userItem);
    852         }
    853         userItem.mChildren.add(newItem);
    854     }
    855 
    856     private boolean update(Context context, ActivityManager am) {
    857         final PackageManager pm = context.getPackageManager();
    858 
    859         mSequence++;
    860 
    861         boolean changed = false;
    862 
    863         // Retrieve list of services, filtering out anything that definitely
    864         // won't be shown in the UI.
    865         List<ActivityManager.RunningServiceInfo> services
    866                 = am.getRunningServices(MAX_SERVICES);
    867         int NS = services != null ? services.size() : 0;
    868         for (int i=0; i<NS; i++) {
    869             ActivityManager.RunningServiceInfo si = services.get(i);
    870             // We are not interested in services that have not been started
    871             // and don't have a known client, because
    872             // there is nothing the user can do about them.
    873             if (!si.started && si.clientLabel == 0) {
    874                 services.remove(i);
    875                 i--;
    876                 NS--;
    877                 continue;
    878             }
    879             // We likewise don't care about services running in a
    880             // persistent process like the system or phone.
    881             if ((si.flags&ActivityManager.RunningServiceInfo.FLAG_PERSISTENT_PROCESS)
    882                     != 0) {
    883                 services.remove(i);
    884                 i--;
    885                 NS--;
    886                 continue;
    887             }
    888         }
    889 
    890         // Retrieve list of running processes, organizing them into a sparse
    891         // array for easy retrieval.
    892         List<ActivityManager.RunningAppProcessInfo> processes
    893                 = am.getRunningAppProcesses();
    894         final int NP = processes != null ? processes.size() : 0;
    895         mTmpAppProcesses.clear();
    896         for (int i=0; i<NP; i++) {
    897             ActivityManager.RunningAppProcessInfo pi = processes.get(i);
    898             mTmpAppProcesses.put(pi.pid, new AppProcessInfo(pi));
    899         }
    900 
    901         // Initial iteration through running services to collect per-process
    902         // info about them.
    903         for (int i=0; i<NS; i++) {
    904             ActivityManager.RunningServiceInfo si = services.get(i);
    905             if (si.restarting == 0 && si.pid > 0) {
    906                 AppProcessInfo ainfo = mTmpAppProcesses.get(si.pid);
    907                 if (ainfo != null) {
    908                     ainfo.hasServices = true;
    909                     if (si.foreground) {
    910                         ainfo.hasForegroundServices = true;
    911                     }
    912                 }
    913             }
    914         }
    915 
    916         // Update state we are maintaining about process that are running services.
    917         for (int i=0; i<NS; i++) {
    918             ActivityManager.RunningServiceInfo si = services.get(i);
    919 
    920             // If this service's process is in use at a higher importance
    921             // due to another process bound to one of its services, then we
    922             // won't put it in the top-level list of services.  Instead we
    923             // want it to be included in the set of processes that the other
    924             // process needs.
    925             if (si.restarting == 0 && si.pid > 0) {
    926                 AppProcessInfo ainfo = mTmpAppProcesses.get(si.pid);
    927                 if (ainfo != null && !ainfo.hasForegroundServices) {
    928                     // This process does not have any foreground services.
    929                     // If its importance is greater than the service importance
    930                     // then there is something else more significant that is
    931                     // keeping it around that it should possibly be included as
    932                     // a part of instead of being shown by itself.
    933                     if (ainfo.info.importance
    934                             < ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE) {
    935                         // Follow process chain to see if there is something
    936                         // else that could be shown
    937                         boolean skip = false;
    938                         ainfo = mTmpAppProcesses.get(ainfo.info.importanceReasonPid);
    939                         while (ainfo != null) {
    940                             if (ainfo.hasServices || isInterestingProcess(ainfo.info)) {
    941                                 skip = true;
    942                                 break;
    943                             }
    944                             ainfo = mTmpAppProcesses.get(ainfo.info.importanceReasonPid);
    945                         }
    946                         if (skip) {
    947                             continue;
    948                         }
    949                     }
    950                 }
    951             }
    952 
    953             HashMap<String, ProcessItem> procs = mServiceProcessesByName.get(si.uid);
    954             if (procs == null) {
    955                 procs = new HashMap<String, ProcessItem>();
    956                 mServiceProcessesByName.put(si.uid, procs);
    957             }
    958             ProcessItem proc = procs.get(si.process);
    959             if (proc == null) {
    960                 changed = true;
    961                 proc = new ProcessItem(context, si.uid, si.process);
    962                 procs.put(si.process, proc);
    963             }
    964 
    965             if (proc.mCurSeq != mSequence) {
    966                 int pid = si.restarting == 0 ? si.pid : 0;
    967                 if (pid != proc.mPid) {
    968                     changed = true;
    969                     if (proc.mPid != pid) {
    970                         if (proc.mPid != 0) {
    971                             mServiceProcessesByPid.remove(proc.mPid);
    972                         }
    973                         if (pid != 0) {
    974                             mServiceProcessesByPid.put(pid, proc);
    975                         }
    976                         proc.mPid = pid;
    977                     }
    978                 }
    979                 proc.mDependentProcesses.clear();
    980                 proc.mCurSeq = mSequence;
    981             }
    982             changed |= proc.updateService(context, si);
    983         }
    984 
    985         // Now update the map of other processes that are running (but
    986         // don't have services actively running inside them).
    987         for (int i=0; i<NP; i++) {
    988             ActivityManager.RunningAppProcessInfo pi = processes.get(i);
    989             ProcessItem proc = mServiceProcessesByPid.get(pi.pid);
    990             if (proc == null) {
    991                 // This process is not one that is a direct container
    992                 // of a service, so look for it in the secondary
    993                 // running list.
    994                 proc = mRunningProcesses.get(pi.pid);
    995                 if (proc == null) {
    996                     changed = true;
    997                     proc = new ProcessItem(context, pi.uid, pi.processName);
    998                     proc.mPid = pi.pid;
    999                     mRunningProcesses.put(pi.pid, proc);
   1000                 }
   1001                 proc.mDependentProcesses.clear();
   1002             }
   1003 
   1004             if (isInterestingProcess(pi)) {
   1005                 if (!mInterestingProcesses.contains(proc)) {
   1006                     changed = true;
   1007                     mInterestingProcesses.add(proc);
   1008                 }
   1009                 proc.mCurSeq = mSequence;
   1010                 proc.mInteresting = true;
   1011                 proc.ensureLabel(pm);
   1012             } else {
   1013                 proc.mInteresting = false;
   1014             }
   1015 
   1016             proc.mRunningSeq = mSequence;
   1017             proc.mRunningProcessInfo = pi;
   1018         }
   1019 
   1020         // Build the chains from client processes to the process they are
   1021         // dependent on; also remove any old running processes.
   1022         int NRP = mRunningProcesses.size();
   1023         for (int i = 0; i < NRP;) {
   1024             ProcessItem proc = mRunningProcesses.valueAt(i);
   1025             if (proc.mRunningSeq == mSequence) {
   1026                 int clientPid = proc.mRunningProcessInfo.importanceReasonPid;
   1027                 if (clientPid != 0) {
   1028                     ProcessItem client = mServiceProcessesByPid.get(clientPid);
   1029                     if (client == null) {
   1030                         client = mRunningProcesses.get(clientPid);
   1031                     }
   1032                     if (client != null) {
   1033                         client.mDependentProcesses.put(proc.mPid, proc);
   1034                     }
   1035                 } else {
   1036                     // In this pass the process doesn't have a client.
   1037                     // Clear to make sure that, if it later gets the same one,
   1038                     // we will detect the change.
   1039                     proc.mClient = null;
   1040                 }
   1041                 i++;
   1042             } else {
   1043                 changed = true;
   1044                 mRunningProcesses.remove(mRunningProcesses.keyAt(i));
   1045                 NRP--;
   1046             }
   1047         }
   1048 
   1049         // Remove any old interesting processes.
   1050         int NHP = mInterestingProcesses.size();
   1051         for (int i=0; i<NHP; i++) {
   1052             ProcessItem proc = mInterestingProcesses.get(i);
   1053             if (!proc.mInteresting || mRunningProcesses.get(proc.mPid) == null) {
   1054                 changed = true;
   1055                 mInterestingProcesses.remove(i);
   1056                 i--;
   1057                 NHP--;
   1058             }
   1059         }
   1060 
   1061         // Follow the tree from all primary service processes to all
   1062         // processes they are dependent on, marking these processes as
   1063         // still being active and determining if anything has changed.
   1064         final int NAP = mServiceProcessesByPid.size();
   1065         for (int i=0; i<NAP; i++) {
   1066             ProcessItem proc = mServiceProcessesByPid.valueAt(i);
   1067             if (proc.mCurSeq == mSequence) {
   1068                 changed |= proc.buildDependencyChain(context, pm, mSequence);
   1069             }
   1070         }
   1071 
   1072         // Look for services and their primary processes that no longer exist...
   1073         ArrayList<Integer> uidToDelete = null;
   1074         for (int i=0; i<mServiceProcessesByName.size(); i++) {
   1075             HashMap<String, ProcessItem> procs = mServiceProcessesByName.valueAt(i);
   1076             Iterator<ProcessItem> pit = procs.values().iterator();
   1077             while (pit.hasNext()) {
   1078                 ProcessItem pi = pit.next();
   1079                 if (pi.mCurSeq == mSequence) {
   1080                     pi.ensureLabel(pm);
   1081                     if (pi.mPid == 0) {
   1082                         // Sanity: a non-process can't be dependent on
   1083                         // anything.
   1084                         pi.mDependentProcesses.clear();
   1085                     }
   1086                 } else {
   1087                     changed = true;
   1088                     pit.remove();
   1089                     if (procs.size() == 0) {
   1090                         if (uidToDelete == null) {
   1091                             uidToDelete = new ArrayList<Integer>();
   1092                         }
   1093                         uidToDelete.add(mServiceProcessesByName.keyAt(i));
   1094                     }
   1095                     if (pi.mPid != 0) {
   1096                         mServiceProcessesByPid.remove(pi.mPid);
   1097                     }
   1098                     continue;
   1099                 }
   1100                 Iterator<ServiceItem> sit = pi.mServices.values().iterator();
   1101                 while (sit.hasNext()) {
   1102                     ServiceItem si = sit.next();
   1103                     if (si.mCurSeq != mSequence) {
   1104                         changed = true;
   1105                         sit.remove();
   1106                     }
   1107                 }
   1108             }
   1109         }
   1110 
   1111         if (uidToDelete != null) {
   1112             for (int i = 0; i < uidToDelete.size(); i++) {
   1113                 int uid = uidToDelete.get(i);
   1114                 mServiceProcessesByName.remove(uid);
   1115             }
   1116         }
   1117 
   1118         if (changed) {
   1119             // First determine an order for the services.
   1120             ArrayList<ProcessItem> sortedProcesses = new ArrayList<ProcessItem>();
   1121             for (int i=0; i<mServiceProcessesByName.size(); i++) {
   1122                 for (ProcessItem pi : mServiceProcessesByName.valueAt(i).values()) {
   1123                     pi.mIsSystem = false;
   1124                     pi.mIsStarted = true;
   1125                     pi.mActiveSince = Long.MAX_VALUE;
   1126                     for (ServiceItem si : pi.mServices.values()) {
   1127                         if (si.mServiceInfo != null
   1128                                 && (si.mServiceInfo.applicationInfo.flags
   1129                                         & ApplicationInfo.FLAG_SYSTEM) != 0) {
   1130                             pi.mIsSystem = true;
   1131                         }
   1132                         if (si.mRunningService != null
   1133                                 && si.mRunningService.clientLabel != 0) {
   1134                             pi.mIsStarted = false;
   1135                             if (pi.mActiveSince > si.mRunningService.activeSince) {
   1136                                 pi.mActiveSince = si.mRunningService.activeSince;
   1137                             }
   1138                         }
   1139                     }
   1140                     sortedProcesses.add(pi);
   1141                 }
   1142             }
   1143 
   1144             Collections.sort(sortedProcesses, mServiceProcessComparator);
   1145 
   1146             ArrayList<BaseItem> newItems = new ArrayList<BaseItem>();
   1147             ArrayList<MergedItem> newMergedItems = new ArrayList<MergedItem>();
   1148             SparseArray<MergedItem> otherUsers = null;
   1149             mProcessItems.clear();
   1150             for (int i=0; i<sortedProcesses.size(); i++) {
   1151                 ProcessItem pi = sortedProcesses.get(i);
   1152                 pi.mNeedDivider = false;
   1153 
   1154                 int firstProc = mProcessItems.size();
   1155                 // First add processes we are dependent on.
   1156                 pi.addDependentProcesses(newItems, mProcessItems);
   1157                 // And add the process itself.
   1158                 newItems.add(pi);
   1159                 if (pi.mPid > 0) {
   1160                     mProcessItems.add(pi);
   1161                 }
   1162 
   1163                 // Now add the services running in it.
   1164                 MergedItem mergedItem = null;
   1165                 boolean haveAllMerged = false;
   1166                 boolean needDivider = false;
   1167                 for (ServiceItem si : pi.mServices.values()) {
   1168                     si.mNeedDivider = needDivider;
   1169                     needDivider = true;
   1170                     newItems.add(si);
   1171                     if (si.mMergedItem != null) {
   1172                         if (mergedItem != null && mergedItem != si.mMergedItem) {
   1173                             haveAllMerged = false;
   1174                         }
   1175                         mergedItem = si.mMergedItem;
   1176                     } else {
   1177                         haveAllMerged = false;
   1178                     }
   1179                 }
   1180 
   1181                 if (!haveAllMerged || mergedItem == null
   1182                         || mergedItem.mServices.size() != pi.mServices.size()) {
   1183                     // Whoops, we need to build a new MergedItem!
   1184                     mergedItem = new MergedItem(pi.mUserId);
   1185                     for (ServiceItem si : pi.mServices.values()) {
   1186                         mergedItem.mServices.add(si);
   1187                         si.mMergedItem = mergedItem;
   1188                     }
   1189                     mergedItem.mProcess = pi;
   1190                     mergedItem.mOtherProcesses.clear();
   1191                     for (int mpi=firstProc; mpi<(mProcessItems.size()-1); mpi++) {
   1192                         mergedItem.mOtherProcesses.add(mProcessItems.get(mpi));
   1193                     }
   1194                 }
   1195 
   1196                 mergedItem.update(context, false);
   1197                 if (mergedItem.mUserId != mMyUserId) {
   1198                     addOtherUserItem(context, newMergedItems, mOtherUserMergedItems, mergedItem);
   1199                 } else {
   1200                     newMergedItems.add(mergedItem);
   1201                 }
   1202             }
   1203 
   1204             // Finally, interesting processes need to be shown and will
   1205             // go at the top.
   1206             NHP = mInterestingProcesses.size();
   1207             for (int i=0; i<NHP; i++) {
   1208                 ProcessItem proc = mInterestingProcesses.get(i);
   1209                 if (proc.mClient == null && proc.mServices.size() <= 0) {
   1210                     if (proc.mMergedItem == null) {
   1211                         proc.mMergedItem = new MergedItem(proc.mUserId);
   1212                         proc.mMergedItem.mProcess = proc;
   1213                     }
   1214                     proc.mMergedItem.update(context, false);
   1215                     if (proc.mMergedItem.mUserId != mMyUserId) {
   1216                         addOtherUserItem(context, newMergedItems, mOtherUserMergedItems,
   1217                                 proc.mMergedItem);
   1218                     } else {
   1219                         newMergedItems.add(0, proc.mMergedItem);
   1220                     }
   1221                     mProcessItems.add(proc);
   1222                 }
   1223             }
   1224 
   1225             // Finally finally, user aggregated merged items need to be
   1226             // updated now that they have all of their children.
   1227             final int NU = mOtherUserMergedItems.size();
   1228             for (int i=0; i<NU; i++) {
   1229                 MergedItem user = mOtherUserMergedItems.valueAt(i);
   1230                 if (user.mCurSeq == mSequence) {
   1231                     user.update(context, false);
   1232                 }
   1233             }
   1234 
   1235             synchronized (mLock) {
   1236                 mItems = newItems;
   1237                 mMergedItems = newMergedItems;
   1238             }
   1239         }
   1240 
   1241         // Count number of interesting other (non-active) processes, and
   1242         // build a list of all processes we will retrieve memory for.
   1243         mAllProcessItems.clear();
   1244         mAllProcessItems.addAll(mProcessItems);
   1245         int numBackgroundProcesses = 0;
   1246         int numForegroundProcesses = 0;
   1247         int numServiceProcesses = 0;
   1248         NRP = mRunningProcesses.size();
   1249         for (int i=0; i<NRP; i++) {
   1250             ProcessItem proc = mRunningProcesses.valueAt(i);
   1251             if (proc.mCurSeq != mSequence) {
   1252                 // We didn't hit this process as a dependency on one
   1253                 // of our active ones, so add it up if needed.
   1254                 if (proc.mRunningProcessInfo.importance >=
   1255                         ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND) {
   1256                     numBackgroundProcesses++;
   1257                     mAllProcessItems.add(proc);
   1258                 } else if (proc.mRunningProcessInfo.importance <=
   1259                         ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE) {
   1260                     numForegroundProcesses++;
   1261                     mAllProcessItems.add(proc);
   1262                 } else {
   1263                     Log.i("RunningState", "Unknown non-service process: "
   1264                             + proc.mProcessName + " #" + proc.mPid);
   1265                 }
   1266             } else {
   1267                 numServiceProcesses++;
   1268             }
   1269         }
   1270 
   1271         long backgroundProcessMemory = 0;
   1272         long foregroundProcessMemory = 0;
   1273         long serviceProcessMemory = 0;
   1274         ArrayList<MergedItem> newBackgroundItems = null;
   1275         ArrayList<MergedItem> newUserBackgroundItems = null;
   1276         boolean diffUsers = false;
   1277         try {
   1278             final int numProc = mAllProcessItems.size();
   1279             int[] pids = new int[numProc];
   1280             for (int i=0; i<numProc; i++) {
   1281                 pids[i] = mAllProcessItems.get(i).mPid;
   1282             }
   1283             long[] pss = ActivityManagerNative.getDefault()
   1284                     .getProcessPss(pids);
   1285             int bgIndex = 0;
   1286             for (int i=0; i<pids.length; i++) {
   1287                 ProcessItem proc = mAllProcessItems.get(i);
   1288                 changed |= proc.updateSize(context, pss[i], mSequence);
   1289                 if (proc.mCurSeq == mSequence) {
   1290                     serviceProcessMemory += proc.mSize;
   1291                 } else if (proc.mRunningProcessInfo.importance >=
   1292                         ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND) {
   1293                     backgroundProcessMemory += proc.mSize;
   1294                     MergedItem mergedItem;
   1295                     if (newBackgroundItems != null) {
   1296                         mergedItem = proc.mMergedItem = new MergedItem(proc.mUserId);
   1297                         proc.mMergedItem.mProcess = proc;
   1298                         diffUsers |= mergedItem.mUserId != mMyUserId;
   1299                         newBackgroundItems.add(mergedItem);
   1300                     } else {
   1301                         if (bgIndex >= mBackgroundItems.size()
   1302                                 || mBackgroundItems.get(bgIndex).mProcess != proc) {
   1303                             newBackgroundItems = new ArrayList<MergedItem>(numBackgroundProcesses);
   1304                             for (int bgi=0; bgi<bgIndex; bgi++) {
   1305                                 mergedItem = mBackgroundItems.get(bgi);
   1306                                 diffUsers |= mergedItem.mUserId != mMyUserId;
   1307                                 newBackgroundItems.add(mergedItem);
   1308                             }
   1309                             mergedItem = proc.mMergedItem = new MergedItem(proc.mUserId);
   1310                             proc.mMergedItem.mProcess = proc;
   1311                             diffUsers |= mergedItem.mUserId != mMyUserId;
   1312                             newBackgroundItems.add(mergedItem);
   1313                         } else {
   1314                             mergedItem = mBackgroundItems.get(bgIndex);
   1315                         }
   1316                     }
   1317                     mergedItem.update(context, true);
   1318                     mergedItem.updateSize(context);
   1319                     bgIndex++;
   1320                 } else if (proc.mRunningProcessInfo.importance <=
   1321                         ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE) {
   1322                     foregroundProcessMemory += proc.mSize;
   1323                 }
   1324             }
   1325         } catch (RemoteException e) {
   1326         }
   1327 
   1328         if (newBackgroundItems == null) {
   1329             // One or more at the bottom may no longer exist.
   1330             if (mBackgroundItems.size() > numBackgroundProcesses) {
   1331                 newBackgroundItems = new ArrayList<MergedItem>(numBackgroundProcesses);
   1332                 for (int bgi=0; bgi<numBackgroundProcesses; bgi++) {
   1333                     MergedItem mergedItem = mBackgroundItems.get(bgi);
   1334                     diffUsers |= mergedItem.mUserId != mMyUserId;
   1335                     newBackgroundItems.add(mergedItem);
   1336                 }
   1337             }
   1338         }
   1339 
   1340         if (newBackgroundItems != null) {
   1341             // The background items have changed; we need to re-build the
   1342             // per-user items.
   1343             if (!diffUsers) {
   1344                 // Easy: there are no other users, we can just use the same array.
   1345                 newUserBackgroundItems = newBackgroundItems;
   1346             } else {
   1347                 // We now need to re-build the per-user list so that background
   1348                 // items for users are collapsed together.
   1349                 newUserBackgroundItems = new ArrayList<MergedItem>();
   1350                 final int NB = newBackgroundItems.size();
   1351                 for (int i=0; i<NB; i++) {
   1352                     MergedItem mergedItem = newBackgroundItems.get(i);
   1353                     if (mergedItem.mUserId != mMyUserId) {
   1354                         addOtherUserItem(context, newUserBackgroundItems,
   1355                                 mOtherUserBackgroundItems, mergedItem);
   1356                     } else {
   1357                         newUserBackgroundItems.add(mergedItem);
   1358                     }
   1359                 }
   1360                 // And user aggregated merged items need to be
   1361                 // updated now that they have all of their children.
   1362                 final int NU = mOtherUserBackgroundItems.size();
   1363                 for (int i=0; i<NU; i++) {
   1364                     MergedItem user = mOtherUserBackgroundItems.valueAt(i);
   1365                     if (user.mCurSeq == mSequence) {
   1366                         user.update(context, true);
   1367                         user.updateSize(context);
   1368                     }
   1369                 }
   1370             }
   1371         }
   1372 
   1373         for (int i=0; i<mMergedItems.size(); i++) {
   1374             mMergedItems.get(i).updateSize(context);
   1375         }
   1376 
   1377         synchronized (mLock) {
   1378             mNumBackgroundProcesses = numBackgroundProcesses;
   1379             mNumForegroundProcesses = numForegroundProcesses;
   1380             mNumServiceProcesses = numServiceProcesses;
   1381             mBackgroundProcessMemory = backgroundProcessMemory;
   1382             mForegroundProcessMemory = foregroundProcessMemory;
   1383             mServiceProcessMemory = serviceProcessMemory;
   1384             if (newBackgroundItems != null) {
   1385                 mBackgroundItems = newBackgroundItems;
   1386                 mUserBackgroundItems = newUserBackgroundItems;
   1387                 if (mWatchingBackgroundItems) {
   1388                     changed = true;
   1389                 }
   1390             }
   1391             if (!mHaveData) {
   1392                 mHaveData = true;
   1393                 mLock.notifyAll();
   1394             }
   1395         }
   1396 
   1397         return changed;
   1398     }
   1399 
   1400     ArrayList<BaseItem> getCurrentItems() {
   1401         synchronized (mLock) {
   1402             return mItems;
   1403         }
   1404     }
   1405 
   1406     void setWatchingBackgroundItems(boolean watching) {
   1407         synchronized (mLock) {
   1408             mWatchingBackgroundItems = watching;
   1409         }
   1410     }
   1411 
   1412     ArrayList<MergedItem> getCurrentMergedItems() {
   1413         synchronized (mLock) {
   1414             return mMergedItems;
   1415         }
   1416     }
   1417 
   1418     ArrayList<MergedItem> getCurrentBackgroundItems() {
   1419         synchronized (mLock) {
   1420             return mUserBackgroundItems;
   1421         }
   1422     }
   1423 }
   1424