private boolean update(Context context, ActivityManager am) {
    final PackageManager pm = context.getPackageManager();

    mSequence++;

    boolean changed = false;

    List<ActivityManager.RunningServiceInfo> services = am.getRunningServices(MAX_SERVICES);
    final int NS = services != null ? services.size() : 0;
    for (int i = 0; i < NS; i++) {
      ActivityManager.RunningServiceInfo si = services.get(i);
      // We are not interested in services that have not been started
      // and don't have a known client, because
      // there is nothing the user can do about them.
      if (!si.started && si.clientLabel == 0) {
        continue;
      }
      // We likewise don't care about services running in a
      // persistent process like the system or phone.
      if ((si.flags & ActivityManager.RunningServiceInfo.FLAG_PERSISTENT_PROCESS) != 0) {
        continue;
      }

      HashMap<String, ProcessItem> procs = mServiceProcessesByName.get(si.uid);
      if (procs == null) {
        procs = new HashMap<String, ProcessItem>();
        mServiceProcessesByName.put(si.uid, procs);
      }
      ProcessItem proc = procs.get(si.process);
      if (proc == null) {
        changed = true;
        proc = new ProcessItem(context, si.uid, si.process);
        procs.put(si.process, proc);
      }

      if (proc.mCurSeq != mSequence) {
        int pid = si.restarting == 0 ? si.pid : 0;
        if (pid != proc.mPid) {
          changed = true;
          if (proc.mPid != pid) {
            if (proc.mPid != 0) {
              mServiceProcessesByPid.remove(proc.mPid);
            }
            if (pid != 0) {
              mServiceProcessesByPid.put(pid, proc);
            }
            proc.mPid = pid;
          }
        }
        proc.mDependentProcesses.clear();
        proc.mCurSeq = mSequence;
      }
      changed |= proc.updateService(context, si);
    }

    // Now update the map of other processes that are running (but
    // don't have services actively running inside them).
    List<ActivityManager.RunningAppProcessInfo> processes = am.getRunningAppProcesses();
    final int NP = processes != null ? processes.size() : 0;
    for (int i = 0; i < NP; i++) {
      ActivityManager.RunningAppProcessInfo pi = processes.get(i);
      ProcessItem proc = mServiceProcessesByPid.get(pi.pid);
      if (proc == null) {
        // This process is not one that is a direct container
        // of a service, so look for it in the secondary
        // running list.
        proc = mRunningProcesses.get(pi.pid);
        if (proc == null) {
          changed = true;
          proc = new ProcessItem(context, pi.uid, pi.processName);
          proc.mPid = pi.pid;
          mRunningProcesses.put(pi.pid, proc);
        }
        proc.mDependentProcesses.clear();
      }

      if (isInterestingProcess(pi)) {
        if (!mInterestingProcesses.contains(proc)) {
          changed = true;
          mInterestingProcesses.add(proc);
        }
        proc.mCurSeq = mSequence;
        proc.ensureLabel(pm);
      }

      proc.mRunningSeq = mSequence;
      proc.mRunningProcessInfo = pi;
    }

    // Build the chains from client processes to the process they are
    // dependent on; also remove any old running processes.
    int NRP = mRunningProcesses.size();
    for (int i = 0; i < NRP; i++) {
      ProcessItem proc = mRunningProcesses.valueAt(i);
      if (proc.mRunningSeq == mSequence) {
        int clientPid = proc.mRunningProcessInfo.importanceReasonPid;
        if (clientPid != 0) {
          ProcessItem client = mServiceProcessesByPid.get(clientPid);
          if (client == null) {
            client = mRunningProcesses.get(clientPid);
          }
          if (client != null) {
            client.mDependentProcesses.put(proc.mPid, proc);
          }
        } else {
          // In this pass the process doesn't have a client.
          // Clear to make sure that, if it later gets the same one,
          // we will detect the change.
          proc.mClient = null;
        }
      } else {
        changed = true;
        mRunningProcesses.remove(mRunningProcesses.keyAt(i));
      }
    }

    // Remove any old interesting processes.
    int NHP = mInterestingProcesses.size();
    for (int i = 0; i < NHP; i++) {
      ProcessItem proc = mInterestingProcesses.get(i);
      if (mRunningProcesses.get(proc.mPid) == null) {
        changed = true;
        mInterestingProcesses.remove(i);
        i--;
        NHP--;
      }
    }

    // Follow the tree from all primary service processes to all
    // processes they are dependent on, marking these processes as
    // still being active and determining if anything has changed.
    final int NAP = mServiceProcessesByPid.size();
    for (int i = 0; i < NAP; i++) {
      ProcessItem proc = mServiceProcessesByPid.valueAt(i);
      if (proc.mCurSeq == mSequence) {
        changed |= proc.buildDependencyChain(context, pm, mSequence);
      }
    }

    // Look for services and their primary processes that no longer exist...
    ArrayList<Integer> uidToDelete = null;
    for (int i = 0; i < mServiceProcessesByName.size(); i++) {
      HashMap<String, ProcessItem> procs = mServiceProcessesByName.valueAt(i);
      Iterator<ProcessItem> pit = procs.values().iterator();
      while (pit.hasNext()) {
        ProcessItem pi = pit.next();
        if (pi.mCurSeq == mSequence) {
          pi.ensureLabel(pm);
          if (pi.mPid == 0) {
            // Sanity: a non-process can't be dependent on
            // anything.
            pi.mDependentProcesses.clear();
          }
        } else {
          changed = true;
          pit.remove();
          if (procs.size() == 0) {
            if (uidToDelete == null) {
              uidToDelete = new ArrayList<Integer>();
            }
            uidToDelete.add(mServiceProcessesByName.keyAt(i));
          }
          if (pi.mPid != 0) {
            mServiceProcessesByPid.remove(pi.mPid);
          }
          continue;
        }
        Iterator<ServiceItem> sit = pi.mServices.values().iterator();
        while (sit.hasNext()) {
          ServiceItem si = sit.next();
          if (si.mCurSeq != mSequence) {
            changed = true;
            sit.remove();
          }
        }
      }
    }

    if (uidToDelete != null) {
      for (int i = 0; i < uidToDelete.size(); i++) {
        int uid = uidToDelete.get(i);
        mServiceProcessesByName.remove(uid);
      }
    }

    if (changed) {
      // First determine an order for the services.
      ArrayList<ProcessItem> sortedProcesses = new ArrayList<ProcessItem>();
      for (int i = 0; i < mServiceProcessesByName.size(); i++) {
        for (ProcessItem pi : mServiceProcessesByName.valueAt(i).values()) {
          pi.mIsSystem = false;
          pi.mIsStarted = true;
          pi.mActiveSince = Long.MAX_VALUE;
          for (ServiceItem si : pi.mServices.values()) {
            if (si.mServiceInfo != null
                && (si.mServiceInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
              pi.mIsSystem = true;
            }
            if (si.mRunningService != null && si.mRunningService.clientLabel != 0) {
              pi.mIsStarted = false;
              if (pi.mActiveSince > si.mRunningService.activeSince) {
                pi.mActiveSince = si.mRunningService.activeSince;
              }
            }
          }
          sortedProcesses.add(pi);
        }
      }

      Collections.sort(sortedProcesses, mServiceProcessComparator);

      ArrayList<BaseItem> newItems = new ArrayList<BaseItem>();
      ArrayList<MergedItem> newMergedItems = new ArrayList<MergedItem>();
      mProcessItems.clear();
      for (int i = 0; i < sortedProcesses.size(); i++) {
        ProcessItem pi = sortedProcesses.get(i);
        pi.mNeedDivider = false;

        int firstProc = mProcessItems.size();
        // First add processes we are dependent on.
        pi.addDependentProcesses(newItems, mProcessItems);
        // And add the process itself.
        newItems.add(pi);
        if (pi.mPid > 0) {
          mProcessItems.add(pi);
        }

        // Now add the services running in it.
        MergedItem mergedItem = null;
        boolean haveAllMerged = false;
        boolean needDivider = false;
        for (ServiceItem si : pi.mServices.values()) {
          si.mNeedDivider = needDivider;
          needDivider = true;
          newItems.add(si);
          if (si.mMergedItem != null) {
            if (mergedItem != null && mergedItem != si.mMergedItem) {
              haveAllMerged = false;
            }
            mergedItem = si.mMergedItem;
          } else {
            haveAllMerged = false;
          }
        }

        if (!haveAllMerged
            || mergedItem == null
            || mergedItem.mServices.size() != pi.mServices.size()) {
          // Whoops, we need to build a new MergedItem!
          mergedItem = new MergedItem();
          for (ServiceItem si : pi.mServices.values()) {
            mergedItem.mServices.add(si);
            si.mMergedItem = mergedItem;
          }
          mergedItem.mProcess = pi;
          mergedItem.mOtherProcesses.clear();
          for (int mpi = firstProc; mpi < (mProcessItems.size() - 1); mpi++) {
            mergedItem.mOtherProcesses.add(mProcessItems.get(mpi));
          }
        }

        mergedItem.update(context, false);
        newMergedItems.add(mergedItem);
      }

      // Finally, interesting processes need to be shown and will
      // go at the top.
      NHP = mInterestingProcesses.size();
      for (int i = 0; i < NHP; i++) {
        ProcessItem proc = mInterestingProcesses.get(i);
        if (proc.mClient == null && proc.mServices.size() <= 0) {
          if (proc.mMergedItem == null) {
            proc.mMergedItem = new MergedItem();
            proc.mMergedItem.mProcess = proc;
          }
          proc.mMergedItem.update(context, false);
          newMergedItems.add(0, proc.mMergedItem);
          mProcessItems.add(proc);
        }
      }

      synchronized (mLock) {
        mItems = newItems;
        mMergedItems = newMergedItems;
      }
    }

    // Count number of interesting other (non-active) processes, and
    // build a list of all processes we will retrieve memory for.
    mAllProcessItems.clear();
    mAllProcessItems.addAll(mProcessItems);
    int numBackgroundProcesses = 0;
    int numForegroundProcesses = 0;
    int numServiceProcesses = 0;
    NRP = mRunningProcesses.size();
    for (int i = 0; i < NRP; i++) {
      ProcessItem proc = mRunningProcesses.valueAt(i);
      if (proc.mCurSeq != mSequence) {
        // We didn't hit this process as a dependency on one
        // of our active ones, so add it up if needed.
        if (proc.mRunningProcessInfo.importance
            >= ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND) {
          numBackgroundProcesses++;
          mAllProcessItems.add(proc);
        } else if (proc.mRunningProcessInfo.importance
            <= ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE) {
          numForegroundProcesses++;
          mAllProcessItems.add(proc);
        } else {
          Log.i(
              "RunningState",
              "Unknown non-service process: " + proc.mProcessName + " #" + proc.mPid);
        }
      } else {
        numServiceProcesses++;
      }
    }

    long backgroundProcessMemory = 0;
    long foregroundProcessMemory = 0;
    long serviceProcessMemory = 0;
    ArrayList<MergedItem> newBackgroundItems = null;
    try {
      final int numProc = mAllProcessItems.size();
      int[] pids = new int[numProc];
      for (int i = 0; i < numProc; i++) {
        pids[i] = mAllProcessItems.get(i).mPid;
      }
      Debug.MemoryInfo[] mem = ActivityManagerNative.getDefault().getProcessMemoryInfo(pids);
      int bgIndex = 0;
      for (int i = 0; i < pids.length; i++) {
        ProcessItem proc = mAllProcessItems.get(i);
        changed |= proc.updateSize(context, mem[i], mSequence);
        if (proc.mCurSeq == mSequence) {
          serviceProcessMemory += proc.mSize;
        } else if (proc.mRunningProcessInfo.importance
            >= ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND) {
          backgroundProcessMemory += proc.mSize;
          MergedItem mergedItem;
          if (newBackgroundItems != null) {
            mergedItem = proc.mMergedItem = new MergedItem();
            proc.mMergedItem.mProcess = proc;
            newBackgroundItems.add(mergedItem);
          } else {
            if (bgIndex >= mBackgroundItems.size()
                || mBackgroundItems.get(bgIndex).mProcess != proc) {
              newBackgroundItems = new ArrayList<MergedItem>(numBackgroundProcesses);
              for (int bgi = 0; bgi < bgIndex; bgi++) {
                newBackgroundItems.add(mBackgroundItems.get(bgi));
              }
              mergedItem = proc.mMergedItem = new MergedItem();
              proc.mMergedItem.mProcess = proc;
              newBackgroundItems.add(mergedItem);
            } else {
              mergedItem = mBackgroundItems.get(bgIndex);
            }
          }
          mergedItem.update(context, true);
          mergedItem.updateSize(context);
          bgIndex++;
        } else if (proc.mRunningProcessInfo.importance
            <= ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE) {
          foregroundProcessMemory += proc.mSize;
        }
      }
    } catch (RemoteException e) {
    }

    if (newBackgroundItems == null) {
      // One or more at the bottom may no longer exit.
      if (mBackgroundItems.size() > numBackgroundProcesses) {
        newBackgroundItems = new ArrayList<MergedItem>(numBackgroundProcesses);
        for (int bgi = 0; bgi < numBackgroundProcesses; bgi++) {
          newBackgroundItems.add(mBackgroundItems.get(bgi));
        }
      }
    }

    for (int i = 0; i < mMergedItems.size(); i++) {
      mMergedItems.get(i).updateSize(context);
    }

    synchronized (mLock) {
      mNumBackgroundProcesses = numBackgroundProcesses;
      mNumForegroundProcesses = numForegroundProcesses;
      mNumServiceProcesses = numServiceProcesses;
      mBackgroundProcessMemory = backgroundProcessMemory;
      mForegroundProcessMemory = foregroundProcessMemory;
      mServiceProcessMemory = serviceProcessMemory;
      if (newBackgroundItems != null) {
        mBackgroundItems = newBackgroundItems;
        if (mWatchingBackgroundItems) {
          changed = true;
        }
      }
      if (!mHaveData) {
        mHaveData = true;
        mLock.notifyAll();
      }
    }

    return changed;
  }
    boolean updateService(Context context, ActivityManager.RunningServiceInfo service) {
      final PackageManager pm = context.getPackageManager();

      boolean changed = false;
      ServiceItem si = mServices.get(service.service);
      if (si == null) {
        changed = true;
        si = new ServiceItem();
        si.mRunningService = service;
        try {
          si.mServiceInfo = pm.getServiceInfo(service.service, 0);
        } catch (PackageManager.NameNotFoundException e) {
        }
        si.mDisplayLabel =
            makeLabel(pm, si.mRunningService.service.getClassName(), si.mServiceInfo);
        mLabel = mDisplayLabel != null ? mDisplayLabel.toString() : null;
        si.mPackageInfo = si.mServiceInfo.applicationInfo;
        mServices.put(service.service, si);
      }
      si.mCurSeq = mCurSeq;
      si.mRunningService = service;
      long activeSince = service.restarting == 0 ? service.activeSince : -1;
      if (si.mActiveSince != activeSince) {
        si.mActiveSince = activeSince;
        changed = true;
      }
      if (service.clientPackage != null && service.clientLabel != 0) {
        if (si.mShownAsStarted) {
          si.mShownAsStarted = false;
          changed = true;
        }
        try {
          Resources clientr = pm.getResourcesForApplication(service.clientPackage);
          String label = clientr.getString(service.clientLabel);
          si.mDescription = context.getResources().getString(R.string.service_client_name, label);
        } catch (PackageManager.NameNotFoundException e) {
          si.mDescription = null;
        }
      } else {
        if (!si.mShownAsStarted) {
          si.mShownAsStarted = true;
          changed = true;
        }
        si.mDescription = context.getResources().getString(R.string.service_started_by_app);
      }

      return changed;
    }