/**
  * Returns the total time (in milliseconds) spent executing in both user and system code. Safe to
  * call without lock held.
  */
 public long getCpuTimeForPid(int pid) {
   synchronized (mSinglePidStatsData) {
     final String statFile = "/proc/" + pid + "/stat";
     final long[] statsData = mSinglePidStatsData;
     if (Process.readProcFile(statFile, PROCESS_STATS_FORMAT, null, statsData, null)) {
       long time = statsData[PROCESS_STAT_UTIME] + statsData[PROCESS_STAT_STIME];
       return time * mJiffyMillis;
     }
     return 0;
   }
 }
  private int[] collectStats(
      String statsFile, int parentPid, boolean first, int[] curPids, ArrayList<Stats> allProcs) {

    int[] pids = Process.getPids(statsFile, curPids);
    int NP = (pids == null) ? 0 : pids.length;
    int NS = allProcs.size();
    int curStatsIndex = 0;
    for (int i = 0; i < NP; i++) {
      int pid = pids[i];
      if (pid < 0) {
        NP = pid;
        break;
      }
      Stats st = curStatsIndex < NS ? allProcs.get(curStatsIndex) : null;

      if (st != null && st.pid == pid) {
        // Update an existing process...
        st.added = false;
        st.working = false;
        curStatsIndex++;
        if (DEBUG)
          Slog.v(
              TAG,
              "Existing " + (parentPid < 0 ? "process" : "thread") + " pid " + pid + ": " + st);

        if (st.interesting) {
          final long uptime = SystemClock.uptimeMillis();

          final long[] procStats = mProcessStatsData;
          if (!Process.readProcFile(
              st.statFile.toString(), PROCESS_STATS_FORMAT, null, procStats, null)) {
            continue;
          }

          final long minfaults = procStats[PROCESS_STAT_MINOR_FAULTS];
          final long majfaults = procStats[PROCESS_STAT_MAJOR_FAULTS];
          final long utime = procStats[PROCESS_STAT_UTIME] * mJiffyMillis;
          final long stime = procStats[PROCESS_STAT_STIME] * mJiffyMillis;

          if (utime == st.base_utime && stime == st.base_stime) {
            st.rel_utime = 0;
            st.rel_stime = 0;
            st.rel_minfaults = 0;
            st.rel_majfaults = 0;
            if (st.active) {
              st.active = false;
            }
            continue;
          }

          if (!st.active) {
            st.active = true;
          }

          if (parentPid < 0) {
            getName(st, st.cmdlineFile);
            if (st.threadStats != null) {
              mCurThreadPids =
                  collectStats(st.threadsDir, pid, false, mCurThreadPids, st.threadStats);
            }
          }

          if (DEBUG)
            Slog.v(
                "Load",
                "Stats changed "
                    + st.name
                    + " pid="
                    + st.pid
                    + " utime="
                    + utime
                    + "-"
                    + st.base_utime
                    + " stime="
                    + stime
                    + "-"
                    + st.base_stime
                    + " minfaults="
                    + minfaults
                    + "-"
                    + st.base_minfaults
                    + " majfaults="
                    + majfaults
                    + "-"
                    + st.base_majfaults);

          st.rel_uptime = uptime - st.base_uptime;
          st.base_uptime = uptime;
          st.rel_utime = (int) (utime - st.base_utime);
          st.rel_stime = (int) (stime - st.base_stime);
          st.base_utime = utime;
          st.base_stime = stime;
          st.rel_minfaults = (int) (minfaults - st.base_minfaults);
          st.rel_majfaults = (int) (majfaults - st.base_majfaults);
          st.base_minfaults = minfaults;
          st.base_majfaults = majfaults;
          st.working = true;
        }

        continue;
      }

      if (st == null || st.pid > pid) {
        // We have a new process!
        st = new Stats(pid, parentPid, mIncludeThreads);
        allProcs.add(curStatsIndex, st);
        curStatsIndex++;
        NS++;
        if (DEBUG)
          Slog.v(TAG, "New " + (parentPid < 0 ? "process" : "thread") + " pid " + pid + ": " + st);

        final String[] procStatsString = mProcessFullStatsStringData;
        final long[] procStats = mProcessFullStatsData;
        st.base_uptime = SystemClock.uptimeMillis();
        String path = st.statFile.toString();
        // Slog.d(TAG, "Reading proc file: " + path);
        if (Process.readProcFile(
            path, PROCESS_FULL_STATS_FORMAT, procStatsString, procStats, null)) {
          // This is a possible way to filter out processes that
          // are actually kernel threads...  do we want to?  Some
          // of them do use CPU, but there can be a *lot* that are
          // not doing anything.
          st.vsize = procStats[PROCESS_FULL_STAT_VSIZE];
          if (true || procStats[PROCESS_FULL_STAT_VSIZE] != 0) {
            st.interesting = true;
            st.baseName = procStatsString[0];
            st.base_minfaults = procStats[PROCESS_FULL_STAT_MINOR_FAULTS];
            st.base_majfaults = procStats[PROCESS_FULL_STAT_MAJOR_FAULTS];
            st.base_utime = procStats[PROCESS_FULL_STAT_UTIME] * mJiffyMillis;
            st.base_stime = procStats[PROCESS_FULL_STAT_STIME] * mJiffyMillis;
          } else {
            Slog.i(TAG, "Skipping kernel process pid " + pid + " name " + procStatsString[0]);
            st.baseName = procStatsString[0];
          }
        } else {
          Slog.w(TAG, "Skipping unknown process pid " + pid);
          st.baseName = "<unknown>";
          st.base_utime = st.base_stime = 0;
          st.base_minfaults = st.base_majfaults = 0;
        }

        if (parentPid < 0) {
          getName(st, st.cmdlineFile);
          if (st.threadStats != null) {
            mCurThreadPids = collectStats(st.threadsDir, pid, true, mCurThreadPids, st.threadStats);
          }
        } else if (st.interesting) {
          st.name = st.baseName;
          st.nameWidth = onMeasureProcessName(st.name);
        }

        if (DEBUG)
          Slog.v(
              "Load",
              "Stats added "
                  + st.name
                  + " pid="
                  + st.pid
                  + " utime="
                  + st.base_utime
                  + " stime="
                  + st.base_stime
                  + " minfaults="
                  + st.base_minfaults
                  + " majfaults="
                  + st.base_majfaults);

        st.rel_utime = 0;
        st.rel_stime = 0;
        st.rel_minfaults = 0;
        st.rel_majfaults = 0;
        st.added = true;
        if (!first && st.interesting) {
          st.working = true;
        }
        continue;
      }

      // This process has gone away!
      st.rel_utime = 0;
      st.rel_stime = 0;
      st.rel_minfaults = 0;
      st.rel_majfaults = 0;
      st.removed = true;
      st.working = true;
      allProcs.remove(curStatsIndex);
      NS--;
      if (DEBUG)
        Slog.v(
            TAG, "Removed " + (parentPid < 0 ? "process" : "thread") + " pid " + pid + ": " + st);
      // Decrement the loop counter so that we process the current pid
      // again the next time through the loop.
      i--;
      continue;
    }

    while (curStatsIndex < NS) {
      // This process has gone away!
      final Stats st = allProcs.get(curStatsIndex);
      st.rel_utime = 0;
      st.rel_stime = 0;
      st.rel_minfaults = 0;
      st.rel_majfaults = 0;
      st.removed = true;
      st.working = true;
      allProcs.remove(curStatsIndex);
      NS--;
      if (localLOGV) Slog.v(TAG, "Removed pid " + st.pid + ": " + st);
    }

    return pids;
  }
  public void update() {
    if (DEBUG) Slog.v(TAG, "Update: " + this);

    final long nowUptime = SystemClock.uptimeMillis();
    final long nowRealtime = SystemClock.elapsedRealtime();
    final long nowWallTime = System.currentTimeMillis();

    final long[] sysCpu = mSystemCpuData;
    if (Process.readProcFile("/proc/stat", SYSTEM_CPU_FORMAT, null, sysCpu, null)) {
      // Total user time is user + nice time.
      final long usertime = (sysCpu[0] + sysCpu[1]) * mJiffyMillis;
      // Total system time is simply system time.
      final long systemtime = sysCpu[2] * mJiffyMillis;
      // Total idle time is simply idle time.
      final long idletime = sysCpu[3] * mJiffyMillis;
      // Total irq time is iowait + irq + softirq time.
      final long iowaittime = sysCpu[4] * mJiffyMillis;
      final long irqtime = sysCpu[5] * mJiffyMillis;
      final long softirqtime = sysCpu[6] * mJiffyMillis;

      // This code is trying to avoid issues with idle time going backwards,
      // but currently it gets into situations where it triggers most of the time. :(
      if (true
          || (usertime >= mBaseUserTime
              && systemtime >= mBaseSystemTime
              && iowaittime >= mBaseIoWaitTime
              && irqtime >= mBaseIrqTime
              && softirqtime >= mBaseSoftIrqTime
              && idletime >= mBaseIdleTime)) {
        mRelUserTime = (int) (usertime - mBaseUserTime);
        mRelSystemTime = (int) (systemtime - mBaseSystemTime);
        mRelIoWaitTime = (int) (iowaittime - mBaseIoWaitTime);
        mRelIrqTime = (int) (irqtime - mBaseIrqTime);
        mRelSoftIrqTime = (int) (softirqtime - mBaseSoftIrqTime);
        mRelIdleTime = (int) (idletime - mBaseIdleTime);
        mRelStatsAreGood = true;

        if (DEBUG) {
          Slog.i(
              "Load",
              "Total U:"
                  + (sysCpu[0] * mJiffyMillis)
                  + " N:"
                  + (sysCpu[1] * mJiffyMillis)
                  + " S:"
                  + (sysCpu[2] * mJiffyMillis)
                  + " I:"
                  + (sysCpu[3] * mJiffyMillis)
                  + " W:"
                  + (sysCpu[4] * mJiffyMillis)
                  + " Q:"
                  + (sysCpu[5] * mJiffyMillis)
                  + " O:"
                  + (sysCpu[6] * mJiffyMillis));
          Slog.i(
              "Load",
              "Rel U:"
                  + mRelUserTime
                  + " S:"
                  + mRelSystemTime
                  + " I:"
                  + mRelIdleTime
                  + " Q:"
                  + mRelIrqTime);
        }

        mBaseUserTime = usertime;
        mBaseSystemTime = systemtime;
        mBaseIoWaitTime = iowaittime;
        mBaseIrqTime = irqtime;
        mBaseSoftIrqTime = softirqtime;
        mBaseIdleTime = idletime;

      } else {
        mRelUserTime = 0;
        mRelSystemTime = 0;
        mRelIoWaitTime = 0;
        mRelIrqTime = 0;
        mRelSoftIrqTime = 0;
        mRelIdleTime = 0;
        mRelStatsAreGood = false;
        Slog.w(TAG, "/proc/stats has gone backwards; skipping CPU update");
        return;
      }
    }

    mLastSampleTime = mCurrentSampleTime;
    mCurrentSampleTime = nowUptime;
    mLastSampleRealTime = mCurrentSampleRealTime;
    mCurrentSampleRealTime = nowRealtime;
    mLastSampleWallTime = mCurrentSampleWallTime;
    mCurrentSampleWallTime = nowWallTime;

    final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads();
    try {
      mCurPids = collectStats("/proc", -1, mFirst, mCurPids, mProcStats);
    } finally {
      StrictMode.setThreadPolicy(savedPolicy);
    }

    final float[] loadAverages = mLoadAverageData;
    if (Process.readProcFile("/proc/loadavg", LOAD_AVERAGE_FORMAT, null, null, loadAverages)) {
      float load1 = loadAverages[0];
      float load5 = loadAverages[1];
      float load15 = loadAverages[2];
      if (load1 != mLoad1 || load5 != mLoad5 || load15 != mLoad15) {
        mLoad1 = load1;
        mLoad5 = load5;
        mLoad15 = load15;
        onLoadChanged(load1, load5, load15);
      }
    }

    if (DEBUG)
      Slog.i(
          TAG, "*** TIME TO COLLECT STATS: " + (SystemClock.uptimeMillis() - mCurrentSampleTime));

    mWorkingProcsSorted = false;
    mFirst = false;
  }