电源管理是 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.java
29.1.2 核心组件
| 组件 | 源码路径 | 作用 |
|---|---|---|
| PowerManagerService | frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java | 核心策略引擎 |
| PowerGroup | frameworks/base/services/core/java/com/android/server/power/PowerGroup.java | 每个显示分组的唤醒状态管理 |
| Notifier | frameworks/base/services/core/java/com/android/server/power/Notifier.java | 电源事件广播发送器 |
| SuspendBlocker | frameworks/base/services/core/java/com/android/server/power/SuspendBlocker.java | 底层 CPU 保活控制 |
| WakeLockLog | frameworks/base/services/core/java/com/android/server/power/WakeLockLog.java | 压缩环形缓冲区日志 |
| DeviceIdleController | frameworks/base/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java | Doze(轻度 + 深度)状态机 |
| AppStandbyController | frameworks/base/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java | 应用待机分组 |
| ThermalManagerService | frameworks/base/services/core/java/com/android/server/power/thermal/ThermalManagerService.java | 热事件分发 |
| BatteryStatsImpl | frameworks/base/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java | 能耗统计记账 |
| IPower HAL | hardware/interfaces/power/aidl/android/hardware/power/IPower.aidl | 厂商电源 Hint 接口 |
| IThermal HAL | hardware/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_AWAKE | 1 | 屏幕点亮,用户正在交互 |
| WAKEFULNESS_DREAMING | 2 | 屏保(Dream)正在运行 |
| WAKEFULNESS_DOZING | 3 | 低功耗常显(AOD) |
| WAKEFULNESS_ASLEEP | 0 | 屏幕熄灭,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、Display
- JNI 调用
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 PowerManagerService
29.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 PowerGroup
Android12 起,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)以及亮度。
显示电源请求在电源状态更新阶段 3 updatePowerGroupsLocked()中计算完成,调用:
mDisplayManagerInternal.requestPowerState(groupId, mDisplayPowerRequest)
显示控制器异步执行状态变更,通过mDisplayPowerCallbacks回调;回调内部设置DIRTY_ACTUAL_DISPLAY_POWER_STATE_UPDATED,触发新一轮电源状态评估。
29.2.7 Notifier
Notifier负责向系统其他组件广播电源状态变更,发送广播例如:
ACTION_SCREEN_ON/ACTION_SCREEN_OFFACTION_DREAMING_STARTED/ACTION_DREAMING_STOPPEDACTION_DEVICE_IDLE_MODE_CHANGED
Notifier运行在主线 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.java
BatterySaverStateMachine依据设备配置条件化创建:
// 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 Detection
PowerManagerService内置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 Detection
AttentionDetector使用设备人眼检测服务(通常基于摄像头)判断用户是否正在观看屏幕。检测到用户注视屏幕时,延长屏幕超时,避免阅读时无触摸自动熄屏。
// PowerManagerService.java,第1243行
mAttentionDetector = new AttentionDetector(this::onUserAttention, mLock);
29.2.14 屏幕防调暗检测 Screen Undim Detection
ScreenUndimDetector跟踪熄屏前调暗阶段用户交互。如果用户频繁阻止屏幕调暗,系统学习并延长屏幕超时。
29.2.15 无线充电器检测 Wireless Charger Detection
WirelessChargerDetector借助传感器确认无线充电底座放置状态。避免设备离开充电器时误唤醒,保证底座接入时正确唤醒行为。
// 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_ON |
| SCREEN_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


1486

被折叠的 条评论
为什么被折叠?



