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