• 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; i++) {
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             } else {
837                 changed = true;
838                 mRunningProcesses.remove(mRunningProcesses.keyAt(i));
839             }
840         }
841 
842         // Remove any old interesting processes.
843         int NHP = mInterestingProcesses.size();
844         for (int i=0; i<NHP; i++) {
845             ProcessItem proc = mInterestingProcesses.get(i);
846             if (!proc.mInteresting || mRunningProcesses.get(proc.mPid) == null) {
847                 changed = true;
848                 mInterestingProcesses.remove(i);
849                 i--;
850                 NHP--;
851             }
852         }
853 
854         // Follow the tree from all primary service processes to all
855         // processes they are dependent on, marking these processes as
856         // still being active and determining if anything has changed.
857         final int NAP = mServiceProcessesByPid.size();
858         for (int i=0; i<NAP; i++) {
859             ProcessItem proc = mServiceProcessesByPid.valueAt(i);
860             if (proc.mCurSeq == mSequence) {
861                 changed |= proc.buildDependencyChain(context, pm, mSequence);
862             }
863         }
864 
865         // Look for services and their primary processes that no longer exist...
866         ArrayList<Integer> uidToDelete = null;
867         for (int i=0; i<mServiceProcessesByName.size(); i++) {
868             HashMap<String, ProcessItem> procs = mServiceProcessesByName.valueAt(i);
869             Iterator<ProcessItem> pit = procs.values().iterator();
870             while (pit.hasNext()) {
871                 ProcessItem pi = pit.next();
872                 if (pi.mCurSeq == mSequence) {
873                     pi.ensureLabel(pm);
874                     if (pi.mPid == 0) {
875                         // Sanity: a non-process can't be dependent on
876                         // anything.
877                         pi.mDependentProcesses.clear();
878                     }
879                 } else {
880                     changed = true;
881                     pit.remove();
882                     if (procs.size() == 0) {
883                         if (uidToDelete == null) {
884                             uidToDelete = new ArrayList<Integer>();
885                         }
886                         uidToDelete.add(mServiceProcessesByName.keyAt(i));
887                     }
888                     if (pi.mPid != 0) {
889                         mServiceProcessesByPid.remove(pi.mPid);
890                     }
891                     continue;
892                 }
893                 Iterator<ServiceItem> sit = pi.mServices.values().iterator();
894                 while (sit.hasNext()) {
895                     ServiceItem si = sit.next();
896                     if (si.mCurSeq != mSequence) {
897                         changed = true;
898                         sit.remove();
899                     }
900                 }
901             }
902         }
903 
904         if (uidToDelete != null) {
905             for (int i = 0; i < uidToDelete.size(); i++) {
906                 int uid = uidToDelete.get(i);
907                 mServiceProcessesByName.remove(uid);
908             }
909         }
910 
911         if (changed) {
912             // First determine an order for the services.
913             ArrayList<ProcessItem> sortedProcesses = new ArrayList<ProcessItem>();
914             for (int i=0; i<mServiceProcessesByName.size(); i++) {
915                 for (ProcessItem pi : mServiceProcessesByName.valueAt(i).values()) {
916                     pi.mIsSystem = false;
917                     pi.mIsStarted = true;
918                     pi.mActiveSince = Long.MAX_VALUE;
919                     for (ServiceItem si : pi.mServices.values()) {
920                         if (si.mServiceInfo != null
921                                 && (si.mServiceInfo.applicationInfo.flags
922                                         & ApplicationInfo.FLAG_SYSTEM) != 0) {
923                             pi.mIsSystem = true;
924                         }
925                         if (si.mRunningService != null
926                                 && si.mRunningService.clientLabel != 0) {
927                             pi.mIsStarted = false;
928                             if (pi.mActiveSince > si.mRunningService.activeSince) {
929                                 pi.mActiveSince = si.mRunningService.activeSince;
930                             }
931                         }
932                     }
933                     sortedProcesses.add(pi);
934                 }
935             }
936 
937             Collections.sort(sortedProcesses, mServiceProcessComparator);
938 
939             ArrayList<BaseItem> newItems = new ArrayList<BaseItem>();
940             ArrayList<MergedItem> newMergedItems = new ArrayList<MergedItem>();
941             mProcessItems.clear();
942             for (int i=0; i<sortedProcesses.size(); i++) {
943                 ProcessItem pi = sortedProcesses.get(i);
944                 pi.mNeedDivider = false;
945 
946                 int firstProc = mProcessItems.size();
947                 // First add processes we are dependent on.
948                 pi.addDependentProcesses(newItems, mProcessItems);
949                 // And add the process itself.
950                 newItems.add(pi);
951                 if (pi.mPid > 0) {
952                     mProcessItems.add(pi);
953                 }
954 
955                 // Now add the services running in it.
956                 MergedItem mergedItem = null;
957                 boolean haveAllMerged = false;
958                 boolean needDivider = false;
959                 for (ServiceItem si : pi.mServices.values()) {
960                     si.mNeedDivider = needDivider;
961                     needDivider = true;
962                     newItems.add(si);
963                     if (si.mMergedItem != null) {
964                         if (mergedItem != null && mergedItem != si.mMergedItem) {
965                             haveAllMerged = false;
966                         }
967                         mergedItem = si.mMergedItem;
968                     } else {
969                         haveAllMerged = false;
970                     }
971                 }
972 
973                 if (!haveAllMerged || mergedItem == null
974                         || mergedItem.mServices.size() != pi.mServices.size()) {
975                     // Whoops, we need to build a new MergedItem!
976                     mergedItem = new MergedItem();
977                     for (ServiceItem si : pi.mServices.values()) {
978                         mergedItem.mServices.add(si);
979                         si.mMergedItem = mergedItem;
980                     }
981                     mergedItem.mProcess = pi;
982                     mergedItem.mOtherProcesses.clear();
983                     for (int mpi=firstProc; mpi<(mProcessItems.size()-1); mpi++) {
984                         mergedItem.mOtherProcesses.add(mProcessItems.get(mpi));
985                     }
986                 }
987 
988                 mergedItem.update(context, false);
989                 newMergedItems.add(mergedItem);
990             }
991 
992             // Finally, interesting processes need to be shown and will
993             // go at the top.
994             NHP = mInterestingProcesses.size();
995             for (int i=0; i<NHP; i++) {
996                 ProcessItem proc = mInterestingProcesses.get(i);
997                 if (proc.mClient == null && proc.mServices.size() <= 0) {
998                     if (proc.mMergedItem == null) {
999                         proc.mMergedItem = new MergedItem();
1000                         proc.mMergedItem.mProcess = proc;
1001                     }
1002                     proc.mMergedItem.update(context, false);
1003                     newMergedItems.add(0, proc.mMergedItem);
1004                     mProcessItems.add(proc);
1005                 }
1006             }
1007 
1008             synchronized (mLock) {
1009                 mItems = newItems;
1010                 mMergedItems = newMergedItems;
1011             }
1012         }
1013 
1014         // Count number of interesting other (non-active) processes, and
1015         // build a list of all processes we will retrieve memory for.
1016         mAllProcessItems.clear();
1017         mAllProcessItems.addAll(mProcessItems);
1018         int numBackgroundProcesses = 0;
1019         int numForegroundProcesses = 0;
1020         int numServiceProcesses = 0;
1021         NRP = mRunningProcesses.size();
1022         for (int i=0; i<NRP; i++) {
1023             ProcessItem proc = mRunningProcesses.valueAt(i);
1024             if (proc.mCurSeq != mSequence) {
1025                 // We didn't hit this process as a dependency on one
1026                 // of our active ones, so add it up if needed.
1027                 if (proc.mRunningProcessInfo.importance >=
1028                         ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND) {
1029                     numBackgroundProcesses++;
1030                     mAllProcessItems.add(proc);
1031                 } else if (proc.mRunningProcessInfo.importance <=
1032                         ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE) {
1033                     numForegroundProcesses++;
1034                     mAllProcessItems.add(proc);
1035                 } else {
1036                     Log.i("RunningState", "Unknown non-service process: "
1037                             + proc.mProcessName + " #" + proc.mPid);
1038                 }
1039             } else {
1040                 numServiceProcesses++;
1041             }
1042         }
1043 
1044         long backgroundProcessMemory = 0;
1045         long foregroundProcessMemory = 0;
1046         long serviceProcessMemory = 0;
1047         ArrayList<MergedItem> newBackgroundItems = null;
1048         try {
1049             final int numProc = mAllProcessItems.size();
1050             int[] pids = new int[numProc];
1051             for (int i=0; i<numProc; i++) {
1052                 pids[i] = mAllProcessItems.get(i).mPid;
1053             }
1054             long[] pss = ActivityManagerNative.getDefault()
1055                     .getProcessPss(pids);
1056             int bgIndex = 0;
1057             for (int i=0; i<pids.length; i++) {
1058                 ProcessItem proc = mAllProcessItems.get(i);
1059                 changed |= proc.updateSize(context, pss[i], mSequence);
1060                 if (proc.mCurSeq == mSequence) {
1061                     serviceProcessMemory += proc.mSize;
1062                 } else if (proc.mRunningProcessInfo.importance >=
1063                         ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND) {
1064                     backgroundProcessMemory += proc.mSize;
1065                     MergedItem mergedItem;
1066                     if (newBackgroundItems != null) {
1067                         mergedItem = proc.mMergedItem = new MergedItem();
1068                         proc.mMergedItem.mProcess = proc;
1069                         newBackgroundItems.add(mergedItem);
1070                     } else {
1071                         if (bgIndex >= mBackgroundItems.size()
1072                                 || mBackgroundItems.get(bgIndex).mProcess != proc) {
1073                             newBackgroundItems = new ArrayList<MergedItem>(numBackgroundProcesses);
1074                             for (int bgi=0; bgi<bgIndex; bgi++) {
1075                                 newBackgroundItems.add(mBackgroundItems.get(bgi));
1076                             }
1077                             mergedItem = proc.mMergedItem = new MergedItem();
1078                             proc.mMergedItem.mProcess = proc;
1079                             newBackgroundItems.add(mergedItem);
1080                         } else {
1081                             mergedItem = mBackgroundItems.get(bgIndex);
1082                         }
1083                     }
1084                     mergedItem.update(context, true);
1085                     mergedItem.updateSize(context);
1086                     bgIndex++;
1087                 } else if (proc.mRunningProcessInfo.importance <=
1088                         ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE) {
1089                     foregroundProcessMemory += proc.mSize;
1090                 }
1091             }
1092         } catch (RemoteException e) {
1093         }
1094 
1095         if (newBackgroundItems == null) {
1096             // One or more at the bottom may no longer exist.
1097             if (mBackgroundItems.size() > numBackgroundProcesses) {
1098                 newBackgroundItems = new ArrayList<MergedItem>(numBackgroundProcesses);
1099                 for (int bgi=0; bgi<numBackgroundProcesses; bgi++) {
1100                     newBackgroundItems.add(mBackgroundItems.get(bgi));
1101                 }
1102             }
1103         }
1104 
1105         for (int i=0; i<mMergedItems.size(); i++) {
1106             mMergedItems.get(i).updateSize(context);
1107         }
1108 
1109         synchronized (mLock) {
1110             mNumBackgroundProcesses = numBackgroundProcesses;
1111             mNumForegroundProcesses = numForegroundProcesses;
1112             mNumServiceProcesses = numServiceProcesses;
1113             mBackgroundProcessMemory = backgroundProcessMemory;
1114             mForegroundProcessMemory = foregroundProcessMemory;
1115             mServiceProcessMemory = serviceProcessMemory;
1116             if (newBackgroundItems != null) {
1117                 mBackgroundItems = newBackgroundItems;
1118                 if (mWatchingBackgroundItems) {
1119                     changed = true;
1120                 }
1121             }
1122             if (!mHaveData) {
1123                 mHaveData = true;
1124                 mLock.notifyAll();
1125             }
1126         }
1127 
1128         return changed;
1129     }
1130 
getCurrentItems()1131     ArrayList<BaseItem> getCurrentItems() {
1132         synchronized (mLock) {
1133             return mItems;
1134         }
1135     }
1136 
setWatchingBackgroundItems(boolean watching)1137     void setWatchingBackgroundItems(boolean watching) {
1138         synchronized (mLock) {
1139             mWatchingBackgroundItems = watching;
1140         }
1141     }
1142 
getCurrentMergedItems()1143     ArrayList<MergedItem> getCurrentMergedItems() {
1144         synchronized (mLock) {
1145             return mMergedItems;
1146         }
1147     }
1148 
getCurrentBackgroundItems()1149     ArrayList<MergedItem> getCurrentBackgroundItems() {
1150         synchronized (mLock) {
1151             return mBackgroundItems;
1152         }
1153     }
1154 }
1155