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 
     21 import android.app.ActivityManager;
     22 import android.app.ActivityManagerNative;
     23 import android.content.ComponentName;
     24 import android.content.Context;
     25 import android.content.pm.ApplicationInfo;
     26 import android.content.pm.PackageInfo;
     27 import android.content.pm.PackageItemInfo;
     28 import android.content.pm.PackageManager;
     29 import android.content.pm.ServiceInfo;
     30 import android.content.res.Resources;
     31 import android.os.Debug;
     32 import android.os.Handler;
     33 import android.os.HandlerThread;
     34 import android.os.Looper;
     35 import android.os.Message;
     36 import android.os.RemoteException;
     37 import android.os.SystemClock;
     38 import android.text.format.Formatter;
     39 import android.util.Log;
     40 import android.util.SparseArray;
     41 
     42 import java.util.ArrayList;
     43 import java.util.Collections;
     44 import java.util.Comparator;
     45 import java.util.HashMap;
     46 import java.util.Iterator;
     47 import java.util.List;
     48 
     49 /**
     50  * Singleton for retrieving and monitoring the state about all running
     51  * applications/processes/services.
     52  */
     53 public class RunningState {
     54     static Object sGlobalLock = new Object();
     55     static RunningState sInstance;
     56 
     57     static final int MSG_UPDATE_CONTENTS = 1;
     58     static final int MSG_REFRESH_UI = 2;
     59     static final int MSG_UPDATE_TIME = 3;
     60 
     61     static final long TIME_UPDATE_DELAY = 1000;
     62     static final long CONTENTS_UPDATE_DELAY = 2000;
     63 
     64     static final int MAX_SERVICES = 100;
     65 
     66     final Context mApplicationContext;
     67     final ActivityManager mAm;
     68     final PackageManager mPm;
     69 
     70     OnRefreshUiListener mRefreshUiListener;
     71 
     72     // Processes that are hosting a service we are interested in, organized
     73     // by uid and name.  Note that this mapping does not change even across
     74     // service restarts, and during a restart there will still be a process
     75     // entry.
     76     final SparseArray<HashMap<String, ProcessItem>> mServiceProcessesByName
     77             = new SparseArray<HashMap<String, ProcessItem>>();
     78 
     79     // Processes that are hosting a service we are interested in, organized
     80     // by their pid.  These disappear and re-appear as services are restarted.
     81     final SparseArray<ProcessItem> mServiceProcessesByPid
     82             = new SparseArray<ProcessItem>();
     83 
     84     // Used to sort the interesting processes.
     85     final ServiceProcessComparator mServiceProcessComparator
     86             = new ServiceProcessComparator();
     87 
     88     // Additional interesting processes to be shown to the user, even if
     89     // there is no service running in them.
     90     final ArrayList<ProcessItem> mInterestingProcesses = new ArrayList<ProcessItem>();
     91 
     92     // All currently running processes, for finding dependencies etc.
     93     final SparseArray<ProcessItem> mRunningProcesses
     94             = new SparseArray<ProcessItem>();
     95 
     96     // The processes associated with services, in sorted order.
     97     final ArrayList<ProcessItem> mProcessItems = new ArrayList<ProcessItem>();
     98 
     99     // All processes, used for retrieving memory information.
    100     final ArrayList<ProcessItem> mAllProcessItems = new ArrayList<ProcessItem>();
    101 
    102     int mSequence = 0;
    103 
    104     // ----- following protected by mLock -----
    105 
    106     // Lock for protecting the state that will be shared between the
    107     // background update thread and the UI thread.
    108     final Object mLock = new Object();
    109 
    110     boolean mResumed;
    111     boolean mHaveData;
    112     boolean mWatchingBackgroundItems;
    113 
    114     ArrayList<BaseItem> mItems = new ArrayList<BaseItem>();
    115     ArrayList<MergedItem> mMergedItems = new ArrayList<MergedItem>();
    116     ArrayList<MergedItem> mBackgroundItems = new ArrayList<MergedItem>();
    117 
    118     int mNumBackgroundProcesses;
    119     long mBackgroundProcessMemory;
    120     int mNumForegroundProcesses;
    121     long mForegroundProcessMemory;
    122     int mNumServiceProcesses;
    123     long mServiceProcessMemory;
    124 
    125     // ----- BACKGROUND MONITORING THREAD -----
    126 
    127     final HandlerThread mBackgroundThread;
    128     final class BackgroundHandler extends Handler {
    129         public BackgroundHandler(Looper looper) {
    130             super(looper);
    131         }
    132 
    133         @Override
    134         public void handleMessage(Message msg) {
    135             switch (msg.what) {
    136                 case MSG_UPDATE_CONTENTS:
    137                     synchronized (mLock) {
    138                         if (!mResumed) {
    139                             return;
    140                         }
    141                     }
    142                     Message cmd = mHandler.obtainMessage(MSG_REFRESH_UI);
    143                     cmd.arg1 = update(mApplicationContext, mAm) ? 1 : 0;
    144                     mHandler.sendMessage(cmd);
    145                     removeMessages(MSG_UPDATE_CONTENTS);
    146                     msg = obtainMessage(MSG_UPDATE_CONTENTS);
    147                     sendMessageDelayed(msg, CONTENTS_UPDATE_DELAY);
    148                     break;
    149             }
    150         }
    151     };
    152 
    153     final BackgroundHandler mBackgroundHandler;
    154 
    155     final Handler mHandler = new Handler() {
    156         int mNextUpdate = OnRefreshUiListener.REFRESH_TIME;
    157 
    158         @Override
    159         public void handleMessage(Message msg) {
    160             switch (msg.what) {
    161                 case MSG_REFRESH_UI:
    162                     mNextUpdate = msg.arg1 != 0
    163                             ? OnRefreshUiListener.REFRESH_STRUCTURE
    164                             : OnRefreshUiListener.REFRESH_DATA;
    165                     break;
    166                 case MSG_UPDATE_TIME:
    167                     synchronized (mLock) {
    168                         if (!mResumed) {
    169                             return;
    170                         }
    171                     }
    172                     removeMessages(MSG_UPDATE_TIME);
    173                     Message m = obtainMessage(MSG_UPDATE_TIME);
    174                     sendMessageDelayed(m, TIME_UPDATE_DELAY);
    175 
    176                     if (mRefreshUiListener != null) {
    177                         //Log.i("foo", "Refresh UI: " + mNextUpdate
    178                         //        + " @ " + SystemClock.uptimeMillis());
    179                         mRefreshUiListener.onRefreshUi(mNextUpdate);
    180                         mNextUpdate = OnRefreshUiListener.REFRESH_TIME;
    181                     }
    182                     break;
    183             }
    184         }
    185     };
    186 
    187     // ----- DATA STRUCTURES -----
    188 
    189     static interface OnRefreshUiListener {
    190         public static final int REFRESH_TIME = 0;
    191         public static final int REFRESH_DATA = 1;
    192         public static final int REFRESH_STRUCTURE = 2;
    193 
    194         public void onRefreshUi(int what);
    195     }
    196 
    197     static class BaseItem {
    198         final boolean mIsProcess;
    199 
    200         PackageItemInfo mPackageInfo;
    201         CharSequence mDisplayLabel;
    202         String mLabel;
    203         String mDescription;
    204 
    205         int mCurSeq;
    206 
    207         long mActiveSince;
    208         long mSize;
    209         String mSizeStr;
    210         String mCurSizeStr;
    211         boolean mNeedDivider;
    212         boolean mBackground;
    213 
    214         public BaseItem(boolean isProcess) {
    215             mIsProcess = isProcess;
    216         }
    217     }
    218 
    219     static class ServiceItem extends BaseItem {
    220         ActivityManager.RunningServiceInfo mRunningService;
    221         ServiceInfo mServiceInfo;
    222         boolean mShownAsStarted;
    223 
    224         MergedItem mMergedItem;
    225 
    226         public ServiceItem() {
    227             super(false);
    228         }
    229     }
    230 
    231     static class ProcessItem extends BaseItem {
    232         final HashMap<ComponentName, ServiceItem> mServices
    233                 = new HashMap<ComponentName, ServiceItem>();
    234         final SparseArray<ProcessItem> mDependentProcesses
    235                 = new SparseArray<ProcessItem>();
    236 
    237         final int mUid;
    238         final String mProcessName;
    239         int mPid;
    240 
    241         ProcessItem mClient;
    242         int mLastNumDependentProcesses;
    243 
    244         int mRunningSeq;
    245         ActivityManager.RunningAppProcessInfo mRunningProcessInfo;
    246 
    247         MergedItem mMergedItem;
    248 
    249         // Purely for sorting.
    250         boolean mIsSystem;
    251         boolean mIsStarted;
    252         long mActiveSince;
    253 
    254         public ProcessItem(Context context, int uid, String processName) {
    255             super(true);
    256             mDescription = context.getResources().getString(
    257                     R.string.service_process_name, processName);
    258             mUid = uid;
    259             mProcessName = processName;
    260         }
    261 
    262         void ensureLabel(PackageManager pm) {
    263             if (mLabel != null) {
    264                 return;
    265             }
    266 
    267             try {
    268                 ApplicationInfo ai = pm.getApplicationInfo(mProcessName, 0);
    269                 if (ai.uid == mUid) {
    270                     mDisplayLabel = ai.loadLabel(pm);
    271                     mLabel = mDisplayLabel.toString();
    272                     mPackageInfo = ai;
    273                     return;
    274                 }
    275             } catch (PackageManager.NameNotFoundException e) {
    276             }
    277 
    278             // If we couldn't get information about the overall
    279             // process, try to find something about the uid.
    280             String[] pkgs = pm.getPackagesForUid(mUid);
    281 
    282             // If there is one package with this uid, that is what we want.
    283             if (pkgs.length == 1) {
    284                 try {
    285                     ApplicationInfo ai = pm.getApplicationInfo(pkgs[0], 0);
    286                     mDisplayLabel = ai.loadLabel(pm);
    287                     mLabel = mDisplayLabel.toString();
    288                     mPackageInfo = ai;
    289                     return;
    290                 } catch (PackageManager.NameNotFoundException e) {
    291                 }
    292             }
    293 
    294             // If there are multiple, see if one gives us the official name
    295             // for this uid.
    296             for (String name : pkgs) {
    297                 try {
    298                     PackageInfo pi = pm.getPackageInfo(name, 0);
    299                     if (pi.sharedUserLabel != 0) {
    300                         CharSequence nm = pm.getText(name,
    301                                 pi.sharedUserLabel, pi.applicationInfo);
    302                         if (nm != null) {
    303                             mDisplayLabel = nm;
    304                             mLabel = nm.toString();
    305                             mPackageInfo = pi.applicationInfo;
    306                             return;
    307                         }
    308                     }
    309                 } catch (PackageManager.NameNotFoundException e) {
    310                 }
    311             }
    312 
    313             // If still don't have anything to display, just use the
    314             // service info.
    315             if (mServices.size() > 0) {
    316                 mPackageInfo = mServices.values().iterator().next()
    317                         .mServiceInfo.applicationInfo;
    318                 mDisplayLabel = mPackageInfo.loadLabel(pm);
    319                 mLabel = mDisplayLabel.toString();
    320                 return;
    321             }
    322 
    323             // Finally... whatever, just pick the first package's name.
    324             try {
    325                 ApplicationInfo ai = pm.getApplicationInfo(pkgs[0], 0);
    326                 mDisplayLabel = ai.loadLabel(pm);
    327                 mLabel = mDisplayLabel.toString();
    328                 mPackageInfo = ai;
    329                 return;
    330             } catch (PackageManager.NameNotFoundException e) {
    331             }
    332         }
    333 
    334         boolean updateService(Context context,
    335                 ActivityManager.RunningServiceInfo service) {
    336             final PackageManager pm = context.getPackageManager();
    337 
    338             boolean changed = false;
    339             ServiceItem si = mServices.get(service.service);
    340             if (si == null) {
    341                 changed = true;
    342                 si = new ServiceItem();
    343                 si.mRunningService = service;
    344                 try {
    345                     si.mServiceInfo = pm.getServiceInfo(service.service, 0);
    346                 } catch (PackageManager.NameNotFoundException e) {
    347                 }
    348                 si.mDisplayLabel = makeLabel(pm,
    349                         si.mRunningService.service.getClassName(), si.mServiceInfo);
    350                 mLabel = mDisplayLabel != null ? mDisplayLabel.toString() : null;
    351                 si.mPackageInfo = si.mServiceInfo.applicationInfo;
    352                 mServices.put(service.service, si);
    353             }
    354             si.mCurSeq = mCurSeq;
    355             si.mRunningService = service;
    356             long activeSince = service.restarting == 0 ? service.activeSince : -1;
    357             if (si.mActiveSince != activeSince) {
    358                 si.mActiveSince = activeSince;
    359                 changed = true;
    360             }
    361             if (service.clientPackage != null && service.clientLabel != 0) {
    362                 if (si.mShownAsStarted) {
    363                     si.mShownAsStarted = false;
    364                     changed = true;
    365                 }
    366                 try {
    367                     Resources clientr = pm.getResourcesForApplication(service.clientPackage);
    368                     String label = clientr.getString(service.clientLabel);
    369                     si.mDescription = context.getResources().getString(
    370                             R.string.service_client_name, label);
    371                 } catch (PackageManager.NameNotFoundException e) {
    372                     si.mDescription = null;
    373                 }
    374             } else {
    375                 if (!si.mShownAsStarted) {
    376                     si.mShownAsStarted = true;
    377                     changed = true;
    378                 }
    379                 si.mDescription = context.getResources().getString(
    380                         R.string.service_started_by_app);
    381             }
    382 
    383             return changed;
    384         }
    385 
    386         boolean updateSize(Context context, Debug.MemoryInfo mem, int curSeq) {
    387             mSize = ((long)mem.getTotalPss()) * 1024;
    388             if (mCurSeq == curSeq) {
    389                 String sizeStr = Formatter.formatShortFileSize(
    390                         context, mSize);
    391                 if (!sizeStr.equals(mSizeStr)){
    392                     mSizeStr = sizeStr;
    393                     // We update this on the second tick where we update just
    394                     // the text in the current items, so no need to say we
    395                     // changed here.
    396                     return false;
    397                 }
    398             }
    399             return false;
    400         }
    401 
    402         boolean buildDependencyChain(Context context, PackageManager pm, int curSeq) {
    403             final int NP = mDependentProcesses.size();
    404             boolean changed = false;
    405             for (int i=0; i<NP; i++) {
    406                 ProcessItem proc = mDependentProcesses.valueAt(i);
    407                 if (proc.mClient != this) {
    408                     changed = true;
    409                     proc.mClient = this;
    410                 }
    411                 proc.mCurSeq = curSeq;
    412                 proc.ensureLabel(pm);
    413                 changed |= proc.buildDependencyChain(context, pm, curSeq);
    414             }
    415 
    416             if (mLastNumDependentProcesses != mDependentProcesses.size()) {
    417                 changed = true;
    418                 mLastNumDependentProcesses = mDependentProcesses.size();
    419             }
    420 
    421             return changed;
    422         }
    423 
    424         void addDependentProcesses(ArrayList<BaseItem> dest,
    425                 ArrayList<ProcessItem> destProc) {
    426             final int NP = mDependentProcesses.size();
    427             for (int i=0; i<NP; i++) {
    428                 ProcessItem proc = mDependentProcesses.valueAt(i);
    429                 proc.addDependentProcesses(dest, destProc);
    430                 dest.add(proc);
    431                 if (proc.mPid > 0) {
    432                     destProc.add(proc);
    433                 }
    434             }
    435         }
    436     }
    437 
    438     static class MergedItem extends BaseItem {
    439         ProcessItem mProcess;
    440         final ArrayList<ProcessItem> mOtherProcesses = new ArrayList<ProcessItem>();
    441         final ArrayList<ServiceItem> mServices = new ArrayList<ServiceItem>();
    442 
    443         private int mLastNumProcesses = -1, mLastNumServices = -1;
    444 
    445         MergedItem() {
    446             super(false);
    447         }
    448 
    449         boolean update(Context context, boolean background) {
    450             mPackageInfo = mProcess.mPackageInfo;
    451             mDisplayLabel = mProcess.mDisplayLabel;
    452             mLabel = mProcess.mLabel;
    453             mBackground = background;
    454 
    455             if (!mBackground) {
    456                 int numProcesses = (mProcess.mPid > 0 ? 1 : 0) + mOtherProcesses.size();
    457                 int numServices = mServices.size();
    458                 if (mLastNumProcesses != numProcesses || mLastNumServices != numServices) {
    459                     mLastNumProcesses = numProcesses;
    460                     mLastNumServices = numServices;
    461                     int resid = R.string.running_processes_item_description_s_s;
    462                     if (numProcesses != 1) {
    463                         resid = numServices != 1
    464                                 ? R.string.running_processes_item_description_p_p
    465                                 : R.string.running_processes_item_description_p_s;
    466                     } else if (numServices != 1) {
    467                         resid = R.string.running_processes_item_description_s_p;
    468                     }
    469                     mDescription = context.getResources().getString(resid, numProcesses,
    470                             numServices);
    471                 }
    472             }
    473 
    474             mActiveSince = -1;
    475             for (int i=0; i<mServices.size(); i++) {
    476                 ServiceItem si = mServices.get(i);
    477                 if (si.mActiveSince >= 0 && mActiveSince < si.mActiveSince) {
    478                     mActiveSince = si.mActiveSince;
    479                 }
    480             }
    481 
    482             return false;
    483         }
    484 
    485         boolean updateSize(Context context) {
    486             mSize = mProcess.mSize;
    487             for (int i=0; i<mOtherProcesses.size(); i++) {
    488                 mSize += mOtherProcesses.get(i).mSize;
    489             }
    490 
    491             String sizeStr = Formatter.formatShortFileSize(
    492                     context, mSize);
    493             if (!sizeStr.equals(mSizeStr)){
    494                 mSizeStr = sizeStr;
    495                 // We update this on the second tick where we update just
    496                 // the text in the current items, so no need to say we
    497                 // changed here.
    498                 return false;
    499             }
    500             return false;
    501         }
    502     }
    503 
    504     static class ServiceProcessComparator implements Comparator<ProcessItem> {
    505         public int compare(ProcessItem object1, ProcessItem object2) {
    506             if (object1.mIsStarted != object2.mIsStarted) {
    507                 // Non-started processes go last.
    508                 return object1.mIsStarted ? -1 : 1;
    509             }
    510             if (object1.mIsSystem != object2.mIsSystem) {
    511                 // System processes go below non-system.
    512                 return object1.mIsSystem ? 1 : -1;
    513             }
    514             if (object1.mActiveSince != object2.mActiveSince) {
    515                 // Remaining ones are sorted with the longest running
    516                 // services last.
    517                 return (object1.mActiveSince > object2.mActiveSince) ? -1 : 1;
    518             }
    519             return 0;
    520         }
    521     }
    522 
    523     static CharSequence makeLabel(PackageManager pm,
    524             String className, PackageItemInfo item) {
    525         if (item != null && (item.labelRes != 0
    526                 || item.nonLocalizedLabel != null)) {
    527             CharSequence label = item.loadLabel(pm);
    528             if (label != null) {
    529                 return label;
    530             }
    531         }
    532 
    533         String label = className;
    534         int tail = label.lastIndexOf('.');
    535         if (tail >= 0) {
    536             label = label.substring(tail+1, label.length());
    537         }
    538         return label;
    539     }
    540 
    541     static RunningState getInstance(Context context) {
    542         synchronized (sGlobalLock) {
    543             if (sInstance == null) {
    544                 sInstance = new RunningState(context);
    545             }
    546             return sInstance;
    547         }
    548     }
    549 
    550     private RunningState(Context context) {
    551         mApplicationContext = context.getApplicationContext();
    552         mAm = (ActivityManager)mApplicationContext.getSystemService(Context.ACTIVITY_SERVICE);
    553         mPm = mApplicationContext.getPackageManager();
    554         mResumed = false;
    555         mBackgroundThread = new HandlerThread("RunningState:Background");
    556         mBackgroundThread.start();
    557         mBackgroundHandler = new BackgroundHandler(mBackgroundThread.getLooper());
    558     }
    559 
    560     void resume(OnRefreshUiListener listener) {
    561         synchronized (mLock) {
    562             mResumed = true;
    563             mRefreshUiListener = listener;
    564             if (!mBackgroundHandler.hasMessages(MSG_UPDATE_CONTENTS)) {
    565                 mBackgroundHandler.sendEmptyMessage(MSG_UPDATE_CONTENTS);
    566             }
    567             mHandler.sendEmptyMessage(MSG_UPDATE_TIME);
    568         }
    569     }
    570 
    571     void updateNow() {
    572         synchronized (mLock) {
    573             mBackgroundHandler.removeMessages(MSG_UPDATE_CONTENTS);
    574             mBackgroundHandler.sendEmptyMessage(MSG_UPDATE_CONTENTS);
    575         }
    576     }
    577 
    578     boolean hasData() {
    579         synchronized (mLock) {
    580             return mHaveData;
    581         }
    582     }
    583 
    584     void waitForData() {
    585         synchronized (mLock) {
    586             while (!mHaveData) {
    587                 try {
    588                     mLock.wait(0);
    589                 } catch (InterruptedException e) {
    590                 }
    591             }
    592         }
    593     }
    594 
    595     void pause() {
    596         synchronized (mLock) {
    597             mResumed = false;
    598             mRefreshUiListener = null;
    599             mHandler.removeMessages(MSG_UPDATE_TIME);
    600         }
    601     }
    602 
    603     private boolean isInterestingProcess(ActivityManager.RunningAppProcessInfo pi) {
    604         if ((pi.flags&ActivityManager.RunningAppProcessInfo.FLAG_CANT_SAVE_STATE) != 0) {
    605             return true;
    606         }
    607         if ((pi.flags&ActivityManager.RunningAppProcessInfo.FLAG_PERSISTENT) == 0
    608                 && pi.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND
    609                 && pi.importanceReasonCode
    610                         == ActivityManager.RunningAppProcessInfo.REASON_UNKNOWN) {
    611             return true;
    612         }
    613         return false;
    614     }
    615 
    616     private boolean update(Context context, ActivityManager am) {
    617         final PackageManager pm = context.getPackageManager();
    618 
    619         mSequence++;
    620 
    621         boolean changed = false;
    622 
    623         List<ActivityManager.RunningServiceInfo> services
    624                 = am.getRunningServices(MAX_SERVICES);
    625         final int NS = services != null ? services.size() : 0;
    626         for (int i=0; i<NS; i++) {
    627             ActivityManager.RunningServiceInfo si = services.get(i);
    628             // We are not interested in services that have not been started
    629             // and don't have a known client, because
    630             // there is nothing the user can do about them.
    631             if (!si.started && si.clientLabel == 0) {
    632                 continue;
    633             }
    634             // We likewise don't care about services running in a
    635             // persistent process like the system or phone.
    636             if ((si.flags&ActivityManager.RunningServiceInfo.FLAG_PERSISTENT_PROCESS)
    637                     != 0) {
    638                 continue;
    639             }
    640 
    641             HashMap<String, ProcessItem> procs = mServiceProcessesByName.get(si.uid);
    642             if (procs == null) {
    643                 procs = new HashMap<String, ProcessItem>();
    644                 mServiceProcessesByName.put(si.uid, procs);
    645             }
    646             ProcessItem proc = procs.get(si.process);
    647             if (proc == null) {
    648                 changed = true;
    649                 proc = new ProcessItem(context, si.uid, si.process);
    650                 procs.put(si.process, proc);
    651             }
    652 
    653             if (proc.mCurSeq != mSequence) {
    654                 int pid = si.restarting == 0 ? si.pid : 0;
    655                 if (pid != proc.mPid) {
    656                     changed = true;
    657                     if (proc.mPid != pid) {
    658                         if (proc.mPid != 0) {
    659                             mServiceProcessesByPid.remove(proc.mPid);
    660                         }
    661                         if (pid != 0) {
    662                             mServiceProcessesByPid.put(pid, proc);
    663                         }
    664                         proc.mPid = pid;
    665                     }
    666                 }
    667                 proc.mDependentProcesses.clear();
    668                 proc.mCurSeq = mSequence;
    669             }
    670             changed |= proc.updateService(context, si);
    671         }
    672 
    673         // Now update the map of other processes that are running (but
    674         // don't have services actively running inside them).
    675         List<ActivityManager.RunningAppProcessInfo> processes
    676                 = am.getRunningAppProcesses();
    677         final int NP = processes != null ? processes.size() : 0;
    678         for (int i=0; i<NP; i++) {
    679             ActivityManager.RunningAppProcessInfo pi = processes.get(i);
    680             ProcessItem proc = mServiceProcessesByPid.get(pi.pid);
    681             if (proc == null) {
    682                 // This process is not one that is a direct container
    683                 // of a service, so look for it in the secondary
    684                 // running list.
    685                 proc = mRunningProcesses.get(pi.pid);
    686                 if (proc == null) {
    687                     changed = true;
    688                     proc = new ProcessItem(context, pi.uid, pi.processName);
    689                     proc.mPid = pi.pid;
    690                     mRunningProcesses.put(pi.pid, proc);
    691                 }
    692                 proc.mDependentProcesses.clear();
    693             }
    694 
    695             if (isInterestingProcess(pi)) {
    696                 if (!mInterestingProcesses.contains(proc)) {
    697                     changed = true;
    698                     mInterestingProcesses.add(proc);
    699                 }
    700                 proc.mCurSeq = mSequence;
    701                 proc.ensureLabel(pm);
    702             }
    703 
    704             proc.mRunningSeq = mSequence;
    705             proc.mRunningProcessInfo = pi;
    706         }
    707 
    708         // Build the chains from client processes to the process they are
    709         // dependent on; also remove any old running processes.
    710         int NRP = mRunningProcesses.size();
    711         for (int i=0; i<NRP; i++) {
    712             ProcessItem proc = mRunningProcesses.valueAt(i);
    713             if (proc.mRunningSeq == mSequence) {
    714                 int clientPid = proc.mRunningProcessInfo.importanceReasonPid;
    715                 if (clientPid != 0) {
    716                     ProcessItem client = mServiceProcessesByPid.get(clientPid);
    717                     if (client == null) {
    718                         client = mRunningProcesses.get(clientPid);
    719                     }
    720                     if (client != null) {
    721                         client.mDependentProcesses.put(proc.mPid, proc);
    722                     }
    723                 } else {
    724                     // In this pass the process doesn't have a client.
    725                     // Clear to make sure that, if it later gets the same one,
    726                     // we will detect the change.
    727                     proc.mClient = null;
    728                 }
    729             } else {
    730                 changed = true;
    731                 mRunningProcesses.remove(mRunningProcesses.keyAt(i));
    732             }
    733         }
    734 
    735         // Remove any old interesting processes.
    736         int NHP = mInterestingProcesses.size();
    737         for (int i=0; i<NHP; i++) {
    738             ProcessItem proc = mInterestingProcesses.get(i);
    739             if (mRunningProcesses.get(proc.mPid) == null) {
    740                 changed = true;
    741                 mInterestingProcesses.remove(i);
    742                 i--;
    743                 NHP--;
    744             }
    745         }
    746 
    747         // Follow the tree from all primary service processes to all
    748         // processes they are dependent on, marking these processes as
    749         // still being active and determining if anything has changed.
    750         final int NAP = mServiceProcessesByPid.size();
    751         for (int i=0; i<NAP; i++) {
    752             ProcessItem proc = mServiceProcessesByPid.valueAt(i);
    753             if (proc.mCurSeq == mSequence) {
    754                 changed |= proc.buildDependencyChain(context, pm, mSequence);
    755             }
    756         }
    757 
    758         // Look for services and their primary processes that no longer exist...
    759         for (int i=0; i<mServiceProcessesByName.size(); i++) {
    760             HashMap<String, ProcessItem> procs = mServiceProcessesByName.valueAt(i);
    761             Iterator<ProcessItem> pit = procs.values().iterator();
    762             while (pit.hasNext()) {
    763                 ProcessItem pi = pit.next();
    764                 if (pi.mCurSeq == mSequence) {
    765                     pi.ensureLabel(pm);
    766                     if (pi.mPid == 0) {
    767                         // Sanity: a non-process can't be dependent on
    768                         // anything.
    769                         pi.mDependentProcesses.clear();
    770                     }
    771                 } else {
    772                     changed = true;
    773                     pit.remove();
    774                     if (procs.size() == 0) {
    775                         mServiceProcessesByName.remove(mServiceProcessesByName.keyAt(i));
    776                     }
    777                     if (pi.mPid != 0) {
    778                         mServiceProcessesByPid.remove(pi.mPid);
    779                     }
    780                     continue;
    781                 }
    782                 Iterator<ServiceItem> sit = pi.mServices.values().iterator();
    783                 while (sit.hasNext()) {
    784                     ServiceItem si = sit.next();
    785                     if (si.mCurSeq != mSequence) {
    786                         changed = true;
    787                         sit.remove();
    788                     }
    789                 }
    790             }
    791         }
    792 
    793         if (changed) {
    794             // First determine an order for the services.
    795             ArrayList<ProcessItem> sortedProcesses = new ArrayList<ProcessItem>();
    796             for (int i=0; i<mServiceProcessesByName.size(); i++) {
    797                 for (ProcessItem pi : mServiceProcessesByName.valueAt(i).values()) {
    798                     pi.mIsSystem = false;
    799                     pi.mIsStarted = true;
    800                     pi.mActiveSince = Long.MAX_VALUE;
    801                     for (ServiceItem si : pi.mServices.values()) {
    802                         if (si.mServiceInfo != null
    803                                 && (si.mServiceInfo.applicationInfo.flags
    804                                         & ApplicationInfo.FLAG_SYSTEM) != 0) {
    805                             pi.mIsSystem = true;
    806                         }
    807                         if (si.mRunningService != null
    808                                 && si.mRunningService.clientLabel != 0) {
    809                             pi.mIsStarted = false;
    810                             if (pi.mActiveSince > si.mRunningService.activeSince) {
    811                                 pi.mActiveSince = si.mRunningService.activeSince;
    812                             }
    813                         }
    814                     }
    815                     sortedProcesses.add(pi);
    816                 }
    817             }
    818 
    819             Collections.sort(sortedProcesses, mServiceProcessComparator);
    820 
    821             ArrayList<BaseItem> newItems = new ArrayList<BaseItem>();
    822             ArrayList<MergedItem> newMergedItems = new ArrayList<MergedItem>();
    823             mProcessItems.clear();
    824             for (int i=0; i<sortedProcesses.size(); i++) {
    825                 ProcessItem pi = sortedProcesses.get(i);
    826                 pi.mNeedDivider = false;
    827 
    828                 int firstProc = mProcessItems.size();
    829                 // First add processes we are dependent on.
    830                 pi.addDependentProcesses(newItems, mProcessItems);
    831                 // And add the process itself.
    832                 newItems.add(pi);
    833                 if (pi.mPid > 0) {
    834                     mProcessItems.add(pi);
    835                 }
    836 
    837                 // Now add the services running in it.
    838                 MergedItem mergedItem = null;
    839                 boolean haveAllMerged = false;
    840                 boolean needDivider = false;
    841                 for (ServiceItem si : pi.mServices.values()) {
    842                     si.mNeedDivider = needDivider;
    843                     needDivider = true;
    844                     newItems.add(si);
    845                     if (si.mMergedItem != null) {
    846                         if (mergedItem != null && mergedItem != si.mMergedItem) {
    847                             haveAllMerged = false;
    848                         }
    849                         mergedItem = si.mMergedItem;
    850                     } else {
    851                         haveAllMerged = false;
    852                     }
    853                 }
    854 
    855                 if (!haveAllMerged || mergedItem == null
    856                         || mergedItem.mServices.size() != pi.mServices.size()) {
    857                     // Whoops, we need to build a new MergedItem!
    858                     mergedItem = new MergedItem();
    859                     for (ServiceItem si : pi.mServices.values()) {
    860                         mergedItem.mServices.add(si);
    861                         si.mMergedItem = mergedItem;
    862                     }
    863                     mergedItem.mProcess = pi;
    864                     mergedItem.mOtherProcesses.clear();
    865                     for (int mpi=firstProc; mpi<(mProcessItems.size()-1); mpi++) {
    866                         mergedItem.mOtherProcesses.add(mProcessItems.get(mpi));
    867                     }
    868                 }
    869 
    870                 mergedItem.update(context, false);
    871                 newMergedItems.add(mergedItem);
    872             }
    873 
    874             // Finally, interesting processes need to be shown and will
    875             // go at the top.
    876             NHP = mInterestingProcesses.size();
    877             for (int i=0; i<NHP; i++) {
    878                 ProcessItem proc = mInterestingProcesses.get(i);
    879                 if (proc.mClient == null && proc.mServices.size() <= 0) {
    880                     if (proc.mMergedItem == null) {
    881                         proc.mMergedItem = new MergedItem();
    882                         proc.mMergedItem.mProcess = proc;
    883                     }
    884                     proc.mMergedItem.update(context, false);
    885                     newMergedItems.add(0, proc.mMergedItem);
    886                     mProcessItems.add(proc);
    887                 }
    888             }
    889 
    890             synchronized (mLock) {
    891                 mItems = newItems;
    892                 mMergedItems = newMergedItems;
    893             }
    894         }
    895 
    896         // Count number of interesting other (non-active) processes, and
    897         // build a list of all processes we will retrieve memory for.
    898         mAllProcessItems.clear();
    899         mAllProcessItems.addAll(mProcessItems);
    900         int numBackgroundProcesses = 0;
    901         int numForegroundProcesses = 0;
    902         int numServiceProcesses = 0;
    903         NRP = mRunningProcesses.size();
    904         for (int i=0; i<NRP; i++) {
    905             ProcessItem proc = mRunningProcesses.valueAt(i);
    906             if (proc.mCurSeq != mSequence) {
    907                 // We didn't hit this process as a dependency on one
    908                 // of our active ones, so add it up if needed.
    909                 if (proc.mRunningProcessInfo.importance >=
    910                         ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND) {
    911                     numBackgroundProcesses++;
    912                     mAllProcessItems.add(proc);
    913                 } else if (proc.mRunningProcessInfo.importance <=
    914                         ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE) {
    915                     numForegroundProcesses++;
    916                     mAllProcessItems.add(proc);
    917                 } else {
    918                     Log.i("RunningState", "Unknown non-service process: "
    919                             + proc.mProcessName + " #" + proc.mPid);
    920                 }
    921             } else {
    922                 numServiceProcesses++;
    923             }
    924         }
    925 
    926         long backgroundProcessMemory = 0;
    927         long foregroundProcessMemory = 0;
    928         long serviceProcessMemory = 0;
    929         ArrayList<MergedItem> newBackgroundItems = null;
    930         try {
    931             final int numProc = mAllProcessItems.size();
    932             int[] pids = new int[numProc];
    933             for (int i=0; i<numProc; i++) {
    934                 pids[i] = mAllProcessItems.get(i).mPid;
    935             }
    936             Debug.MemoryInfo[] mem = ActivityManagerNative.getDefault()
    937                     .getProcessMemoryInfo(pids);
    938             int bgIndex = 0;
    939             for (int i=0; i<pids.length; i++) {
    940                 ProcessItem proc = mAllProcessItems.get(i);
    941                 changed |= proc.updateSize(context, mem[i], mSequence);
    942                 if (proc.mCurSeq == mSequence) {
    943                     serviceProcessMemory += proc.mSize;
    944                 } else if (proc.mRunningProcessInfo.importance >=
    945                         ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND) {
    946                     backgroundProcessMemory += proc.mSize;
    947                     MergedItem mergedItem;
    948                     if (newBackgroundItems != null) {
    949                         mergedItem = proc.mMergedItem = new MergedItem();
    950                         proc.mMergedItem.mProcess = proc;
    951                         newBackgroundItems.add(mergedItem);
    952                     } else {
    953                         if (bgIndex >= mBackgroundItems.size()
    954                                 || mBackgroundItems.get(bgIndex).mProcess != proc) {
    955                             newBackgroundItems = new ArrayList<MergedItem>(numBackgroundProcesses);
    956                             for (int bgi=0; bgi<bgIndex; bgi++) {
    957                                 newBackgroundItems.add(mBackgroundItems.get(bgi));
    958                             }
    959                             mergedItem = proc.mMergedItem = new MergedItem();
    960                             proc.mMergedItem.mProcess = proc;
    961                             newBackgroundItems.add(mergedItem);
    962                         } else {
    963                             mergedItem = mBackgroundItems.get(bgIndex);
    964                         }
    965                     }
    966                     mergedItem.update(context, true);
    967                     mergedItem.updateSize(context);
    968                     bgIndex++;
    969                 } else if (proc.mRunningProcessInfo.importance <=
    970                         ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE) {
    971                     foregroundProcessMemory += proc.mSize;
    972                 }
    973             }
    974         } catch (RemoteException e) {
    975         }
    976 
    977         if (newBackgroundItems == null) {
    978             // One or more at the bottom may no longer exit.
    979             if (mBackgroundItems.size() > numBackgroundProcesses) {
    980                 newBackgroundItems = new ArrayList<MergedItem>(numBackgroundProcesses);
    981                 for (int bgi=0; bgi<numBackgroundProcesses; bgi++) {
    982                     newBackgroundItems.add(mBackgroundItems.get(bgi));
    983                 }
    984             }
    985         }
    986 
    987         for (int i=0; i<mMergedItems.size(); i++) {
    988             mMergedItems.get(i).updateSize(context);
    989         }
    990 
    991         synchronized (mLock) {
    992             mNumBackgroundProcesses = numBackgroundProcesses;
    993             mNumForegroundProcesses = numForegroundProcesses;
    994             mNumServiceProcesses = numServiceProcesses;
    995             mBackgroundProcessMemory = backgroundProcessMemory;
    996             mForegroundProcessMemory = foregroundProcessMemory;
    997             mServiceProcessMemory = serviceProcessMemory;
    998             if (newBackgroundItems != null) {
    999                 mBackgroundItems = newBackgroundItems;
   1000                 if (mWatchingBackgroundItems) {
   1001                     changed = true;
   1002                 }
   1003             }
   1004             if (!mHaveData) {
   1005                 mHaveData = true;
   1006                 mLock.notifyAll();
   1007             }
   1008         }
   1009 
   1010         return changed;
   1011     }
   1012 
   1013     ArrayList<BaseItem> getCurrentItems() {
   1014         synchronized (mLock) {
   1015             return mItems;
   1016         }
   1017     }
   1018 
   1019     void setWatchingBackgroundItems(boolean watching) {
   1020         synchronized (mLock) {
   1021             mWatchingBackgroundItems = watching;
   1022         }
   1023     }
   1024 
   1025     ArrayList<MergedItem> getCurrentMergedItems() {
   1026         synchronized (mLock) {
   1027             return mMergedItems;
   1028         }
   1029     }
   1030 
   1031     ArrayList<MergedItem> getCurrentBackgroundItems() {
   1032         synchronized (mLock) {
   1033             return mBackgroundItems;
   1034         }
   1035     }
   1036 }
   1037