第 29 章:电源管理

📅 2026/8/21 9:24:55
第 29 章:电源管理
电源管理是 Android 最关键的子系统之一。手机想要维持一整天续航,每毫安电流都至关重要。Android 依靠多层架构实现续航能力:从 Linux 内核挂起机制,电源与热控硬件抽象层,再到框架层服务;框架层服务负责跟踪唤醒锁、执行 Doze 与应用待机策略、将功耗统计归属到各个 UID。本章以 AOSP 真实源码为主要参考,逐层剖析上述各个组件。29.1 电源管理架构29.1.1 高层概述Android 电源管理由 Linux 内核、厂商定制 HAL、Android 框架协同工作。高层架构如下:应用 | v PowerManager(android.os.PowerManager) -- 公开 API | v PowerManagerService(system_server) -- 策略引擎 | ├── Notifier(广播、电池统计) ├── PowerGroup(每个显示分组状态) ├── SuspendBlocker(阻止内核挂起) | v Power HAL(IPower) -- 厂商插件 | v Linux 内核(cpufreq、suspend、wakeup_sources)框架服务PowerManagerService处于核心位置。接收应用请求(唤醒锁、用户活动事件),与策略模块(Doze、省电模式、显示控制器)交互,通过 Power HAL 以及原生 JNI 调用驱动硬件,向下访问内核。源码文件:frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java29.1.2 核心组件组件源码路径作用PowerManagerServiceframeworks/base/services/core/java/com/android/server/power/PowerManagerService.java核心策略引擎PowerGroupframeworks/base/services/core/java/com/android/server/power/PowerGroup.java每个显示分组的唤醒状态管理Notifierframeworks/base/services/core/java/com/android/server/power/Notifier.java电源事件广播发送器SuspendBlockerframeworks/base/services/core/java/com/android/server/power/SuspendBlocker.java底层 CPU 保活控制WakeLockLogframeworks/base/services/core/java/com/android/server/power/WakeLockLog.java压缩环形缓冲区日志DeviceIdleControllerframeworks/base/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.javaDoze(轻度 + 深度)状态机AppStandbyControllerframeworks/base/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java应用待机分组ThermalManagerServiceframeworks/base/services/core/java/com/android/server/power/thermal/ThermalManagerService.java热事件分发BatteryStatsImplframeworks/base/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java能耗统计记账IPower HALhardware/interfaces/power/aidl/android/hardware/power/IPower.aidl厂商电源 Hint 接口IThermal HALhardware/interfaces/thermal/aidl/android/hardware/thermal/IThermal.aidl温度监控29.1.3 设备唤醒状态Android 使用四状态机跟踪设备唤醒状态,常量定义在PowerManagerInternal:// frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java 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;状态数值说明WAKEFULNESS_AWAKE1屏幕点亮,用户正在交互WAKEFULNESS_DREAMING2屏保(Dream)正在运行WAKEFULNESS_DOZING3低功耗常显(AOD)WAKEFULNESS_ASLEEP0屏幕熄灭,CPU 可以进入挂起状态流转:29.1.4 Dirty Bits(脏位)机制PowerManagerService使用名为mDirty的位掩码,记录电源状态发生变更、需要重新计算的项。这是核心优化点:微小事件到来时不会全量重算电源策略,只重新计算被标记为脏的部分。// PowerManagerService.java,第201‑232行 // Dirty bit:mWakeLocks发生变更 private static final int DIRTY_WAKE_LOCKS = 1 0; // Dirty bit:mWakefulness发生变更 private static final int DIRTY_WAKEFULNESS = 1 1; // Dirty bit:用户被触发活动或者可能超时 private static final int DIRTY_USER_ACTIVITY = 1 2; // Dirty bit:实际显示电源状态已异步更新 private static final int DIRTY_ACTUAL_DISPLAY_POWER_STATE_UPDATED = 1 3; // Dirty bit:mBootCompleted发生变更 private static final int DIRTY_BOOT_COMPLETED = 1 4; // Dirty bit:设置项发生变更 private static final int DIRTY_SETTINGS = 1 5; // Dirty bit:mIsPowered发生变更 private static final int DIRTY_IS_POWERED = 1 6; // Dirty bit:mStayOn发生变更 private static final int DIRTY_STAY_ON = 1 7; // Dirty bit:电池状态发生变更 private static final int DIRTY_BATTERY_STATE = 1 8; // Dirty bit:距离传感器状态发生变更 private static final int DIRTY_PROXIMITY_POSITIVE = 1 9; // Dirty bit:底座状态发生变更 private static final int DIRTY_DOCK_STATE = 1 10; // Dirty bit:亮度增强状态变更 private static final int DIRTY_SCREEN_BRIGHTNESS_BOOST = 1 11; // Dirty bit:sQuiescent发生变更 private static final int DIRTY_QUIESCENT = 1 12; // Dirty bit:attentive计时器可能超时 private static final int DIRTY_ATTENTIVE = 1 14; // Dirty bit:显示分组唤醒状态变更 private static final int DIRTY_DISPLAY_GROUP_WAKEFULNESS = 1 16; // Dirty bit:设备姿态状态变更 private static final int DIRTY_POSTURED_STATE = 1 17;任意属性发生变更,通过或运算设置对应脏位,调用updatePowerStateLocked()重新计算所有脏项。29.1.5 电源状态更新循环PowerManagerService的核心是updatePowerStateLocked()方法。每当电源相关状态变化,该方法执行多阶段循环。// PowerManagerService.java,第2689行 private void updatePowerStateLocked() { if (!mSystemReady || mDirty == 0 || mUpdatePowerStateInProgress) { return; } Trace.traceBegin(Trace.TRACE_TAG_POWER, "updatePowerState"); mUpdatePowerStateInProgress = true; try { // 阶段0:基础状态更新 updateIsPoweredLocked(mDirty); updateStayOnLocked(mDirty); updateScreenBrightnessBoostLocked(mDirty); // 阶段1:更新唤醒状态 // 使用循环:唤醒锁、用户活动计算会被唤醒状态变更影响 final long now = mClock.uptimeMillis(); int dirtyPhase2 = 0; for (;;) { int dirtyPhase1 = mDirty; dirtyPhase2 |= dirtyPhase1; mDirty = 0; updateWakeLockSummaryLocked(dirtyPhase1); updateUserActivitySummaryLocked(now, dirtyPhase1); updateAttentiveStateLocked(now, dirtyPhase1); if (!updateWakefulnessLocked(dirtyPhase1)) { break; } } // 阶段2:更新不再活跃、不再保活的锁配置 updateProfilesLocked(now); // 阶段3:更新所有PowerGroup电源状态 final boolean powerGroupsBecameReady = updatePowerGroupsLocked(dirtyPhase2); // 阶段4:更新屏保状态(依赖PowerGroup就绪信号) updateDreamLocked(dirtyPhase2, powerGroupsBecameReady); // 阶段5:按需发送通知 finishWakefulnessChangeIfNeededLocked(); // 阶段6:按需通知屏幕超时策略变更 notifyScreenTimeoutPolicyChangesLocked(); // 阶段7:更新SuspendBlocker // 此处可能释放最后一个suspend blocker,必须保证前面所有逻辑执行完毕 updateSuspendBlockerLocked(); } finally { Trace.traceEnd(Trace.TRACE_TAG_POWER); mUpdatePowerStateInProgress = false; } }七个阶段构成 Android 电源管理的心跳。阶段 1 内部循环,因为唤醒状态变更会让唤醒锁、用户活动汇总结果失效,需要再次迭代。29.1.6 完整更新流程详解以用户按下电源键熄屏场景,追踪各阶段协同工作流程:goToSleepInternal()逆序遍历 PowerGroup,非默认分组优先完成状态切换,之后再处理默认分组:// PowerManagerService.java,第7561行 private void goToSleepInternal(IntArray groupIds, long eventTime, int reason, int flags) { // ... synchronized (mLock) { // 逆序遍历,保证所有非默认显示分组先完成状态变更,再处理默认分组 for (int i = groupIds.size() - 1; i = 0; i--) { int groupId = groupIds.get(i); PowerGroup powerGroup = mPowerGroups.get(groupId); if ((flags PowerManager.GO_TO_SLEEP_FLAG_SOFT_SLEEP) != 0) { if (!powerGroup.hasWakeLockKeepingScreenOnLocked()) { mNotifier.showDismissibleKeyguard(); } continue; } if (isNoDoze) { sleepPowerGroupLocked(powerGroup, eventTime, reason, uid); } else { dozePowerGroupLocked(powerGroup, eventTime, reason, uid, false); } } } }注意GO_TO_SLEEP_FLAG_SOFT_SLEEP分支:不会真正熄屏,而是展示可关闭的锁屏界面,供部分无障碍流程使用。29.1.7 PowerGroup 唤醒状态切换每一个PowerGroup实现真实的唤醒状态切换。wakePowerGroupLocked()负责唤醒操作:// PowerManagerService.java,第2315行 private void wakePowerGroupLocked(final PowerGroup powerGroup, long eventTime, @WakeReason int reason, String details, int uid, String opPackageName, int opUid) { if (mForceSuspendActive || !mSystemReady || (powerGroup == null) || hasWakeLockKeepingGroupAsleep( powerGroup.getWakeLockSummaryLocked())) { return; } powerGroup.wakeUpLocked(eventTime, reason, details, uid, opPackageName, opUid, LatencyTracker.getInstance(mContext)); }进入 Doze 状态包含多显示器场景特殊逻辑:如果默认分组存在相邻显示分组仍然处于交互状态,则默认分组直接进入睡眠,而不是 Doze。// PowerManagerService.java,第2363行 private boolean dozePowerGroupLocked(final PowerGroup powerGroup, long eventTime, @GoToSleepReason int reason, int uid, boolean allowSleepToDozeTransition) { if (powerGroup.getGroupId() != Display.DEFAULT_DISPLAY_GROUP) { return sleepPowerGroupLocked(powerGroup, eventTime, reason, uid); } // 折叠屏/多显示器:如果相邻分组仍然交互,默认分组直接睡眠而非Doze if (com.android.server.display.feature.flags.Flags.separateTimeouts()) { boolean shouldSleep = (isDefaultAdjacentGroupInteractiveLocked()) || (powerGroup.getWakefulnessLocked() == WAKEFULNESS_ASLEEP !doAnyAdjacentGroupsExistLocked()); if (shouldSleep powerGroup.isDefaultOrAdjacentGroup()) { return sleepPowerGroupLocked(powerGroup, eventTime, reason, uid); } } return powerGroup.dozeLocked(eventTime, uid, reason, allowSleepToDozeTransition); }29.1.8 PowerManagerService 初始化PowerManagerService在system_server启动阶段完成实例化与注册。构造函数创建 Handler 线程、SuspendBlocker 以及原生封装对象。// PowerManagerService.java,第1216行 public PowerManagerService(Context context) { this(context, new Injector()); }Injector注入模式支持单元测试,可以将真实实现替换为 Mock 对象。关键初始化步骤:创建 Handler 线程,线程优先级THREAD_PRIORITY_DISPLAY创建 3 个 SuspendBlocker:Booting、WakeLocks、DisplayJNI 调用nativeInit(),完成与 Power HAL 连接开机默认关闭 auto‑suspend,开启 interactive 模式读取系统属性ro.boot.quiescent得到sQuiescent标记// PowerManagerService.java,第1304行 synchronized (mLock) { mBootingSuspendBlocker = mInjector.createSuspendBlocker(this, "PowerManagerService.Booting"); mWakeLockSuspendBlocker = mInjector.createSuspendBlocker(this, "PowerManagerService.WakeLocks"); mDisplaySuspendBlocker = mInjector.createSuspendBlocker(this, "PowerManagerService.Display"); // ... mNativeWrapper.nativeInit(this); mNativeWrapper.nativeSetAutoSuspend(false); mNativeWrapper.nativeSetPowerMode(Mode.INTERACTIVE, true); mNativeWrapper.nativeSetPowerMode(Mode.DOUBLE_TAP_TO_WAKE, false); }systemReady()阶段,服务连接DisplayManagerInternal、DreamManagerInternal、WindowManagerPolicy、BatteryManagerInternal;创建默认显示分组对应的PowerGroup,注册DisplayGroupListener监听动态新增显示器。29.2 PowerManagerService29.2.1 服务架构PowerManagerService继承SystemService,同时实现Watchdog.Monitor。对外发布两套服务接口:Binder 服务(Context.POWER_SERVICE):IPowerManagerAIDL,应用访问的公开接口本地服务(PowerManagerInternal):系统内部进程间调用接口,供其他系统服务使用// PowerManagerService.java,第1361行 @Override public void onStart() { publishBinderService(Context.POWER_SERVICE, mBinderService, /* allowIsolated= */ false, DUMP_FLAG_PRIORITY_CRITICAL); publishLocalService(PowerManagerInternal.class, mLocalService); Watchdog.getInstance().addMonitor(this); Watchdog.getInstance().addThread(mHandler); }向 Watchdog 注册至关重要:如果PowerManagerService发生死锁,Watchdog 会杀死并重启system_server。29.2.2 唤醒锁汇总位掩码服务内部维护所有活跃唤醒锁的汇总位掩码,避免每次决策遍历全部唤醒锁列表。// PowerManagerService.java,第234‑244行 // 汇总所有活跃唤醒锁状态 static final int WAKE_LOCK_CPU = 1 0; static final int WAKE_LOCK_SCREEN_BRIGHT = 1 1; static final int WAKE_LOCK_SCREEN_DIM = 1 2; static final int WAKE_LOCK_BUTTON_BRIGHT = 1 3; static final int WAKE_LOCK_PROXIMITY_SCREEN_OFF = 1 4; static final int WAKE_LOCK_STAY_AWAKE = 1 5; static final int WAKE_LOCK_DOZE = 1 6; static final int WAKE_LOCK_DRAW = 1 7; static final int WAKE_LOCK_SCREEN_TIMEOUT_OVERRIDE = 1 8; static final int WAKE_LOCK_PARTIAL_SLEEP = 1 9;用户活动状态同样使用位掩码汇总:// 汇总用户活动状态 static final int USER_ACTIVITY_SCREEN_BRIGHT = 1 0; static final int USER_ACTIVITY_SCREEN_DIM = 1 1; static final int USER_ACTIVITY_SCREEN_DREAM = 1 2;29.2.3 用户活动与超时机制用户活动是维持屏幕点亮的机制。触摸、按键等交互调用userActivity()重置无活动计时器。屏幕超时由Settings.System.SCREEN_OFF_TIMEOUT控制。用户活动调用流程:内部记录lastUserActivityTime,依据screen_off_timeout计算超时时间。29.2.4 休眠与唤醒goToSleep()与wakeUp()驱动设备在各个唤醒状态之间切换;可以由电源按键、超时、代码调用触发。休眠原因(来自 PowerManager):GO_TO_SLEEP_REASON_APPLICATION应用请求休眠GO_TO_SLEEP_REASON_DEVICE_ADMIN设备管理员强制休眠GO_TO_SLEEP_REASON_TIMEOUT用户无操作超时GO_TO_SLEEP_REASON_LID_SWITCH笔记本合盖GO_TO_SLEEP_REASON_POWER_BUTTON用户按下电源键GO_TO_SLEEP_REASON_HDMIHDMI 断开GO_TO_SLEEP_REASON_SLEEP_BUTTON专用休眠按键GO_TO_SLEEP_REASON_ACCESSIBILITY无障碍动作GO_TO_SLEEP_REASON_FORCE_SUSPEND强制挂起GO_TO_SLEEP_REASON_DISPLAY_GROUPS_TURNED_OFF所有显示分组关闭GO_TO_SLEEP_REASON_DISPLAY_GROUP_REMOVED显示分组被移除GO_TO_SLEEP_REASON_QUIESCENT静默启动模式唤醒原因(来自 PowerManager):WAKE_REASON_POWER_BUTTON按下电源键WAKE_REASON_APPLICATION应用请求唤醒WAKE_REASON_PLUGGED_IN接入充电器WAKE_REASON_GESTURE检测到手势WAKE_REASON_WAKE_KEY唤醒按键按下WAKE_REASON_WAKE_MOTION检测到运动WAKE_REASON_DREAM_FINISHED屏保结束WAKE_REASON_DISPLAY_GROUP_ADDED新显示器接入WAKE_REASON_DISPLAY_GROUP_TURNED_ON显示器开启29.2.5 PowerGroupAndroid12 起,PowerManagerService以显示分组为单位管理电源状态,每一个DisplayGroup(一组共享电源状态的显示器)对应一个PowerGroup对象。// PowerGroup.java,第61行 public class PowerGroup { private final int mGroupId; private int mWakefulness; private int mWakeLockSummary; private int mUserActivitySummary; private long mLastWakeTime; private long mLastSleepTime; final DisplayPowerRequest mDisplayPowerRequest = new DisplayPowerRequest(); // ... }默认显示分组永久存在;外接显示器、虚拟显示器接入时动态创建额外分组。非默认分组可以标记为default‑group‑adjacent,代表与默认分组共用电源按键、锁屏行为。// PowerManagerService.java,第872行 private boolean isDefaultGroupAdjacent(int groupId) { long flags = mDisplayManagerInternal.getDisplayGroupFlags(groupId); return (flags DisplayGroup.FLAG_DEFAULT_GROUP_ADJACENT) != 0; }PowerGroupWakefulnessChangeListener监听唤醒状态变更:// PowerManagerService.java,第729行 private final class PowerGroupWakefulnessChangeListener implements PowerGroup.PowerGroupListener { @Override public void onWakefulnessChangedLocked(int groupId, int wakefulness, long eventTime, int reason, int uid, int opUid, String opPackageName, String details) { mWakefulnessChanging = true; mDirty |= DIRTY_WAKEFULNESS; // ... mDirty |= DIRTY_DISPLAY_GROUP_WAKEFULNESS; mNotifier.onGroupWakefulnessChangeStarted(groupId, wakefulness, reason, eventTime); updateGlobalWakefulnessLocked(eventTime, reason, uid, opUid, opPackageName, details); updatePowerStateLocked(); } }29.2.6 显示电源集成PowerManagerService通过DisplayManagerInternal控制显示器电源。每个PowerGroup维护DisplayPowerRequest,描述期望显示状态(ON/OFF/DOZE)以及亮度。显示电源请求在电源状态更新阶段 3updatePowerGroupsLocked()中计算完成,调用:mDisplayManagerInternal.requestPowerState(groupId, mDisplayPowerRequest)显示控制器异步执行状态变更,通过mDisplayPowerCallbacks回调;回调内部设置DIRTY_ACTUAL_DISPLAY_POWER_STATE_UPDATED,触发新一轮电源状态评估。29.2.7 NotifierNotifier负责向系统其他组件广播电源状态变更,发送广播例如:ACTION_SCREEN_ON/ACTION_SCREEN_OFFACTION_DREAMING_STARTED/ACTION_DREAMING_STOPPEDACTION_DEVICE_IDLE_MODE_CHANGEDNotifier运行在主线 Looper,而不是电源管理 Handler 线程,避免干扰电源管理关键时序。// PowerManagerService.java,第1420行 mNotifier = mInjector.createNotifier(Looper.getMainLooper(), mContext, mBatteryStats, mInjector.createSuspendBlocker(this, "PowerManagerService.Broadcasts"), mPolicy, mFaceDownDetector, mScreenUndimDetector, BackgroundThread.getExecutor(), mFeatureFlags);29.2.8 消息处理PowerManagerService使用消息机制处理延迟任务:// PowerManagerService.java,第182‑199行 private static final int MSG_USER_ACTIVITY_TIMEOUT = 1; private static final int MSG_SANDMAN = 2; private static final int MSG_SCREEN_BRIGHTNESS_BOOST_TIMEOUT = 3; private static final int MSG_CHECK_FOR_LONG_WAKELOCKS = 4; private static final int MSG_ATTENTIVE_TIMEOUT = 5; private static final int MSG_RELEASE_ALL_OVERRIDE_WAKE_LOCKS = 6; private static final int MSG_PROCESS_FROZEN_STATE_CHANGED = 7; private static final int MSG_FORCE_DISABLE_WAKELOCKS = 8;MSG_SANDMAN消息尤为关键:触发屏保、Doze 状态切换。用户活动计时器超时后调度该消息,最终调用DreamManagerService启动 / 停止屏保 / 常显界面。29.2.9 设置项观察者PowerManagerService注册内容观察者监听大量影响电源行为的系统设置:SCREENSAVER_ENABLED是否启用屏保SCREENSAVER_ACTIVATE_ON_SLEEP休眠时启动屏保SCREENSAVER_ACTIVATE_ON_DOCK底座接入时启动屏保SCREEN_OFF_TIMEOUT屏幕超时时长SLEEP_TIMEOUT附加休眠超时ATTENTIVE_TIMEOUT人眼检测超时STAY_ON_WHILE_PLUGGED_IN充电时保持屏幕常亮DOZE_ALWAYS_ON常显 AOD 开关DOUBLE_TAP_TO_WAKE双击亮屏手势THEATER_MODE_ON影院模式29.2.10 省电模式集成省电模式与PowerManagerService深度集成,相关源码目录:frameworks/base/services/core/java/com/android/server/power/batterysaver/BatterySaverController.javaBatterySaverPolicy.javaBatterySaverStateMachine.javaBatterySavingStats.javaBatterySaverStateMachine依据设备配置条件化创建:// PowerManagerService.java,第1247行 mBatterySaverSupported = mContext.getResources().getBoolean( com.android.internal.R.bool.config_batterySaverSupported); mBatterySaverStateMachine = mBatterySaverSupported ? mInjector.createBatterySaverStateMachine(mLock, mContext) : null;BatterySaverPolicy定义省电模式生效时启用的各项限制:// BatterySaverPolicy.java static final String KEY_LOCATION_MODE = "location_mode"; static final String KEY_DISABLE_VIBRATION = "disable_vibration"; static final String KEY_DISABLE_ANIMATION = "disable_animation"; static final String KEY_SOUNDTRIGGER_MODE = "soundtrigger_mode"; static final String KEY_ENABLE_FIREWALL = "enable_firewall"; static final String KEY_ENABLE_BRIGHTNESS_ADJUSTMENT = "enable_brightness_adjustment"; static final String KEY_ENABLE_DATASAVER = "enable_datasaver";省电模式激活,PowerManagerService通知 Power HAL:nativeSetPowerMode(Mode.LOW_POWER, true);厂商 HAL 可以降低 CPU 频率、关闭大核、降低 GPU 时钟,执行其他省电动作。29.2.11 静默模式 Quiescent Mode静默模式是特殊开机模式:开机后屏幕保持熄灭。用于无屏幕设备或者工厂测试。// PowerManagerService.java,第263行 private static final String SYSTEM_PROPERTY_QUIESCENT = "ro.boot.quiescent"; // 构造函数中读取 sQuiescent = mSystemProperties.get(SYSTEM_PROPERTY_QUIESCENT, "0").equals("1"); // 开机完成后处理 if (sQuiescent) { sleepPowerGroupLocked( mPowerGroups.get(Display.DEFAULT_DISPLAY_GROUP), mClock.uptimeMillis(), PowerManager.GO_TO_SLEEP_REASON_QUIESCENT, Process.SYSTEM_UID); }29.2.12 翻面检测 Face‑Down DetectionPowerManagerService内置FaceDownDetector,使用加速度传感器检测设备屏幕朝下放置。检测到后缩短屏幕超时时间。// PowerManagerService.java,第1333行 private void onFlip(boolean isFaceDown) { synchronized (mLock) { mIsFaceDown = isFaceDown; if (isFaceDown) { final long currentTime = mClock.uptimeMillis(); mLastFlipTime = currentTime; // 触发用户活动,启动更短超时 userActivityInternal(Display.DEFAULT_DISPLAY, currentTime, PowerManager.USER_ACTIVITY_EVENT_FACE_DOWN, PowerManager.USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS, Process.SYSTEM_UID); } } if (isFaceDown) { mFaceDownDetector.setMillisSaved(millisUntilNormalTimeout); } }29.2.13 人眼注意力检测 Attention DetectionAttentionDetector使用设备人眼检测服务(通常基于摄像头)判断用户是否正在观看屏幕。检测到用户注视屏幕时,延长屏幕超时,避免阅读时无触摸自动熄屏。// PowerManagerService.java,第1243行 mAttentionDetector = new AttentionDetector(this::onUserAttention, mLock);29.2.14 屏幕防调暗检测 Screen Undim DetectionScreenUndimDetector跟踪熄屏前调暗阶段用户交互。如果用户频繁阻止屏幕调暗,系统学习并延长屏幕超时。29.2.15 无线充电器检测 Wireless Charger DetectionWirelessChargerDetector借助传感器确认无线充电底座放置状态。避免设备离开充电器时误唤醒,保证底座接入时正确唤醒行为。// PowerManagerService.java,第1439行 mWirelessChargerDetector = mInjector.createWirelessChargerDetector( sensorManager, mInjector.createSuspendBlocker(this, "PowerManagerService.WirelessChargerDetector"), mHandler);29.3 WakeLocks 唤醒锁29.3.1 唤醒锁等级唤醒锁是应用阻止设备(或部分硬件)进入休眠的基础机制。每个唤醒锁拥有等级与可选标记。唤醒锁等级定义在android.os.PowerManager:// frameworks/base/core/java/android/os/PowerManager.java public static final int PARTIAL_WAKE_LOCK = 0x00000001; public static final int SCREEN_DIM_WAKE_LOCK = 0x00000006; // @Deprecated public static final int SCREEN_BRIGHT_WAKE_LOCK = 0x0000000a; // @Deprecated public static final int FULL_WAKE_LOCK = 0x0000001a; // @Deprecated public static final int PROXIMITY_SCREEN_OFF_WAKE_LOCK = 0x00000020; public static final int DOZE_WAKE_LOCK = 0x00000040; // @SystemApi public static final int DRAW_WAKE_LOCK = 0x00000080; // @SystemApi等级CPU屏幕按键背光说明PARTIAL_WAKE_LOCK开启‑‑‑‑最常用;CPU 保持运行,屏幕可以熄灭SCREEN_DIM_WAKE_LOCK开启调暗‑‑已废弃;使用窗口FLAG_KEEP_SCREEN_ONSCREEN_BRIGHT_WAKE_LOCK开启高亮‑‑已废弃FULL_WAKE_LOCK开启高亮高亮已废弃PROXIMITY_SCREEN_OFF_WAKE_LOCK开启熄灭 / 点亮‑‑靠近距离传感器时熄屏DOZE_WAKE_LOCK开启‑‑‑‑仅系统使用;维持 Doze 运行DRAW_WAKE_LOCK开启‑‑‑‑仅系统使用;允许 Doze 模式绘制29.3.2 唤醒锁标记可选标记修改唤醒锁行为:// PowerManager.java public static final int ACQUIRE_CAUSES_WAKEUP = 0x10000000; public static final int ON_AFTER_RELEASE = 0x20000000;ACQUIRE_CAUSES_WAKEUP:获取唤醒锁同时点亮屏幕。Android V + 应用需要持有TURN_SCREEN_ON