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