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