RunningState.java revision 728ac35373028b79205a788c526ef4b495518ec1
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
17package com.android.settings.applications;
18
19import com.android.settings.R;
20
21import android.app.ActivityManager;
22import android.app.ActivityManagerNative;
23import android.content.ComponentName;
24import android.content.Context;
25import android.content.pm.ApplicationInfo;
26import android.content.pm.PackageInfo;
27import android.content.pm.PackageItemInfo;
28import android.content.pm.PackageManager;
29import android.content.pm.ServiceInfo;
30import android.content.res.Resources;
31import android.os.Debug;
32import android.os.RemoteException;
33import android.text.format.Formatter;
34import android.util.Log;
35import android.util.SparseArray;
36
37import java.util.ArrayList;
38import java.util.Collections;
39import java.util.Comparator;
40import java.util.HashMap;
41import java.util.Iterator;
42import java.util.List;
43
44/**
45 * Singleton for retrieving and monitoring the state about all running
46 * applications/processes/services.
47 */
48public class RunningState {
49
50    final SparseArray<HashMap<String, ProcessItem>> mProcesses
51            = new SparseArray<HashMap<String, ProcessItem>>();
52    final SparseArray<ProcessItem> mActiveProcesses
53            = new SparseArray<ProcessItem>();
54    final ServiceProcessComparator mServiceProcessComparator
55            = new ServiceProcessComparator();
56
57    // Temporary for finding process dependencies.
58    final SparseArray<ProcessItem> mRunningProcesses
59            = new SparseArray<ProcessItem>();
60
61    final ArrayList<ProcessItem> mProcessItems = new ArrayList<ProcessItem>();
62    final ArrayList<ProcessItem> mAllProcessItems = new ArrayList<ProcessItem>();
63
64    int mSequence = 0;
65
66    // ----- following protected by mLock -----
67
68    // Lock for protecting the state that will be shared between the
69    // background update thread and the UI thread.
70    final Object mLock = new Object();
71
72    ArrayList<BaseItem> mItems = new ArrayList<BaseItem>();
73    ArrayList<MergedItem> mMergedItems = new ArrayList<MergedItem>();
74
75    int mNumBackgroundProcesses;
76    long mBackgroundProcessMemory;
77    int mNumForegroundProcesses;
78    long mForegroundProcessMemory;
79    int mNumServiceProcesses;
80    long mServiceProcessMemory;
81
82    static class BaseItem {
83        final boolean mIsProcess;
84
85        PackageItemInfo mPackageInfo;
86        CharSequence mDisplayLabel;
87        String mLabel;
88        String mDescription;
89
90        int mCurSeq;
91
92        long mActiveSince;
93        long mSize;
94        String mSizeStr;
95        String mCurSizeStr;
96        boolean mNeedDivider;
97
98        public BaseItem(boolean isProcess) {
99            mIsProcess = isProcess;
100        }
101    }
102
103    static class ServiceItem extends BaseItem {
104        ActivityManager.RunningServiceInfo mRunningService;
105        ServiceInfo mServiceInfo;
106        boolean mShownAsStarted;
107
108        MergedItem mMergedItem;
109
110        public ServiceItem() {
111            super(false);
112        }
113    }
114
115    static class ProcessItem extends BaseItem {
116        final HashMap<ComponentName, ServiceItem> mServices
117                = new HashMap<ComponentName, ServiceItem>();
118        final SparseArray<ProcessItem> mDependentProcesses
119                = new SparseArray<ProcessItem>();
120
121        final int mUid;
122        final String mProcessName;
123        int mPid;
124
125        ProcessItem mClient;
126        int mLastNumDependentProcesses;
127
128        int mRunningSeq;
129        ActivityManager.RunningAppProcessInfo mRunningProcessInfo;
130
131        // Purely for sorting.
132        boolean mIsSystem;
133        boolean mIsStarted;
134        long mActiveSince;
135
136        public ProcessItem(Context context, int uid, String processName) {
137            super(true);
138            mDescription = context.getResources().getString(
139                    R.string.service_process_name, processName);
140            mUid = uid;
141            mProcessName = processName;
142        }
143
144        void ensureLabel(PackageManager pm) {
145            if (mLabel != null) {
146                return;
147            }
148
149            try {
150                ApplicationInfo ai = pm.getApplicationInfo(mProcessName, 0);
151                if (ai.uid == mUid) {
152                    mDisplayLabel = ai.loadLabel(pm);
153                    mLabel = mDisplayLabel.toString();
154                    mPackageInfo = ai;
155                    return;
156                }
157            } catch (PackageManager.NameNotFoundException e) {
158            }
159
160            // If we couldn't get information about the overall
161            // process, try to find something about the uid.
162            String[] pkgs = pm.getPackagesForUid(mUid);
163
164            // If there is one package with this uid, that is what we want.
165            if (pkgs.length == 1) {
166                try {
167                    ApplicationInfo ai = pm.getApplicationInfo(pkgs[0], 0);
168                    mDisplayLabel = ai.loadLabel(pm);
169                    mLabel = mDisplayLabel.toString();
170                    mPackageInfo = ai;
171                    return;
172                } catch (PackageManager.NameNotFoundException e) {
173                }
174            }
175
176            // If there are multiple, see if one gives us the official name
177            // for this uid.
178            for (String name : pkgs) {
179                try {
180                    PackageInfo pi = pm.getPackageInfo(name, 0);
181                    if (pi.sharedUserLabel != 0) {
182                        CharSequence nm = pm.getText(name,
183                                pi.sharedUserLabel, pi.applicationInfo);
184                        if (nm != null) {
185                            mDisplayLabel = nm;
186                            mLabel = nm.toString();
187                            mPackageInfo = pi.applicationInfo;
188                            return;
189                        }
190                    }
191                } catch (PackageManager.NameNotFoundException e) {
192                }
193            }
194
195            // If still don't have anything to display, just use the
196            // service info.
197            if (mServices.size() > 0) {
198                mPackageInfo = mServices.values().iterator().next()
199                        .mServiceInfo.applicationInfo;
200                mDisplayLabel = mPackageInfo.loadLabel(pm);
201                mLabel = mDisplayLabel.toString();
202                return;
203            }
204
205            // Finally... whatever, just pick the first package's name.
206            try {
207                ApplicationInfo ai = pm.getApplicationInfo(pkgs[0], 0);
208                mDisplayLabel = ai.loadLabel(pm);
209                mLabel = mDisplayLabel.toString();
210                mPackageInfo = ai;
211                return;
212            } catch (PackageManager.NameNotFoundException e) {
213            }
214        }
215
216        boolean updateService(Context context,
217                ActivityManager.RunningServiceInfo service) {
218            final PackageManager pm = context.getPackageManager();
219
220            boolean changed = false;
221            ServiceItem si = mServices.get(service.service);
222            if (si == null) {
223                changed = true;
224                si = new ServiceItem();
225                si.mRunningService = service;
226                try {
227                    si.mServiceInfo = pm.getServiceInfo(service.service, 0);
228                } catch (PackageManager.NameNotFoundException e) {
229                }
230                si.mDisplayLabel = makeLabel(pm,
231                        si.mRunningService.service.getClassName(), si.mServiceInfo);
232                mLabel = mDisplayLabel != null ? mDisplayLabel.toString() : null;
233                si.mPackageInfo = si.mServiceInfo.applicationInfo;
234                mServices.put(service.service, si);
235            }
236            si.mCurSeq = mCurSeq;
237            si.mRunningService = service;
238            long activeSince = service.restarting == 0 ? service.activeSince : -1;
239            if (si.mActiveSince != activeSince) {
240                si.mActiveSince = activeSince;
241                changed = true;
242            }
243            if (service.clientPackage != null && service.clientLabel != 0) {
244                if (si.mShownAsStarted) {
245                    si.mShownAsStarted = false;
246                    changed = true;
247                }
248                try {
249                    Resources clientr = pm.getResourcesForApplication(service.clientPackage);
250                    String label = clientr.getString(service.clientLabel);
251                    si.mDescription = context.getResources().getString(
252                            R.string.service_client_name, label);
253                } catch (PackageManager.NameNotFoundException e) {
254                    si.mDescription = null;
255                }
256            } else {
257                if (!si.mShownAsStarted) {
258                    si.mShownAsStarted = true;
259                    changed = true;
260                }
261                si.mDescription = context.getResources().getString(
262                        R.string.service_started_by_app);
263            }
264
265            return changed;
266        }
267
268        boolean updateSize(Context context, Debug.MemoryInfo mem, int curSeq) {
269            mSize = ((long)mem.getTotalPss()) * 1024;
270            if (mCurSeq == curSeq) {
271                String sizeStr = Formatter.formatShortFileSize(
272                        context, mSize);
273                if (!sizeStr.equals(mSizeStr)){
274                    mSizeStr = sizeStr;
275                    // We update this on the second tick where we update just
276                    // the text in the current items, so no need to say we
277                    // changed here.
278                    return false;
279                }
280            }
281            return false;
282        }
283
284        boolean buildDependencyChain(Context context, PackageManager pm, int curSeq) {
285            final int NP = mDependentProcesses.size();
286            boolean changed = false;
287            for (int i=0; i<NP; i++) {
288                ProcessItem proc = mDependentProcesses.valueAt(i);
289                if (proc.mClient != this) {
290                    changed = true;
291                    proc.mClient = this;
292                }
293                proc.mCurSeq = curSeq;
294                proc.ensureLabel(pm);
295                changed |= proc.buildDependencyChain(context, pm, curSeq);
296            }
297
298            if (mLastNumDependentProcesses != mDependentProcesses.size()) {
299                changed = true;
300                mLastNumDependentProcesses = mDependentProcesses.size();
301            }
302
303            return changed;
304        }
305
306        void addDependentProcesses(ArrayList<BaseItem> dest,
307                ArrayList<ProcessItem> destProc) {
308            final int NP = mDependentProcesses.size();
309            for (int i=0; i<NP; i++) {
310                ProcessItem proc = mDependentProcesses.valueAt(i);
311                proc.addDependentProcesses(dest, destProc);
312                dest.add(proc);
313                if (proc.mPid > 0) {
314                    destProc.add(proc);
315                }
316            }
317        }
318    }
319
320    static class MergedItem extends BaseItem {
321        ProcessItem mProcess;
322        final ArrayList<ProcessItem> mOtherProcesses = new ArrayList<ProcessItem>();
323        final ArrayList<ServiceItem> mServices = new ArrayList<ServiceItem>();
324
325        MergedItem() {
326            super(false);
327        }
328
329        boolean update(Context context) {
330            mPackageInfo = mProcess.mPackageInfo;
331            mDisplayLabel = mProcess.mDisplayLabel;
332            mLabel = mProcess.mLabel;
333
334            int numProcesses = (mProcess.mPid > 0 ? 1 : 0) + mOtherProcesses.size();
335            int numServices = mServices.size();
336            int resid = R.string.running_processes_item_description_s_s;
337            if (numProcesses != 1) {
338                resid = numServices != 1
339                        ? R.string.running_processes_item_description_p_p
340                        : R.string.running_processes_item_description_p_s;
341            } else if (numServices != 1) {
342                resid = R.string.running_processes_item_description_s_p;
343            }
344            mDescription = context.getResources().getString(resid, numProcesses, numServices);
345
346            mActiveSince = -1;
347            for (int i=0; i<mServices.size(); i++) {
348                ServiceItem si = mServices.get(i);
349                if (si.mActiveSince >= 0 && mActiveSince < si.mActiveSince) {
350                    mActiveSince = si.mActiveSince;
351                }
352            }
353
354            return false;
355        }
356
357        boolean updateSize(Context context) {
358            mSize = mProcess.mSize;
359            for (int i=0; i<mOtherProcesses.size(); i++) {
360                mSize += mOtherProcesses.get(i).mSize;
361            }
362
363            String sizeStr = Formatter.formatShortFileSize(
364                    context, mSize);
365            if (!sizeStr.equals(mSizeStr)){
366                mSizeStr = sizeStr;
367                // We update this on the second tick where we update just
368                // the text in the current items, so no need to say we
369                // changed here.
370                return false;
371            }
372            return false;
373        }
374    }
375
376    static class ServiceProcessComparator implements Comparator<ProcessItem> {
377        public int compare(ProcessItem object1, ProcessItem object2) {
378            if (object1.mIsStarted != object2.mIsStarted) {
379                // Non-started processes go last.
380                return object1.mIsStarted ? -1 : 1;
381            }
382            if (object1.mIsSystem != object2.mIsSystem) {
383                // System processes go below non-system.
384                return object1.mIsSystem ? 1 : -1;
385            }
386            if (object1.mActiveSince != object2.mActiveSince) {
387                // Remaining ones are sorted with the longest running
388                // services last.
389                return (object1.mActiveSince > object2.mActiveSince) ? -1 : 1;
390            }
391            return 0;
392        }
393    }
394
395    static CharSequence makeLabel(PackageManager pm,
396            String className, PackageItemInfo item) {
397        if (item != null && (item.labelRes != 0
398                || item.nonLocalizedLabel != null)) {
399            CharSequence label = item.loadLabel(pm);
400            if (label != null) {
401                return label;
402            }
403        }
404
405        String label = className;
406        int tail = label.lastIndexOf('.');
407        if (tail >= 0) {
408            label = label.substring(tail+1, label.length());
409        }
410        return label;
411    }
412
413    boolean update(Context context, ActivityManager am) {
414        final PackageManager pm = context.getPackageManager();
415
416        mSequence++;
417
418        boolean changed = false;
419
420        List<ActivityManager.RunningServiceInfo> services
421                = am.getRunningServices(RunningServices.MAX_SERVICES);
422        final int NS = services != null ? services.size() : 0;
423        for (int i=0; i<NS; i++) {
424            ActivityManager.RunningServiceInfo si = services.get(i);
425            // We are not interested in services that have not been started
426            // and don't have a known client, because
427            // there is nothing the user can do about them.
428            if (!si.started && si.clientLabel == 0) {
429                continue;
430            }
431            // We likewise don't care about services running in a
432            // persistent process like the system or phone.
433            if ((si.flags&ActivityManager.RunningServiceInfo.FLAG_PERSISTENT_PROCESS)
434                    != 0) {
435                continue;
436            }
437
438            HashMap<String, ProcessItem> procs = mProcesses.get(si.uid);
439            if (procs == null) {
440                procs = new HashMap<String, ProcessItem>();
441                mProcesses.put(si.uid, procs);
442            }
443            ProcessItem proc = procs.get(si.process);
444            if (proc == null) {
445                changed = true;
446                proc = new ProcessItem(context, si.uid, si.process);
447                procs.put(si.process, proc);
448            }
449
450            if (proc.mCurSeq != mSequence) {
451                int pid = si.restarting == 0 ? si.pid : 0;
452                if (pid != proc.mPid) {
453                    changed = true;
454                    if (proc.mPid != pid) {
455                        if (proc.mPid != 0) {
456                            mActiveProcesses.remove(proc.mPid);
457                        }
458                        if (pid != 0) {
459                            mActiveProcesses.put(pid, proc);
460                        }
461                        proc.mPid = pid;
462                    }
463                }
464                proc.mDependentProcesses.clear();
465                proc.mCurSeq = mSequence;
466            }
467            changed |= proc.updateService(context, si);
468        }
469
470        // Now update the map of other processes that are running (but
471        // don't have services actively running inside them).
472        List<ActivityManager.RunningAppProcessInfo> processes
473                = am.getRunningAppProcesses();
474        final int NP = processes != null ? processes.size() : 0;
475        for (int i=0; i<NP; i++) {
476            ActivityManager.RunningAppProcessInfo pi = processes.get(i);
477            ProcessItem proc = mActiveProcesses.get(pi.pid);
478            if (proc == null) {
479                // This process is not one that is a direct container
480                // of a service, so look for it in the secondary
481                // running list.
482                proc = mRunningProcesses.get(pi.pid);
483                if (proc == null) {
484                    proc = new ProcessItem(context, pi.uid, pi.processName);
485                    proc.mPid = pi.pid;
486                    mRunningProcesses.put(pi.pid, proc);
487                }
488                proc.mDependentProcesses.clear();
489            }
490            proc.mRunningSeq = mSequence;
491            proc.mRunningProcessInfo = pi;
492        }
493
494        // Build the chains from client processes to the process they are
495        // dependent on; also remove any old running processes.
496        int NRP = mRunningProcesses.size();
497        for (int i=0; i<NRP; i++) {
498            ProcessItem proc = mRunningProcesses.valueAt(i);
499            if (proc.mRunningSeq == mSequence) {
500                int clientPid = proc.mRunningProcessInfo.importanceReasonPid;
501                if (clientPid != 0) {
502                    ProcessItem client = mActiveProcesses.get(clientPid);
503                    if (client == null) {
504                        client = mRunningProcesses.get(clientPid);
505                    }
506                    if (client != null) {
507                        client.mDependentProcesses.put(proc.mPid, proc);
508                    }
509                } else {
510                    // In this pass the process doesn't have a client.
511                    // Clear to make sure if it later gets the same one
512                    // that we will detect the change.
513                    proc.mClient = null;
514                }
515            } else {
516                mRunningProcesses.remove(mRunningProcesses.keyAt(i));
517            }
518        }
519
520        // Follow the tree from all primary service processes to all
521        // processes they are dependent on, marking these processes as
522        // still being active and determining if anything has changed.
523        final int NAP = mActiveProcesses.size();
524        for (int i=0; i<NAP; i++) {
525            ProcessItem proc = mActiveProcesses.valueAt(i);
526            if (proc.mCurSeq == mSequence) {
527                changed |= proc.buildDependencyChain(context, pm, mSequence);
528            }
529        }
530
531        // Look for services and their primary processes that no longer exist...
532        for (int i=0; i<mProcesses.size(); i++) {
533            HashMap<String, ProcessItem> procs = mProcesses.valueAt(i);
534            Iterator<ProcessItem> pit = procs.values().iterator();
535            while (pit.hasNext()) {
536                ProcessItem pi = pit.next();
537                if (pi.mCurSeq == mSequence) {
538                    pi.ensureLabel(pm);
539                    if (pi.mPid == 0) {
540                        // Sanity: a non-process can't be dependent on
541                        // anything.
542                        pi.mDependentProcesses.clear();
543                    }
544                } else {
545                    changed = true;
546                    pit.remove();
547                    if (procs.size() == 0) {
548                        mProcesses.remove(mProcesses.keyAt(i));
549                    }
550                    if (pi.mPid != 0) {
551                        mActiveProcesses.remove(pi.mPid);
552                    }
553                    continue;
554                }
555                Iterator<ServiceItem> sit = pi.mServices.values().iterator();
556                while (sit.hasNext()) {
557                    ServiceItem si = sit.next();
558                    if (si.mCurSeq != mSequence) {
559                        changed = true;
560                        sit.remove();
561                    }
562                }
563            }
564        }
565
566        if (changed) {
567            // First determine an order for the services.
568            ArrayList<ProcessItem> sortedProcesses = new ArrayList<ProcessItem>();
569            for (int i=0; i<mProcesses.size(); i++) {
570                for (ProcessItem pi : mProcesses.valueAt(i).values()) {
571                    pi.mIsSystem = false;
572                    pi.mIsStarted = true;
573                    pi.mActiveSince = Long.MAX_VALUE;
574                    for (ServiceItem si : pi.mServices.values()) {
575                        if (si.mServiceInfo != null
576                                && (si.mServiceInfo.applicationInfo.flags
577                                        & ApplicationInfo.FLAG_SYSTEM) != 0) {
578                            pi.mIsSystem = true;
579                        }
580                        if (si.mRunningService != null
581                                && si.mRunningService.clientLabel != 0) {
582                            pi.mIsStarted = false;
583                            if (pi.mActiveSince > si.mRunningService.activeSince) {
584                                pi.mActiveSince = si.mRunningService.activeSince;
585                            }
586                        }
587                    }
588                    sortedProcesses.add(pi);
589                }
590            }
591
592            Collections.sort(sortedProcesses, mServiceProcessComparator);
593
594            ArrayList<BaseItem> newItems = new ArrayList<BaseItem>();
595            ArrayList<MergedItem> newMergedItems = new ArrayList<MergedItem>();
596            mProcessItems.clear();
597            for (int i=0; i<sortedProcesses.size(); i++) {
598                ProcessItem pi = sortedProcesses.get(i);
599                pi.mNeedDivider = false;
600
601                int firstProc = mProcessItems.size();
602                // First add processes we are dependent on.
603                pi.addDependentProcesses(newItems, mProcessItems);
604                // And add the process itself.
605                newItems.add(pi);
606                if (pi.mPid > 0) {
607                    mProcessItems.add(pi);
608                }
609
610                // Now add the services running in it.
611                MergedItem mergedItem = null;
612                boolean haveAllMerged = false;
613                boolean needDivider = false;
614                for (ServiceItem si : pi.mServices.values()) {
615                    si.mNeedDivider = needDivider;
616                    needDivider = true;
617                    newItems.add(si);
618                    if (si.mMergedItem != null) {
619                        if (mergedItem != null && mergedItem != si.mMergedItem) {
620                            haveAllMerged = false;
621                        }
622                        mergedItem = si.mMergedItem;
623                    } else {
624                        haveAllMerged = false;
625                    }
626                }
627
628                if (!haveAllMerged || mergedItem == null
629                        || mergedItem.mServices.size() != pi.mServices.size()) {
630                    // Whoops, we need to build a new MergedItem!
631                    mergedItem = new MergedItem();
632                    for (ServiceItem si : pi.mServices.values()) {
633                        mergedItem.mServices.add(si);
634                        si.mMergedItem = mergedItem;
635                    }
636                    mergedItem.mProcess = pi;
637                    mergedItem.mOtherProcesses.clear();
638                    for (int mpi=firstProc; mpi<(mProcessItems.size()-1); mpi++) {
639                        mergedItem.mOtherProcesses.add(mProcessItems.get(mpi));
640                    }
641                }
642
643                mergedItem.update(context);
644                newMergedItems.add(mergedItem);
645            }
646            synchronized (mLock) {
647                mItems = newItems;
648                mMergedItems = newMergedItems;
649            }
650        }
651
652        // Count number of interesting other (non-active) processes, and
653        // build a list of all processes we will retrieve memory for.
654        mAllProcessItems.clear();
655        mAllProcessItems.addAll(mProcessItems);
656        int numBackgroundProcesses = 0;
657        int numForegroundProcesses = 0;
658        int numServiceProcesses = 0;
659        NRP = mRunningProcesses.size();
660        for (int i=0; i<NRP; i++) {
661            ProcessItem proc = mRunningProcesses.valueAt(i);
662            if (proc.mCurSeq != mSequence) {
663                // We didn't hit this process as a dependency on one
664                // of our active ones, so add it up if needed.
665                if (proc.mRunningProcessInfo.importance >=
666                        ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND) {
667                    numBackgroundProcesses++;
668                    mAllProcessItems.add(proc);
669                } else if (proc.mRunningProcessInfo.importance <=
670                        ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE) {
671                    numForegroundProcesses++;
672                    mAllProcessItems.add(proc);
673                } else {
674                    Log.i(RunningServices.TAG, "Unknown non-service process: "
675                            + proc.mProcessName + " #" + proc.mPid);
676                }
677            } else {
678                numServiceProcesses++;
679            }
680        }
681
682        long backgroundProcessMemory = 0;
683        long foregroundProcessMemory = 0;
684        long serviceProcessMemory = 0;
685        try {
686            final int numProc = mAllProcessItems.size();
687            int[] pids = new int[numProc];
688            for (int i=0; i<numProc; i++) {
689                pids[i] = mAllProcessItems.get(i).mPid;
690            }
691            Debug.MemoryInfo[] mem = ActivityManagerNative.getDefault()
692                    .getProcessMemoryInfo(pids);
693            for (int i=pids.length-1; i>=0; i--) {
694                ProcessItem proc = mAllProcessItems.get(i);
695                changed |= proc.updateSize(context, mem[i], mSequence);
696                if (proc.mCurSeq == mSequence) {
697                    serviceProcessMemory += proc.mSize;
698                } else if (proc.mRunningProcessInfo.importance >=
699                        ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND) {
700                    backgroundProcessMemory += proc.mSize;
701                } else if (proc.mRunningProcessInfo.importance <=
702                        ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE) {
703                    foregroundProcessMemory += proc.mSize;
704                }
705            }
706        } catch (RemoteException e) {
707        }
708
709        for (int i=0; i<mMergedItems.size(); i++) {
710            mMergedItems.get(i).updateSize(context);
711        }
712
713        synchronized (mLock) {
714            mNumBackgroundProcesses = numBackgroundProcesses;
715            mNumForegroundProcesses = numForegroundProcesses;
716            mNumServiceProcesses = numServiceProcesses;
717            mBackgroundProcessMemory = backgroundProcessMemory;
718            mForegroundProcessMemory = foregroundProcessMemory;
719            mServiceProcessMemory = serviceProcessMemory;
720        }
721
722        return changed;
723    }
724
725    ArrayList<BaseItem> getCurrentItems() {
726        synchronized (mLock) {
727            return mItems;
728        }
729    }
730
731    ArrayList<MergedItem> getCurrentMergedItems() {
732        synchronized (mLock) {
733            return mMergedItems;
734        }
735    }
736}
737