content: /*
   * Copyright (C) 2007 The Android Open Source Project
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package com.android.server.power;
  
  import static android.os.PowerManagerInternal.WAKEFULNESS_ASLEEP;
  import static android.os.PowerManagerInternal.WAKEFULNESS_AWAKE;
  import static android.os.PowerManagerInternal.WAKEFULNESS_DOZING;
  import static android.os.PowerManagerInternal.WAKEFULNESS_DREAMING;
  
  import android.annotation.IntDef;
  import android.annotation.NonNull;
  import android.annotation.UserIdInt;
  import android.app.ActivityManager;
  import android.app.SynchronousUserSwitchObserver;
  import android.content.BroadcastReceiver;
  import android.content.ContentResolver;
  import android.content.Context;
  import android.content.Intent;
  import android.content.IntentFilter;
  import android.content.pm.PackageManager;
  import android.content.res.Resources;
  import android.database.ContentObserver;
  import android.hardware.SensorManager;
  import android.hardware.SystemSensorManager;
  import android.hardware.display.AmbientDisplayConfiguration;
  import android.hardware.display.DisplayManagerInternal;
  import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest;
  import android.hardware.power.V1_0.PowerHint;
  import android.net.Uri;
  import android.os.BatteryManager;
  import android.os.BatteryManagerInternal;
  import android.os.BatterySaverPolicyConfig;
  import android.os.Binder;
  import android.os.Handler;
  import android.os.IBinder;
  import android.os.IPowerManager;
  import android.os.Looper;
  import android.os.Message;
  import android.os.PowerManager;
  import android.os.PowerManager.ServiceType;
  import android.os.PowerManager.WakeData;
  import android.os.PowerManager.WakeReason;
  import android.os.PowerManagerInternal;
  import android.os.PowerSaveState;
  import android.os.Process;
  import android.os.RemoteException;
  import android.os.ResultReceiver;
  import android.os.ShellCallback;
  import android.os.SystemClock;
  import android.os.SystemProperties;
  import android.os.Trace;
  import android.os.UserHandle;
  import android.os.UserManager;
  import android.os.WorkSource;
  import android.os.WorkSource.WorkChain;
  import android.provider.Settings;
  import android.provider.Settings.SettingNotFoundException;
  import android.service.dreams.DreamManagerInternal;
  import android.service.vr.IVrManager;
  import android.service.vr.IVrStateCallbacks;
  import android.util.KeyValueListParser;
  import android.util.PrintWriterPrinter;
  import android.util.Slog;
  import android.util.SparseArray;
  import android.util.TimeUtils;
  import android.util.proto.ProtoOutputStream;
  import android.view.Display;
  
  import com.android.internal.annotations.VisibleForTesting;
  import com.android.internal.app.IAppOpsService;
  import com.android.internal.app.IBatteryStats;
  import com.android.internal.os.BackgroundThread;
  import com.android.internal.util.DumpUtils;
  import com.android.server.EventLogTags;
  import com.android.server.LockGuard;
  import com.android.server.RescueParty;
  import com.android.server.ServiceThread;
  import com.android.server.SystemService;
  import com.android.server.UiThread;
  import com.android.server.Watchdog;
  import com.android.server.am.BatteryStatsService;
  import com.android.server.lights.Light;
  import com.android.server.lights.LightsManager;
  import com.android.server.policy.WindowManagerPolicy;
  import com.android.server.power.batterysaver.BatterySaverController;
  import com.android.server.power.batterysaver.BatterySaverPolicy;
  import com.android.server.power.batterysaver.BatterySaverStateMachine;
  import com.android.server.power.batterysaver.BatterySavingStats;
  
  import java.io.FileDescriptor;
  import java.io.PrintWriter;
  import java.lang.annotation.Retention;
  import java.lang.annotation.RetentionPolicy;
  import java.util.ArrayList;
  import java.util.Arrays;
  import java.util.Objects;
  
  /**
   * The power manager service is responsible for coordinating power management
   * functions on the device.
   */
  public final class PowerManagerService extends SystemService
          implements Watchdog.Monitor {
      private static final String TAG = "PowerManagerService";
  
      private static final boolean DEBUG = false;
      private static final boolean DEBUG_SPEW = DEBUG && true;
  
      // Message: Sent when a user activity timeout occurs to update the power state.
      private static final int MSG_USER_ACTIVITY_TIMEOUT = 1;
      // Message: Sent when the device enters or exits a dreaming or dozing state.
      private static final int MSG_SANDMAN = 2;
      // Message: Sent when the screen brightness boost expires.
      private static final int MSG_SCREEN_BRIGHTNESS_BOOST_TIMEOUT = 3;
      // Message: Polling to look for long held wake locks.
      private static final int MSG_CHECK_FOR_LONG_WAKELOCKS = 4;
  
      // Dirty bit: mWakeLocks changed
      private static final int DIRTY_WAKE_LOCKS = 1 << 0;
      // Dirty bit: mWakefulness changed
      private static final int DIRTY_WAKEFULNESS = 1 << 1;
      // Dirty bit: user activity was poked or may have timed out
      private static final int DIRTY_USER_ACTIVITY = 1 << 2;
      // Dirty bit: actual display power state was updated asynchronously
      private static final int DIRTY_ACTUAL_DISPLAY_POWER_STATE_UPDATED = 1 << 3;
      // Dirty bit: mBootCompleted changed
      private static final int DIRTY_BOOT_COMPLETED = 1 << 4;
      // Dirty bit: settings changed
      private static final int DIRTY_SETTINGS = 1 << 5;
      // Dirty bit: mIsPowered changed
      private static final int DIRTY_IS_POWERED = 1 << 6;
      // Dirty bit: mStayOn changed
      private static final int DIRTY_STAY_ON = 1 << 7;
      // Dirty bit: battery state changed
      private static final int DIRTY_BATTERY_STATE = 1 << 8;
      // Dirty bit: proximity state changed
      private static final int DIRTY_PROXIMITY_POSITIVE = 1 << 9;
      // Dirty bit: dock state changed
      private static final int DIRTY_DOCK_STATE = 1 << 10;
      // Dirty bit: brightness boost changed
      private static final int DIRTY_SCREEN_BRIGHTNESS_BOOST = 1 << 11;
      // Dirty bit: sQuiescent changed
      private static final int DIRTY_QUIESCENT = 1 << 12;
      // Dirty bit: VR Mode enabled changed
      private static final int DIRTY_VR_MODE_CHANGED = 1 << 13;
  
      // Summarizes the state of all active wakelocks.
      private static final int WAKE_LOCK_CPU = 1 << 0;
      private static final int WAKE_LOCK_SCREEN_BRIGHT = 1 << 1;
      private static final int WAKE_LOCK_SCREEN_DIM = 1 << 2;
      private static final int WAKE_LOCK_BUTTON_BRIGHT = 1 << 3;
      private static final int WAKE_LOCK_PROXIMITY_SCREEN_OFF = 1 << 4;
      private static final int WAKE_LOCK_STAY_AWAKE = 1 << 5; // only set if already awake
      private static final int WAKE_LOCK_DOZE = 1 << 6;
      private static final int WAKE_LOCK_DRAW = 1 << 7;
  
      // Summarizes the user activity state.
      private static final int USER_ACTIVITY_SCREEN_BRIGHT = 1 << 0;
      private static final int USER_ACTIVITY_SCREEN_DIM = 1 << 1;
      private static final int USER_ACTIVITY_SCREEN_DREAM = 1 << 2;
  
      // Default timeout in milliseconds.  This is only used until the settings
      // provider populates the actual default value (R.integer.def_screen_off_timeout).
      private static final int DEFAULT_SCREEN_OFF_TIMEOUT = 15 * 1000;
      private static final int DEFAULT_SLEEP_TIMEOUT = -1;
  
      // Screen brightness boost timeout.
      // Hardcoded for now until we decide what the right policy should be.
      // This should perhaps be a setting.
      private static final int SCREEN_BRIGHTNESS_BOOST_TIMEOUT = 5 * 1000;
  
      // How long a partial wake lock must be held until we consider it a long wake lock.
      static final long MIN_LONG_WAKE_CHECK_INTERVAL = 60*1000;
  
      // Power features defined in hardware/libhardware/include/hardware/power.h.
      private static final int POWER_FEATURE_DOUBLE_TAP_TO_WAKE = 1;
  
      // Default setting for double tap to wake.
      private static final int DEFAULT_DOUBLE_TAP_TO_WAKE = 0;
  
      // System property indicating that the screen should remain off until an explicit user action
      private static final String SYSTEM_PROPERTY_QUIESCENT = "ro.boot.quiescent";
  
      // System Property indicating that retail demo mode is currently enabled.
      private static final String SYSTEM_PROPERTY_RETAIL_DEMO_ENABLED = "sys.retaildemo.enabled";
  
      // Possible reasons for shutting down or reboot for use in REBOOT_PROPERTY(sys.boot.reason)
      // which is set by bootstat
      private static final String REASON_SHUTDOWN = "shutdown";
      private static final String REASON_REBOOT = "reboot";
      private static final String REASON_USERREQUESTED = "shutdown,userrequested";
      private static final String REASON_THERMAL_SHUTDOWN = "shutdown,thermal";
      private static final String REASON_LOW_BATTERY = "shutdown,battery";
      private static final String REASON_BATTERY_THERMAL_STATE = "shutdown,thermal,battery";
  
      private static final String TRACE_SCREEN_ON = "Screen turning on";
  
      /** If turning screen on takes more than this long, we show a warning on logcat. */
      private static final int SCREEN_ON_LATENCY_WARNING_MS = 200;
  
      /** Constants for {@link #shutdownOrRebootInternal} */
      @Retention(RetentionPolicy.SOURCE)
      @IntDef({HALT_MODE_SHUTDOWN, HALT_MODE_REBOOT, HALT_MODE_REBOOT_SAFE_MODE})
      public @interface HaltMode {}
      private static final int HALT_MODE_SHUTDOWN = 0;
      private static final int HALT_MODE_REBOOT = 1;
      private static final int HALT_MODE_REBOOT_SAFE_MODE = 2;
  
      // property for last reboot reason
      private static final String REBOOT_PROPERTY = "sys.boot.reason";
  
      private final Context mContext;
      private final ServiceThread mHandlerThread;
      private final PowerManagerHandler mHandler;
      private final AmbientDisplayConfiguration mAmbientDisplayConfiguration;
      private final BatterySaverPolicy mBatterySaverPolicy;
      private final BatterySaverController mBatterySaverController;
      private final BatterySaverStateMachine mBatterySaverStateMachine;
      private final BatterySavingStats mBatterySavingStats;
      private final AttentionDetector mAttentionDetector;
      private final BinderService mBinderService;
      private final LocalService mLocalService;
      private final NativeWrapper mNativeWrapper;
      private final Injector mInjector;
  
      private LightsManager mLightsManager;
      private BatteryManagerInternal mBatteryManagerInternal;
      private DisplayManagerInternal mDisplayManagerInternal;
      private IBatteryStats mBatteryStats;
      private IAppOpsService mAppOps;
      private WindowManagerPolicy mPolicy;
      private Notifier mNotifier;
      private WirelessChargerDetector mWirelessChargerDetector;
      private SettingsObserver mSettingsObserver;
      private DreamManagerInternal mDreamManager;
      private Light mAttentionLight;
  
      private final Object mLock = LockGuard.installNewLock(LockGuard.INDEX_POWER);
  
      // A bitfield that indicates what parts of the power state have
      // changed and need to be recalculated.
      private int mDirty;
  
      // Indicates whether the device is awake or asleep or somewhere in between.
      // This is distinct from the screen power state, which is managed separately.
      private int mWakefulness;
      private boolean mWakefulnessChanging;
  
      // True if the sandman has just been summoned for the first time since entering the
      // dreaming or dozing state.  Indicates whether a new dream should begin.
      private boolean mSandmanSummoned;
  
      // True if MSG_SANDMAN has been scheduled.
      private boolean mSandmanScheduled;
  
      // Table of all suspend blockers.
      // There should only be a few of these.
      private final ArrayList<SuspendBlocker> mSuspendBlockers = new ArrayList<SuspendBlocker>();
  
      // Table of all wake locks acquired by applications.
      private final ArrayList<WakeLock> mWakeLocks = new ArrayList<WakeLock>();
  
      // A bitfield that summarizes the state of all active wakelocks.
      private int mWakeLockSummary;
  
      // Have we scheduled a message to check for long wake locks?  This is when we will check.
      private long mNotifyLongScheduled;
  
      // Last time we checked for long wake locks.
      private long mNotifyLongDispatched;
  
      // The time we decided to do next long check.
      private long mNotifyLongNextCheck;
  
      // If true, instructs the display controller to wait for the proximity sensor to
      // go negative before turning the screen on.
      private boolean mRequestWaitForNegativeProximity;
  
      // Timestamp of the last time the device was awoken or put to sleep.
      private long mLastWakeTime;
      private long mLastSleepTime;
  
      // Last reason the device went to sleep.
      private @WakeReason int mLastWakeReason;
      private int mLastSleepReason;
  
      // Timestamp of the last call to user activity.
      private long mLastUserActivityTime;
      private long mLastUserActivityTimeNoChangeLights;
  
      // Timestamp of last interactive power hint.
      private long mLastInteractivePowerHintTime;
  
      // Timestamp of the last screen brightness boost.
      private long mLastScreenBrightnessBoostTime;
      private boolean mScreenBrightnessBoostInProgress;
  
      // A bitfield that summarizes the effect of the user activity timer.
      private int mUserActivitySummary;
  
      // The desired display power state.  The actual state may lag behind the
      // requested because it is updated asynchronously by the display power controller.
      private final DisplayPowerRequest mDisplayPowerRequest = new DisplayPowerRequest();
  
      // True if the display power state has been fully applied, which means the display
      // is actually on or actually off or whatever was requested.
      private boolean mDisplayReady;
  
      // The suspend blocker used to keep the CPU alive when an application has acquired
      // a wake lock.
      private final SuspendBlocker mWakeLockSuspendBlocker;
  
      // True if the wake lock suspend blocker has been acquired.
      private boolean mHoldingWakeLockSuspendBlocker;
  
      // The suspend blocker used to keep the CPU alive when the display is on, the
      // display is getting ready or there is user activity (in which case the display
      // must be on).
      private final SuspendBlocker mDisplaySuspendBlocker;
  
      // True if the display suspend blocker has been acquired.
      private boolean mHoldingDisplaySuspendBlocker;
  
      // True if systemReady() has been called.
      private boolean mSystemReady;
  
      // True if boot completed occurred.  We keep the screen on until this happens.
      private boolean mBootCompleted;
  
      // True if auto-suspend mode is enabled.
      // Refer to autosuspend.h.
      private boolean mHalAutoSuspendModeEnabled;
  
      // True if interactive mode is enabled.
      // Refer to power.h.
      private boolean mHalInteractiveModeEnabled;
  
      // True if the device is plugged into a power source.
      private boolean mIsPowered;
  
      // The current plug type, such as BatteryManager.BATTERY_PLUGGED_WIRELESS.
      private int mPlugType;
  
      // The current battery level percentage.
      private int mBatteryLevel;
  
      // The battery level percentage at the time the dream started.
      // This is used to terminate a dream and go to sleep if the battery is
      // draining faster than it is charging and the user activity timeout has expired.
      private int mBatteryLevelWhenDreamStarted;
  
      // The current dock state.
      private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
  
      // True to decouple auto-suspend mode from the display state.
      private boolean mDecoupleHalAutoSuspendModeFromDisplayConfig;
  
      // True to decouple interactive mode from the display state.
      private boolean mDecoupleHalInteractiveModeFromDisplayConfig;
  
      // True if the device should wake up when plugged or unplugged.
      private boolean mWakeUpWhenPluggedOrUnpluggedConfig;
  
      // True if the device should wake up when plugged or unplugged in theater mode.
      private boolean mWakeUpWhenPluggedOrUnpluggedInTheaterModeConfig;
  
      // True if the device should suspend when the screen is off due to proximity.
      private boolean mSuspendWhenScreenOffDueToProximityConfig;
  
      // True if dreams are supported on this device.
      private boolean mDreamsSupportedConfig;
  
      // Default value for dreams enabled
      private boolean mDreamsEnabledByDefaultConfig;
  
      // Default value for dreams activate-on-sleep
      private boolean mDreamsActivatedOnSleepByDefaultConfig;
  
      // Default value for dreams activate-on-dock
      private boolean mDreamsActivatedOnDockByDefaultConfig;
  
      // True if dreams can run while not plugged in.
      private boolean mDreamsEnabledOnBatteryConfig;
  
      // Minimum battery level to allow dreaming when powered.
      // Use -1 to disable this safety feature.
      private int mDreamsBatteryLevelMinimumWhenPoweredConfig;
  
      // Minimum battery level to allow dreaming when not powered.
      // Use -1 to disable this safety feature.
      private int mDreamsBatteryLevelMinimumWhenNotPoweredConfig;
  
      // If the battery level drops by this percentage and the user activity timeout
      // has expired, then assume the device is receiving insufficient current to charge
      // effectively and terminate the dream.  Use -1 to disable this safety feature.
      private int mDreamsBatteryLevelDrainCutoffConfig;
  
      // True if dreams are enabled by the user.
      private boolean mDreamsEnabledSetting;
  
      // True if dreams should be activated on sleep.
      private boolean mDreamsActivateOnSleepSetting;
  
      // True if dreams should be activated on dock.
      private boolean mDreamsActivateOnDockSetting;
  
      // True if doze should not be started until after the screen off transition.
      private boolean mDozeAfterScreenOff;
  
      private boolean mEnableAutoSuspendConfig;
  
      // The minimum screen off timeout, in milliseconds.
      private long mMinimumScreenOffTimeoutConfig;
  
      // The screen dim duration, in milliseconds.
      // This is subtracted from the end of the screen off timeout so the
      // minimum screen off timeout should be longer than this.
      private long mMaximumScreenDimDurationConfig;
  
      // The maximum screen dim time expressed as a ratio relative to the screen
      // off timeout.  If the screen off timeout is very short then we want the
      // dim timeout to also be quite short so that most of the time is spent on.
      // Otherwise the user won't get much screen on time before dimming occurs.
      private float mMaximumScreenDimRatioConfig;
  
      // Whether device supports double tap to wake.
      private boolean mSupportsDoubleTapWakeConfig;
  
      // The screen off timeout setting value in milliseconds.
      private long mScreenOffTimeoutSetting;
  
      // The sleep timeout setting value in milliseconds.
      private long mSleepTimeoutSetting;
  
      // The maximum allowable screen off timeout according to the device
      // administration policy.  Overrides other settings.
      private long mMaximumScreenOffTimeoutFromDeviceAdmin = Long.MAX_VALUE;
  
      // The stay on while plugged in setting.
      // A bitfield of battery conditions under which to make the screen stay on.
      private int mStayOnWhilePluggedInSetting;
  
      // True if the device should stay on.
      private boolean mStayOn;
  
      // True if the lights should stay off until an explicit user action.
      private static boolean sQuiescent;
  
      // True if the proximity sensor reads a positive result.
      private boolean mProximityPositive;
  
      // Screen brightness setting limits.
      private int mScreenBrightnessSettingMinimum;
      private int mScreenBrightnessSettingMaximum;
      private int mScreenBrightnessSettingDefault;
  
      // The screen brightness setting, from 0 to 255.
      // Use -1 if no value has been set.
      private int mScreenBrightnessSetting;
  
      // The screen brightness mode.
      // One of the Settings.System.SCREEN_BRIGHTNESS_MODE_* constants.
      private int mScreenBrightnessModeSetting;
  
      // The screen brightness setting override from the window manager
      // to allow the current foreground activity to override the brightness.
      // Use -1 to disable.
      private int mScreenBrightnessOverrideFromWindowManager = -1;
  
      // The window manager has determined the user to be inactive via other means.
      // Set this to false to disable.
      private boolean mUserInactiveOverrideFromWindowManager;
  
      // The next possible user activity timeout after being explicitly told the user is inactive.
      // Set to -1 when not told the user is inactive since the last period spent dozing or asleep.
      private long mOverriddenTimeout = -1;
  
      // The user activity timeout override from the window manager
      // to allow the current foreground activity to override the user activity timeout.
      // Use -1 to disable.
      private long mUserActivityTimeoutOverrideFromWindowManager = -1;
  
      // The screen state to use while dozing.
      private int mDozeScreenStateOverrideFromDreamManager = Display.STATE_UNKNOWN;
  
      // The screen brightness to use while dozing.
      private int mDozeScreenBrightnessOverrideFromDreamManager = PowerManager.BRIGHTNESS_DEFAULT;
  
      // Keep display state when dozing.
      private boolean mDrawWakeLockOverrideFromSidekick;
  
      // Time when we last logged a warning about calling userActivity() without permission.
      private long mLastWarningAboutUserActivityPermission = Long.MIN_VALUE;
  
      // True if the battery level is currently considered low.
      private boolean mBatteryLevelLow;
  
      // True if we are currently in device idle mode.
      private boolean mDeviceIdleMode;
  
      // True if we are currently in light device idle mode.
      private boolean mLightDeviceIdleMode;
  
      // Set of app ids that we will always respect the wake locks for.
      int[] mDeviceIdleWhitelist = new int[0];
  
      // Set of app ids that are temporarily allowed to acquire wakelocks due to high-pri message
      int[] mDeviceIdleTempWhitelist = new int[0];
  
      private final SparseArray<UidState> mUidState = new SparseArray<>();
  
      // We are currently in the middle of a batch change of uids.
      private boolean mUidsChanging;
  
      // Some uids have actually changed while mUidsChanging was true.
      private boolean mUidsChanged;
  
      // True if theater mode is enabled
      private boolean mTheaterModeEnabled;
  
      // True if always on display is enabled
      private boolean mAlwaysOnEnabled;
  
      // True if double tap to wake is enabled
      private boolean mDoubleTapWakeEnabled;
  
      // True if we are currently in VR Mode.
      private boolean mIsVrModeEnabled;
  
      // True if we in the process of performing a forceSuspend
      private boolean mForceSuspendActive;
  
      // Transition to Doze is in progress.  We have transitioned to WAKEFULNESS_DOZING,
      // but the DreamService has not yet been told to start (it's an async process).
      private boolean mDozeStartInProgress;
  
      private final class ForegroundProfileObserver extends SynchronousUserSwitchObserver {
          @Override
          public void onUserSwitching(int newUserId) throws RemoteException {}
  
          @Override
          public void onForegroundProfileSwitch(@UserIdInt int newProfileId) throws RemoteException {
              final long now = SystemClock.uptimeMillis();
              synchronized(mLock) {
                  mForegroundProfile = newProfileId;
                  maybeUpdateForegroundProfileLastActivityLocked(now);
              }
          }
      }
  
      // User id corresponding to activity the user is currently interacting with.
      private @UserIdInt int mForegroundProfile;
  
      // Per-profile state to track when a profile should be locked.
      private final SparseArray<ProfilePowerState> mProfilePowerState = new SparseArray<>();
  
      private static final class ProfilePowerState {
          // Profile user id.
          final @UserIdInt int mUserId;
          // Maximum time to lock set by admin.
          long mScreenOffTimeout;
          // Like top-level mWakeLockSummary, but only for wake locks that affect current profile.
          int mWakeLockSummary;
          // Last user activity that happened in an app running in the profile.
          long mLastUserActivityTime;
          // Whether profile has been locked last time it timed out.
          boolean mLockingNotified;
  
          public ProfilePowerState(@UserIdInt int userId, long screenOffTimeout) {
              mUserId = userId;
              mScreenOffTimeout = screenOffTimeout;
              // Not accurate but at least won't cause immediate locking of the profile.
              mLastUserActivityTime = SystemClock.uptimeMillis();
          }
      }
  
      /**
       * All times are in milliseconds. These constants are kept synchronized with the system
       * global Settings. Any access to this class or its fields should be done while
       * holding the PowerManagerService.mLock lock.
       */
      private final class Constants extends ContentObserver {
          // Key names stored in the settings value.
          private static final String KEY_NO_CACHED_WAKE_LOCKS = "no_cached_wake_locks";
  
          private static final boolean DEFAULT_NO_CACHED_WAKE_LOCKS = true;
  
          // Prevent processes that are cached from holding wake locks?
          public boolean NO_CACHED_WAKE_LOCKS = DEFAULT_NO_CACHED_WAKE_LOCKS;
  
          private ContentResolver mResolver;
          private final KeyValueListParser mParser = new KeyValueListParser(',');
  
          public Constants(Handler handler) {
              super(handler);
          }
  
          public void start(ContentResolver resolver) {
              mResolver = resolver;
              mResolver.registerContentObserver(Settings.Global.getUriFor(
                      Settings.Global.POWER_MANAGER_CONSTANTS), false, this);
              updateConstants();
          }
  
          @Override
          public void onChange(boolean selfChange, Uri uri) {
              updateConstants();
          }
  
          private void updateConstants() {
              synchronized (mLock) {
                  try {
                      mParser.setString(Settings.Global.getString(mResolver,
                              Settings.Global.POWER_MANAGER_CONSTANTS));
                  } catch (IllegalArgumentException e) {
                      // Failed to parse the settings string, log this and move on
                      // with defaults.
                      Slog.e(TAG, "Bad alarm manager settings", e);
                  }
  
                  NO_CACHED_WAKE_LOCKS = mParser.getBoolean(KEY_NO_CACHED_WAKE_LOCKS,
                          DEFAULT_NO_CACHED_WAKE_LOCKS);
              }
          }
  
          void dump(PrintWriter pw) {
              pw.println("  Settings " + Settings.Global.POWER_MANAGER_CONSTANTS + ":");
  
              pw.print("    "); pw.print(KEY_NO_CACHED_WAKE_LOCKS); pw.print("=");
              pw.println(NO_CACHED_WAKE_LOCKS);
          }
  
          void dumpProto(ProtoOutputStream proto) {
              final long constantsToken = proto.start(PowerManagerServiceDumpProto.CONSTANTS);
              proto.write(PowerManagerServiceDumpProto.ConstantsProto.IS_NO_CACHED_WAKE_LOCKS,
                      NO_CACHED_WAKE_LOCKS);
              proto.end(constantsToken);
          }
      }
  
      /**
       * Wrapper around the static-native methods of PowerManagerService.
       *
       * This class exists to allow us to mock static native methods in our tests. If mocking static
       * methods becomes easier than this in the future, we can delete this class.
       */
      @VisibleForTesting
      public static class NativeWrapper {
          /** Wrapper for PowerManager.nativeInit */
          public void nativeInit(PowerManagerService service) {
              service.nativeInit();
          }
  
          /** Wrapper for PowerManager.nativeAcquireSuspectBlocker */
          public void nativeAcquireSuspendBlocker(String name) {
              PowerManagerService.nativeAcquireSuspendBlocker(name);
          }
  
          /** Wrapper for PowerManager.nativeReleaseSuspendBlocker */
          public void nativeReleaseSuspendBlocker(String name) {
              PowerManagerService.nativeReleaseSuspendBlocker(name);
          }
  
          /** Wrapper for PowerManager.nativeSetInteractive */
          public void nativeSetInteractive(boolean enable) {
              PowerManagerService.nativeSetInteractive(enable);
          }
  
          /** Wrapper for PowerManager.nativeSetAutoSuspend */
          public void nativeSetAutoSuspend(boolean enable) {
              PowerManagerService.nativeSetAutoSuspend(enable);
          }
  
          /** Wrapper for PowerManager.nativeSendPowerHint */
          public void nativeSendPowerHint(int hintId, int data) {
              PowerManagerService.nativeSendPowerHint(hintId, data);
          }
  
          /** Wrapper for PowerManager.nativeSetFeature */
          public void nativeSetFeature(int featureId, int data) {
              PowerManagerService.nativeSetFeature(featureId, data);
          }
  
          /** Wrapper for PowerManager.nativeForceSuspend */
          public boolean nativeForceSuspend() {
              return PowerManagerService.nativeForceSuspend();
          }
      }
  
      @VisibleForTesting
      static class Injector {
          Notifier createNotifier(Looper looper, Context context, IBatteryStats batteryStats,
                  SuspendBlocker suspendBlocker, WindowManagerPolicy policy) {
              return new Notifier(looper, context, batteryStats, suspendBlocker, policy);
          }
  
          SuspendBlocker createSuspendBlocker(PowerManagerService service, String name) {
              SuspendBlocker suspendBlocker = service.new SuspendBlockerImpl(name);
              service.mSuspendBlockers.add(suspendBlocker);
              return suspendBlocker;
          }
  
          BatterySaverPolicy createBatterySaverPolicy(
                  Object lock, Context context, BatterySavingStats batterySavingStats) {
              return new BatterySaverPolicy(lock, context, batterySavingStats);
          }
  
          NativeWrapper createNativeWrapper() {
              return new NativeWrapper();
          }
  
          WirelessChargerDetector createWirelessChargerDetector(
                  SensorManager sensorManager, SuspendBlocker suspendBlocker, Handler handler) {
              return new WirelessChargerDetector(sensorManager, suspendBlocker, handler);
          }
  
          AmbientDisplayConfiguration createAmbientDisplayConfiguration(Context context) {
              return new AmbientDisplayConfiguration(context);
          }
      }
  
      final Constants mConstants;
  
      private native void nativeInit();
      private static native void nativeAcquireSuspendBlocker(String name);
      private static native void nativeReleaseSuspendBlocker(String name);
      private static native void nativeSetInteractive(boolean enable);
      private static native void nativeSetAutoSuspend(boolean enable);
      private static native void nativeSendPowerHint(int hintId, int data);
      private static native void nativeSetFeature(int featureId, int data);
      private static native boolean nativeForceSuspend();
  
      public PowerManagerService(Context context) {
          this(context, new Injector());
      }
  
      @VisibleForTesting
      PowerManagerService(Context context, Injector injector) {
          super(context);
  
          mContext = context;
          mBinderService = new BinderService();
          mLocalService = new LocalService();
          mNativeWrapper = injector.createNativeWrapper();
          mInjector = injector;
  
          mHandlerThread = new ServiceThread(TAG,
                  Process.THREAD_PRIORITY_DISPLAY, false /*allowIo*/);
          mHandlerThread.start();
          mHandler = new PowerManagerHandler(mHandlerThread.getLooper());
          mConstants = new Constants(mHandler);
          mAmbientDisplayConfiguration = mInjector.createAmbientDisplayConfiguration(context);
          mAttentionDetector = new AttentionDetector(this::onUserAttention, mLock);
  
          mBatterySavingStats = new BatterySavingStats(mLock);
          mBatterySaverPolicy =
                  mInjector.createBatterySaverPolicy(mLock, mContext, mBatterySavingStats);
          mBatterySaverController = new BatterySaverController(mLock, mContext,
                  BackgroundThread.get().getLooper(), mBatterySaverPolicy,
                  mBatterySavingStats);
          mBatterySaverStateMachine = new BatterySaverStateMachine(
                  mLock, mContext, mBatterySaverController);
  
          synchronized (mLock) {
              mWakeLockSuspendBlocker =
                      mInjector.createSuspendBlocker(this, "PowerManagerService.WakeLocks");
              mDisplaySuspendBlocker =
                      mInjector.createSuspendBlocker(this, "PowerManagerService.Display");
              if (mDisplaySuspendBlocker != null) {
                  mDisplaySuspendBlocker.acquire();
                  mHoldingDisplaySuspendBlocker = true;
              }
              mHalAutoSuspendModeEnabled = false;
              mHalInteractiveModeEnabled = true;
  
              mWakefulness = WAKEFULNESS_AWAKE;
              sQuiescent = SystemProperties.get(SYSTEM_PROPERTY_QUIESCENT, "0").equals("1");
  
              mNativeWrapper.nativeInit(this);
              mNativeWrapper.nativeSetAutoSuspend(false);
              mNativeWrapper.nativeSetInteractive(true);
              mNativeWrapper.nativeSetFeature(POWER_FEATURE_DOUBLE_TAP_TO_WAKE, 0);
          }
      }
  
      @Override
      public void onStart() {
          publishBinderService(Context.POWER_SERVICE, mBinderService);
          publishLocalService(PowerManagerInternal.class, mLocalService);
  
          Watchdog.getInstance().addMonitor(this);
          Watchdog.getInstance().addThread(mHandler);
      }
  
      @Override
      public void onBootPhase(int phase) {
          synchronized (mLock) {
              if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
                  incrementBootCount();
  
              } else if (phase == PHASE_BOOT_COMPLETED) {
                  final long now = SystemClock.uptimeMillis();
                  mBootCompleted = true;
                  mDirty |= DIRTY_BOOT_COMPLETED;
  
                  mBatterySaverStateMachine.onBootCompleted();
                  userActivityNoUpdateLocked(
                          now, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, Process.SYSTEM_UID);
                  updatePowerStateLocked();
              }
          }
      }
  
      public void systemReady(IAppOpsService appOps) {
          synchronized (mLock) {
              mSystemReady = true;
              mAppOps = appOps;
              mDreamManager = getLocalService(DreamManagerInternal.class);
              mDisplayManagerInternal = getLocalService(DisplayManagerInternal.class);
              mPolicy = getLocalService(WindowManagerPolicy.class);
              mBatteryManagerInternal = getLocalService(BatteryManagerInternal.class);
              mAttentionDetector.systemReady(mContext);
  
              PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
              mScreenBrightnessSettingMinimum = pm.getMinimumScreenBrightnessSetting();
              mScreenBrightnessSettingMaximum = pm.getMaximumScreenBrightnessSetting();
              mScreenBrightnessSettingDefault = pm.getDefaultScreenBrightnessSetting();
  
              SensorManager sensorManager = new SystemSensorManager(mContext, mHandler.getLooper());
  
              // The notifier runs on the system server's main looper so as not to interfere
              // with the animations and other critical functions of the power manager.
              mBatteryStats = BatteryStatsService.getService();
              mNotifier = mInjector.createNotifier(Looper.getMainLooper(), mContext, mBatteryStats,
                      mInjector.createSuspendBlocker(this, "PowerManagerService.Broadcasts"),
                      mPolicy);
  
              mWirelessChargerDetector = mInjector.createWirelessChargerDetector(sensorManager,
                      mInjector.createSuspendBlocker(
                              this, "PowerManagerService.WirelessChargerDetector"),
                      mHandler);
              mSettingsObserver = new SettingsObserver(mHandler);
  
              mLightsManager = getLocalService(LightsManager.class);
              mAttentionLight = mLightsManager.getLight(LightsManager.LIGHT_ID_ATTENTION);
  
              // Initialize display power management.
              mDisplayManagerInternal.initPowerManagement(
                      mDisplayPowerCallbacks, mHandler, sensorManager);
  
              try {
                  final ForegroundProfileObserver observer = new ForegroundProfileObserver();
                  ActivityManager.getService().registerUserSwitchObserver(observer, TAG);
              } catch (RemoteException e) {
                  // Shouldn't happen since in-process.
              }
  
              // Go.
              readConfigurationLocked();
              updateSettingsLocked();
              mDirty |= DIRTY_BATTERY_STATE;
              updatePowerStateLocked();
          }
  
          final ContentResolver resolver = mContext.getContentResolver();
          mConstants.start(resolver);
  
          mBatterySaverController.systemReady();
          mBatterySaverPolicy.systemReady();
  
          // Register for settings changes.
          resolver.registerContentObserver(Settings.Secure.getUriFor(
                  Settings.Secure.SCREENSAVER_ENABLED),
                  false, mSettingsObserver, UserHandle.USER_ALL);
          resolver.registerContentObserver(Settings.Secure.getUriFor(
                  Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP),
                  false, mSettingsObserver, UserHandle.USER_ALL);
          resolver.registerContentObserver(Settings.Secure.getUriFor(
                  Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK),
                  false, mSettingsObserver, UserHandle.USER_ALL);
          resolver.registerContentObserver(Settings.System.getUriFor(
                  Settings.System.SCREEN_OFF_TIMEOUT),
                  false, mSettingsObserver, UserHandle.USER_ALL);
          resolver.registerContentObserver(Settings.Secure.getUriFor(
                  Settings.Secure.SLEEP_TIMEOUT),
                  false, mSettingsObserver, UserHandle.USER_ALL);
          resolver.registerContentObserver(Settings.Global.getUriFor(
                  Settings.Global.STAY_ON_WHILE_PLUGGED_IN),
                  false, mSettingsObserver, UserHandle.USER_ALL);
          resolver.registerContentObserver(Settings.System.getUriFor(
                  Settings.System.SCREEN_BRIGHTNESS_MODE),
                  false, mSettingsObserver, UserHandle.USER_ALL);
          resolver.registerContentObserver(Settings.System.getUriFor(
                  Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ),
                  false, mSettingsObserver, UserHandle.USER_ALL);
          resolver.registerContentObserver(Settings.Global.getUriFor(
                  Settings.Global.THEATER_MODE_ON),
                  false, mSettingsObserver, UserHandle.USER_ALL);
          resolver.registerContentObserver(Settings.Secure.getUriFor(
                  Settings.Secure.DOZE_ALWAYS_ON),
                  false, mSettingsObserver, UserHandle.USER_ALL);
          resolver.registerContentObserver(Settings.Secure.getUriFor(
                  Settings.Secure.DOUBLE_TAP_TO_WAKE),
                  false, mSettingsObserver, UserHandle.USER_ALL);
          resolver.registerContentObserver(Settings.Global.getUriFor(
                  Settings.Global.DEVICE_DEMO_MODE),
                  false, mSettingsObserver, UserHandle.USER_SYSTEM);
          IVrManager vrManager = IVrManager.Stub.asInterface(getBinderService(Context.VR_SERVICE));
          if (vrManager != null) {
              try {
                  vrManager.registerListener(mVrStateCallbacks);
              } catch (RemoteException e) {
                  Slog.e(TAG, "Failed to register VR mode state listener: " + e);
              }
          }
  
          // Register for broadcasts from other components of the system.
          IntentFilter filter = new IntentFilter();
          filter.addAction(Intent.ACTION_BATTERY_CHANGED);
          filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
          mContext.registerReceiver(new BatteryReceiver(), filter, null, mHandler);
  
          filter = new IntentFilter();
          filter.addAction(Intent.ACTION_DREAMING_STARTED);
          filter.addAction(Intent.ACTION_DREAMING_STOPPED);
          mContext.registerReceiver(new DreamReceiver(), filter, null, mHandler);
  
          filter = new IntentFilter();
          filter.addAction(Intent.ACTION_USER_SWITCHED);
          mContext.registerReceiver(new UserSwitchedReceiver(), filter, null, mHandler);
  
          filter = new IntentFilter();
          filter.addAction(Intent.ACTION_DOCK_EVENT);
          mContext.registerReceiver(new DockReceiver(), filter, null, mHandler);
      }
  
      @VisibleForTesting
      void readConfigurationLocked() {
          final Resources resources = mContext.getResources();
  
          mDecoupleHalAutoSuspendModeFromDisplayConfig = resources.getBoolean(
                  com.android.internal.R.bool.config_powerDecoupleAutoSuspendModeFromDisplay);
          mDecoupleHalInteractiveModeFromDisplayConfig = resources.getBoolean(
                  com.android.internal.R.bool.config_powerDecoupleInteractiveModeFromDisplay);
          mEnableAutoSuspendConfig = resources.getBoolean(
                  com.android.internal.R.bool.config_enableAutoSuspend);
          mWakeUpWhenPluggedOrUnpluggedConfig = resources.getBoolean(
                  com.android.internal.R.bool.config_unplugTurnsOnScreen);
          mWakeUpWhenPluggedOrUnpluggedInTheaterModeConfig = resources.getBoolean(
                  com.android.internal.R.bool.config_allowTheaterModeWakeFromUnplug);
          mSuspendWhenScreenOffDueToProximityConfig = resources.getBoolean(
                  com.android.internal.R.bool.config_suspendWhenScreenOffDueToProximity);
          mDreamsSupportedConfig = resources.getBoolean(
                  com.android.internal.R.bool.config_dreamsSupported);
          mDreamsEnabledByDefaultConfig = resources.getBoolean(
                  com.android.internal.R.bool.config_dreamsEnabledByDefault);
          mDreamsActivatedOnSleepByDefaultConfig = resources.getBoolean(
                  com.android.internal.R.bool.config_dreamsActivatedOnSleepByDefault);
          mDreamsActivatedOnDockByDefaultConfig = resources.getBoolean(
                  com.android.internal.R.bool.config_dreamsActivatedOnDockByDefault);
          mDreamsEnabledOnBatteryConfig = resources.getBoolean(
                  com.android.internal.R.bool.config_dreamsEnabledOnBattery);
          mDreamsBatteryLevelMinimumWhenPoweredConfig = resources.getInteger(
                  com.android.internal.R.integer.config_dreamsBatteryLevelMinimumWhenPowered);
          mDreamsBatteryLevelMinimumWhenNotPoweredConfig = resources.getInteger(
                  com.android.internal.R.integer.config_dreamsBatteryLevelMinimumWhenNotPowered);
          mDreamsBatteryLevelDrainCutoffConfig = resources.getInteger(
                  com.android.internal.R.integer.config_dreamsBatteryLevelDrainCutoff);
          mDozeAfterScreenOff = resources.getBoolean(
                  com.android.internal.R.bool.config_dozeAfterScreenOffByDefault);
          mMinimumScreenOffTimeoutConfig = resources.getInteger(
                  com.android.internal.R.integer.config_minimumScreenOffTimeout);
          mMaximumScreenDimDurationConfig = resources.getInteger(
                  com.android.internal.R.integer.config_maximumScreenDimDuration);
          mMaximumScreenDimRatioConfig = resources.getFraction(
                  com.android.internal.R.fraction.config_maximumScreenDimRatio, 1, 1);
          mSupportsDoubleTapWakeConfig = resources.getBoolean(
                  com.android.internal.R.bool.config_supportDoubleTapWake);
      }
  
      private void updateSettingsLocked() {
          final ContentResolver resolver = mContext.getContentResolver();
  
          mDreamsEnabledSetting = (Settings.Secure.getIntForUser(resolver,
                  Settings.Secure.SCREENSAVER_ENABLED,
                  mDreamsEnabledByDefaultConfig ? 1 : 0,
                  UserHandle.USER_CURRENT) != 0);
          mDreamsActivateOnSleepSetting = (Settings.Secure.getIntForUser(resolver,
                  Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP,
                  mDreamsActivatedOnSleepByDefaultConfig ? 1 : 0,
                  UserHandle.USER_CURRENT) != 0);
          mDreamsActivateOnDockSetting = (Settings.Secure.getIntForUser(resolver,
                  Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK,
                  mDreamsActivatedOnDockByDefaultConfig ? 1 : 0,
                  UserHandle.USER_CURRENT) != 0);
          mScreenOffTimeoutSetting = Settings.System.getIntForUser(resolver,
                  Settings.System.SCREEN_OFF_TIMEOUT, DEFAULT_SCREEN_OFF_TIMEOUT,
                  UserHandle.USER_CURRENT);
          mSleepTimeoutSetting = Settings.Secure.getIntForUser(resolver,
                  Settings.Secure.SLEEP_TIMEOUT, DEFAULT_SLEEP_TIMEOUT,
                  UserHandle.USER_CURRENT);
          mStayOnWhilePluggedInSetting = Settings.Global.getInt(resolver,
                  Settings.Global.STAY_ON_WHILE_PLUGGED_IN, BatteryManager.BATTERY_PLUGGED_AC);
          mTheaterModeEnabled = Settings.Global.getInt(mContext.getContentResolver(),
                  Settings.Global.THEATER_MODE_ON, 0) == 1;
          mAlwaysOnEnabled = mAmbientDisplayConfiguration.alwaysOnEnabled(UserHandle.USER_CURRENT);
  
          if (mSupportsDoubleTapWakeConfig) {
              boolean doubleTapWakeEnabled = Settings.Secure.getIntForUser(resolver,
                      Settings.Secure.DOUBLE_TAP_TO_WAKE, DEFAULT_DOUBLE_TAP_TO_WAKE,
                              UserHandle.USER_CURRENT) != 0;
              if (doubleTapWakeEnabled != mDoubleTapWakeEnabled) {
                  mDoubleTapWakeEnabled = doubleTapWakeEnabled;
                  mNativeWrapper.nativeSetFeature(
                          POWER_FEATURE_DOUBLE_TAP_TO_WAKE, mDoubleTapWakeEnabled ? 1 : 0);
              }
          }
  
          final String retailDemoValue = UserManager.isDeviceInDemoMode(mContext) ? "1" : "0";
          if (!retailDemoValue.equals(SystemProperties.get(SYSTEM_PROPERTY_RETAIL_DEMO_ENABLED))) {
              SystemProperties.set(SYSTEM_PROPERTY_RETAIL_DEMO_ENABLED, retailDemoValue);
          }
  
          mScreenBrightnessModeSetting = Settings.System.getIntForUser(resolver,
                  Settings.System.SCREEN_BRIGHTNESS_MODE,
                  Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL, UserHandle.USER_CURRENT);
  
          mDirty |= DIRTY_SETTINGS;
      }
  
      private void handleSettingsChangedLocked() {
          updateSettingsLocked();
          updatePowerStateLocked();
      }
  
      private void acquireWakeLockInternal(IBinder lock, int flags, String tag, String packageName,
              WorkSource ws, String historyTag, int uid, int pid) {
          synchronized (mLock) {
              if (DEBUG_SPEW) {
                  Slog.d(TAG, "acquireWakeLockInternal: lock=" + Objects.hashCode(lock)
                          + ", flags=0x" + Integer.toHexString(flags)
                          + ", tag=\"" + tag + "\", ws=" + ws + ", uid=" + uid + ", pid=" + pid);
              }
  
              WakeLock wakeLock;
              int index = findWakeLockIndexLocked(lock);
              boolean notifyAcquire;
              if (index >= 0) {
                  wakeLock = mWakeLocks.get(index);
                  if (!wakeLock.hasSameProperties(flags, tag, ws, uid, pid)) {
                      // Update existing wake lock.  This shouldn't happen but is harmless.
                      notifyWakeLockChangingLocked(wakeLock, flags, tag, packageName,
                              uid, pid, ws, historyTag);
                      wakeLock.updateProperties(flags, tag, packageName, ws, historyTag, uid, pid);
                  }
                  notifyAcquire = false;
              } else {
                  UidState state = mUidState.get(uid);
                  if (state == null) {
                      state = new UidState(uid);
                      state.mProcState = ActivityManager.PROCESS_STATE_NONEXISTENT;
                      mUidState.put(uid, state);
                  }
                  state.mNumWakeLocks++;
                  wakeLock = new WakeLock(lock, flags, tag, packageName, ws, historyTag, uid, pid,
                          state);
                  try {
                      lock.linkToDeath(wakeLock, 0);
                  } catch (RemoteException ex) {
                      throw new IllegalArgumentException("Wake lock is already dead.");
                  }
                  mWakeLocks.add(wakeLock);
                  setWakeLockDisabledStateLocked(wakeLock);
                  notifyAcquire = true;
              }
  
              applyWakeLockFlagsOnAcquireLocked(wakeLock, uid);
              mDirty |= DIRTY_WAKE_LOCKS;
              updatePowerStateLocked();
              if (notifyAcquire) {
                  // This needs to be done last so we are sure we have acquired the
                  // kernel wake lock.  Otherwise we have a race where the system may
                  // go to sleep between the time we start the accounting in battery
                  // stats and when we actually get around to telling the kernel to
                  // stay awake.
                  notifyWakeLockAcquiredLocked(wakeLock);
              }
          }
      }
  
      @SuppressWarnings("deprecation")
      private static boolean isScreenLock(final WakeLock wakeLock) {
          switch (wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK) {
              case PowerManager.FULL_WAKE_LOCK:
              case PowerManager.SCREEN_BRIGHT_WAKE_LOCK:
              case PowerManager.SCREEN_DIM_WAKE_LOCK:
                  return true;
          }
          return false;
      }
  
      private static WorkChain getFirstNonEmptyWorkChain(WorkSource workSource) {
          if (workSource.getWorkChains() == null) {
              return null;
          }
  
          for (WorkChain workChain: workSource.getWorkChains()) {
              if (workChain.getSize() > 0) {
                  return workChain;
              }
          }
  
          return null;
      }
  
      private void applyWakeLockFlagsOnAcquireLocked(WakeLock wakeLock, int uid) {
          if ((wakeLock.mFlags & PowerManager.ACQUIRE_CAUSES_WAKEUP) != 0
                  && isScreenLock(wakeLock)) {
              String opPackageName;
              int opUid;
              if (wakeLock.mWorkSource != null && !wakeLock.mWorkSource.isEmpty()) {
                  WorkSource workSource = wakeLock.mWorkSource;
                  WorkChain workChain = getFirstNonEmptyWorkChain(workSource);
                  if (workChain != null) {
                      opPackageName = workChain.getAttributionTag();
                      opUid = workChain.getAttributionUid();
                  } else {
                      opPackageName = workSource.getName(0) != null
                              ? workSource.getName(0) : wakeLock.mPackageName;
                      opUid = workSource.get(0);
                  }
              } else {
                  opPackageName = wakeLock.mPackageName;
                  opUid = wakeLock.mOwnerUid;
              }
              wakeUpNoUpdateLocked(SystemClock.uptimeMillis(),
                      PowerManager.WAKE_REASON_APPLICATION, wakeLock.mTag,
                      opUid, opPackageName, opUid);
          }
      }
  
      private void releaseWakeLockInternal(IBinder lock, int flags) {
          synchronized (mLock) {
              int index = findWakeLockIndexLocked(lock);
              if (index < 0) {
                  if (DEBUG_SPEW) {
                      Slog.d(TAG, "releaseWakeLockInternal: lock=" + Objects.hashCode(lock)
                              + " [not found], flags=0x" + Integer.toHexString(flags));
                  }
                  return;
              }
  
              WakeLock wakeLock = mWakeLocks.get(index);
              if (DEBUG_SPEW) {
                  Slog.d(TAG, "releaseWakeLockInternal: lock=" + Objects.hashCode(lock)
                          + " [" + wakeLock.mTag + "], flags=0x" + Integer.toHexString(flags));
              }
  
              if ((flags & PowerManager.RELEASE_FLAG_WAIT_FOR_NO_PROXIMITY) != 0) {
                  mRequestWaitForNegativeProximity = true;
              }
  
              wakeLock.mLock.unlinkToDeath(wakeLock, 0);
              removeWakeLockLocked(wakeLock, index);
          }
      }
  
      private void handleWakeLockDeath(WakeLock wakeLock) {
          synchronized (mLock) {
              if (DEBUG_SPEW) {
                  Slog.d(TAG, "handleWakeLockDeath: lock=" + Objects.hashCode(wakeLock.mLock)
                          + " [" + wakeLock.mTag + "]");
              }
  
              int index = mWakeLocks.indexOf(wakeLock);
              if (index < 0) {
                  return;
              }
  
              removeWakeLockLocked(wakeLock, index);
          }
      }
  
      private void removeWakeLockLocked(WakeLock wakeLock, int index) {
          mWakeLocks.remove(index);
          UidState state = wakeLock.mUidState;
          state.mNumWakeLocks--;
          if (state.mNumWakeLocks <= 0 &&
                  state.mProcState == ActivityManager.PROCESS_STATE_NONEXISTENT) {
              mUidState.remove(state.mUid);
          }
          notifyWakeLockReleasedLocked(wakeLock);
  
          applyWakeLockFlagsOnReleaseLocked(wakeLock);
          mDirty |= DIRTY_WAKE_LOCKS;
          updatePowerStateLocked();
      }
  
      private void applyWakeLockFlagsOnReleaseLocked(WakeLock wakeLock) {
          if ((wakeLock.mFlags & PowerManager.ON_AFTER_RELEASE) != 0
                  && isScreenLock(wakeLock)) {
              userActivityNoUpdateLocked(SystemClock.uptimeMillis(),
                      PowerManager.USER_ACTIVITY_EVENT_OTHER,
                      PowerManager.USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS,
                      wakeLock.mOwnerUid);
          }
      }
  
      private void updateWakeLockWorkSourceInternal(IBinder lock, WorkSource ws, String historyTag,
              int callingUid) {
          synchronized (mLock) {
              int index = findWakeLockIndexLocked(lock);
              if (index < 0) {
                  if (DEBUG_SPEW) {
                      Slog.d(TAG, "updateWakeLockWorkSourceInternal: lock=" + Objects.hashCode(lock)
                              + " [not found], ws=" + ws);
                  }
                  throw new IllegalArgumentException("Wake lock not active: " + lock
                          + " from uid " + callingUid);
              }
  
              WakeLock wakeLock = mWakeLocks.get(index);
              if (DEBUG_SPEW) {
                  Slog.d(TAG, "updateWakeLockWorkSourceInternal: lock=" + Objects.hashCode(lock)
                          + " [" + wakeLock.mTag + "], ws=" + ws);
              }
  
              if (!wakeLock.hasSameWorkSource(ws)) {
                  notifyWakeLockChangingLocked(wakeLock, wakeLock.mFlags, wakeLock.mTag,
                          wakeLock.mPackageName, wakeLock.mOwnerUid, wakeLock.mOwnerPid,
                          ws, historyTag);
                  wakeLock.mHistoryTag = historyTag;
                  wakeLock.updateWorkSource(ws);
              }
          }
      }
  
      private int findWakeLockIndexLocked(IBinder lock) {
          final int count = mWakeLocks.size();
          for (int i = 0; i < count; i++) {
              if (mWakeLocks.get(i).mLock == lock) {
                  return i;
              }
          }
          return -1;
      }
  
      private void notifyWakeLockAcquiredLocked(WakeLock wakeLock) {
          if (mSystemReady && !wakeLock.mDisabled) {
              wakeLock.mNotifiedAcquired = true;
              mNotifier.onWakeLockAcquired(wakeLock.mFlags, wakeLock.mTag, wakeLock.mPackageName,
                      wakeLock.mOwnerUid, wakeLock.mOwnerPid, wakeLock.mWorkSource,
                      wakeLock.mHistoryTag);
              restartNofifyLongTimerLocked(wakeLock);
          }
      }
  
      private void enqueueNotifyLongMsgLocked(long time) {
          mNotifyLongScheduled = time;
          Message msg = mHandler.obtainMessage(MSG_CHECK_FOR_LONG_WAKELOCKS);
          msg.setAsynchronous(true);
          mHandler.sendMessageAtTime(msg, time);
      }
  
      private void restartNofifyLongTimerLocked(WakeLock wakeLock) {
          wakeLock.mAcquireTime = SystemClock.uptimeMillis();
          if ((wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK)
                  == PowerManager.PARTIAL_WAKE_LOCK && mNotifyLongScheduled == 0) {
              enqueueNotifyLongMsgLocked(wakeLock.mAcquireTime + MIN_LONG_WAKE_CHECK_INTERVAL);
          }
      }
  
      private void notifyWakeLockLongStartedLocked(WakeLock wakeLock) {
          if (mSystemReady && !wakeLock.mDisabled) {
              wakeLock.mNotifiedLong = true;
              mNotifier.onLongPartialWakeLockStart(wakeLock.mTag, wakeLock.mOwnerUid,
                      wakeLock.mWorkSource, wakeLock.mHistoryTag);
          }
      }
  
      private void notifyWakeLockLongFinishedLocked(WakeLock wakeLock) {
          if (wakeLock.mNotifiedLong) {
              wakeLock.mNotifiedLong = false;
              mNotifier.onLongPartialWakeLockFinish(wakeLock.mTag, wakeLock.mOwnerUid,
                      wakeLock.mWorkSource, wakeLock.mHistoryTag);
          }
      }
  
      private void notifyWakeLockChangingLocked(WakeLock wakeLock, int flags, String tag,
              String packageName, int uid, int pid, WorkSource ws, String historyTag) {
          if (mSystemReady && wakeLock.mNotifiedAcquired) {
              mNotifier.onWakeLockChanging(wakeLock.mFlags, wakeLock.mTag, wakeLock.mPackageName,
                      wakeLock.mOwnerUid, wakeLock.mOwnerPid, wakeLock.mWorkSource,
                      wakeLock.mHistoryTag, flags, tag, packageName, uid, pid, ws, historyTag);
              notifyWakeLockLongFinishedLocked(wakeLock);
              // Changing the wake lock will count as releasing the old wake lock(s) and
              // acquiring the new ones...  we do this because otherwise once a wakelock
              // becomes long, if we just continued to treat it as long we can get in to
              // situations where we spam battery stats with every following change to it.
              restartNofifyLongTimerLocked(wakeLock);
          }
      }
  
      private void notifyWakeLockReleasedLocked(WakeLock wakeLock) {
          if (mSystemReady && wakeLock.mNotifiedAcquired) {
              wakeLock.mNotifiedAcquired = false;
              wakeLock.mAcquireTime = 0;
              mNotifier.onWakeLockReleased(wakeLock.mFlags, wakeLock.mTag,
                      wakeLock.mPackageName, wakeLock.mOwnerUid, wakeLock.mOwnerPid,
                      wakeLock.mWorkSource, wakeLock.mHistoryTag);
              notifyWakeLockLongFinishedLocked(wakeLock);
          }
      }
  
      @SuppressWarnings("deprecation")
      private boolean isWakeLockLevelSupportedInternal(int level) {
          synchronized (mLock) {
              switch (level) {
                  case PowerManager.PARTIAL_WAKE_LOCK:
                  case PowerManager.SCREEN_DIM_WAKE_LOCK:
                  case PowerManager.SCREEN_BRIGHT_WAKE_LOCK:
                  case PowerManager.FULL_WAKE_LOCK:
                  case PowerManager.DOZE_WAKE_LOCK:
                  case PowerManager.DRAW_WAKE_LOCK:
                      return true;
  
                  case PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK:
                      return mSystemReady && mDisplayManagerInternal.isProximitySensorAvailable();
  
                  default:
                      return false;
              }
          }
      }
  
      // Called from native code.
      private void userActivityFromNative(long eventTime, int event, int flags) {
          userActivityInternal(eventTime, event, flags, Process.SYSTEM_UID);
      }
  
      private void userActivityInternal(long eventTime, int event, int flags, int uid) {
          synchronized (mLock) {
              if (userActivityNoUpdateLocked(eventTime, event, flags, uid)) {
                  updatePowerStateLocked();
              }
          }
      }
  
      private void onUserAttention() {
          synchronized (mLock) {
              if (userActivityNoUpdateLocked(SystemClock.uptimeMillis(),
                      PowerManager.USER_ACTIVITY_EVENT_ATTENTION, 0 /* flags */,
                      Process.SYSTEM_UID)) {
                  updatePowerStateLocked();
              }
          }
      }
  
      private boolean userActivityNoUpdateLocked(long eventTime, int event, int flags, int uid) {
          if (DEBUG_SPEW) {
              Slog.d(TAG, "userActivityNoUpdateLocked: eventTime=" + eventTime
                      + ", event=" + event + ", flags=0x" + Integer.toHexString(flags)
                      + ", uid=" + uid);
          }
  
          if (eventTime < mLastSleepTime || eventTime < mLastWakeTime
                  || !mBootCompleted || !mSystemReady) {
              return false;
          }
  
          Trace.traceBegin(Trace.TRACE_TAG_POWER, "userActivity");
          try {
              if (eventTime > mLastInteractivePowerHintTime) {
                  powerHintInternal(PowerHint.INTERACTION, 0);
                  mLastInteractivePowerHintTime = eventTime;
              }
  
              mNotifier.onUserActivity(event, uid);
              mAttentionDetector.onUserActivity(eventTime, event);
  
              if (mUserInactiveOverrideFromWindowManager) {
                  mUserInactiveOverrideFromWindowManager = false;
                  mOverriddenTimeout = -1;
              }
  
              if (mWakefulness == WAKEFULNESS_ASLEEP
                      || mWakefulness == WAKEFULNESS_DOZING
                      || (flags & PowerManager.USER_ACTIVITY_FLAG_INDIRECT) != 0) {
                  return false;
              }
  
              maybeUpdateForegroundProfileLastActivityLocked(eventTime);
  
              if ((flags & PowerManager.USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS) != 0) {
                  if (eventTime > mLastUserActivityTimeNoChangeLights
                          && eventTime > mLastUserActivityTime) {
                      mLastUserActivityTimeNoChangeLights = eventTime;
                      mDirty |= DIRTY_USER_ACTIVITY;
                      if (event == PowerManager.USER_ACTIVITY_EVENT_BUTTON) {
                          mDirty |= DIRTY_QUIESCENT;
                      }
  
                      return true;
                  }
              } else {
                  if (eventTime > mLastUserActivityTime) {
                      mLastUserActivityTime = eventTime;
                      mDirty |= DIRTY_USER_ACTIVITY;
                      if (event == PowerManager.USER_ACTIVITY_EVENT_BUTTON) {
                          mDirty |= DIRTY_QUIESCENT;
                      }
                      return true;
                  }
              }
          } finally {
              Trace.traceEnd(Trace.TRACE_TAG_POWER);
          }
          return false;
      }
  
      private void maybeUpdateForegroundProfileLastActivityLocked(long eventTime) {
          final ProfilePowerState profile = mProfilePowerState.get(mForegroundProfile);
          if (profile != null && eventTime > profile.mLastUserActivityTime) {
              profile.mLastUserActivityTime = eventTime;
          }
      }
  
      private void wakeUpInternal(long eventTime, @WakeReason int reason, String details, int uid,
              String opPackageName, int opUid) {
          synchronized (mLock) {
              if (wakeUpNoUpdateLocked(eventTime, reason, details, uid, opPackageName, opUid)) {
                  updatePowerStateLocked();
              }
          }
      }
  
      private boolean wakeUpNoUpdateLocked(long eventTime, @WakeReason int reason, String details,
              int reasonUid, String opPackageName, int opUid) {
          if (DEBUG_SPEW) {
              Slog.d(TAG, "wakeUpNoUpdateLocked: eventTime=" + eventTime + ", uid=" + reasonUid);
          }
  
          if (eventTime < mLastSleepTime || mWakefulness == WAKEFULNESS_AWAKE
                  || !mBootCompleted || !mSystemReady || mForceSuspendActive) {
              return false;
          }
  
          Trace.asyncTraceBegin(Trace.TRACE_TAG_POWER, TRACE_SCREEN_ON, 0);
  
          Trace.traceBegin(Trace.TRACE_TAG_POWER, "wakeUp");
          try {
              Slog.i(TAG, "Waking up from "
                      + PowerManagerInternal.wakefulnessToString(mWakefulness)
                      + " (uid=" + reasonUid
                      + ", reason=" + PowerManager.wakeReasonToString(reason)
                      + ", details=" + details
                      + ")...");
  
              mLastWakeTime = eventTime;
              mLastWakeReason = reason;
              setWakefulnessLocked(WAKEFULNESS_AWAKE, reason, eventTime);
  
              mNotifier.onWakeUp(reason, details, reasonUid, opPackageName, opUid);
              userActivityNoUpdateLocked(
                      eventTime, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, reasonUid);
          } finally {
              Trace.traceEnd(Trace.TRACE_TAG_POWER);
          }
          return true;
      }
  
      private void goToSleepInternal(long eventTime, int reason, int flags, int uid) {
          synchronized (mLock) {
              if (goToSleepNoUpdateLocked(eventTime, reason, flags, uid)) {
                  updatePowerStateLocked();
              }
          }
      }
  
      /**
       * Puts the system in doze.
       *
       * This method is called goToSleep for historical reasons but actually attempts to DOZE,
       * and only tucks itself in to SLEEP if requested with the flag
       * {@link PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE}.
       */
      @SuppressWarnings("deprecation")
      private boolean goToSleepNoUpdateLocked(long eventTime, int reason, int flags, int uid) {
          if (DEBUG_SPEW) {
              Slog.d(TAG, "goToSleepNoUpdateLocked: eventTime=" + eventTime
                      + ", reason=" + reason + ", flags=" + flags + ", uid=" + uid);
          }
  
          if (eventTime < mLastWakeTime
                  || mWakefulness == WAKEFULNESS_ASLEEP
                  || mWakefulness == WAKEFULNESS_DOZING
                  || !mBootCompleted || !mSystemReady) {
              return false;
          }
  
          Trace.traceBegin(Trace.TRACE_TAG_POWER, "goToSleep");
          try {
              reason = Math.min(PowerManager.GO_TO_SLEEP_REASON_MAX,
                      Math.max(reason, PowerManager.GO_TO_SLEEP_REASON_MIN));
              Slog.i(TAG, "Going to sleep due to " + PowerManager.sleepReasonToString(reason)
                      + " (uid " + uid + ")...");
  
              mLastSleepTime = eventTime;
              mLastSleepReason = reason;
              mSandmanSummoned = true;
              mDozeStartInProgress = true;
              setWakefulnessLocked(WAKEFULNESS_DOZING, reason, eventTime);
  
              // Report the number of wake locks that will be cleared by going to sleep.
              int numWakeLocksCleared = 0;
              final int numWakeLocks = mWakeLocks.size();
              for (int i = 0; i < numWakeLocks; i++) {
                  final WakeLock wakeLock = mWakeLocks.get(i);
                  switch (wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK) {
                      case PowerManager.FULL_WAKE_LOCK:
                      case PowerManager.SCREEN_BRIGHT_WAKE_LOCK:
                      case PowerManager.SCREEN_DIM_WAKE_LOCK:
                          numWakeLocksCleared += 1;
                          break;
                  }
              }
              EventLogTags.writePowerSleepRequested(numWakeLocksCleared);
  
              // Skip dozing if requested.
              if ((flags & PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE) != 0) {
                  reallyGoToSleepNoUpdateLocked(eventTime, uid);
              }
          } finally {
              Trace.traceEnd(Trace.TRACE_TAG_POWER);
          }
          return true;
      }
  
      private void napInternal(long eventTime, int uid) {
          synchronized (mLock) {
              if (napNoUpdateLocked(eventTime, uid)) {
                  updatePowerStateLocked();
              }
          }
      }
  
      private boolean napNoUpdateLocked(long eventTime, int uid) {
          if (DEBUG_SPEW) {
              Slog.d(TAG, "napNoUpdateLocked: eventTime=" + eventTime + ", uid=" + uid);
          }
  
          if (eventTime < mLastWakeTime || mWakefulness != WAKEFULNESS_AWAKE
                  || !mBootCompleted || !mSystemReady) {
              return false;
          }
  
          Trace.traceBegin(Trace.TRACE_TAG_POWER, "nap");
          try {
              Slog.i(TAG, "Nap time (uid " + uid +")...");
  
              mSandmanSummoned = true;
              setWakefulnessLocked(WAKEFULNESS_DREAMING, 0, eventTime);
          } finally {
              Trace.traceEnd(Trace.TRACE_TAG_POWER);
          }
          return true;
      }
  
      // Done dozing, drop everything and go to sleep.
      private boolean reallyGoToSleepNoUpdateLocked(long eventTime, int uid) {
          if (DEBUG_SPEW) {
              Slog.d(TAG, "reallyGoToSleepNoUpdateLocked: eventTime=" + eventTime
                      + ", uid=" + uid);
          }
  
          if (eventTime < mLastWakeTime || mWakefulness == WAKEFULNESS_ASLEEP
                  || !mBootCompleted || !mSystemReady) {
              return false;
          }
  
          Trace.traceBegin(Trace.TRACE_TAG_POWER, "reallyGoToSleep");
          try {
              Slog.i(TAG, "Sleeping (uid " + uid +")...");
  
              setWakefulnessLocked(WAKEFULNESS_ASLEEP, PowerManager.GO_TO_SLEEP_REASON_TIMEOUT,
                      eventTime);
          } finally {
              Trace.traceEnd(Trace.TRACE_TAG_POWER);
          }
          return true;
      }
  
      @VisibleForTesting
      void setWakefulnessLocked(int wakefulness, int reason, long eventTime) {
          if (mWakefulness != wakefulness) {
              mWakefulness = wakefulness;
              mWakefulnessChanging = true;
              mDirty |= DIRTY_WAKEFULNESS;
  
              // This is only valid while we are in wakefulness dozing. Set to false otherwise.
              mDozeStartInProgress &= (mWakefulness == WAKEFULNESS_DOZING);
  
              if (mNotifier != null) {
                  mNotifier.onWakefulnessChangeStarted(wakefulness, reason, eventTime);
              }
              mAttentionDetector.onWakefulnessChangeStarted(wakefulness);
          }
      }
  
      @VisibleForTesting
      int getWakefulness() {
          return mWakefulness;
      }
  
      /**
       * Logs the time the device would have spent awake before user activity timeout,
       * had the system not been told the user was inactive.
       */
      private void logSleepTimeoutRecapturedLocked() {
          final long now = SystemClock.uptimeMillis();
          final long savedWakeTimeMs = mOverriddenTimeout - now;
          if (savedWakeTimeMs >= 0) {
              EventLogTags.writePowerSoftSleepRequested(savedWakeTimeMs);
              mOverriddenTimeout = -1;
          }
      }
  
      private void finishWakefulnessChangeIfNeededLocked() {
          if (mWakefulnessChanging && mDisplayReady) {
              if (mWakefulness == WAKEFULNESS_DOZING
                      && (mWakeLockSummary & WAKE_LOCK_DOZE) == 0) {
                  return; // wait until dream has enabled dozing
              } else {
                  // Doze wakelock acquired (doze started) or device is no longer dozing.
                  mDozeStartInProgress = false;
              }
              if (mWakefulness == WAKEFULNESS_DOZING || mWakefulness == WAKEFULNESS_ASLEEP) {
                  logSleepTimeoutRecapturedLocked();
              }
              if (mWakefulness == WAKEFULNESS_AWAKE) {
                  Trace.asyncTraceEnd(Trace.TRACE_TAG_POWER, TRACE_SCREEN_ON, 0);
                  final int latencyMs = (int) (SystemClock.uptimeMillis() - mLastWakeTime);
                  if (latencyMs >= SCREEN_ON_LATENCY_WARNING_MS) {
                      Slog.w(TAG, "Screen on took " + latencyMs + " ms");
                  }
              }
              mWakefulnessChanging = false;
              mNotifier.onWakefulnessChangeFinished();
          }
      }
  
      /**
       * Updates the global power state based on dirty bits recorded in mDirty.
       *
       * This is the main function that performs power state transitions.
       * We centralize them here so that we can recompute the power state completely
       * each time something important changes, and ensure that we do it the same
       * way each time.  The point is to gather all of the transition logic here.
       */
      private void updatePowerStateLocked() {
          if (!mSystemReady || mDirty == 0) {
              return;
          }
          if (!Thread.holdsLock(mLock)) {
              Slog.wtf(TAG, "Power manager lock was not held when calling updatePowerStateLocked");
          }
  
          Trace.traceBegin(Trace.TRACE_TAG_POWER, "updatePowerState");
          try {
              // Phase 0: Basic state updates.
              updateIsPoweredLocked(mDirty);
              updateStayOnLocked(mDirty);
              updateScreenBrightnessBoostLocked(mDirty);
  
              // Phase 1: Update wakefulness.
              // Loop because the wake lock and user activity computations are influenced
              // by changes in wakefulness.
              final long now = SystemClock.uptimeMillis();
              int dirtyPhase2 = 0;
              for (;;) {
                  int dirtyPhase1 = mDirty;
                  dirtyPhase2 |= dirtyPhase1;
                  mDirty = 0;
  
                  updateWakeLockSummaryLocked(dirtyPhase1);
                  updateUserActivitySummaryLocked(now, dirtyPhase1);
                  if (!updateWakefulnessLocked(dirtyPhase1)) {
                      break;
                  }
              }
  
              // Phase 2: Lock profiles that became inactive/not kept awake.
              updateProfilesLocked(now);
  
              // Phase 3: Update display power state.
              final boolean displayBecameReady = updateDisplayPowerStateLocked(dirtyPhase2);
  
              // Phase 4: Update dream state (depends on display ready signal).
              updateDreamLocked(dirtyPhase2, displayBecameReady);
  
              // Phase 5: Send notifications, if needed.
              finishWakefulnessChangeIfNeededLocked();
  
              // Phase 6: Update suspend blocker.
              // Because we might release the last suspend blocker here, we need to make sure
              // we finished everything else first!
              updateSuspendBlockerLocked();
          } finally {
              Trace.traceEnd(Trace.TRACE_TAG_POWER);
          }
      }
  
      /**
       * Check profile timeouts and notify profiles that should be locked.
       */
      private void updateProfilesLocked(long now) {
          final int numProfiles = mProfilePowerState.size();
          for (int i = 0; i < numProfiles; i++) {
              final ProfilePowerState profile = mProfilePowerState.valueAt(i);
              if (isProfileBeingKeptAwakeLocked(profile, now)) {
                  profile.mLockingNotified = false;
              } else if (!profile.mLockingNotified) {
                  profile.mLockingNotified = true;
                  mNotifier.onProfileTimeout(profile.mUserId);
              }
          }
      }
  
      private boolean isProfileBeingKeptAwakeLocked(ProfilePowerState profile, long now) {
          return (profile.mLastUserActivityTime + profile.mScreenOffTimeout > now)
                  || (profile.mWakeLockSummary & WAKE_LOCK_STAY_AWAKE) != 0
                  || (mProximityPositive &&
                      (profile.mWakeLockSummary & WAKE_LOCK_PROXIMITY_SCREEN_OFF) != 0);
      }
  
      /**
       * Updates the value of mIsPowered.
       * Sets DIRTY_IS_POWERED if a change occurred.
       */
      private void updateIsPoweredLocked(int dirty) {
          if ((dirty & DIRTY_BATTERY_STATE) != 0) {
              final boolean wasPowered = mIsPowered;
              final int oldPlugType = mPlugType;
              final boolean oldLevelLow = mBatteryLevelLow;
              mIsPowered = mBatteryManagerInternal.isPowered(BatteryManager.BATTERY_PLUGGED_ANY);
              mPlugType = mBatteryManagerInternal.getPlugType();
              mBatteryLevel = mBatteryManagerInternal.getBatteryLevel();
              mBatteryLevelLow = mBatteryManagerInternal.getBatteryLevelLow();
  
              if (DEBUG_SPEW) {
                  Slog.d(TAG, "updateIsPoweredLocked: wasPowered=" + wasPowered
                          + ", mIsPowered=" + mIsPowered
                          + ", oldPlugType=" + oldPlugType
                          + ", mPlugType=" + mPlugType
                          + ", mBatteryLevel=" + mBatteryLevel);
              }
  
              if (wasPowered != mIsPowered || oldPlugType != mPlugType) {
                  mDirty |= DIRTY_IS_POWERED;
  
                  // Update wireless dock detection state.
                  final boolean dockedOnWirelessCharger = mWirelessChargerDetector.update(
                          mIsPowered, mPlugType);
  
                  // Treat plugging and unplugging the devices as a user activity.
                  // Users find it disconcerting when they plug or unplug the device
                  // and it shuts off right away.
                  // Some devices also wake the device when plugged or unplugged because
                  // they don't have a charging LED.
                  final long now = SystemClock.uptimeMillis();
                  if (shouldWakeUpWhenPluggedOrUnpluggedLocked(wasPowered, oldPlugType,
                          dockedOnWirelessCharger)) {
                      wakeUpNoUpdateLocked(now, PowerManager.WAKE_REASON_PLUGGED_IN,
                              "android.server.power:PLUGGED:" + mIsPowered, Process.SYSTEM_UID,
                              mContext.getOpPackageName(), Process.SYSTEM_UID);
                  }
                  userActivityNoUpdateLocked(
                          now, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, Process.SYSTEM_UID);
  
                  // only play charging sounds if boot is completed so charging sounds don't play
                  // with potential notification sounds
                  if (mBootCompleted) {
                      if (mIsPowered && !BatteryManager.isPlugWired(oldPlugType)
                              && BatteryManager.isPlugWired(mPlugType)) {
                          mNotifier.onWiredChargingStarted(mForegroundProfile);
                      } else if (dockedOnWirelessCharger) {
                          mNotifier.onWirelessChargingStarted(mBatteryLevel, mForegroundProfile);
                      }
                  }
              }
  
              mBatterySaverStateMachine.setBatteryStatus(mIsPowered, mBatteryLevel, mBatteryLevelLow);
          }
      }
  
      private boolean shouldWakeUpWhenPluggedOrUnpluggedLocked(
              boolean wasPowered, int oldPlugType, boolean dockedOnWirelessCharger) {
          // Don't wake when powered unless configured to do so.
          if (!mWakeUpWhenPluggedOrUnpluggedConfig) {
              return false;
          }
  
          // Don't wake when undocked from wireless charger.
          // See WirelessChargerDetector for justification.
          if (wasPowered && !mIsPowered
                  && oldPlugType == BatteryManager.BATTERY_PLUGGED_WIRELESS) {
              return false;
          }
  
          // Don't wake when docked on wireless charger unless we are certain of it.
          // See WirelessChargerDetector for justification.
          if (!wasPowered && mIsPowered
                  && mPlugType == BatteryManager.BATTERY_PLUGGED_WIRELESS
                  && !dockedOnWirelessCharger) {
              return false;
          }
  
          // If already dreaming and becoming powered, then don't wake.
          if (mIsPowered && mWakefulness == WAKEFULNESS_DREAMING) {
              return false;
          }
  
          // Don't wake while theater mode is enabled.
          if (mTheaterModeEnabled && !mWakeUpWhenPluggedOrUnpluggedInTheaterModeConfig) {
              return false;
          }
  
          // On Always On Display, SystemUI shows the charging indicator
          if (mAlwaysOnEnabled && mWakefulness == WAKEFULNESS_DOZING) {
              return false;
          }
  
          // Otherwise wake up!
          return true;
      }
  
      /**
       * Updates the value of mStayOn.
       * Sets DIRTY_STAY_ON if a change occurred.
       */
      private void updateStayOnLocked(int dirty) {
          if ((dirty & (DIRTY_BATTERY_STATE | DIRTY_SETTINGS)) != 0) {
              final boolean wasStayOn = mStayOn;
              if (mStayOnWhilePluggedInSetting != 0
                      && !isMaximumScreenOffTimeoutFromDeviceAdminEnforcedLocked()) {
                  mStayOn = mBatteryManagerInternal.isPowered(mStayOnWhilePluggedInSetting);
              } else {
                  mStayOn = false;
              }
  
              if (mStayOn != wasStayOn) {
                  mDirty |= DIRTY_STAY_ON;
              }
          }
      }
  
      /**
       * Updates the value of mWakeLockSummary to summarize the state of all active wake locks.
       * Note that most wake-locks are ignored when the system is asleep.
       *
       * This function must have no other side-effects.
       */
      @SuppressWarnings("deprecation")
      private void updateWakeLockSummaryLocked(int dirty) {
          if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_WAKEFULNESS)) != 0) {
              mWakeLockSummary = 0;
  
              final int numProfiles = mProfilePowerState.size();
              for (int i = 0; i < numProfiles; i++) {
                  mProfilePowerState.valueAt(i).mWakeLockSummary = 0;
              }
  
              final int numWakeLocks = mWakeLocks.size();
              for (int i = 0; i < numWakeLocks; i++) {
                  final WakeLock wakeLock = mWakeLocks.get(i);
                  final int wakeLockFlags = getWakeLockSummaryFlags(wakeLock);
                  mWakeLockSummary |= wakeLockFlags;
                  for (int j = 0; j < numProfiles; j++) {
                      final ProfilePowerState profile = mProfilePowerState.valueAt(j);
                      if (wakeLockAffectsUser(wakeLock, profile.mUserId)) {
                          profile.mWakeLockSummary |= wakeLockFlags;
                      }
                  }
              }
  
              mWakeLockSummary = adjustWakeLockSummaryLocked(mWakeLockSummary);
              for (int i = 0; i < numProfiles; i++) {
                  final ProfilePowerState profile = mProfilePowerState.valueAt(i);
                  profile.mWakeLockSummary = adjustWakeLockSummaryLocked(profile.mWakeLockSummary);
              }
  
              if (DEBUG_SPEW) {
                  Slog.d(TAG, "updateWakeLockSummaryLocked: mWakefulness="
                          + PowerManagerInternal.wakefulnessToString(mWakefulness)
                          + ", mWakeLockSummary=0x" + Integer.toHexString(mWakeLockSummary));
              }
          }
      }
  
      private int adjustWakeLockSummaryLocked(int wakeLockSummary) {
          // Cancel wake locks that make no sense based on the current state.
          if (mWakefulness != WAKEFULNESS_DOZING) {
              wakeLockSummary &= ~(WAKE_LOCK_DOZE | WAKE_LOCK_DRAW);
          }
          if (mWakefulness == WAKEFULNESS_ASLEEP
                  || (wakeLockSummary & WAKE_LOCK_DOZE) != 0) {
              wakeLockSummary &= ~(WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_SCREEN_DIM
                      | WAKE_LOCK_BUTTON_BRIGHT);
              if (mWakefulness == WAKEFULNESS_ASLEEP) {
                  wakeLockSummary &= ~WAKE_LOCK_PROXIMITY_SCREEN_OFF;
              }
          }
  
          // Infer implied wake locks where necessary based on the current state.
          if ((wakeLockSummary & (WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_SCREEN_DIM)) != 0) {
              if (mWakefulness == WAKEFULNESS_AWAKE) {
                  wakeLockSummary |= WAKE_LOCK_CPU | WAKE_LOCK_STAY_AWAKE;
              } else if (mWakefulness == WAKEFULNESS_DREAMING) {
                  wakeLockSummary |= WAKE_LOCK_CPU;
              }
          }
          if ((wakeLockSummary & WAKE_LOCK_DRAW) != 0) {
              wakeLockSummary |= WAKE_LOCK_CPU;
          }
  
          return wakeLockSummary;
      }
  
      /** Get wake lock summary flags that correspond to the given wake lock. */
      private int getWakeLockSummaryFlags(WakeLock wakeLock) {
          switch (wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK) {
              case PowerManager.PARTIAL_WAKE_LOCK:
                  if (!wakeLock.mDisabled) {
                      // We only respect this if the wake lock is not disabled.
                      return WAKE_LOCK_CPU;
                  }
                  break;
              case PowerManager.FULL_WAKE_LOCK:
                  return WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_BUTTON_BRIGHT;
              case PowerManager.SCREEN_BRIGHT_WAKE_LOCK:
                  return WAKE_LOCK_SCREEN_BRIGHT;
              case PowerManager.SCREEN_DIM_WAKE_LOCK:
                  return WAKE_LOCK_SCREEN_DIM;
              case PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK:
                  return WAKE_LOCK_PROXIMITY_SCREEN_OFF;
              case PowerManager.DOZE_WAKE_LOCK:
                  return WAKE_LOCK_DOZE;
              case PowerManager.DRAW_WAKE_LOCK:
                  return WAKE_LOCK_DRAW;
          }
          return 0;
      }
  
      private boolean wakeLockAffectsUser(WakeLock wakeLock, @UserIdInt int userId) {
          if (wakeLock.mWorkSource != null) {
              for (int k = 0; k < wakeLock.mWorkSource.size(); k++) {
                  final int uid = wakeLock.mWorkSource.get(k);
                  if (userId == UserHandle.getUserId(uid)) {
                      return true;
                  }
              }
  
              final ArrayList<WorkChain> workChains = wakeLock.mWorkSource.getWorkChains();
              if (workChains != null) {
                  for (int k = 0; k < workChains.size(); k++) {
                      final int uid = workChains.get(k).getAttributionUid();
                      if (userId == UserHandle.getUserId(uid)) {
                          return true;
                      }
                  }
              }
          }
          return userId == UserHandle.getUserId(wakeLock.mOwnerUid);
      }
  
      void checkForLongWakeLocks() {
          synchronized (mLock) {
              final long now = SystemClock.uptimeMillis();
              mNotifyLongDispatched = now;
              final long when = now - MIN_LONG_WAKE_CHECK_INTERVAL;
              long nextCheckTime = Long.MAX_VALUE;
              final int numWakeLocks = mWakeLocks.size();
              for (int i = 0; i < numWakeLocks; i++) {
                  final WakeLock wakeLock = mWakeLocks.get(i);
                  if ((wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK)
                          == PowerManager.PARTIAL_WAKE_LOCK) {
                      if (wakeLock.mNotifiedAcquired && !wakeLock.mNotifiedLong) {
                          if (wakeLock.mAcquireTime < when) {
                              // This wake lock has exceeded the long acquire time, report!
                              notifyWakeLockLongStartedLocked(wakeLock);
                          } else {
                              // This wake lock could still become a long one, at this time.
                              long checkTime = wakeLock.mAcquireTime + MIN_LONG_WAKE_CHECK_INTERVAL;
                              if (checkTime < nextCheckTime) {
                                  nextCheckTime = checkTime;
                              }
                          }
                      }
                  }
              }
              mNotifyLongScheduled = 0;
              mHandler.removeMessages(MSG_CHECK_FOR_LONG_WAKELOCKS);
              if (nextCheckTime != Long.MAX_VALUE) {
                  mNotifyLongNextCheck = nextCheckTime;
                  enqueueNotifyLongMsgLocked(nextCheckTime);
              } else {
                  mNotifyLongNextCheck = 0;
              }
          }
      }
  
      /**
       * Updates the value of mUserActivitySummary to summarize the user requested
       * state of the system such as whether the screen should be bright or dim.
       * Note that user activity is ignored when the system is asleep.
       *
       * This function must have no other side-effects.
       */
      private void updateUserActivitySummaryLocked(long now, int dirty) {
          // Update the status of the user activity timeout timer.
          if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_USER_ACTIVITY
                  | DIRTY_WAKEFULNESS | DIRTY_SETTINGS)) != 0) {
              mHandler.removeMessages(MSG_USER_ACTIVITY_TIMEOUT);
  
              long nextTimeout = 0;
              if (mWakefulness == WAKEFULNESS_AWAKE
                      || mWakefulness == WAKEFULNESS_DREAMING
                      || mWakefulness == WAKEFULNESS_DOZING) {
                  final long sleepTimeout = getSleepTimeoutLocked();
                  final long screenOffTimeout = getScreenOffTimeoutLocked(sleepTimeout);
                  final long screenDimDuration = getScreenDimDurationLocked(screenOffTimeout);
                  final boolean userInactiveOverride = mUserInactiveOverrideFromWindowManager;
                  final long nextProfileTimeout = getNextProfileTimeoutLocked(now);
  
                  mUserActivitySummary = 0;
                  if (mLastUserActivityTime >= mLastWakeTime) {
                      nextTimeout = mLastUserActivityTime
                              + screenOffTimeout - screenDimDuration;
                      if (now < nextTimeout) {
                          mUserActivitySummary = USER_ACTIVITY_SCREEN_BRIGHT;
                      } else {
                          nextTimeout = mLastUserActivityTime + screenOffTimeout;
                          if (now < nextTimeout) {
                              mUserActivitySummary = USER_ACTIVITY_SCREEN_DIM;
                          }
                      }
                  }
                  if (mUserActivitySummary == 0
                          && mLastUserActivityTimeNoChangeLights >= mLastWakeTime) {
                      nextTimeout = mLastUserActivityTimeNoChangeLights + screenOffTimeout;
                      if (now < nextTimeout) {
                          if (mDisplayPowerRequest.policy == DisplayPowerRequest.POLICY_BRIGHT
                                  || mDisplayPowerRequest.policy == DisplayPowerRequest.POLICY_VR) {
                              mUserActivitySummary = USER_ACTIVITY_SCREEN_BRIGHT;
                          } else if (mDisplayPowerRequest.policy == DisplayPowerRequest.POLICY_DIM) {
                              mUserActivitySummary = USER_ACTIVITY_SCREEN_DIM;
                          }
                      }
                  }
  
                  if (mUserActivitySummary == 0) {
                      if (sleepTimeout >= 0) {
                          final long anyUserActivity = Math.max(mLastUserActivityTime,
                                  mLastUserActivityTimeNoChangeLights);
                          if (anyUserActivity >= mLastWakeTime) {
                              nextTimeout = anyUserActivity + sleepTimeout;
                              if (now < nextTimeout) {
                                  mUserActivitySummary = USER_ACTIVITY_SCREEN_DREAM;
                              }
                          }
                      } else {
                          mUserActivitySummary = USER_ACTIVITY_SCREEN_DREAM;
                          nextTimeout = -1;
                      }
                  }
  
                  if (mUserActivitySummary != USER_ACTIVITY_SCREEN_DREAM && userInactiveOverride) {
                      if ((mUserActivitySummary &
                              (USER_ACTIVITY_SCREEN_BRIGHT | USER_ACTIVITY_SCREEN_DIM)) != 0) {
                          // Device is being kept awake by recent user activity
                          if (nextTimeout >= now && mOverriddenTimeout == -1) {
                              // Save when the next timeout would have occurred
                              mOverriddenTimeout = nextTimeout;
                          }
                      }
                      mUserActivitySummary = USER_ACTIVITY_SCREEN_DREAM;
                      nextTimeout = -1;
                  }
  
                  if ((mUserActivitySummary & USER_ACTIVITY_SCREEN_BRIGHT) != 0
                          && (mWakeLockSummary & WAKE_LOCK_STAY_AWAKE) == 0) {
                      nextTimeout = mAttentionDetector.updateUserActivity(nextTimeout);
                  }
  
                  if (nextProfileTimeout > 0) {
                      nextTimeout = Math.min(nextTimeout, nextProfileTimeout);
                  }
  
                  if (mUserActivitySummary != 0 && nextTimeout >= 0) {
                      scheduleUserInactivityTimeout(nextTimeout);
                  }
              } else {
                  mUserActivitySummary = 0;
              }
  
              if (DEBUG_SPEW) {
                  Slog.d(TAG, "updateUserActivitySummaryLocked: mWakefulness="
                          + PowerManagerInternal.wakefulnessToString(mWakefulness)
                          + ", mUserActivitySummary=0x" + Integer.toHexString(mUserActivitySummary)
                          + ", nextTimeout=" + TimeUtils.formatUptime(nextTimeout));
              }
          }
      }
  
      private void scheduleUserInactivityTimeout(long timeMs) {
          final Message msg = mHandler.obtainMessage(MSG_USER_ACTIVITY_TIMEOUT);
          msg.setAsynchronous(true);
          mHandler.sendMessageAtTime(msg, timeMs);
      }
  
      /**
       * Finds the next profile timeout time or returns -1 if there are no profiles to be locked.
       */
      private long getNextProfileTimeoutLocked(long now) {
          long nextTimeout = -1;
          final int numProfiles = mProfilePowerState.size();
          for (int i = 0; i < numProfiles; i++) {
              final ProfilePowerState profile = mProfilePowerState.valueAt(i);
              final long timeout = profile.mLastUserActivityTime + profile.mScreenOffTimeout;
              if (timeout > now && (nextTimeout == -1 || timeout < nextTimeout)) {
                  nextTimeout = timeout;
              }
          }
          return nextTimeout;
      }
  
      /**
       * Called when a user activity timeout has occurred.
       * Simply indicates that something about user activity has changed so that the new
       * state can be recomputed when the power state is updated.
       *
       * This function must have no other side-effects besides setting the dirty
       * bit and calling update power state.  Wakefulness transitions are handled elsewhere.
       */
      private void handleUserActivityTimeout() { // runs on handler thread
          synchronized (mLock) {
              if (DEBUG_SPEW) {
                  Slog.d(TAG, "handleUserActivityTimeout");
              }
  
              mDirty |= DIRTY_USER_ACTIVITY;
              updatePowerStateLocked();
          }
      }
  
      private long getSleepTimeoutLocked() {
          final long timeout = mSleepTimeoutSetting;
          if (timeout <= 0) {
              return -1;
          }
          return Math.max(timeout, mMinimumScreenOffTimeoutConfig);
      }
  
      private long getScreenOffTimeoutLocked(long sleepTimeout) {
          long timeout = mScreenOffTimeoutSetting;
          if (isMaximumScreenOffTimeoutFromDeviceAdminEnforcedLocked()) {
              timeout = Math.min(timeout, mMaximumScreenOffTimeoutFromDeviceAdmin);
          }
          if (mUserActivityTimeoutOverrideFromWindowManager >= 0) {
              timeout = Math.min(timeout, mUserActivityTimeoutOverrideFromWindowManager);
          }
          if (sleepTimeout >= 0) {
              timeout = Math.min(timeout, sleepTimeout);
          }
          return Math.max(timeout, mMinimumScreenOffTimeoutConfig);
      }
  
      private long getScreenDimDurationLocked(long screenOffTimeout) {
          return Math.min(mMaximumScreenDimDurationConfig,
                  (long)(screenOffTimeout * mMaximumScreenDimRatioConfig));
      }
  
      /**
       * Updates the wakefulness of the device.
       *
       * This is the function that decides whether the device should start dreaming
       * based on the current wake locks and user activity state.  It may modify mDirty
       * if the wakefulness changes.
       *
       * Returns true if the wakefulness changed and we need to restart power state calculation.
       */
      private boolean updateWakefulnessLocked(int dirty) {
          boolean changed = false;
          if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_USER_ACTIVITY | DIRTY_BOOT_COMPLETED
                  | DIRTY_WAKEFULNESS | DIRTY_STAY_ON | DIRTY_PROXIMITY_POSITIVE
                  | DIRTY_DOCK_STATE)) != 0) {
              if (mWakefulness == WAKEFULNESS_AWAKE && isItBedTimeYetLocked()) {
                  if (DEBUG_SPEW) {
                      Slog.d(TAG, "updateWakefulnessLocked: Bed time...");
                  }
                  final long time = SystemClock.uptimeMillis();
                  if (shouldNapAtBedTimeLocked()) {
                      changed = napNoUpdateLocked(time, Process.SYSTEM_UID);
                  } else {
                      changed = goToSleepNoUpdateLocked(time,
                              PowerManager.GO_TO_SLEEP_REASON_TIMEOUT, 0, Process.SYSTEM_UID);
                  }
              }
          }
          return changed;
      }
  
      /**
       * Returns true if the device should automatically nap and start dreaming when the user
       * activity timeout has expired and it's bedtime.
       */
      private boolean shouldNapAtBedTimeLocked() {
          return mDreamsActivateOnSleepSetting
                  || (mDreamsActivateOnDockSetting
                          && mDockState != Intent.EXTRA_DOCK_STATE_UNDOCKED);
      }
  
      /**
       * Returns true if the device should go to sleep now.
       * Also used when exiting a dream to determine whether we should go back
       * to being fully awake or else go to sleep for good.
       */
      private boolean isItBedTimeYetLocked() {
          return mBootCompleted && !isBeingKeptAwakeLocked();
      }
  
      /**
       * Returns true if the device is being kept awake by a wake lock, user activity
       * or the stay on while powered setting.  We also keep the phone awake when
       * the proximity sensor returns a positive result so that the device does not
       * lock while in a phone call.  This function only controls whether the device
       * will go to sleep or dream which is independent of whether it will be allowed
       * to suspend.
       */
      private boolean isBeingKeptAwakeLocked() {
          return mStayOn
                  || mProximityPositive
                  || (mWakeLockSummary & WAKE_LOCK_STAY_AWAKE) != 0
                  || (mUserActivitySummary & (USER_ACTIVITY_SCREEN_BRIGHT
                          | USER_ACTIVITY_SCREEN_DIM)) != 0
                  || mScreenBrightnessBoostInProgress;
      }
  
      /**
       * Determines whether to post a message to the sandman to update the dream state.
       */
      private void updateDreamLocked(int dirty, boolean displayBecameReady) {
          if ((dirty & (DIRTY_WAKEFULNESS
                  | DIRTY_USER_ACTIVITY
                  | DIRTY_WAKE_LOCKS
                  | DIRTY_BOOT_COMPLETED
                  | DIRTY_SETTINGS
                  | DIRTY_IS_POWERED
                  | DIRTY_STAY_ON
                  | DIRTY_PROXIMITY_POSITIVE
                  | DIRTY_BATTERY_STATE)) != 0 || displayBecameReady) {
              if (mDisplayReady) {
                  scheduleSandmanLocked();
              }
          }
      }
  
      private void scheduleSandmanLocked() {
          if (!mSandmanScheduled) {
              mSandmanScheduled = true;
              Message msg = mHandler.obtainMessage(MSG_SANDMAN);
              msg.setAsynchronous(true);
              mHandler.sendMessage(msg);
          }
      }
  
      /**
       * Called when the device enters or exits a dreaming or dozing state.
       *
       * We do this asynchronously because we must call out of the power manager to start
       * the dream and we don't want to hold our lock while doing so.  There is a risk that
       * the device will wake or go to sleep in the meantime so we have to handle that case.
       */
      private void handleSandman() { // runs on handler thread
          // Handle preconditions.
          final boolean startDreaming;
          final int wakefulness;
          synchronized (mLock) {
              mSandmanScheduled = false;
              wakefulness = mWakefulness;
              if (mSandmanSummoned && mDisplayReady) {
                  startDreaming = canDreamLocked() || canDozeLocked();
                  mSandmanSummoned = false;
              } else {
                  startDreaming = false;
              }
          }
  
          // Start dreaming if needed.
          // We only control the dream on the handler thread, so we don't need to worry about
          // concurrent attempts to start or stop the dream.
          final boolean isDreaming;
          if (mDreamManager != null) {
              // Restart the dream whenever the sandman is summoned.
              if (startDreaming) {
                  mDreamManager.stopDream(false /*immediate*/);
                  mDreamManager.startDream(wakefulness == WAKEFULNESS_DOZING);
              }
              isDreaming = mDreamManager.isDreaming();
          } else {
              isDreaming = false;
          }
  
          // At this point, we either attempted to start the dream or no attempt will be made,
          // so stop holding the display suspend blocker for Doze.
          mDozeStartInProgress = false;
  
          // Update dream state.
          synchronized (mLock) {
              // Remember the initial battery level when the dream started.
              if (startDreaming && isDreaming) {
                  mBatteryLevelWhenDreamStarted = mBatteryLevel;
                  if (wakefulness == WAKEFULNESS_DOZING) {
                      Slog.i(TAG, "Dozing...");
                  } else {
                      Slog.i(TAG, "Dreaming...");
                  }
              }
  
              // If preconditions changed, wait for the next iteration to determine
              // whether the dream should continue (or be restarted).
              if (mSandmanSummoned || mWakefulness != wakefulness) {
                  return; // wait for next cycle
              }
  
              // Determine whether the dream should continue.
              if (wakefulness == WAKEFULNESS_DREAMING) {
                  if (isDreaming && canDreamLocked()) {
                      if (mDreamsBatteryLevelDrainCutoffConfig >= 0
                              && mBatteryLevel < mBatteryLevelWhenDreamStarted
                                      - mDreamsBatteryLevelDrainCutoffConfig
                              && !isBeingKeptAwakeLocked()) {
                          // If the user activity timeout expired and the battery appears
                          // to be draining faster than it is charging then stop dreaming
                          // and go to sleep.
                          Slog.i(TAG, "Stopping dream because the battery appears to "
                                  + "be draining faster than it is charging.  "
                                  + "Battery level when dream started: "
                                  + mBatteryLevelWhenDreamStarted + "%.  "
                                  + "Battery level now: " + mBatteryLevel + "%.");
                      } else {
                          return; // continue dreaming
                      }
                  }
  
                  // Dream has ended or will be stopped.  Update the power state.
                  if (isItBedTimeYetLocked()) {
                      goToSleepNoUpdateLocked(SystemClock.uptimeMillis(),
                              PowerManager.GO_TO_SLEEP_REASON_TIMEOUT, 0, Process.SYSTEM_UID);
                      updatePowerStateLocked();
                  } else {
                      wakeUpNoUpdateLocked(SystemClock.uptimeMillis(),
                              PowerManager.WAKE_REASON_UNKNOWN,
                              "android.server.power:DREAM_FINISHED", Process.SYSTEM_UID,
                              mContext.getOpPackageName(), Process.SYSTEM_UID);
                      updatePowerStateLocked();
                  }
              } else if (wakefulness == WAKEFULNESS_DOZING) {
                  if (isDreaming) {
                      return; // continue dozing
                  }
  
                  // Doze has ended or will be stopped.  Update the power state.
                  reallyGoToSleepNoUpdateLocked(SystemClock.uptimeMillis(), Process.SYSTEM_UID);
                  updatePowerStateLocked();
              }
          }
  
          // Stop dream.
          if (isDreaming) {
              mDreamManager.stopDream(false /*immediate*/);
          }
      }
  
      /**
       * Returns true if the device is allowed to dream in its current state.
       */
      private boolean canDreamLocked() {
          if (mWakefulness != WAKEFULNESS_DREAMING
                  || !mDreamsSupportedConfig
                  || !mDreamsEnabledSetting
                  || !mDisplayPowerRequest.isBrightOrDim()
                  || mDisplayPowerRequest.isVr()
                  || (mUserActivitySummary & (USER_ACTIVITY_SCREEN_BRIGHT
                          | USER_ACTIVITY_SCREEN_DIM | USER_ACTIVITY_SCREEN_DREAM)) == 0
                  || !mBootCompleted) {
              return false;
          }
          if (!isBeingKeptAwakeLocked()) {
              if (!mIsPowered && !mDreamsEnabledOnBatteryConfig) {
                  return false;
              }
              if (!mIsPowered
                      && mDreamsBatteryLevelMinimumWhenNotPoweredConfig >= 0
                      && mBatteryLevel < mDreamsBatteryLevelMinimumWhenNotPoweredConfig) {
                  return false;
              }
              if (mIsPowered
                      && mDreamsBatteryLevelMinimumWhenPoweredConfig >= 0
                      && mBatteryLevel < mDreamsBatteryLevelMinimumWhenPoweredConfig) {
                  return false;
              }
          }
          return true;
      }
  
      /**
       * Returns true if the device is allowed to doze in its current state.
       */
      private boolean canDozeLocked() {
          return mWakefulness == WAKEFULNESS_DOZING;
      }
  
      /**
       * Updates the display power state asynchronously.
       * When the update is finished, mDisplayReady will be set to true.  The display
       * controller posts a message to tell us when the actual display power state
       * has been updated so we come back here to double-check and finish up.
       *
       * This function recalculates the display power state each time.
       *
       * @return True if the display became ready.
       */
      private boolean updateDisplayPowerStateLocked(int dirty) {
          final boolean oldDisplayReady = mDisplayReady;
          if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_USER_ACTIVITY | DIRTY_WAKEFULNESS
                  | DIRTY_ACTUAL_DISPLAY_POWER_STATE_UPDATED | DIRTY_BOOT_COMPLETED
                  | DIRTY_SETTINGS | DIRTY_SCREEN_BRIGHTNESS_BOOST | DIRTY_VR_MODE_CHANGED |
                  DIRTY_QUIESCENT)) != 0) {
              mDisplayPowerRequest.policy = getDesiredScreenPolicyLocked();
  
              // Determine appropriate screen brightness and auto-brightness adjustments.
              final boolean autoBrightness;
              final int screenBrightnessOverride;
              if (!mBootCompleted) {
                  // Keep the brightness steady during boot. This requires the
                  // bootloader brightness and the default brightness to be identical.
                  autoBrightness = false;
                  screenBrightnessOverride = mScreenBrightnessSettingDefault;
              } else if (isValidBrightness(mScreenBrightnessOverrideFromWindowManager)) {
                  autoBrightness = false;
                  screenBrightnessOverride = mScreenBrightnessOverrideFromWindowManager;
              } else {
                  autoBrightness = (mScreenBrightnessModeSetting ==
                          Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC);
                  screenBrightnessOverride = -1;
              }
  
              // Update display power request.
              mDisplayPowerRequest.screenBrightnessOverride = screenBrightnessOverride;
              mDisplayPowerRequest.useAutoBrightness = autoBrightness;
              mDisplayPowerRequest.useProximitySensor = shouldUseProximitySensorLocked();
              mDisplayPowerRequest.boostScreenBrightness = shouldBoostScreenBrightness();
  
              updatePowerRequestFromBatterySaverPolicy(mDisplayPowerRequest);
  
              if (mDisplayPowerRequest.policy == DisplayPowerRequest.POLICY_DOZE) {
                  mDisplayPowerRequest.dozeScreenState = mDozeScreenStateOverrideFromDreamManager;
                  if ((mWakeLockSummary & WAKE_LOCK_DRAW) != 0
                          && !mDrawWakeLockOverrideFromSidekick) {
                      if (mDisplayPowerRequest.dozeScreenState == Display.STATE_DOZE_SUSPEND) {
                          mDisplayPowerRequest.dozeScreenState = Display.STATE_DOZE;
                      }
                      if (mDisplayPowerRequest.dozeScreenState == Display.STATE_ON_SUSPEND) {
                          mDisplayPowerRequest.dozeScreenState = Display.STATE_ON;
                      }
                  }
                  mDisplayPowerRequest.dozeScreenBrightness =
                          mDozeScreenBrightnessOverrideFromDreamManager;
              } else {
                  mDisplayPowerRequest.dozeScreenState = Display.STATE_UNKNOWN;
                  mDisplayPowerRequest.dozeScreenBrightness = PowerManager.BRIGHTNESS_DEFAULT;
              }
  
              mDisplayReady = mDisplayManagerInternal.requestPowerState(mDisplayPowerRequest,
                      mRequestWaitForNegativeProximity);
              mRequestWaitForNegativeProximity = false;
  
              if ((dirty & DIRTY_QUIESCENT) != 0) {
                  sQuiescent = false;
              }
              if (DEBUG_SPEW) {
                  Slog.d(TAG, "updateDisplayPowerStateLocked: mDisplayReady=" + mDisplayReady
                          + ", policy=" + mDisplayPowerRequest.policy
                          + ", mWakefulness=" + mWakefulness
                          + ", mWakeLockSummary=0x" + Integer.toHexString(mWakeLockSummary)
                          + ", mUserActivitySummary=0x" + Integer.toHexString(mUserActivitySummary)
                          + ", mBootCompleted=" + mBootCompleted
                          + ", screenBrightnessOverride=" + screenBrightnessOverride
                          + ", useAutoBrightness=" + autoBrightness
                          + ", mScreenBrightnessBoostInProgress=" + mScreenBrightnessBoostInProgress
                          + ", mIsVrModeEnabled= " + mIsVrModeEnabled
                          + ", sQuiescent=" + sQuiescent);
              }
          }
          return mDisplayReady && !oldDisplayReady;
      }
  
      private void updateScreenBrightnessBoostLocked(int dirty) {
          if ((dirty & DIRTY_SCREEN_BRIGHTNESS_BOOST) != 0) {
              if (mScreenBrightnessBoostInProgress) {
                  final long now = SystemClock.uptimeMillis();
                  mHandler.removeMessages(MSG_SCREEN_BRIGHTNESS_BOOST_TIMEOUT);
                  if (mLastScreenBrightnessBoostTime > mLastSleepTime) {
                      final long boostTimeout = mLastScreenBrightnessBoostTime +
                              SCREEN_BRIGHTNESS_BOOST_TIMEOUT;
                      if (boostTimeout > now) {
                          Message msg = mHandler.obtainMessage(MSG_SCREEN_BRIGHTNESS_BOOST_TIMEOUT);
                          msg.setAsynchronous(true);
                          mHandler.sendMessageAtTime(msg, boostTimeout);
                          return;
                      }
                  }
                  mScreenBrightnessBoostInProgress = false;
                  mNotifier.onScreenBrightnessBoostChanged();
                  userActivityNoUpdateLocked(now,
                          PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, Process.SYSTEM_UID);
              }
          }
      }
  
      private boolean shouldBoostScreenBrightness() {
          return !mIsVrModeEnabled && mScreenBrightnessBoostInProgress;
      }
  
      private static boolean isValidBrightness(int value) {
          return value >= 0 && value <= 255;
      }
  
      @VisibleForTesting
      int getDesiredScreenPolicyLocked() {
          if (mWakefulness == WAKEFULNESS_ASLEEP || sQuiescent) {
              return DisplayPowerRequest.POLICY_OFF;
          }
  
          if (mWakefulness == WAKEFULNESS_DOZING) {
              if ((mWakeLockSummary & WAKE_LOCK_DOZE) != 0) {
                  return DisplayPowerRequest.POLICY_DOZE;
              }
              if (mDozeAfterScreenOff) {
                  return DisplayPowerRequest.POLICY_OFF;
              }
              // Fall through and preserve the current screen policy if not configured to
              // doze after screen off.  This causes the screen off transition to be skipped.
          }
  
          // It is important that POLICY_VR check happens after the wakefulness checks above so
          // that VR-mode does not prevent displays from transitioning to the correct state when
          // dozing or sleeping.
          if (mIsVrModeEnabled) {
              return DisplayPowerRequest.POLICY_VR;
          }
  
          if ((mWakeLockSummary & WAKE_LOCK_SCREEN_BRIGHT) != 0
                  || (mUserActivitySummary & USER_ACTIVITY_SCREEN_BRIGHT) != 0
                  || !mBootCompleted
                  || mScreenBrightnessBoostInProgress) {
              return DisplayPowerRequest.POLICY_BRIGHT;
          }
  
          return DisplayPowerRequest.POLICY_DIM;
      }
  
      private final DisplayManagerInternal.DisplayPowerCallbacks mDisplayPowerCallbacks =
              new DisplayManagerInternal.DisplayPowerCallbacks() {
          private int mDisplayState = Display.STATE_UNKNOWN;
  
          @Override
          public void onStateChanged() {
              synchronized (mLock) {
                  mDirty |= DIRTY_ACTUAL_DISPLAY_POWER_STATE_UPDATED;
                  updatePowerStateLocked();
              }
          }
  
          @Override
          public void onProximityPositive() {
              synchronized (mLock) {
                  mProximityPositive = true;
                  mDirty |= DIRTY_PROXIMITY_POSITIVE;
                  updatePowerStateLocked();
              }
          }
  
          @Override
          public void onProximityNegative() {
              synchronized (mLock) {
                  mProximityPositive = false;
                  mDirty |= DIRTY_PROXIMITY_POSITIVE;
                  userActivityNoUpdateLocked(SystemClock.uptimeMillis(),
                          PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, Process.SYSTEM_UID);
                  updatePowerStateLocked();
              }
          }
  
          @Override
          public void onDisplayStateChange(int state) {
              // This method is only needed to support legacy display blanking behavior
              // where the display's power state is coupled to suspend or to the power HAL.
              // The order of operations matters here.
              synchronized (mLock) {
                  if (mDisplayState != state) {
                      mDisplayState = state;
                      if (state == Display.STATE_OFF) {
                          if (!mDecoupleHalInteractiveModeFromDisplayConfig) {
                              setHalInteractiveModeLocked(false);
                          }
                          if (mEnableAutoSuspendConfig
                                  && !mDecoupleHalAutoSuspendModeFromDisplayConfig) {
                              setHalAutoSuspendModeLocked(true);
                          }
                      } else {
                          if (!mDecoupleHalAutoSuspendModeFromDisplayConfig) {
                              setHalAutoSuspendModeLocked(false);
                          }
                          if (!mDecoupleHalInteractiveModeFromDisplayConfig) {
                              setHalInteractiveModeLocked(true);
                          }
                      }
                  }
              }
          }
  
          @Override
          public void acquireSuspendBlocker() {
              mDisplaySuspendBlocker.acquire();
          }
  
          @Override
          public void releaseSuspendBlocker() {
              mDisplaySuspendBlocker.release();
          }
  
          @Override
          public String toString() {
              synchronized (this) {
                  return "state=" + Display.stateToString(mDisplayState);
              }
          }
      };
  
      private boolean shouldUseProximitySensorLocked() {
          return !mIsVrModeEnabled && (mWakeLockSummary & WAKE_LOCK_PROXIMITY_SCREEN_OFF) != 0;
      }
  
      /**
       * Updates the suspend blocker that keeps the CPU alive.
       *
       * This function must have no other side-effects.
       */
      private void updateSuspendBlockerLocked() {
          final boolean needWakeLockSuspendBlocker = ((mWakeLockSummary & WAKE_LOCK_CPU) != 0);
          final boolean needDisplaySuspendBlocker = needDisplaySuspendBlockerLocked();
          final boolean autoSuspend = mEnableAutoSuspendConfig && !needDisplaySuspendBlocker;
          final boolean interactive = mDisplayPowerRequest.isBrightOrDim();
  
          // Disable auto-suspend if needed.
          // FIXME We should consider just leaving auto-suspend enabled forever since
          // we already hold the necessary wakelocks.
          if (!autoSuspend && mDecoupleHalAutoSuspendModeFromDisplayConfig) {
              setHalAutoSuspendModeLocked(false);
          }
  
          // First acquire suspend blockers if needed.
          if (needWakeLockSuspendBlocker && !mHoldingWakeLockSuspendBlocker) {
              mWakeLockSuspendBlocker.acquire();
              mHoldingWakeLockSuspendBlocker = true;
          }
          if (needDisplaySuspendBlocker && !mHoldingDisplaySuspendBlocker) {
              mDisplaySuspendBlocker.acquire();
              mHoldingDisplaySuspendBlocker = true;
          }
  
          // Inform the power HAL about interactive mode.
          // Although we could set interactive strictly based on the wakefulness
          // as reported by isInteractive(), it is actually more desirable to track
          // the display policy state instead so that the interactive state observed
          // by the HAL more accurately tracks transitions between AWAKE and DOZING.
          // Refer to getDesiredScreenPolicyLocked() for details.
          if (mDecoupleHalInteractiveModeFromDisplayConfig) {
              // When becoming non-interactive, we want to defer sending this signal
              // until the display is actually ready so that all transitions have
              // completed.  This is probably a good sign that things have gotten
              // too tangled over here...
              if (interactive || mDisplayReady) {
                  setHalInteractiveModeLocked(interactive);
              }
          }
  
          // Then release suspend blockers if needed.
          if (!needWakeLockSuspendBlocker && mHoldingWakeLockSuspendBlocker) {
              mWakeLockSuspendBlocker.release();
              mHoldingWakeLockSuspendBlocker = false;
          }
          if (!needDisplaySuspendBlocker && mHoldingDisplaySuspendBlocker) {
              mDisplaySuspendBlocker.release();
              mHoldingDisplaySuspendBlocker = false;
          }
  
          // Enable auto-suspend if needed.
          if (autoSuspend && mDecoupleHalAutoSuspendModeFromDisplayConfig) {
              setHalAutoSuspendModeLocked(true);
          }
      }
  
      /**
       * Return true if we must keep a suspend blocker active on behalf of the display.
       * We do so if the screen is on or is in transition between states.
       */
      private boolean needDisplaySuspendBlockerLocked() {
          if (!mDisplayReady) {
              return true;
          }
          if (mDisplayPowerRequest.isBrightOrDim()) {
              // If we asked for the screen to be on but it is off due to the proximity
              // sensor then we may suspend but only if the configuration allows it.
              // On some hardware it may not be safe to suspend because the proximity
              // sensor may not be correctly configured as a wake-up source.
              if (!mDisplayPowerRequest.useProximitySensor || !mProximityPositive
                      || !mSuspendWhenScreenOffDueToProximityConfig) {
                  return true;
              }
          }
  
          if (mDisplayPowerRequest.policy == DisplayPowerRequest.POLICY_DOZE
                  && mDisplayPowerRequest.dozeScreenState == Display.STATE_ON) {
              // Although we are in DOZE and would normally allow the device to suspend,
              // the doze service has explicitly requested the display to remain in the ON
              // state which means we should hold the display suspend blocker.
              return true;
          }
          if (mScreenBrightnessBoostInProgress) {
              return true;
          }
  
          // When we transition to DOZING, we have to keep the display suspend blocker
          // up until the Doze service has a change to acquire the DOZE wakelock.
          // Here we wait for mWakefulnessChanging to become false since the wakefulness
          // transition to DOZING isn't considered "changed" until the doze wake lock is
          // acquired.
          if (mWakefulness == WAKEFULNESS_DOZING && mDozeStartInProgress) {
              return true;
          }
  
          // Let the system suspend if the screen is off or dozing.
          return false;
      }
  
      private void setHalAutoSuspendModeLocked(boolean enable) {
          if (enable != mHalAutoSuspendModeEnabled) {
              if (DEBUG) {
                  Slog.d(TAG, "Setting HAL auto-suspend mode to " + enable);
              }
              mHalAutoSuspendModeEnabled = enable;
              Trace.traceBegin(Trace.TRACE_TAG_POWER, "setHalAutoSuspend(" + enable + ")");
              try {
                  mNativeWrapper.nativeSetAutoSuspend(enable);
              } finally {
                  Trace.traceEnd(Trace.TRACE_TAG_POWER);
              }
          }
      }
  
      private void setHalInteractiveModeLocked(boolean enable) {
          if (enable != mHalInteractiveModeEnabled) {
              if (DEBUG) {
                  Slog.d(TAG, "Setting HAL interactive mode to " + enable);
              }
              mHalInteractiveModeEnabled = enable;
              Trace.traceBegin(Trace.TRACE_TAG_POWER, "setHalInteractive(" + enable + ")");
              try {
                  mNativeWrapper.nativeSetInteractive(enable);
              } finally {
                  Trace.traceEnd(Trace.TRACE_TAG_POWER);
              }
          }
      }
  
      private boolean isInteractiveInternal() {
          synchronized (mLock) {
              return PowerManagerInternal.isInteractive(mWakefulness);
          }
      }
  
      private boolean setLowPowerModeInternal(boolean enabled) {
          synchronized (mLock) {
              if (DEBUG) {
                  Slog.d(TAG, "setLowPowerModeInternal " + enabled + " mIsPowered=" + mIsPowered);
              }
              if (mIsPowered) {
                  return false;
              }
  
              mBatterySaverStateMachine.setBatterySaverEnabledManually(enabled);
  
              return true;
          }
      }
  
      boolean isDeviceIdleModeInternal() {
          synchronized (mLock) {
              return mDeviceIdleMode;
          }
      }
  
      boolean isLightDeviceIdleModeInternal() {
          synchronized (mLock) {
              return mLightDeviceIdleMode;
          }
      }
  
      private void handleBatteryStateChangedLocked() {
          mDirty |= DIRTY_BATTERY_STATE;
          updatePowerStateLocked();
      }
  
      private void shutdownOrRebootInternal(final @HaltMode int haltMode, final boolean confirm,
              final String reason, boolean wait) {
          if (mHandler == null || !mSystemReady) {
              if (RescueParty.isAttemptingFactoryReset()) {
                  // If we're stuck in a really low-level reboot loop, and a
                  // rescue party is trying to prompt the user for a factory data
                  // reset, we must GET TO DA CHOPPA!
                  PowerManagerService.lowLevelReboot(reason);
              } else {
                  throw new IllegalStateException("Too early to call shutdown() or reboot()");
              }
          }
  
          Runnable runnable = new Runnable() {
              @Override
              public void run() {
                  synchronized (this) {
                      if (haltMode == HALT_MODE_REBOOT_SAFE_MODE) {
                          ShutdownThread.rebootSafeMode(getUiContext(), confirm);
                      } else if (haltMode == HALT_MODE_REBOOT) {
                          ShutdownThread.reboot(getUiContext(), reason, confirm);
                      } else {
                          ShutdownThread.shutdown(getUiContext(), reason, confirm);
                      }
                  }
              }
          };
  
          // ShutdownThread must run on a looper capable of displaying the UI.
          Message msg = Message.obtain(UiThread.getHandler(), runnable);
          msg.setAsynchronous(true);
          UiThread.getHandler().sendMessage(msg);
  
          // PowerManager.reboot() is documented not to return so just wait for the inevitable.
          if (wait) {
              synchronized (runnable) {
                  while (true) {
                      try {
                          runnable.wait();
                      } catch (InterruptedException e) {
                      }
                  }
              }
          }
      }
  
      private void crashInternal(final String message) {
          Thread t = new Thread("PowerManagerService.crash()") {
              @Override
              public void run() {
                  throw new RuntimeException(message);
              }
          };
          try {
              t.start();
              t.join();
          } catch (InterruptedException e) {
              Slog.wtf(TAG, e);
          }
      }
  
      @VisibleForTesting
      void updatePowerRequestFromBatterySaverPolicy(DisplayPowerRequest displayPowerRequest) {
          PowerSaveState state = mBatterySaverPolicy.
                  getBatterySaverPolicy(ServiceType.SCREEN_BRIGHTNESS);
          displayPowerRequest.lowPowerMode = state.batterySaverEnabled;
          displayPowerRequest.screenLowPowerBrightnessFactor = state.brightnessFactor;
      }
  
      void setStayOnSettingInternal(int val) {
          Settings.Global.putInt(mContext.getContentResolver(),
                  Settings.Global.STAY_ON_WHILE_PLUGGED_IN, val);
      }
  
      void setMaximumScreenOffTimeoutFromDeviceAdminInternal(@UserIdInt int userId, long timeMs) {
          if (userId < 0) {
              Slog.wtf(TAG, "Attempt to set screen off timeout for invalid user: " + userId);
              return;
          }
          synchronized (mLock) {
              // System-wide timeout
              if (userId == UserHandle.USER_SYSTEM) {
                  mMaximumScreenOffTimeoutFromDeviceAdmin = timeMs;
              } else if (timeMs == Long.MAX_VALUE || timeMs == 0) {
                  mProfilePowerState.delete(userId);
              } else {
                  final ProfilePowerState profile = mProfilePowerState.get(userId);
                  if (profile != null) {
                      profile.mScreenOffTimeout = timeMs;
                  } else {
                      mProfilePowerState.put(userId, new ProfilePowerState(userId, timeMs));
                      // We need to recalculate wake locks for the new profile state.
                      mDirty |= DIRTY_WAKE_LOCKS;
                  }
              }
              mDirty |= DIRTY_SETTINGS;
              updatePowerStateLocked();
          }
      }
  
      boolean setDeviceIdleModeInternal(boolean enabled) {
          synchronized (mLock) {
              if (mDeviceIdleMode == enabled) {
                  return false;
              }
              mDeviceIdleMode = enabled;
              updateWakeLockDisabledStatesLocked();
          }
          if (enabled) {
              EventLogTags.writeDeviceIdleOnPhase("power");
          } else {
              EventLogTags.writeDeviceIdleOffPhase("power");
          }
          return true;
      }
  
      boolean setLightDeviceIdleModeInternal(boolean enabled) {
          synchronized (mLock) {
              if (mLightDeviceIdleMode != enabled) {
                  mLightDeviceIdleMode = enabled;
                  return true;
              }
              return false;
          }
      }
  
      void setDeviceIdleWhitelistInternal(int[] appids) {
          synchronized (mLock) {
              mDeviceIdleWhitelist = appids;
              if (mDeviceIdleMode) {
                  updateWakeLockDisabledStatesLocked();
              }
          }
      }
  
      void setDeviceIdleTempWhitelistInternal(int[] appids) {
          synchronized (mLock) {
              mDeviceIdleTempWhitelist = appids;
              if (mDeviceIdleMode) {
                  updateWakeLockDisabledStatesLocked();
              }
          }
      }
  
      void startUidChangesInternal() {
          synchronized (mLock) {
              mUidsChanging = true;
          }
      }
  
      void finishUidChangesInternal() {
          synchronized (mLock) {
              mUidsChanging = false;
              if (mUidsChanged) {
                  updateWakeLockDisabledStatesLocked();
                  mUidsChanged = false;
              }
          }
      }
  
      private void handleUidStateChangeLocked() {
          if (mUidsChanging) {
              mUidsChanged = true;
          } else {
              updateWakeLockDisabledStatesLocked();
          }
      }
  
      void updateUidProcStateInternal(int uid, int procState) {
          synchronized (mLock) {
              UidState state = mUidState.get(uid);
              if (state == null) {
                  state = new UidState(uid);
                  mUidState.put(uid, state);
              }
              final boolean oldShouldAllow = state.mProcState
                      <= ActivityManager.PROCESS_STATE_RECEIVER;
              state.mProcState = procState;
              if (state.mNumWakeLocks > 0) {
                  if (mDeviceIdleMode) {
                      handleUidStateChangeLocked();
                  } else if (!state.mActive && oldShouldAllow !=
                          (procState <= ActivityManager.PROCESS_STATE_RECEIVER)) {
                      // If this uid is not active, but the process state has changed such
                      // that we may still want to allow it to hold a wake lock, then take care of it.
                      handleUidStateChangeLocked();
                  }
              }
          }
      }
  
      void uidGoneInternal(int uid) {
          synchronized (mLock) {
              final int index = mUidState.indexOfKey(uid);
              if (index >= 0) {
                  UidState state = mUidState.valueAt(index);
                  state.mProcState = ActivityManager.PROCESS_STATE_NONEXISTENT;
                  state.mActive = false;
                  mUidState.removeAt(index);
                  if (mDeviceIdleMode && state.mNumWakeLocks > 0) {
                      handleUidStateChangeLocked();
                  }
              }
          }
      }
  
      void uidActiveInternal(int uid) {
          synchronized (mLock) {
              UidState state = mUidState.get(uid);
              if (state == null) {
                  state = new UidState(uid);
                  state.mProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;
                  mUidState.put(uid, state);
              }
              state.mActive = true;
              if (state.mNumWakeLocks > 0) {
                  handleUidStateChangeLocked();
              }
          }
      }
  
      void uidIdleInternal(int uid) {
          synchronized (mLock) {
              UidState state = mUidState.get(uid);
              if (state != null) {
                  state.mActive = false;
                  if (state.mNumWakeLocks > 0) {
                      handleUidStateChangeLocked();
                  }
              }
          }
      }
  
      private void updateWakeLockDisabledStatesLocked() {
          boolean changed = false;
          final int numWakeLocks = mWakeLocks.size();
          for (int i = 0; i < numWakeLocks; i++) {
              final WakeLock wakeLock = mWakeLocks.get(i);
              if ((wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK)
                      == PowerManager.PARTIAL_WAKE_LOCK) {
                  if (setWakeLockDisabledStateLocked(wakeLock)) {
                      changed = true;
                      if (wakeLock.mDisabled) {
                          // This wake lock is no longer being respected.
                          notifyWakeLockReleasedLocked(wakeLock);
                      } else {
                          notifyWakeLockAcquiredLocked(wakeLock);
                      }
                  }
              }
          }
          if (changed) {
              mDirty |= DIRTY_WAKE_LOCKS;
              updatePowerStateLocked();
          }
      }
  
      private boolean setWakeLockDisabledStateLocked(WakeLock wakeLock) {
          if ((wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK)
                  == PowerManager.PARTIAL_WAKE_LOCK) {
              boolean disabled = false;
              final int appid = UserHandle.getAppId(wakeLock.mOwnerUid);
              if (appid >= Process.FIRST_APPLICATION_UID) {
                  // Cached inactive processes are never allowed to hold wake locks.
                  if (mConstants.NO_CACHED_WAKE_LOCKS) {
                      disabled = mForceSuspendActive
                              || (!wakeLock.mUidState.mActive && wakeLock.mUidState.mProcState
                                      != ActivityManager.PROCESS_STATE_NONEXISTENT &&
                              wakeLock.mUidState.mProcState > ActivityManager.PROCESS_STATE_RECEIVER);
                  }
                  if (mDeviceIdleMode) {
                      // If we are in idle mode, we will also ignore all partial wake locks that are
                      // for application uids that are not whitelisted.
                      final UidState state = wakeLock.mUidState;
                      if (Arrays.binarySearch(mDeviceIdleWhitelist, appid) < 0 &&
                              Arrays.binarySearch(mDeviceIdleTempWhitelist, appid) < 0 &&
                              state.mProcState != ActivityManager.PROCESS_STATE_NONEXISTENT &&
                              state.mProcState >
                                      ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE) {
                          disabled = true;
                      }
                  }
              }
              if (wakeLock.mDisabled != disabled) {
                  wakeLock.mDisabled = disabled;
                  return true;
              }
          }
          return false;
      }
  
      private boolean isMaximumScreenOffTimeoutFromDeviceAdminEnforcedLocked() {
          return mMaximumScreenOffTimeoutFromDeviceAdmin >= 0
                  && mMaximumScreenOffTimeoutFromDeviceAdmin < Long.MAX_VALUE;
      }
  
      private void setAttentionLightInternal(boolean on, int color) {
          Light light;
          synchronized (mLock) {
              if (!mSystemReady) {
                  return;
              }
              light = mAttentionLight;
          }
  
          // Control light outside of lock.
          light.setFlashing(color, Light.LIGHT_FLASH_HARDWARE, (on ? 3 : 0), 0);
      }
  
      private void setDozeAfterScreenOffInternal(boolean on) {
          synchronized (mLock) {
              mDozeAfterScreenOff = on;
          }
      }
  
      private void boostScreenBrightnessInternal(long eventTime, int uid) {
          synchronized (mLock) {
              if (!mSystemReady || mWakefulness == WAKEFULNESS_ASLEEP
                      || eventTime < mLastScreenBrightnessBoostTime) {
                  return;
              }
  
              Slog.i(TAG, "Brightness boost activated (uid " + uid +")...");
              mLastScreenBrightnessBoostTime = eventTime;
              if (!mScreenBrightnessBoostInProgress) {
                  mScreenBrightnessBoostInProgress = true;
                  mNotifier.onScreenBrightnessBoostChanged();
              }
              mDirty |= DIRTY_SCREEN_BRIGHTNESS_BOOST;
  
              userActivityNoUpdateLocked(eventTime,
                      PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, uid);
              updatePowerStateLocked();
          }
      }
  
      private boolean isScreenBrightnessBoostedInternal() {
          synchronized (mLock) {
              return mScreenBrightnessBoostInProgress;
          }
      }
  
      /**
       * Called when a screen brightness boost timeout has occurred.
       *
       * This function must have no other side-effects besides setting the dirty
       * bit and calling update power state.
       */
      private void handleScreenBrightnessBoostTimeout() { // runs on handler thread
          synchronized (mLock) {
              if (DEBUG_SPEW) {
                  Slog.d(TAG, "handleScreenBrightnessBoostTimeout");
              }
  
              mDirty |= DIRTY_SCREEN_BRIGHTNESS_BOOST;
              updatePowerStateLocked();
          }
      }
  
      private void setScreenBrightnessOverrideFromWindowManagerInternal(int brightness) {
          synchronized (mLock) {
              if (mScreenBrightnessOverrideFromWindowManager != brightness) {
                  mScreenBrightnessOverrideFromWindowManager = brightness;
                  mDirty |= DIRTY_SETTINGS;
                  updatePowerStateLocked();
              }
          }
      }
  
      private void setUserInactiveOverrideFromWindowManagerInternal() {
          synchronized (mLock) {
              mUserInactiveOverrideFromWindowManager = true;
              mDirty |= DIRTY_USER_ACTIVITY;
              updatePowerStateLocked();
          }
      }
  
      private void setUserActivityTimeoutOverrideFromWindowManagerInternal(long timeoutMillis) {
          synchronized (mLock) {
              if (mUserActivityTimeoutOverrideFromWindowManager != timeoutMillis) {
                  mUserActivityTimeoutOverrideFromWindowManager = timeoutMillis;
                  EventLogTags.writeUserActivityTimeoutOverride(timeoutMillis);
                  mDirty |= DIRTY_SETTINGS;
                  updatePowerStateLocked();
              }
          }
      }
  
      private void setDozeOverrideFromDreamManagerInternal(
              int screenState, int screenBrightness) {
          synchronized (mLock) {
              if (mDozeScreenStateOverrideFromDreamManager != screenState
                      || mDozeScreenBrightnessOverrideFromDreamManager != screenBrightness) {
                  mDozeScreenStateOverrideFromDreamManager = screenState;
                  mDozeScreenBrightnessOverrideFromDreamManager = screenBrightness;
                  mDirty |= DIRTY_SETTINGS;
                  updatePowerStateLocked();
              }
          }
      }
  
      private void setDrawWakeLockOverrideFromSidekickInternal(boolean keepState) {
          synchronized (mLock) {
              if (mDrawWakeLockOverrideFromSidekick != keepState) {
                  mDrawWakeLockOverrideFromSidekick = keepState;
                  mDirty |= DIRTY_SETTINGS;
                  updatePowerStateLocked();
              }
          }
      }
  
      @VisibleForTesting
      void setVrModeEnabled(boolean enabled) {
          mIsVrModeEnabled = enabled;
      }
  
      private void powerHintInternal(int hintId, int data) {
          // Maybe filter the event.
          switch (hintId) {
              case PowerHint.LAUNCH: // 1: activate launch boost 0: deactivate.
                  if (data == 1 && mBatterySaverController.isLaunchBoostDisabled()) {
                      return;
                  }
                  break;
          }
  
          mNativeWrapper.nativeSendPowerHint(hintId, data);
      }
  
      @VisibleForTesting
      boolean wasDeviceIdleForInternal(long ms) {
          synchronized (mLock) {
              return mLastUserActivityTime + ms < SystemClock.uptimeMillis();
          }
      }
  
      @VisibleForTesting
      void onUserActivity() {
          synchronized (mLock) {
              mLastUserActivityTime = SystemClock.uptimeMillis();
          }
      }
  
      private boolean forceSuspendInternal(int uid) {
          try {
              synchronized (mLock) {
                  mForceSuspendActive = true;
                  // Place the system in an non-interactive state
                  goToSleepInternal(SystemClock.uptimeMillis(),
                          PowerManager.GO_TO_SLEEP_REASON_FORCE_SUSPEND,
                          PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE, uid);
  
                  // Disable all the partial wake locks as well
                  updateWakeLockDisabledStatesLocked();
              }
  
              Slog.i(TAG, "Force-Suspending (uid " + uid + ")...");
              boolean success = mNativeWrapper.nativeForceSuspend();
              if (!success) {
                  Slog.i(TAG, "Force-Suspending failed in native.");
              }
              return success;
          } finally {
              synchronized (mLock) {
                  mForceSuspendActive = false;
                  // Re-enable wake locks once again.
                  updateWakeLockDisabledStatesLocked();
              }
          }
      }
  
      /**
       * Low-level function turn the device off immediately, without trying
       * to be clean.  Most people should use {@link ShutdownThread} for a clean shutdown.
       *
       * @param reason code to pass to android_reboot() (e.g. "userrequested"), or null.
       */
      public static void lowLevelShutdown(String reason) {
          if (reason == null) {
              reason = "";
          }
          SystemProperties.set("sys.powerctl", "shutdown," + reason);
      }
  
      /**
       * Low-level function to reboot the device. On success, this
       * function doesn't return. If more than 20 seconds passes from
       * the time a reboot is requested, this method returns.
       *
       * @param reason code to pass to the kernel (e.g. "recovery"), or null.
       */
      public static void lowLevelReboot(String reason) {
          if (reason == null) {
              reason = "";
          }
  
          // If the reason is "quiescent", it means that the boot process should proceed
          // without turning on the screen/lights.
          // The "quiescent" property is sticky, meaning that any number
          // of subsequent reboots should honor the property until it is reset.
          if (reason.equals(PowerManager.REBOOT_QUIESCENT)) {
              sQuiescent = true;
              reason = "";
          } else if (reason.endsWith("," + PowerManager.REBOOT_QUIESCENT)) {
              sQuiescent = true;
              reason = reason.substring(0,
                      reason.length() - PowerManager.REBOOT_QUIESCENT.length() - 1);
          }
  
          if (reason.equals(PowerManager.REBOOT_RECOVERY)
                  || reason.equals(PowerManager.REBOOT_RECOVERY_UPDATE)) {
              reason = "recovery";
          }
  
          if (sQuiescent) {
              // Pass the optional "quiescent" argument to the bootloader to let it know
              // that it should not turn the screen/lights on.
              reason = reason + ",quiescent";
          }
  
          SystemProperties.set("sys.powerctl", "reboot," + reason);
          try {
              Thread.sleep(20 * 1000L);
          } catch (InterruptedException e) {
              Thread.currentThread().interrupt();
          }
          Slog.wtf(TAG, "Unexpected return from lowLevelReboot!");
      }
  
      @Override // Watchdog.Monitor implementation
      public void monitor() {
          // Grab and release lock for watchdog monitor to detect deadlocks.
          synchronized (mLock) {
          }
      }
  
      private void dumpInternal(PrintWriter pw) {
          pw.println("POWER MANAGER (dumpsys power)\n");
  
          final WirelessChargerDetector wcd;
          synchronized (mLock) {
              pw.println("Power Manager State:");
              mConstants.dump(pw);
              pw.println("  mDirty=0x" + Integer.toHexString(mDirty));
              pw.println("  mWakefulness=" + PowerManagerInternal.wakefulnessToString(mWakefulness));
              pw.println("  mWakefulnessChanging=" + mWakefulnessChanging);
              pw.println("  mIsPowered=" + mIsPowered);
              pw.println("  mPlugType=" + mPlugType);
              pw.println("  mBatteryLevel=" + mBatteryLevel);
              pw.println("  mBatteryLevelWhenDreamStarted=" + mBatteryLevelWhenDreamStarted);
              pw.println("  mDockState=" + mDockState);
              pw.println("  mStayOn=" + mStayOn);
              pw.println("  mProximityPositive=" + mProximityPositive);
              pw.println("  mBootCompleted=" + mBootCompleted);
              pw.println("  mSystemReady=" + mSystemReady);
              pw.println("  mHalAutoSuspendModeEnabled=" + mHalAutoSuspendModeEnabled);
              pw.println("  mHalInteractiveModeEnabled=" + mHalInteractiveModeEnabled);
              pw.println("  mWakeLockSummary=0x" + Integer.toHexString(mWakeLockSummary));
              pw.print("  mNotifyLongScheduled=");
              if (mNotifyLongScheduled == 0) {
                  pw.print("(none)");
              } else {
                  TimeUtils.formatDuration(mNotifyLongScheduled, SystemClock.uptimeMillis(), pw);
              }
              pw.println();
              pw.print("  mNotifyLongDispatched=");
              if (mNotifyLongDispatched == 0) {
                  pw.print("(none)");
              } else {
                  TimeUtils.formatDuration(mNotifyLongDispatched, SystemClock.uptimeMillis(), pw);
              }
              pw.println();
              pw.print("  mNotifyLongNextCheck=");
              if (mNotifyLongNextCheck == 0) {
                  pw.print("(none)");
              } else {
                  TimeUtils.formatDuration(mNotifyLongNextCheck, SystemClock.uptimeMillis(), pw);
              }
              pw.println();
              pw.println("  mUserActivitySummary=0x" + Integer.toHexString(mUserActivitySummary));
              pw.println("  mRequestWaitForNegativeProximity=" + mRequestWaitForNegativeProximity);
              pw.println("  mSandmanScheduled=" + mSandmanScheduled);
              pw.println("  mSandmanSummoned=" + mSandmanSummoned);
              pw.println("  mBatteryLevelLow=" + mBatteryLevelLow);
              pw.println("  mLightDeviceIdleMode=" + mLightDeviceIdleMode);
              pw.println("  mDeviceIdleMode=" + mDeviceIdleMode);
              pw.println("  mDeviceIdleWhitelist=" + Arrays.toString(mDeviceIdleWhitelist));
              pw.println("  mDeviceIdleTempWhitelist=" + Arrays.toString(mDeviceIdleTempWhitelist));
              pw.println("  mLastWakeTime=" + TimeUtils.formatUptime(mLastWakeTime));
              pw.println("  mLastSleepTime=" + TimeUtils.formatUptime(mLastSleepTime));
              pw.println("  mLastSleepReason=" + PowerManager.sleepReasonToString(mLastSleepReason));
              pw.println("  mLastUserActivityTime=" + TimeUtils.formatUptime(mLastUserActivityTime));
              pw.println("  mLastUserActivityTimeNoChangeLights="
                      + TimeUtils.formatUptime(mLastUserActivityTimeNoChangeLights));
              pw.println("  mLastInteractivePowerHintTime="
                      + TimeUtils.formatUptime(mLastInteractivePowerHintTime));
              pw.println("  mLastScreenBrightnessBoostTime="
                      + TimeUtils.formatUptime(mLastScreenBrightnessBoostTime));
              pw.println("  mScreenBrightnessBoostInProgress="
                      + mScreenBrightnessBoostInProgress);
              pw.println("  mDisplayReady=" + mDisplayReady);
              pw.println("  mHoldingWakeLockSuspendBlocker=" + mHoldingWakeLockSuspendBlocker);
              pw.println("  mHoldingDisplaySuspendBlocker=" + mHoldingDisplaySuspendBlocker);
  
              pw.println();
              pw.println("Settings and Configuration:");
              pw.println("  mDecoupleHalAutoSuspendModeFromDisplayConfig="
                      + mDecoupleHalAutoSuspendModeFromDisplayConfig);
              pw.println("  mDecoupleHalInteractiveModeFromDisplayConfig="
                      + mDecoupleHalInteractiveModeFromDisplayConfig);
              pw.println("  mWakeUpWhenPluggedOrUnpluggedConfig="
                      + mWakeUpWhenPluggedOrUnpluggedConfig);
              pw.println("  mWakeUpWhenPluggedOrUnpluggedInTheaterModeConfig="
                      + mWakeUpWhenPluggedOrUnpluggedInTheaterModeConfig);
              pw.println("  mTheaterModeEnabled="
                      + mTheaterModeEnabled);
              pw.println("  mSuspendWhenScreenOffDueToProximityConfig="
                      + mSuspendWhenScreenOffDueToProximityConfig);
              pw.println("  mDreamsSupportedConfig=" + mDreamsSupportedConfig);
              pw.println("  mDreamsEnabledByDefaultConfig=" + mDreamsEnabledByDefaultConfig);
              pw.println("  mDreamsActivatedOnSleepByDefaultConfig="
                      + mDreamsActivatedOnSleepByDefaultConfig);
              pw.println("  mDreamsActivatedOnDockByDefaultConfig="
                      + mDreamsActivatedOnDockByDefaultConfig);
              pw.println("  mDreamsEnabledOnBatteryConfig="
                      + mDreamsEnabledOnBatteryConfig);
              pw.println("  mDreamsBatteryLevelMinimumWhenPoweredConfig="
                      + mDreamsBatteryLevelMinimumWhenPoweredConfig);
              pw.println("  mDreamsBatteryLevelMinimumWhenNotPoweredConfig="
                      + mDreamsBatteryLevelMinimumWhenNotPoweredConfig);
              pw.println("  mDreamsBatteryLevelDrainCutoffConfig="
                      + mDreamsBatteryLevelDrainCutoffConfig);
              pw.println("  mDreamsEnabledSetting=" + mDreamsEnabledSetting);
              pw.println("  mDreamsActivateOnSleepSetting=" + mDreamsActivateOnSleepSetting);
              pw.println("  mDreamsActivateOnDockSetting=" + mDreamsActivateOnDockSetting);
              pw.println("  mDozeAfterScreenOff=" + mDozeAfterScreenOff);
              pw.println("  mMinimumScreenOffTimeoutConfig=" + mMinimumScreenOffTimeoutConfig);
              pw.println("  mMaximumScreenDimDurationConfig=" + mMaximumScreenDimDurationConfig);
              pw.println("  mMaximumScreenDimRatioConfig=" + mMaximumScreenDimRatioConfig);
              pw.println("  mScreenOffTimeoutSetting=" + mScreenOffTimeoutSetting);
              pw.println("  mSleepTimeoutSetting=" + mSleepTimeoutSetting);
              pw.println("  mMaximumScreenOffTimeoutFromDeviceAdmin="
                      + mMaximumScreenOffTimeoutFromDeviceAdmin + " (enforced="
                      + isMaximumScreenOffTimeoutFromDeviceAdminEnforcedLocked() + ")");
              pw.println("  mStayOnWhilePluggedInSetting=" + mStayOnWhilePluggedInSetting);
              pw.println("  mScreenBrightnessSetting=" + mScreenBrightnessSetting);
              pw.println("  mScreenBrightnessModeSetting=" + mScreenBrightnessModeSetting);
              pw.println("  mScreenBrightnessOverrideFromWindowManager="
                      + mScreenBrightnessOverrideFromWindowManager);
              pw.println("  mUserActivityTimeoutOverrideFromWindowManager="
                      + mUserActivityTimeoutOverrideFromWindowManager);
              pw.println("  mUserInactiveOverrideFromWindowManager="
                      + mUserInactiveOverrideFromWindowManager);
              pw.println("  mDozeScreenStateOverrideFromDreamManager="
                      + mDozeScreenStateOverrideFromDreamManager);
              pw.println("  mDrawWakeLockOverrideFromSidekick=" + mDrawWakeLockOverrideFromSidekick);
              pw.println("  mDozeScreenBrightnessOverrideFromDreamManager="
                      + mDozeScreenBrightnessOverrideFromDreamManager);
              pw.println("  mScreenBrightnessSettingMinimum=" + mScreenBrightnessSettingMinimum);
              pw.println("  mScreenBrightnessSettingMaximum=" + mScreenBrightnessSettingMaximum);
              pw.println("  mScreenBrightnessSettingDefault=" + mScreenBrightnessSettingDefault);
              pw.println("  mDoubleTapWakeEnabled=" + mDoubleTapWakeEnabled);
              pw.println("  mIsVrModeEnabled=" + mIsVrModeEnabled);
              pw.println("  mForegroundProfile=" + mForegroundProfile);
  
              final long sleepTimeout = getSleepTimeoutLocked();
              final long screenOffTimeout = getScreenOffTimeoutLocked(sleepTimeout);
              final long screenDimDuration = getScreenDimDurationLocked(screenOffTimeout);
              pw.println();
              pw.println("Sleep timeout: " + sleepTimeout + " ms");
              pw.println("Screen off timeout: " + screenOffTimeout + " ms");
              pw.println("Screen dim duration: " + screenDimDuration + " ms");
  
              pw.println();
              pw.print("UID states (changing=");
              pw.print(mUidsChanging);
              pw.print(" changed=");
              pw.print(mUidsChanged);
              pw.println("):");
              for (int i=0; i<mUidState.size(); i++) {
                  final UidState state = mUidState.valueAt(i);
                  pw.print("  UID "); UserHandle.formatUid(pw, mUidState.keyAt(i));
                  pw.print(": ");
                  if (state.mActive) pw.print("  ACTIVE ");
                  else pw.print("INACTIVE ");
                  pw.print(" count=");
                  pw.print(state.mNumWakeLocks);
                  pw.print(" state=");
                  pw.println(state.mProcState);
              }
  
              pw.println();
              pw.println("Looper state:");
              mHandler.getLooper().dump(new PrintWriterPrinter(pw), "  ");
  
              pw.println();
              pw.println("Wake Locks: size=" + mWakeLocks.size());
              for (WakeLock wl : mWakeLocks) {
                  pw.println("  " + wl);
              }
  
              pw.println();
              pw.println("Suspend Blockers: size=" + mSuspendBlockers.size());
              for (SuspendBlocker sb : mSuspendBlockers) {
                  pw.println("  " + sb);
              }
  
              pw.println();
              pw.println("Display Power: " + mDisplayPowerCallbacks);
  
              mBatterySaverPolicy.dump(pw);
              mBatterySaverStateMachine.dump(pw);
              mAttentionDetector.dump(pw);
  
              pw.println();
              final int numProfiles = mProfilePowerState.size();
              pw.println("Profile power states: size=" + numProfiles);
              for (int i = 0; i < numProfiles; i++) {
                  final ProfilePowerState profile = mProfilePowerState.valueAt(i);
                  pw.print("  mUserId=");
                  pw.print(profile.mUserId);
                  pw.print(" mScreenOffTimeout=");
                  pw.print(profile.mScreenOffTimeout);
                  pw.print(" mWakeLockSummary=");
                  pw.print(profile.mWakeLockSummary);
                  pw.print(" mLastUserActivityTime=");
                  pw.print(profile.mLastUserActivityTime);
                  pw.print(" mLockingNotified=");
                  pw.println(profile.mLockingNotified);
              }
  
              wcd = mWirelessChargerDetector;
          }
  
          if (wcd != null) {
              wcd.dump(pw);
          }
      }
  
      private void dumpProto(FileDescriptor fd) {
          final WirelessChargerDetector wcd;
          final ProtoOutputStream proto = new ProtoOutputStream(fd);
  
          synchronized (mLock) {
              mConstants.dumpProto(proto);
              proto.write(PowerManagerServiceDumpProto.DIRTY, mDirty);
              proto.write(PowerManagerServiceDumpProto.WAKEFULNESS, mWakefulness);
              proto.write(PowerManagerServiceDumpProto.IS_WAKEFULNESS_CHANGING, mWakefulnessChanging);
              proto.write(PowerManagerServiceDumpProto.IS_POWERED, mIsPowered);
              proto.write(PowerManagerServiceDumpProto.PLUG_TYPE, mPlugType);
              proto.write(PowerManagerServiceDumpProto.BATTERY_LEVEL, mBatteryLevel);
              proto.write(
                      PowerManagerServiceDumpProto.BATTERY_LEVEL_WHEN_DREAM_STARTED,
                      mBatteryLevelWhenDreamStarted);
              proto.write(PowerManagerServiceDumpProto.DOCK_STATE, mDockState);
              proto.write(PowerManagerServiceDumpProto.IS_STAY_ON, mStayOn);
              proto.write(PowerManagerServiceDumpProto.IS_PROXIMITY_POSITIVE, mProximityPositive);
              proto.write(PowerManagerServiceDumpProto.IS_BOOT_COMPLETED, mBootCompleted);
              proto.write(PowerManagerServiceDumpProto.IS_SYSTEM_READY, mSystemReady);
              proto.write(
                      PowerManagerServiceDumpProto.IS_HAL_AUTO_SUSPEND_MODE_ENABLED,
                      mHalAutoSuspendModeEnabled);
              proto.write(
                      PowerManagerServiceDumpProto.IS_HAL_AUTO_INTERACTIVE_MODE_ENABLED,
                      mHalInteractiveModeEnabled);
  
              final long activeWakeLocksToken = proto.start(PowerManagerServiceDumpProto.ACTIVE_WAKE_LOCKS);
              proto.write(
                      PowerManagerServiceDumpProto.ActiveWakeLocksProto.IS_CPU,
                      (mWakeLockSummary & WAKE_LOCK_CPU) != 0);
              proto.write(
                      PowerManagerServiceDumpProto.ActiveWakeLocksProto.IS_SCREEN_BRIGHT,
                      (mWakeLockSummary & WAKE_LOCK_SCREEN_BRIGHT) != 0);
              proto.write(
                      PowerManagerServiceDumpProto.ActiveWakeLocksProto.IS_SCREEN_DIM,
                      (mWakeLockSummary & WAKE_LOCK_SCREEN_DIM) != 0);
              proto.write(
                      PowerManagerServiceDumpProto.ActiveWakeLocksProto.IS_BUTTON_BRIGHT,
                      (mWakeLockSummary & WAKE_LOCK_BUTTON_BRIGHT) != 0);
              proto.write(
                      PowerManagerServiceDumpProto.ActiveWakeLocksProto.IS_PROXIMITY_SCREEN_OFF,
                      (mWakeLockSummary & WAKE_LOCK_PROXIMITY_SCREEN_OFF) != 0);
              proto.write(
                      PowerManagerServiceDumpProto.ActiveWakeLocksProto.IS_STAY_AWAKE,
                      (mWakeLockSummary & WAKE_LOCK_STAY_AWAKE) != 0);
              proto.write(
                      PowerManagerServiceDumpProto.ActiveWakeLocksProto.IS_DOZE,
                      (mWakeLockSummary & WAKE_LOCK_DOZE) != 0);
              proto.write(
                      PowerManagerServiceDumpProto.ActiveWakeLocksProto.IS_DRAW,
                      (mWakeLockSummary & WAKE_LOCK_DRAW) != 0);
              proto.end(activeWakeLocksToken);
  
              proto.write(PowerManagerServiceDumpProto.NOTIFY_LONG_SCHEDULED_MS, mNotifyLongScheduled);
              proto.write(PowerManagerServiceDumpProto.NOTIFY_LONG_DISPATCHED_MS, mNotifyLongDispatched);
              proto.write(PowerManagerServiceDumpProto.NOTIFY_LONG_NEXT_CHECK_MS, mNotifyLongNextCheck);
  
              final long userActivityToken = proto.start(PowerManagerServiceDumpProto.USER_ACTIVITY);
              proto.write(
                      PowerManagerServiceDumpProto.UserActivityProto.IS_SCREEN_BRIGHT,
                      (mUserActivitySummary & USER_ACTIVITY_SCREEN_BRIGHT) != 0);
              proto.write(
                      PowerManagerServiceDumpProto.UserActivityProto.IS_SCREEN_DIM,
                      (mUserActivitySummary & USER_ACTIVITY_SCREEN_DIM) != 0);
              proto.write(
                      PowerManagerServiceDumpProto.UserActivityProto.IS_SCREEN_DREAM,
                      (mUserActivitySummary & USER_ACTIVITY_SCREEN_DREAM) != 0);
              proto.end(userActivityToken);
  
              proto.write(
                      PowerManagerServiceDumpProto.IS_REQUEST_WAIT_FOR_NEGATIVE_PROXIMITY,
                      mRequestWaitForNegativeProximity);
              proto.write(PowerManagerServiceDumpProto.IS_SANDMAN_SCHEDULED, mSandmanScheduled);
              proto.write(PowerManagerServiceDumpProto.IS_SANDMAN_SUMMONED, mSandmanSummoned);
              proto.write(PowerManagerServiceDumpProto.IS_BATTERY_LEVEL_LOW, mBatteryLevelLow);
              proto.write(PowerManagerServiceDumpProto.IS_LIGHT_DEVICE_IDLE_MODE, mLightDeviceIdleMode);
              proto.write(PowerManagerServiceDumpProto.IS_DEVICE_IDLE_MODE, mDeviceIdleMode);
  
              for (int id : mDeviceIdleWhitelist) {
                  proto.write(PowerManagerServiceDumpProto.DEVICE_IDLE_WHITELIST, id);
              }
              for (int id : mDeviceIdleTempWhitelist) {
                  proto.write(PowerManagerServiceDumpProto.DEVICE_IDLE_TEMP_WHITELIST, id);
              }
  
              proto.write(PowerManagerServiceDumpProto.LAST_WAKE_TIME_MS, mLastWakeTime);
              proto.write(PowerManagerServiceDumpProto.LAST_SLEEP_TIME_MS, mLastSleepTime);
              proto.write(PowerManagerServiceDumpProto.LAST_USER_ACTIVITY_TIME_MS, mLastUserActivityTime);
              proto.write(
                      PowerManagerServiceDumpProto.LAST_USER_ACTIVITY_TIME_NO_CHANGE_LIGHTS_MS,
                      mLastUserActivityTimeNoChangeLights);
              proto.write(
                      PowerManagerServiceDumpProto.LAST_INTERACTIVE_POWER_HINT_TIME_MS,
                      mLastInteractivePowerHintTime);
              proto.write(
                      PowerManagerServiceDumpProto.LAST_SCREEN_BRIGHTNESS_BOOST_TIME_MS,
                      mLastScreenBrightnessBoostTime);
              proto.write(
                      PowerManagerServiceDumpProto.IS_SCREEN_BRIGHTNESS_BOOST_IN_PROGRESS,
                      mScreenBrightnessBoostInProgress);
              proto.write(PowerManagerServiceDumpProto.IS_DISPLAY_READY, mDisplayReady);
              proto.write(
                      PowerManagerServiceDumpProto.IS_HOLDING_WAKE_LOCK_SUSPEND_BLOCKER,
                      mHoldingWakeLockSuspendBlocker);
              proto.write(
                      PowerManagerServiceDumpProto.IS_HOLDING_DISPLAY_SUSPEND_BLOCKER,
                      mHoldingDisplaySuspendBlocker);
  
              final long settingsAndConfigurationToken =
                      proto.start(PowerManagerServiceDumpProto.SETTINGS_AND_CONFIGURATION);
              proto.write(
                      PowerServiceSettingsAndConfigurationDumpProto
                              .IS_DECOUPLE_HAL_AUTO_SUSPEND_MODE_FROM_DISPLAY_CONFIG,
                      mDecoupleHalAutoSuspendModeFromDisplayConfig);
              proto.write(
                      PowerServiceSettingsAndConfigurationDumpProto
                              .IS_DECOUPLE_HAL_INTERACTIVE_MODE_FROM_DISPLAY_CONFIG,
                      mDecoupleHalInteractiveModeFromDisplayConfig);
              proto.write(
                      PowerServiceSettingsAndConfigurationDumpProto
                              .IS_WAKE_UP_WHEN_PLUGGED_OR_UNPLUGGED_CONFIG,
                      mWakeUpWhenPluggedOrUnpluggedConfig);
              proto.write(
                      PowerServiceSettingsAndConfigurationDumpProto
                              .IS_WAKE_UP_WHEN_PLUGGED_OR_UNPLUGGED_IN_THEATER_MODE_CONFIG,
                      mWakeUpWhenPluggedOrUnpluggedInTheaterModeConfig);
              proto.write(
                      PowerServiceSettingsAndConfigurationDumpProto.IS_THEATER_MODE_ENABLED,
                      mTheaterModeEnabled);
              proto.write(
                      PowerServiceSettingsAndConfigurationDumpProto
                              .IS_SUSPEND_WHEN_SCREEN_OFF_DUE_TO_PROXIMITY_CONFIG,
                      mSuspendWhenScreenOffDueToProximityConfig);
              proto.write(
                      PowerServiceSettingsAndConfigurationDumpProto.ARE_DREAMS_SUPPORTED_CONFIG,
                      mDreamsSupportedConfig);
              proto.write(
                      PowerServiceSettingsAndConfigurationDumpProto
                              .ARE_DREAMS_ENABLED_BY_DEFAULT_CONFIG,
                      mDreamsEnabledByDefaultConfig);
              proto.write(
                      PowerServiceSettingsAndConfigurationDumpProto
                              .ARE_DREAMS_ACTIVATED_ON_SLEEP_BY_DEFAULT_CONFIG,
                      mDreamsActivatedOnSleepByDefaultConfig);
              proto.write(
                      PowerServiceSettingsAndConfigurationDumpProto
                              .ARE_DREAMS_ACTIVATED_ON_DOCK_BY_DEFAULT_CONFIG,
                      mDreamsActivatedOnDockByDefaultConfig);
              proto.write(
                      PowerServiceSettingsAndConfigurationDumpProto
                              .ARE_DREAMS_ENABLED_ON_BATTERY_CONFIG,
                      mDreamsEnabledOnBatteryConfig);
              proto.write(
                      PowerServiceSettingsAndConfigurationDumpProto
                              .DREAMS_BATTERY_LEVEL_MINIMUM_WHEN_POWERED_CONFIG,
                      mDreamsBatteryLevelMinimumWhenPoweredConfig);
              proto.write(
                      PowerServiceSettingsAndConfigurationDumpProto
                              .DREAMS_BATTERY_LEVEL_MINIMUM_WHEN_NOT_POWERED_CONFIG,
                      mDreamsBatteryLevelMinimumWhenNotPoweredConfig);
              proto.write(
                      PowerServiceSettingsAndConfigurationDumpProto
                              .DREAMS_BATTERY_LEVEL_DRAIN_CUTOFF_CONFIG,
                      mDreamsBatteryLevelDrainCutoffConfig);
              proto.write(
                      PowerServiceSettingsAndConfigurationDumpProto.ARE_DREAMS_ENABLED_SETTING,
                      mDreamsEnabledSetting);
              proto.write(
                      PowerServiceSettingsAndConfigurationDumpProto
                              .ARE_DREAMS_ACTIVATE_ON_SLEEP_SETTING,
                      mDreamsActivateOnSleepSetting);
              proto.write(
                      PowerServiceSettingsAndConfigurationDumpProto
                              .ARE_DREAMS_ACTIVATE_ON_DOCK_SETTING,
                      mDreamsActivateOnDockSetting);
              proto.write(
                      PowerServiceSettingsAndConfigurationDumpProto.IS_DOZE_AFTER_SCREEN_OFF_CONFIG,
                      mDozeAfterScreenOff);
              proto.write(
                      PowerServiceSettingsAndConfigurationDumpProto
                              .MINIMUM_SCREEN_OFF_TIMEOUT_CONFIG_MS,
                      mMinimumScreenOffTimeoutConfig);
              proto.write(
                      PowerServiceSettingsAndConfigurationDumpProto
                              .MAXIMUM_SCREEN_DIM_DURATION_CONFIG_MS,
                      mMaximumScreenDimDurationConfig);
              proto.write(
                      PowerServiceSettingsAndConfigurationDumpProto.MAXIMUM_SCREEN_DIM_RATIO_CONFIG,
                      mMaximumScreenDimRatioConfig);
              proto.write(
                      PowerServiceSettingsAndConfigurationDumpProto.SCREEN_OFF_TIMEOUT_SETTING_MS,
                      mScreenOffTimeoutSetting);
              proto.write(
                      PowerServiceSettingsAndConfigurationDumpProto.SLEEP_TIMEOUT_SETTING_MS,
                      mSleepTimeoutSetting);
              proto.write(
                      PowerServiceSettingsAndConfigurationDumpProto
                              .MAXIMUM_SCREEN_OFF_TIMEOUT_FROM_DEVICE_ADMIN_MS,
                      // Clamp to int32
                      Math.min(mMaximumScreenOffTimeoutFromDeviceAdmin, Integer.MAX_VALUE));
              proto.write(
                      PowerServiceSettingsAndConfigurationDumpProto
                              .IS_MAXIMUM_SCREEN_OFF_TIMEOUT_FROM_DEVICE_ADMIN_ENFORCED_LOCKED,
                      isMaximumScreenOffTimeoutFromDeviceAdminEnforcedLocked());
  
              final long stayOnWhilePluggedInToken =
                      proto.start(
                              PowerServiceSettingsAndConfigurationDumpProto.STAY_ON_WHILE_PLUGGED_IN);
              proto.write(
                      PowerServiceSettingsAndConfigurationDumpProto.StayOnWhilePluggedInProto
                              .IS_STAY_ON_WHILE_PLUGGED_IN_AC,
                      ((mStayOnWhilePluggedInSetting & BatteryManager.BATTERY_PLUGGED_AC) != 0));
              proto.write(
                      PowerServiceSettingsAndConfigurationDumpProto.StayOnWhilePluggedInProto
                              .IS_STAY_ON_WHILE_PLUGGED_IN_USB,
                      ((mStayOnWhilePluggedInSetting & BatteryManager.BATTERY_PLUGGED_USB) != 0));
              proto.write(
                      PowerServiceSettingsAndConfigurationDumpProto.StayOnWhilePluggedInProto
                              .IS_STAY_ON_WHILE_PLUGGED_IN_WIRELESS,
                      ((mStayOnWhilePluggedInSetting & BatteryManager.BATTERY_PLUGGED_WIRELESS)
                              != 0));
              proto.end(stayOnWhilePluggedInToken);
  
              proto.write(
                      PowerServiceSettingsAndConfigurationDumpProto.SCREEN_BRIGHTNESS_MODE_SETTING,
                      mScreenBrightnessModeSetting);
              proto.write(
                      PowerServiceSettingsAndConfigurationDumpProto
                              .SCREEN_BRIGHTNESS_OVERRIDE_FROM_WINDOW_MANAGER,
                      mScreenBrightnessOverrideFromWindowManager);
              proto.write(
                      PowerServiceSettingsAndConfigurationDumpProto
                              .USER_ACTIVITY_TIMEOUT_OVERRIDE_FROM_WINDOW_MANAGER_MS,
                      mUserActivityTimeoutOverrideFromWindowManager);
              proto.write(
                      PowerServiceSettingsAndConfigurationDumpProto
                              .IS_USER_INACTIVE_OVERRIDE_FROM_WINDOW_MANAGER,
                      mUserInactiveOverrideFromWindowManager);
              proto.write(
                      PowerServiceSettingsAndConfigurationDumpProto
                              .DOZE_SCREEN_STATE_OVERRIDE_FROM_DREAM_MANAGER,
                      mDozeScreenStateOverrideFromDreamManager);
              proto.write(
                      PowerServiceSettingsAndConfigurationDumpProto
                              .DRAW_WAKE_LOCK_OVERRIDE_FROM_SIDEKICK,
                      mDrawWakeLockOverrideFromSidekick);
              proto.write(
                      PowerServiceSettingsAndConfigurationDumpProto
                              .DOZED_SCREEN_BRIGHTNESS_OVERRIDE_FROM_DREAM_MANAGER,
                      mDozeScreenBrightnessOverrideFromDreamManager);
  
              final long screenBrightnessSettingLimitsToken =
                      proto.start(
                              PowerServiceSettingsAndConfigurationDumpProto
                                      .SCREEN_BRIGHTNESS_SETTING_LIMITS);
              proto.write(
                      PowerServiceSettingsAndConfigurationDumpProto.ScreenBrightnessSettingLimitsProto
                              .SETTING_MINIMUM,
                      mScreenBrightnessSettingMinimum);
              proto.write(
                      PowerServiceSettingsAndConfigurationDumpProto.ScreenBrightnessSettingLimitsProto
                              .SETTING_MAXIMUM,
                      mScreenBrightnessSettingMaximum);
              proto.write(
                      PowerServiceSettingsAndConfigurationDumpProto.ScreenBrightnessSettingLimitsProto
                              .SETTING_DEFAULT,
                      mScreenBrightnessSettingDefault);
              proto.end(screenBrightnessSettingLimitsToken);
  
              proto.write(
                      PowerServiceSettingsAndConfigurationDumpProto.IS_DOUBLE_TAP_WAKE_ENABLED,
                      mDoubleTapWakeEnabled);
              proto.write(
                      PowerServiceSettingsAndConfigurationDumpProto.IS_VR_MODE_ENABLED,
                      mIsVrModeEnabled);
              proto.end(settingsAndConfigurationToken);
  
              final long sleepTimeout = getSleepTimeoutLocked();
              final long screenOffTimeout = getScreenOffTimeoutLocked(sleepTimeout);
              final long screenDimDuration = getScreenDimDurationLocked(screenOffTimeout);
              proto.write(PowerManagerServiceDumpProto.SLEEP_TIMEOUT_MS, sleepTimeout);
              proto.write(PowerManagerServiceDumpProto.SCREEN_OFF_TIMEOUT_MS, screenOffTimeout);
              proto.write(PowerManagerServiceDumpProto.SCREEN_DIM_DURATION_MS, screenDimDuration);
              proto.write(PowerManagerServiceDumpProto.ARE_UIDS_CHANGING, mUidsChanging);
              proto.write(PowerManagerServiceDumpProto.ARE_UIDS_CHANGED, mUidsChanged);
  
              for (int i = 0; i < mUidState.size(); i++) {
                  final UidState state = mUidState.valueAt(i);
                  final long uIDToken = proto.start(PowerManagerServiceDumpProto.UID_STATES);
                  final int uid = mUidState.keyAt(i);
                  proto.write(PowerManagerServiceDumpProto.UidStateProto.UID, uid);
                  proto.write(PowerManagerServiceDumpProto.UidStateProto.UID_STRING, UserHandle.formatUid(uid));
                  proto.write(PowerManagerServiceDumpProto.UidStateProto.IS_ACTIVE, state.mActive);
                  proto.write(PowerManagerServiceDumpProto.UidStateProto.NUM_WAKE_LOCKS, state.mNumWakeLocks);
                  proto.write(PowerManagerServiceDumpProto.UidStateProto.PROCESS_STATE,
                          ActivityManager.processStateAmToProto(state.mProcState));
                  proto.end(uIDToken);
              }
  
              mBatterySaverStateMachine.dumpProto(proto,
                      PowerManagerServiceDumpProto.BATTERY_SAVER_STATE_MACHINE);
  
              mHandler.getLooper().writeToProto(proto, PowerManagerServiceDumpProto.LOOPER);
  
              for (WakeLock wl : mWakeLocks) {
                  wl.writeToProto(proto, PowerManagerServiceDumpProto.WAKE_LOCKS);
              }
  
              for (SuspendBlocker sb : mSuspendBlockers) {
                  sb.writeToProto(proto, PowerManagerServiceDumpProto.SUSPEND_BLOCKERS);
              }
              wcd = mWirelessChargerDetector;
          }
  
          if (wcd != null) {
              wcd.writeToProto(proto, PowerManagerServiceDumpProto.WIRELESS_CHARGER_DETECTOR);
          }
          proto.flush();
      }
  
      private void incrementBootCount() {
          synchronized (mLock) {
              int count;
              try {
                  count = Settings.Global.getInt(
                          getContext().getContentResolver(), Settings.Global.BOOT_COUNT);
              } catch (SettingNotFoundException e) {
                  count = 0;
              }
              Settings.Global.putInt(
                      getContext().getContentResolver(), Settings.Global.BOOT_COUNT, count + 1);
          }
      }
  
      private static WorkSource copyWorkSource(WorkSource workSource) {
          return workSource != null ? new WorkSource(workSource) : null;
      }
  
      @VisibleForTesting
      final class BatteryReceiver extends BroadcastReceiver {
          @Override
          public void onReceive(Context context, Intent intent) {
              synchronized (mLock) {
                  handleBatteryStateChangedLocked();
              }
          }
      }
  
      private final class DreamReceiver extends BroadcastReceiver {
          @Override
          public void onReceive(Context context, Intent intent) {
              synchronized (mLock) {
                  scheduleSandmanLocked();
              }
          }
      }
  
      @VisibleForTesting
      final class UserSwitchedReceiver extends BroadcastReceiver {
          @Override
          public void onReceive(Context context, Intent intent) {
              synchronized (mLock) {
                  handleSettingsChangedLocked();
              }
          }
      }
  
      private final class DockReceiver extends BroadcastReceiver {
          @Override
          public void onReceive(Context context, Intent intent) {
              synchronized (mLock) {
                  int dockState = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
                          Intent.EXTRA_DOCK_STATE_UNDOCKED);
                  if (mDockState != dockState) {
                      mDockState = dockState;
                      mDirty |= DIRTY_DOCK_STATE;
                      updatePowerStateLocked();
                  }
              }
          }
      }
  
      private final class SettingsObserver extends ContentObserver {
          public SettingsObserver(Handler handler) {
              super(handler);
          }
  
          @Override
          public void onChange(boolean selfChange, Uri uri) {
              synchronized (mLock) {
                  handleSettingsChangedLocked();
              }
          }
      }
  
      private final IVrStateCallbacks mVrStateCallbacks = new IVrStateCallbacks.Stub() {
          @Override
          public void onVrStateChanged(boolean enabled) {
              powerHintInternal(PowerHint.VR_MODE, enabled ? 1 : 0);
  
              synchronized (mLock) {
                  if (mIsVrModeEnabled != enabled) {
                      setVrModeEnabled(enabled);
                      mDirty |= DIRTY_VR_MODE_CHANGED;
                      updatePowerStateLocked();
                  }
              }
          }
      };
  
      /**
       * Handler for asynchronous operations performed by the power manager.
       */
      private final class PowerManagerHandler extends Handler {
          public PowerManagerHandler(Looper looper) {
              super(looper, null, true /*async*/);
          }
  
          @Override
          public void handleMessage(Message msg) {
              switch (msg.what) {
                  case MSG_USER_ACTIVITY_TIMEOUT:
                      handleUserActivityTimeout();
                      break;
                  case MSG_SANDMAN:
                      handleSandman();
                      break;
                  case MSG_SCREEN_BRIGHTNESS_BOOST_TIMEOUT:
                      handleScreenBrightnessBoostTimeout();
                      break;
                  case MSG_CHECK_FOR_LONG_WAKELOCKS:
                      checkForLongWakeLocks();
                      break;
              }
          }
      }
  
      /**
       * Represents a wake lock that has been acquired by an application.
       */
      private final class WakeLock implements IBinder.DeathRecipient {
          public final IBinder mLock;
          public int mFlags;
          public String mTag;
          public final String mPackageName;
          public WorkSource mWorkSource;
          public String mHistoryTag;
          public final int mOwnerUid;
          public final int mOwnerPid;
          public final UidState mUidState;
          public long mAcquireTime;
          public boolean mNotifiedAcquired;
          public boolean mNotifiedLong;
          public boolean mDisabled;
  
          public WakeLock(IBinder lock, int flags, String tag, String packageName,
                  WorkSource workSource, String historyTag, int ownerUid, int ownerPid,
                  UidState uidState) {
              mLock = lock;
              mFlags = flags;
              mTag = tag;
              mPackageName = packageName;
              mWorkSource = copyWorkSource(workSource);
              mHistoryTag = historyTag;
              mOwnerUid = ownerUid;
              mOwnerPid = ownerPid;
              mUidState = uidState;
          }
  
          @Override
          public void binderDied() {
              PowerManagerService.this.handleWakeLockDeath(this);
          }
  
          public boolean hasSameProperties(int flags, String tag, WorkSource workSource,
                  int ownerUid, int ownerPid) {
              return mFlags == flags
                      && mTag.equals(tag)
                      && hasSameWorkSource(workSource)
                      && mOwnerUid == ownerUid
                      && mOwnerPid == ownerPid;
          }
  
          public void updateProperties(int flags, String tag, String packageName,
                  WorkSource workSource, String historyTag, int ownerUid, int ownerPid) {
              if (!mPackageName.equals(packageName)) {
                  throw new IllegalStateException("Existing wake lock package name changed: "
                          + mPackageName + " to " + packageName);
              }
              if (mOwnerUid != ownerUid) {
                  throw new IllegalStateException("Existing wake lock uid changed: "
                          + mOwnerUid + " to " + ownerUid);
              }
              if (mOwnerPid != ownerPid) {
                  throw new IllegalStateException("Existing wake lock pid changed: "
                          + mOwnerPid + " to " + ownerPid);
              }
              mFlags = flags;
              mTag = tag;
              updateWorkSource(workSource);
              mHistoryTag = historyTag;
          }
  
          public boolean hasSameWorkSource(WorkSource workSource) {
              return Objects.equals(mWorkSource, workSource);
          }
  
          public void updateWorkSource(WorkSource workSource) {
              mWorkSource = copyWorkSource(workSource);
          }
  
          @Override
          public String toString() {
              StringBuilder sb = new StringBuilder();
              sb.append(getLockLevelString());
              sb.append(" '");
              sb.append(mTag);
              sb.append("'");
              sb.append(getLockFlagsString());
              if (mDisabled) {
                  sb.append(" DISABLED");
              }
              if (mNotifiedAcquired) {
                  sb.append(" ACQ=");
                  TimeUtils.formatDuration(mAcquireTime-SystemClock.uptimeMillis(), sb);
              }
              if (mNotifiedLong) {
                  sb.append(" LONG");
              }
              sb.append(" (uid=");
              sb.append(mOwnerUid);
              if (mOwnerPid != 0) {
                  sb.append(" pid=");
                  sb.append(mOwnerPid);
              }
              if (mWorkSource != null) {
                  sb.append(" ws=");
                  sb.append(mWorkSource);
              }
              sb.append(")");
              return sb.toString();
          }
  
          public void writeToProto(ProtoOutputStream proto, long fieldId) {
              final long wakeLockToken = proto.start(fieldId);
              proto.write(WakeLockProto.LOCK_LEVEL, (mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK));
              proto.write(WakeLockProto.TAG, mTag);
  
              final long wakeLockFlagsToken = proto.start(WakeLockProto.FLAGS);
              proto.write(WakeLockProto.WakeLockFlagsProto.IS_ACQUIRE_CAUSES_WAKEUP,
                      (mFlags & PowerManager.ACQUIRE_CAUSES_WAKEUP)!=0);
              proto.write(WakeLockProto.WakeLockFlagsProto.IS_ON_AFTER_RELEASE,
                      (mFlags & PowerManager.ON_AFTER_RELEASE)!=0);
              proto.end(wakeLockFlagsToken);
  
              proto.write(WakeLockProto.IS_DISABLED, mDisabled);
              if (mNotifiedAcquired) {
                  proto.write(WakeLockProto.ACQ_MS, mAcquireTime);
              }
              proto.write(WakeLockProto.IS_NOTIFIED_LONG, mNotifiedLong);
              proto.write(WakeLockProto.UID, mOwnerUid);
              proto.write(WakeLockProto.PID, mOwnerPid);
  
              if (mWorkSource != null) {
                  mWorkSource.writeToProto(proto, WakeLockProto.WORK_SOURCE);
              }
              proto.end(wakeLockToken);
          }
  
          @SuppressWarnings("deprecation")
          private String getLockLevelString() {
              switch (mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK) {
                  case PowerManager.FULL_WAKE_LOCK:
                      return "FULL_WAKE_LOCK                ";
                  case PowerManager.SCREEN_BRIGHT_WAKE_LOCK:
                      return "SCREEN_BRIGHT_WAKE_LOCK       ";
                  case PowerManager.SCREEN_DIM_WAKE_LOCK:
                      return "SCREEN_DIM_WAKE_LOCK          ";
                  case PowerManager.PARTIAL_WAKE_LOCK:
                      return "PARTIAL_WAKE_LOCK             ";
                  case PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK:
                      return "PROXIMITY_SCREEN_OFF_WAKE_LOCK";
                  case PowerManager.DOZE_WAKE_LOCK:
                      return "DOZE_WAKE_LOCK                ";
                  case PowerManager.DRAW_WAKE_LOCK:
                      return "DRAW_WAKE_LOCK                ";
                  default:
                      return "???                           ";
              }
          }
  
          private String getLockFlagsString() {
              String result = "";
              if ((mFlags & PowerManager.ACQUIRE_CAUSES_WAKEUP) != 0) {
                  result += " ACQUIRE_CAUSES_WAKEUP";
              }
              if ((mFlags & PowerManager.ON_AFTER_RELEASE) != 0) {
                  result += " ON_AFTER_RELEASE";
              }
              return result;
          }
      }
  
      private final class SuspendBlockerImpl implements SuspendBlocker {
          private final String mName;
          private final String mTraceName;
          private int mReferenceCount;
  
          public SuspendBlockerImpl(String name) {
              mName = name;
              mTraceName = "SuspendBlocker (" + name + ")";
          }
  
          @Override
          protected void finalize() throws Throwable {
              try {
                  if (mReferenceCount != 0) {
                      Slog.wtf(TAG, "Suspend blocker \"" + mName
                              + "\" was finalized without being released!");
                      mReferenceCount = 0;
                      mNativeWrapper.nativeReleaseSuspendBlocker(mName);
                      Trace.asyncTraceEnd(Trace.TRACE_TAG_POWER, mTraceName, 0);
                  }
              } finally {
                  super.finalize();
              }
          }
  
          @Override
          public void acquire() {
              synchronized (this) {
                  mReferenceCount += 1;
                  if (mReferenceCount == 1) {
                      if (DEBUG_SPEW) {
                          Slog.d(TAG, "Acquiring suspend blocker \"" + mName + "\".");
                      }
                      Trace.asyncTraceBegin(Trace.TRACE_TAG_POWER, mTraceName, 0);
                      mNativeWrapper.nativeAcquireSuspendBlocker(mName);
                  }
              }
          }
  
          @Override
          public void release() {
              synchronized (this) {
                  mReferenceCount -= 1;
                  if (mReferenceCount == 0) {
                      if (DEBUG_SPEW) {
                          Slog.d(TAG, "Releasing suspend blocker \"" + mName + "\".");
                      }
                      mNativeWrapper.nativeReleaseSuspendBlocker(mName);
                      Trace.asyncTraceEnd(Trace.TRACE_TAG_POWER, mTraceName, 0);
                  } else if (mReferenceCount < 0) {
                      Slog.wtf(TAG, "Suspend blocker \"" + mName
                              + "\" was released without being acquired!", new Throwable());
                      mReferenceCount = 0;
                  }
              }
          }
  
          @Override
          public String toString() {
              synchronized (this) {
                  return mName + ": ref count=" + mReferenceCount;
              }
          }
  
          public void writeToProto(ProtoOutputStream proto, long fieldId) {
              final long sbToken = proto.start(fieldId);
              synchronized (this) {
                  proto.write(SuspendBlockerProto.NAME, mName);
                  proto.write(SuspendBlockerProto.REFERENCE_COUNT, mReferenceCount);
              }
              proto.end(sbToken);
          }
      }
  
      static final class UidState {
          final int mUid;
          int mNumWakeLocks;
          int mProcState;
          boolean mActive;
  
          UidState(int uid) {
              mUid = uid;
          }
      }
  
      @VisibleForTesting
      final class BinderService extends IPowerManager.Stub {
          @Override
          public void onShellCommand(FileDescriptor in, FileDescriptor out,
                  FileDescriptor err, String[] args, ShellCallback callback,
                  ResultReceiver resultReceiver) {
              (new PowerManagerShellCommand(this)).exec(
                      this, in, out, err, args, callback, resultReceiver);
          }
  
          @Override // Binder call
          public void acquireWakeLockWithUid(IBinder lock, int flags, String tag,
                  String packageName, int uid) {
              if (uid < 0) {
                  uid = Binder.getCallingUid();
              }
              acquireWakeLock(lock, flags, tag, packageName, new WorkSource(uid), null);
          }
  
          @Override // Binder call
          public void powerHint(int hintId, int data) {
              if (!mSystemReady) {
                  // Service not ready yet, so who the heck cares about power hints, bah.
                  return;
              }
              mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
              powerHintInternal(hintId, data);
          }
  
          @Override // Binder call
          public void acquireWakeLock(IBinder lock, int flags, String tag, String packageName,
                  WorkSource ws, String historyTag) {
              if (lock == null) {
                  throw new IllegalArgumentException("lock must not be null");
              }
              if (packageName == null) {
                  throw new IllegalArgumentException("packageName must not be null");
              }
              PowerManager.validateWakeLockParameters(flags, tag);
  
              mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
              if ((flags & PowerManager.DOZE_WAKE_LOCK) != 0) {
                  mContext.enforceCallingOrSelfPermission(
                          android.Manifest.permission.DEVICE_POWER, null);
              }
              if (ws != null && !ws.isEmpty()) {
                  mContext.enforceCallingOrSelfPermission(
                          android.Manifest.permission.UPDATE_DEVICE_STATS, null);
              } else {
                  ws = null;
              }
  
              final int uid = Binder.getCallingUid();
              final int pid = Binder.getCallingPid();
              final long ident = Binder.clearCallingIdentity();
              try {
                  acquireWakeLockInternal(lock, flags, tag, packageName, ws, historyTag, uid, pid);
              } finally {
                  Binder.restoreCallingIdentity(ident);
              }
          }
  
          @Override // Binder call
          public void releaseWakeLock(IBinder lock, int flags) {
              if (lock == null) {
                  throw new IllegalArgumentException("lock must not be null");
              }
  
              mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
  
              final long ident = Binder.clearCallingIdentity();
              try {
                  releaseWakeLockInternal(lock, flags);
              } finally {
                  Binder.restoreCallingIdentity(ident);
              }
          }
  
          @Override // Binder call
          public void updateWakeLockUids(IBinder lock, int[] uids) {
              WorkSource ws = null;
  
              if (uids != null) {
                  ws = new WorkSource();
                  // XXX should WorkSource have a way to set uids as an int[] instead of adding them
                  // one at a time?
                  for (int i = 0; i < uids.length; i++) {
                      ws.add(uids[i]);
                  }
              }
              updateWakeLockWorkSource(lock, ws, null);
          }
  
          @Override // Binder call
          public void updateWakeLockWorkSource(IBinder lock, WorkSource ws, String historyTag) {
              if (lock == null) {
                  throw new IllegalArgumentException("lock must not be null");
              }
  
              mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
              if (ws != null && !ws.isEmpty()) {
                  mContext.enforceCallingOrSelfPermission(
                          android.Manifest.permission.UPDATE_DEVICE_STATS, null);
              } else {
                  ws = null;
              }
  
              final int callingUid = Binder.getCallingUid();
              final long ident = Binder.clearCallingIdentity();
              try {
                  updateWakeLockWorkSourceInternal(lock, ws, historyTag, callingUid);
              } finally {
                  Binder.restoreCallingIdentity(ident);
              }
          }
  
          @Override // Binder call
          public boolean isWakeLockLevelSupported(int level) {
              final long ident = Binder.clearCallingIdentity();
              try {
                  return isWakeLockLevelSupportedInternal(level);
              } finally {
                  Binder.restoreCallingIdentity(ident);
              }
          }
  
          @Override // Binder call
          public void userActivity(long eventTime, int event, int flags) {
              final long now = SystemClock.uptimeMillis();
              if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER)
                      != PackageManager.PERMISSION_GRANTED
                      && mContext.checkCallingOrSelfPermission(
                              android.Manifest.permission.USER_ACTIVITY)
                              != PackageManager.PERMISSION_GRANTED) {
                  // Once upon a time applications could call userActivity().
                  // Now we require the DEVICE_POWER permission.  Log a warning and ignore the
                  // request instead of throwing a SecurityException so we don't break old apps.
                  synchronized (mLock) {
                      if (now >= mLastWarningAboutUserActivityPermission + (5 * 60 * 1000)) {
                          mLastWarningAboutUserActivityPermission = now;
                          Slog.w(TAG, "Ignoring call to PowerManager.userActivity() because the "
                                  + "caller does not have DEVICE_POWER or USER_ACTIVITY "
                                  + "permission.  Please fix your app!  "
                                  + " pid=" + Binder.getCallingPid()
                                  + " uid=" + Binder.getCallingUid());
                      }
                  }
                  return;
              }
  
              if (eventTime > now) {
                  throw new IllegalArgumentException("event time must not be in the future");
              }
  
              final int uid = Binder.getCallingUid();
              final long ident = Binder.clearCallingIdentity();
              try {
                  userActivityInternal(eventTime, event, flags, uid);
              } finally {
                  Binder.restoreCallingIdentity(ident);
              }
          }
  
          @Override // Binder call
          public void wakeUp(long eventTime, @WakeReason int reason, String details,
                  String opPackageName) {
              if (eventTime > SystemClock.uptimeMillis()) {
                  throw new IllegalArgumentException("event time must not be in the future");
              }
  
              mContext.enforceCallingOrSelfPermission(
                      android.Manifest.permission.DEVICE_POWER, null);
  
              final int uid = Binder.getCallingUid();
              final long ident = Binder.clearCallingIdentity();
              try {
                  wakeUpInternal(eventTime, reason, details, uid, opPackageName, uid);
              } finally {
                  Binder.restoreCallingIdentity(ident);
              }
          }
  
          @Override // Binder call
          public void goToSleep(long eventTime, int reason, int flags) {
              if (eventTime > SystemClock.uptimeMillis()) {
                  throw new IllegalArgumentException("event time must not be in the future");
              }
  
              mContext.enforceCallingOrSelfPermission(
                      android.Manifest.permission.DEVICE_POWER, null);
  
              final int uid = Binder.getCallingUid();
              final long ident = Binder.clearCallingIdentity();
              try {
                  goToSleepInternal(eventTime, reason, flags, uid);
              } finally {
                  Binder.restoreCallingIdentity(ident);
              }
          }
  
          @Override // Binder call
          public void nap(long eventTime) {
              if (eventTime > SystemClock.uptimeMillis()) {
                  throw new IllegalArgumentException("event time must not be in the future");
              }
  
              mContext.enforceCallingOrSelfPermission(
                      android.Manifest.permission.DEVICE_POWER, null);
  
              final int uid = Binder.getCallingUid();
              final long ident = Binder.clearCallingIdentity();
              try {
                  napInternal(eventTime, uid);
              } finally {
                  Binder.restoreCallingIdentity(ident);
              }
          }
  
          @Override // Binder call
          public boolean isInteractive() {
              final long ident = Binder.clearCallingIdentity();
              try {
                  return isInteractiveInternal();
              } finally {
                  Binder.restoreCallingIdentity(ident);
              }
          }
  
          @Override // Binder call
          public boolean isPowerSaveMode() {
              final long ident = Binder.clearCallingIdentity();
              try {
                  return mBatterySaverController.isEnabled();
              } finally {
                  Binder.restoreCallingIdentity(ident);
              }
          }
  
          // Binder call
          public PowerSaveState getPowerSaveState(@ServiceType int serviceType) {
              final long ident = Binder.clearCallingIdentity();
              try {
                  return mBatterySaverPolicy.getBatterySaverPolicy(serviceType);
              } finally {
                  Binder.restoreCallingIdentity(ident);
              }
          }
  
          @Override // Binder call
          public boolean setPowerSaveModeEnabled(boolean enabled) {
              if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.POWER_SAVER)
                      != PackageManager.PERMISSION_GRANTED) {
                  mContext.enforceCallingOrSelfPermission(
                          android.Manifest.permission.DEVICE_POWER, null);
              }
              final long ident = Binder.clearCallingIdentity();
              try {
                  return setLowPowerModeInternal(enabled);
              } finally {
                  Binder.restoreCallingIdentity(ident);
              }
          }
  
          @Override // Binder call
          public boolean setDynamicPowerSaveHint(boolean powerSaveHint, int disableThreshold) {
              mContext.enforceCallingOrSelfPermission(android.Manifest.permission.POWER_SAVER,
                      "updateDynamicPowerSavings");
              final long ident = Binder.clearCallingIdentity();
              try {
                  final ContentResolver resolver = mContext.getContentResolver();
                  boolean success = Settings.Global.putInt(resolver,
                          Settings.Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD,
                          disableThreshold);
                  if (success) {
                      // abort updating if we weren't able to succeed on the threshold
                      success &= Settings.Global.putInt(resolver,
                              Settings.Global.DYNAMIC_POWER_SAVINGS_ENABLED,
                              powerSaveHint ? 1 : 0);
                  }
                  return success;
              } finally {
                  Binder.restoreCallingIdentity(ident);
              }
          }
  
          @Override // Binder call
          public boolean setAdaptivePowerSavePolicy(@NonNull BatterySaverPolicyConfig config) {
              if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.POWER_SAVER)
                      != PackageManager.PERMISSION_GRANTED) {
                  mContext.enforceCallingOrSelfPermission(
                          android.Manifest.permission.DEVICE_POWER, "setAdaptivePowerSavePolicy");
              }
              final long ident = Binder.clearCallingIdentity();
              try {
                  return mBatterySaverStateMachine.setAdaptiveBatterySaverPolicy(config);
              } finally {
                  Binder.restoreCallingIdentity(ident);
              }
          }
  
          @Override // Binder call
          public boolean setAdaptivePowerSaveEnabled(boolean enabled) {
              if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.POWER_SAVER)
                      != PackageManager.PERMISSION_GRANTED) {
                  mContext.enforceCallingOrSelfPermission(
                          android.Manifest.permission.DEVICE_POWER, "setAdaptivePowerSaveEnabled");
              }
              final long ident = Binder.clearCallingIdentity();
              try {
                  return mBatterySaverStateMachine.setAdaptiveBatterySaverEnabled(enabled);
              } finally {
                  Binder.restoreCallingIdentity(ident);
              }
          }
  
          @Override // Binder call
          public int getPowerSaveModeTrigger() {
              mContext.enforceCallingOrSelfPermission(android.Manifest.permission.POWER_SAVER, null);
              final long ident = Binder.clearCallingIdentity();
              try {
                  return Settings.Global.getInt(mContext.getContentResolver(),
                          Settings.Global.AUTOMATIC_POWER_SAVE_MODE,
                          PowerManager.POWER_SAVE_MODE_TRIGGER_PERCENTAGE);
              } finally {
                  Binder.restoreCallingIdentity(ident);
              }
          }
  
          @Override // Binder call
          public boolean isDeviceIdleMode() {
              final long ident = Binder.clearCallingIdentity();
              try {
                  return isDeviceIdleModeInternal();
              } finally {
                  Binder.restoreCallingIdentity(ident);
              }
          }
  
          @Override // Binder call
          public boolean isLightDeviceIdleMode() {
              final long ident = Binder.clearCallingIdentity();
              try {
                  return isLightDeviceIdleModeInternal();
              } finally {
                  Binder.restoreCallingIdentity(ident);
              }
          }
  
          /**
           * Gets the reason for the last time the phone had to reboot.
           *
           * @return The reason the phone last shut down as an int or
           * {@link PowerManager#SHUTDOWN_REASON_UNKNOWN} if the file could not be opened.
           */
          @Override // Binder call
          public int getLastShutdownReason() {
              mContext.enforceCallingOrSelfPermission(
                      android.Manifest.permission.DEVICE_POWER, null);
  
              final long ident = Binder.clearCallingIdentity();
              try {
                  return getLastShutdownReasonInternal(REBOOT_PROPERTY);
              } finally {
                  Binder.restoreCallingIdentity(ident);
              }
          }
  
          @Override // Binder call
          public int getLastSleepReason() {
              mContext.enforceCallingOrSelfPermission(
                      android.Manifest.permission.DEVICE_POWER, null);
  
              final long ident = Binder.clearCallingIdentity();
              try {
                  return getLastSleepReasonInternal();
              } finally {
                  Binder.restoreCallingIdentity(ident);
              }
          }
  
          /**
           * Reboots the device.
           *
           * @param confirm If true, shows a reboot confirmation dialog.
           * @param reason The reason for the reboot, or null if none.
           * @param wait If true, this call waits for the reboot to complete and does not return.
           */
          @Override // Binder call
          public void reboot(boolean confirm, String reason, boolean wait) {
              mContext.enforceCallingOrSelfPermission(android.Manifest.permission.REBOOT, null);
              if (PowerManager.REBOOT_RECOVERY.equals(reason)
                      || PowerManager.REBOOT_RECOVERY_UPDATE.equals(reason)) {
                  mContext.enforceCallingOrSelfPermission(android.Manifest.permission.RECOVERY, null);
              }
  
              final long ident = Binder.clearCallingIdentity();
              try {
                  shutdownOrRebootInternal(HALT_MODE_REBOOT, confirm, reason, wait);
              } finally {
                  Binder.restoreCallingIdentity(ident);
              }
          }
  
          /**
           * Reboots the device into safe mode
           *
           * @param confirm If true, shows a reboot confirmation dialog.
           * @param wait If true, this call waits for the reboot to complete and does not return.
           */
          @Override // Binder call
          public void rebootSafeMode(boolean confirm, boolean wait) {
              mContext.enforceCallingOrSelfPermission(android.Manifest.permission.REBOOT, null);
  
              final long ident = Binder.clearCallingIdentity();
              try {
                  shutdownOrRebootInternal(HALT_MODE_REBOOT_SAFE_MODE, confirm,
                          PowerManager.REBOOT_SAFE_MODE, wait);
              } finally {
                  Binder.restoreCallingIdentity(ident);
              }
          }
  
          /**
           * Shuts down the device.
           *
           * @param confirm If true, shows a shutdown confirmation dialog.
           * @param wait If true, this call waits for the shutdown to complete and does not return.
           */
          @Override // Binder call
          public void shutdown(boolean confirm, String reason, boolean wait) {
              mContext.enforceCallingOrSelfPermission(android.Manifest.permission.REBOOT, null);
  
              final long ident = Binder.clearCallingIdentity();
              try {
                  shutdownOrRebootInternal(HALT_MODE_SHUTDOWN, confirm, reason, wait);
              } finally {
                  Binder.restoreCallingIdentity(ident);
              }
          }
  
          /**
           * Crash the runtime (causing a complete restart of the Android framework).
           * Requires REBOOT permission.  Mostly for testing.  Should not return.
           */
          @Override // Binder call
          public void crash(String message) {
              mContext.enforceCallingOrSelfPermission(android.Manifest.permission.REBOOT, null);
  
              final long ident = Binder.clearCallingIdentity();
              try {
                  crashInternal(message);
              } finally {
                  Binder.restoreCallingIdentity(ident);
              }
          }
  
          /**
           * Set the setting that determines whether the device stays on when plugged in.
           * The argument is a bit string, with each bit specifying a power source that,
           * when the device is connected to that source, causes the device to stay on.
           * See {@link android.os.BatteryManager} for the list of power sources that
           * can be specified. Current values include
           * {@link android.os.BatteryManager#BATTERY_PLUGGED_AC}
           * and {@link android.os.BatteryManager#BATTERY_PLUGGED_USB}
           *
           * Used by "adb shell svc power stayon ..."
           *
           * @param val an {@code int} containing the bits that specify which power sources
           * should cause the device to stay on.
           */
          @Override // Binder call
          public void setStayOnSetting(int val) {
              int uid = Binder.getCallingUid();
              // if uid is of root's, we permit this operation straight away
              if (uid != Process.ROOT_UID) {
                  if (!Settings.checkAndNoteWriteSettingsOperation(mContext, uid,
                          Settings.getPackageNameForUid(mContext, uid), true)) {
                      return;
                  }
              }
  
              final long ident = Binder.clearCallingIdentity();
              try {
                  setStayOnSettingInternal(val);
              } finally {
                  Binder.restoreCallingIdentity(ident);
              }
          }
  
          /**
           * Used by the phone application to make the attention LED flash when ringing.
           */
          @Override // Binder call
          public void setAttentionLight(boolean on, int color) {
              mContext.enforceCallingOrSelfPermission(
                      android.Manifest.permission.DEVICE_POWER, null);
  
              final long ident = Binder.clearCallingIdentity();
              try {
                  setAttentionLightInternal(on, color);
              } finally {
                  Binder.restoreCallingIdentity(ident);
              }
          }
  
          @Override // Binder call
          public void setDozeAfterScreenOff(boolean on) {
              mContext.enforceCallingOrSelfPermission(
                      android.Manifest.permission.DEVICE_POWER, null);
  
              final long ident = Binder.clearCallingIdentity();
              try {
                  setDozeAfterScreenOffInternal(on);
              } finally {
                  Binder.restoreCallingIdentity(ident);
              }
          }
  
          @Override // Binder call
          public void boostScreenBrightness(long eventTime) {
              if (eventTime > SystemClock.uptimeMillis()) {
                  throw new IllegalArgumentException("event time must not be in the future");
              }
  
              mContext.enforceCallingOrSelfPermission(
                      android.Manifest.permission.DEVICE_POWER, null);
  
              final int uid = Binder.getCallingUid();
              final long ident = Binder.clearCallingIdentity();
              try {
                  boostScreenBrightnessInternal(eventTime, uid);
              } finally {
                  Binder.restoreCallingIdentity(ident);
              }
          }
  
          @Override // Binder call
          public boolean isScreenBrightnessBoosted() {
              final long ident = Binder.clearCallingIdentity();
              try {
                  return isScreenBrightnessBoostedInternal();
              } finally {
                  Binder.restoreCallingIdentity(ident);
              }
          }
  
          @Override // binder call
          public boolean forceSuspend() {
              mContext.enforceCallingOrSelfPermission(
                      android.Manifest.permission.DEVICE_POWER, null);
  
              final int uid = Binder.getCallingUid();
              final long ident = Binder.clearCallingIdentity();
              try {
                  return forceSuspendInternal(uid);
              } finally {
                  Binder.restoreCallingIdentity(ident);
              }
          }
  
          @Override // Binder call
          protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
              if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
  
              final long ident = Binder.clearCallingIdentity();
  
              boolean isDumpProto = false;
              for (String arg : args) {
                  if (arg.equals("--proto")) {
                      isDumpProto = true;
                  }
              }
              try {
                  if (isDumpProto) {
                      dumpProto(fd);
                  } else {
                      dumpInternal(pw);
                  }
              } finally {
                  Binder.restoreCallingIdentity(ident);
              }
          }
      }
  
      @VisibleForTesting
      BinderService getBinderServiceInstance() {
          return mBinderService;
      }
  
      @VisibleForTesting
      LocalService getLocalServiceInstance() {
          return mLocalService;
      }
  
      @VisibleForTesting
      // lastRebootReasonProperty argument to permit testing
      int getLastShutdownReasonInternal(String lastRebootReasonProperty) {
          String line = SystemProperties.get(lastRebootReasonProperty);
          if (line == null) {
              return PowerManager.SHUTDOWN_REASON_UNKNOWN;
          }
          switch (line) {
              case REASON_SHUTDOWN:
                  return PowerManager.SHUTDOWN_REASON_SHUTDOWN;
              case REASON_REBOOT:
                  return PowerManager.SHUTDOWN_REASON_REBOOT;
              case REASON_USERREQUESTED:
                  return PowerManager.SHUTDOWN_REASON_USER_REQUESTED;
              case REASON_THERMAL_SHUTDOWN:
                  return PowerManager.SHUTDOWN_REASON_THERMAL_SHUTDOWN;
              case REASON_LOW_BATTERY:
                  return PowerManager.SHUTDOWN_REASON_LOW_BATTERY;
              case REASON_BATTERY_THERMAL_STATE:
                  return PowerManager.SHUTDOWN_REASON_BATTERY_THERMAL;
              default:
                  return PowerManager.SHUTDOWN_REASON_UNKNOWN;
          }
      }
  
      private int getLastSleepReasonInternal() {
          synchronized (mLock) {
              return mLastSleepReason;
          }
      }
  
      private PowerManager.WakeData getLastWakeupInternal() {
          synchronized (mLock) {
              return new WakeData(mLastWakeTime, mLastWakeReason);
          }
      }
  
      @VisibleForTesting
      final class LocalService extends PowerManagerInternal {
          @Override
          public void setScreenBrightnessOverrideFromWindowManager(int screenBrightness) {
              if (screenBrightness < PowerManager.BRIGHTNESS_DEFAULT
                      || screenBrightness > PowerManager.BRIGHTNESS_ON) {
                  screenBrightness = PowerManager.BRIGHTNESS_DEFAULT;
              }
              setScreenBrightnessOverrideFromWindowManagerInternal(screenBrightness);
          }
  
          @Override
          public void setDozeOverrideFromDreamManager(int screenState, int screenBrightness) {
              switch (screenState) {
                  case Display.STATE_UNKNOWN:
                  case Display.STATE_OFF:
                  case Display.STATE_DOZE:
                  case Display.STATE_DOZE_SUSPEND:
                  case Display.STATE_ON_SUSPEND:
                  case Display.STATE_ON:
                  case Display.STATE_VR:
                      break;
                  default:
                      screenState = Display.STATE_UNKNOWN;
                      break;
              }
              if (screenBrightness < PowerManager.BRIGHTNESS_DEFAULT
                      || screenBrightness > PowerManager.BRIGHTNESS_ON) {
                  screenBrightness = PowerManager.BRIGHTNESS_DEFAULT;
              }
              setDozeOverrideFromDreamManagerInternal(screenState, screenBrightness);
          }
  
          @Override
          public void setUserInactiveOverrideFromWindowManager() {
              setUserInactiveOverrideFromWindowManagerInternal();
          }
  
          @Override
          public void setUserActivityTimeoutOverrideFromWindowManager(long timeoutMillis) {
              setUserActivityTimeoutOverrideFromWindowManagerInternal(timeoutMillis);
          }
  
          @Override
          public void setDrawWakeLockOverrideFromSidekick(boolean keepState) {
              setDrawWakeLockOverrideFromSidekickInternal(keepState);
          }
  
          @Override
          public void setMaximumScreenOffTimeoutFromDeviceAdmin(@UserIdInt int userId, long timeMs) {
              setMaximumScreenOffTimeoutFromDeviceAdminInternal(userId, timeMs);
          }
  
          @Override
          public PowerSaveState getLowPowerState(@ServiceType int serviceType) {
              return mBatterySaverPolicy.getBatterySaverPolicy(serviceType);
          }
  
          @Override
          public void registerLowPowerModeObserver(LowPowerModeListener listener) {
              mBatterySaverController.addListener(listener);
          }
  
          @Override
          public boolean setDeviceIdleMode(boolean enabled) {
              return setDeviceIdleModeInternal(enabled);
          }
  
          @Override
          public boolean setLightDeviceIdleMode(boolean enabled) {
              return setLightDeviceIdleModeInternal(enabled);
          }
  
          @Override
          public void setDeviceIdleWhitelist(int[] appids) {
              setDeviceIdleWhitelistInternal(appids);
          }
  
          @Override
          public void setDeviceIdleTempWhitelist(int[] appids) {
              setDeviceIdleTempWhitelistInternal(appids);
          }
  
          @Override
          public void startUidChanges() {
              startUidChangesInternal();
          }
  
          @Override
          public void finishUidChanges() {
              finishUidChangesInternal();
          }
  
          @Override
          public void updateUidProcState(int uid, int procState) {
              updateUidProcStateInternal(uid, procState);
          }
  
          @Override
          public void uidGone(int uid) {
              uidGoneInternal(uid);
          }
  
          @Override
          public void uidActive(int uid) {
              uidActiveInternal(uid);
          }
  
          @Override
          public void uidIdle(int uid) {
              uidIdleInternal(uid);
          }
  
          @Override
          public void powerHint(int hintId, int data) {
              powerHintInternal(hintId, data);
          }
  
          @Override
          public boolean wasDeviceIdleFor(long ms) {
              return wasDeviceIdleForInternal(ms);
          }
  
          @Override
          public WakeData getLastWakeup() {
              return getLastWakeupInternal();
          }
      }
  }
  