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