本文基于Android 11源码分析
前言
亮屏有很多种方式,如Power键亮屏、插拔USB亮屏、来电亮屏......,虽然方式不同,但只要发起亮屏,其流程都是一样的。PowerManager中提供了wakeUp()方法给其他组件或应用来点亮屏幕,下面就从这个方法开始分析亮屏流程。
// frameworks/base/core/java/android/os/PowerManager.java
/**
* @param time 亮屏时间
* @param reason 亮屏原因
* @param details 细节描述
*/
public void wakeUp(long time, @WakeReason int reason, String details) {
try {
mService.wakeUp(time, reason, details, mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
调用PowerManager的wakeUp()后,将直接调用PMS#wakeUp()方法,在进行权限检查后,调用wakeUpInternal()进入到PMS内部流程:
// frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
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();
}
}
}
这个方法中:
首先,调用wakeUpNoUpdateLocked()方法;
然后,根据调用返回值确定是否更新全局状态。
1.wakeUpNoUpdateLocked()验证和亮屏状态更新
此方法是进行亮屏的主要方法,如果亮屏成功,该方法返回true,并更新全局状态;如果因不满足亮屏条件,则返回false,说明亮屏失败:
// frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
private boolean wakeUpNoUpdateLocked(long eventTime, @WakeReason int reason, String details,
int reasonUid, String opPackageName, int opUid) {
// 此次亮屏时间小于最近一次灭屏时间、已经处于亮屏、系统未启动完成或强制suspend,不会进行亮屏
if (eventTime < mLastSleepTime || mWakefulness == WAKEFULNESS_AWAKE
|| !mBootCompleted || !mSystemReady || mForceSuspendActive) {
return false;
}
try {
mLastWakeTime = eventTime; // 更新最后一次亮屏时间
mLastWakeReason = reason; // 更新亮屏原因
// 更新mWakefulness值
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;
}
首先,进行亮屏时间和状态的验证,如果满足以下三个条件之一,则亮屏不会成功,返回false,验证完成后,开始执行亮屏流程:
此次亮屏时间小于最近一次灭屏时间;
唤醒状态已经处于亮屏;
系统未启动完成或强制suspend。
接下来,会更新mLastWakeTime和mLastWakeReason,表示最后一次亮屏时间和原因。
然后,调用setWakefulnessLocked()方法来设置表示PMS唤醒状态mWakefulness的值。
最后,执行userActivityNoUpdateLocked()方法更新用户活动时间。
1.1 setWakefulnessLocked()更新唤醒状态
// frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
void setWakefulnessLocked(int wakefulness, int reason, long eventTime) {
if (getWakefulnessLocked() != wakefulness) {
// 更新mWakefulness
mWakefulnessRaw = wakefulness;
mWakefulnessChanging = true;
mDirty |= DIRTY_WAKEFULNESS;
mDozeStartInProgress &= (getWakefulnessLocked() == WAKEFULNESS_DOZING);
// mNotifier中做mWakefuless转变的开始工作
if (mNotifier != null) {
mNotifier.onWakefulnessChangeStarted(wakefulness, reason, eventTime);
}
// 通知mAttentionDetector系统状态的改变
mAttentionDetector.onWakefulnessChangeStarted(wakefulness);
}
}
这里会将mWakefulnessRaw的值设置为WAKEFULNESS_AWAKE,表示屏幕状态为Awake。然后通过Notifier#onWakefulnessChangeStarted()方法进行屏幕状态开始改变但未完成切断的工作(如亮灭屏广播)。
1.2 Notifier#onWakefulnessChangeStarted()
// frameworks/base/services/core/java/com/android/server/power/Notifier.java
public void onWakefulnessChangeStarted(final int wakefulness, int reason, long eventTime) {
// 是否为可交互状态
final boolean interactive = PowerManagerInternal.isInteractive(wakefulness);
......
if (mInteractive != interactive) {
// Finish up late behaviors if needed.
if (mInteractiveChanging) {
handleLateInteractiveChange();
}
.......
// 更新交互状态
mInteractive = interactive;
mInteractiveChangeReason = reason;
mInteractiveChangeStartTime = eventTime;
// 交互状态开始变化
mInteractiveChanging = true;
// 进行交状态变化早期任务
handleEarlyInteractiveChange();
}
}
首先更新mInteractive值,表示系统是否可交互,并将交互状态设置给Input模块。当PMS唤醒状态为Awake和Dreaming时,认为是可交互状态。然后调用handleEarlyInteractiveChange()方法,进行交状态变化后的早期任务。
1.3 handleEarlyInteractiveChange()进行交互状态变化后的早期任务
// frameworks/base/services/core/java/com/android/server/power/Notifier.java
private void handleEarlyInteractiveChange() {
synchronized (mLock) {
if (mInteractive) { // 可交互状态
// 在system_server主线程进行
mHandler.post(new Runnable() {
@Override
public void run() {
final int why = translateOnReason(mInteractiveChangeReason);
// 通知PhoneWindowManager开始亮屏
mPolicy.startedWakingUp(why);
}
});
// 表示处于哪种交互状态变化过程中
mPendingInteractiveState = INTERACTIVE_STATE_AWAKE;
// 表示将要发送亮屏广播
mPendingWakeUpBroadcast = true;
// 发送亮屏广播
updatePendingBroadcastLocked();
} else {
// Going to sleep...
......
}
}
}
亮屏时属于可交互状态,mInteractive此时为true,因此调用PhoneWindowManager#startedWakingUp()方法,该方法中将会通知锁屏等组件进行相应操作,需要注意的是,这个调用是在system_server主线程进行。然后通过updatePendingBroadcastLocked()方法发送亮屏广播。
1.4 updatePendingBroadcastLocked()发送亮屏广播
该方法负责亮灭屏广播的发送:
// frameworks/base/services/core/java/com/android/server/power/Notifier.java
private void updatePendingBroadcastLocked() {
if (!mBroadcastInProgress
&& mPendingInteractiveState != INTERACTIVE_STATE_UNKNOWN
&& (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast
|| mPendingInteractiveState != mBroadcastedInteractiveState)) {
mBroadcastInProgress = true; // 表示处于广播发送过程中
mSuspendBlocker.acquire(); // 申请SuspendBlocker,防止CPU休眠
Message msg = mHandler.obtainMessage(MSG_BROADCAST); // system_server中进行发送亮屏广播流程
msg.setAsynchronous(true);
mHandler.sendMessage(msg);
}
}
这里会先进行条件判断,确认是否满足发送广播条件,这几个条件含义如下:
mBroadcastInProgress:是否正在进行广播发送;
mPendingInteractiveState:即将发送广播的状态值:INTERACTIVE_STATE_UNKNOWN为默认值,INTERACTIVE_STATE_AWAKE表示亮屏广播,INTERACTIVE_STATE_ASLEEP表示灭屏广播;
mBroadcastedInteractiveState:表示当前广播的状态值;
mPendingWakeUpBroadcast:表示将要发送亮屏广播;
mPendingGoToSleepBroadcast:表示将要发送灭屏广播。
进入此方法后,首先申请一个SuspendBlocker锁,目的是避免在发送广播过程中出现CPU进入休眠状态导致广播发送失败。之后通过Handler中调用sendNextBroadcaset()方法发送广播:
// frameworks/base/services/core/java/com/android/server/power/Notifier.java
private void sendNextBroadcast() {
final int powerState;
synchronized (mLock) {
// 首次执行
if (mBroadcastedInteractiveState == INTERACTIVE_STATE_UNKNOWN) {
......
} else if (mBroadcastedInteractiveState == INTERACTIVE_STATE_AWAKE) {
//如果当前广播状态为INTERACTIVE_STATE_AWAKE,可能会发送灭屏广播
if (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast
|| mPendingInteractiveState == INTERACTIVE_STATE_ASLEEP) {
mPendingGoToSleepBroadcast = false;
mBroadcastedInteractiveState = INTERACTIVE_STATE_ASLEEP;
} else {
// 结束亮屏广播发送
finishPendingBroadcastLocked();
return;
}
} else {// 如果当前广播状态为INTERACTIVE_STATE_ASLEEP送亮屏广播
if (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast
|| mPendingInteractiveState == INTERACTIVE_STATE_AWAKE) {
mPendingWakeUpBroadcast = false;
// 更新mBroadcastedInteractiveState值
mBroadcastedInteractiveState = INTERACTIVE_STATE_AWAKE;
} else {
// 结束灭屏广播发送
finishPendingBroadcastLocked();
return;
}
}
powerState = mBroadcastedInteractiveState;
}
if (powerState == INTERACTIVE_STATE_AWAKE) {
// 发送亮屏广播
sendWakeUpBroadcast();
} else {
// 发送灭屏广播
sendGoToSleepBroadcast();
}
}
最终,通过sendWakeUpBroadcast()方法,发送亮屏广播:
// frameworks/base/services/core/java/com/android/server/power/Notifier.java
private void sendWakeUpBroadcast() {
// 发送Intent.ACTION_SCREEN_ON广播
if (mActivityManagerInternal.isSystemReady()) {
mContext.sendOrderedBroadcastAsUser(mScreenOnIntent, UserHandle.ALL, null,
mWakeUpBroadcastDone, mHandler, 0, null, null);
}
......
}
这里指定了一个mWakeUpBroadcastDone,会在广播发送后,作为最后一个广播接收器接收该广播,进行广播发送完毕后的工作。mWakeUpBroadcastDone中则继续执行sendNextBroadcast()方法,在这次执行时,根据条件会执行finishPendingBroadcastLocked()方法:
private void finishPendingBroadcastLocked() {
// 重置mBroadcastInProgress,表示当前没有正在进行发送的广播
mBroadcastInProgress = false;
// 释放SuspendBlocker锁
mSuspendBlocker.release();
}
从而完成亮屏广播的发送。
1.5 userActivityNoUpdateLocked()更新用户交互时间
回到wakeUpNoUpdateLocked()方法中,setWakefulnessLocked()执行完毕后,执行userActivityNoUpdateLocked()方法,此方法用来更新系统和用户最后的交互时间,根据这个时间可以决定何时自动休眠。详细内容在自动灭屏流程中分析。
此时wakeUpNoUpdateLocked()执行完毕并返回true,接下来执行updatePowerStateLocked()方法。
2.updatePowerStateLocked()更新PMS全局状态
此方法在第一篇已进行了分析,这里只看进行亮屏的最关键操作——执行updateDisplayPowerStateLocked()方法。
2.1 updateDisplayPowerStateLocked()向DMS发起请求
PMS中所有请求数据会封装到DisplayPowerRequest对象中,向DMS中发起请求。DMS中收到请求后,在DisplayPowerController中更新Display状态和亮度,并将请求结果返回给PMS。DisplayPowerController中处理请求逻辑如下:
// frameworks/base/services/core/java/com/android/server/display/DisplayPowerController.java
public boolean requestPowerState(DisplayPowerRequest request,
boolean waitForNegativeProximity) {
synchronized (mLock) {
boolean changed = false;
// 是否需要等待PSensor上报远离事件
if (waitForNegativeProximity
&& !mPendingWaitForNegativeProximityLocked) {
mPendingWaitForNegativeProximityLocked = true;
changed = true;
}
// 判断是否是新的请求
if (mPendingRequestLocked == null) {
mPendingRequestLocked = new DisplayPowerRequest(request);
changed = true;
} else if (!mPendingRequestLocked.equals(request)) {
mPendingRequestLocked.copyFrom(request);
changed = true;
}
if (changed) {
mDisplayReadyLocked = false;
}
// 开始处理请求
if (changed && !mPendingRequestChangedLocked) {
mPendingRequestChangedLocked = true;
sendUpdatePowerStateLocked();
}
// 返回给PMS,表示请求是否处理完成
return mDisplayReadyLocked;
}
}
这个方法中,会判断请求时携带的DisplayPowerRequest对象是否和上一次发生请求的DisplayRequest对象相同,如果不同表示发生了的请求,则开始处理这次新请求,并向PMS返回mDisplayReadyLocked,该值表示DMS中是否处理完毕请求。
当请求处理完毕后,会将mDisplayReadyLocked值置为true,同时回调PMS#onStateChanged()方法通知PMS更新完成。
经过这一步后,会将系统的亮度、显示状态全部设置完毕,此时屏幕已经亮了。
2.2 finishWakefulnessChangeIfNeededLocked()进行唤醒状态变化完成时任务
回到updatePowerStateLocked()方法中,当DMS处理请求完成,并且返回请求结果后,执行finishWakefulnessChangeIfNeededLocked()方法,进行屏幕状态改变完成后的操作:
// frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
private void finishWakefulnessChangeIfNeededLocked() {
// 通过Notifier进行系统状态wakefulness改变后的处理
if (mWakefulnessChanging && mDisplayReady) {
if (getWakefulnessLocked() == WAKEFULNESS_DOZING
&& (mWakeLockSummary & WAKE_LOCK_DOZE) == 0) {
return;
} else {
mDozeStartInProgress = false;
}
// 唤醒状态变化完成
mWakefulnessChanging = false;
mNotifier.onWakefulnessChangeFinished();
}
}
这里会执行Notifier#onWakefulnessChangeFinished()方法,通知Notifier做唤醒状态改变完成后,交互状态相关的一些任务。
2.3 Notifier#onWakefulnessChangeFinished()
// frameworks/base/services/core/java/com/android/server/power/Notifier.java
public void onWakefulnessChangeFinished() {
// 将mInteractiveChanging设置为false,表示交互状态也改变完成
if (mInteractiveChanging) {
mInteractiveChanging = false;
// 处理进行交互状态变化完成后的任务
handleLateInteractiveChange();
}
}
这里将mInteractiveChanging值重置为false,表示交互状态的变化已经完成,接下来执行handleLateInteractiveChange()方法。
2.4 handleLateInteractiveChange()进行交互状态变化完成后的任务
handleLateInteractiveChange()方法和handleEarlyInteractiveChange()方法相对应,一个处理交互状态改变后的早期工作,一个处理交互状态改变后的后期工作:
// frameworks/base/services/core/java/com/android/server/power/Notifier.java
private void handleLateInteractiveChange() {
synchronized (mLock) {
if (mInteractive) {
mHandler.post(new Runnable() {
@Override
public void run() {
// 通知PhoneWindowManager完成亮屏
mPolicy.finishedWakingUp(why);
}
});
} else {
// 不可交互状态时流程
......
}
}
}
在system_server主线程中,通知PhoneWindowManager完成亮屏。
3.总结
亮屏过程中,关键步骤如下:
更新PMS唤醒状态;
更新交互状态;
system_server主线程执行PhoneWindowManager#startedWakingUp()方法,通知WMS开始亮屏;
system_server主线程发送亮屏广播;
向DMS请求Display状态和亮度;
DMS返回请求状态后,system_server主线程执行PhoneWindowManager#finishedWakingUp()通知WMS模块完成亮屏。
整个过程时序图如下: