/** Called by the Binder stub. */
  void dump(String[] args, PrintWriter pw) {
    synchronized (mLock) {
      final long screenOnTime = getScreenOnTimeLocked(checkAndGetTimeLocked());
      IndentingPrintWriter idpw = new IndentingPrintWriter(pw, "  ");
      ArraySet<String> argSet = new ArraySet<>();
      argSet.addAll(Arrays.asList(args));

      final int userCount = mUserState.size();
      for (int i = 0; i < userCount; i++) {
        idpw.printPair("user", mUserState.keyAt(i));
        idpw.println();
        idpw.increaseIndent();
        if (argSet.contains("--checkin")) {
          mUserState.valueAt(i).checkin(idpw, screenOnTime);
        } else {
          mUserState.valueAt(i).dump(idpw, screenOnTime);
          idpw.println();
          if (args.length > 0 && "history".equals(args[0])) {
            mAppIdleHistory.dump(idpw, mUserState.keyAt(i));
          }
        }
        idpw.decreaseIndent();
      }
      pw.write("Screen On Timebase:" + mScreenOnTime + "\n");
    }
  }
  /** Check all running users' apps to see if they enter an idle state. */
  void checkIdleStates() {
    if (DEBUG) Slog.d(TAG, "Checking idle state");
    final int[] runningUsers;
    try {
      runningUsers = ActivityManagerNative.getDefault().getRunningUserIds();
    } catch (RemoteException re) {
      return;
    }

    for (int i = 0; i < runningUsers.length; i++) {
      final int userId = runningUsers[i];
      List<PackageInfo> packages =
          getContext()
              .getPackageManager()
              .getInstalledPackages(
                  PackageManager.GET_DISABLED_COMPONENTS | PackageManager.GET_UNINSTALLED_PACKAGES,
                  userId);
      synchronized (mLock) {
        final long timeNow = checkAndGetTimeLocked();
        final int packageCount = packages.size();
        for (int p = 0; p < packageCount; p++) {
          final String packageName = packages.get(p).packageName;
          final boolean isIdle = isAppIdleFiltered(packageName, userId);
          mHandler.sendMessage(
              mHandler.obtainMessage(MSG_INFORM_LISTENERS, userId, isIdle ? 1 : 0, packageName));
          mAppIdleHistory.addEntry(packageName, userId, isIdle, timeNow);
        }
      }
    }
    mHandler.sendEmptyMessageDelayed(MSG_CHECK_IDLE_STATES, mCheckIdleIntervalMillis);
  }
  /**
   * Forces the app's beginIdleTime to reflect idle or active. If idle, then it rolls back the
   * beginIdleTime to a point in time thats behind the threshold for idle.
   */
  void forceIdleState(String packageName, int userId, boolean idle) {
    synchronized (mLock) {
      final long timeNow = checkAndGetTimeLocked();
      final long screenOnTime = getScreenOnTimeLocked(timeNow);
      final long deviceUsageTime = screenOnTime - (idle ? mAppIdleDurationMillis : 0) - 5000;

      final UserUsageStatsService service = getUserDataAndInitializeIfNeededLocked(userId, timeNow);
      final long lastUsed = service.getBeginIdleTime(packageName);
      final boolean previouslyIdle = hasPassedIdleTimeout(lastUsed, getScreenOnTimeLocked(timeNow));
      service.setBeginIdleTime(packageName, deviceUsageTime);
      // Inform listeners if necessary
      if (previouslyIdle != idle) {
        // Slog.d(TAG, "Informing listeners of out-of-idle " + event.mPackage);
        mHandler.sendMessage(
            mHandler.obtainMessage(
                MSG_INFORM_LISTENERS, userId, /* idle = */ idle ? 1 : 0, packageName));
        mAppIdleHistory.addEntry(packageName, userId, idle, timeNow);
      }
    }
  }
  /** Called by the Binder stub. */
  void reportEvent(UsageEvents.Event event, int userId) {
    synchronized (mLock) {
      final long timeNow = checkAndGetTimeLocked();
      convertToSystemTimeLocked(event);

      final UserUsageStatsService service = getUserDataAndInitializeIfNeededLocked(userId, timeNow);
      final long lastUsed = service.getBeginIdleTime(event.mPackage);
      final long screenOnTime = getScreenOnTimeLocked(timeNow);
      final boolean previouslyIdle = hasPassedIdleTimeout(lastUsed, screenOnTime);
      service.reportEvent(event, screenOnTime);
      // Inform listeners if necessary
      if ((event.mEventType == Event.MOVE_TO_FOREGROUND
          || event.mEventType == Event.MOVE_TO_BACKGROUND
          || event.mEventType == Event.INTERACTION)) {
        if (previouslyIdle) {
          // Slog.d(TAG, "Informing listeners of out-of-idle " + event.mPackage);
          mHandler.sendMessage(
              mHandler.obtainMessage(MSG_INFORM_LISTENERS, userId, /* idle = */ 0, event.mPackage));
          mAppIdleHistory.addEntry(event.mPackage, userId, false, timeNow);
        }
      }
    }
  }