PMS亮灭屏流程

1、亮屏流程

PMS模块提供了亮屏接口供应用或组件点亮屏幕。

wakeup()方法

1
2
3
4
5
6
7
8
9
10
11
12
/**
* @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.BinderService中的wakeup()方法。

**Binder:**在Android系统中,Binder用来实现进程之间的通信(IPC)。它是一个工作在Linux层面的驱动,这一驱动运行在内核态。我们在客户端调用Binder最终都是通过系统调用完成的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@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");
}
//首先会检查是否声明了android.Manifest.permission.DEVICE_POWER权限
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.DEVICE_POWER, null);

final int uid = Binder.getCallingUid();
final long ident = Binder.clearCallingIdentity();
try {
//然后将调用wakeUpInternal()进入到PMS内部流程
wakeUpInternal(eventTime, reason, details, uid, opPackageName, uid);
} finally {
Binder.restoreCallingIdentity(ident);
}
}

wakeUpInternal()方法:

1
2
3
4
5
6
7
8
9
10
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()方法:该方法用以点亮屏幕,亮屏成功返回true并更新全局状态,失败则返回false。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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);
// 通知其他组件亮屏动作,即通知给BatteryStatsService,以便统计状态。
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;
}

在上述方法中,首先更新最后一次亮屏时间和原因,然后调用setWakefulnessLocked()方法用于更新设备的wakefulness值,再通过mNotifier将亮屏动作通知给电池状态服务以进行统计,最后更新用户活动时间。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void setWakefulnessLocked(int wakefulness, int reason, long eventTime) {
if (mWakefulness != wakefulness) {
// 更新mWakefulness
mWakefulness = wakefulness;
mWakefulnessChanging = true;
mDirty |= DIRTY_WAKEFULNESS;
// mNotifier中做mWakefuless转变的开始工作
if (mNotifier != null) {
mNotifier.onWakefulnessChangeStarted(wakefulness, reason, eventTime);
}
// 通知mAttentionDetector系统状态的改变
mAttentionDetector.onWakefulnessChangeStarted(wakefulness);
}
}

onWakefulnessChangeStarted()方法:该方法负责屏幕状态改变后的相关工作,如发送亮灭屏广播。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
public void onWakefulnessChangeStarted(final int wakefulness, int reason, long eventTime) {

if (wakefulness == PowerManagerInternal.WAKEFULNESS_HANGUP) {
return;
}

//判断屏幕是否为可交互状态,awake和dream时为可交互状态
final boolean interactive = PowerManagerInternal.isInteractive(wakefulness);
if (DEBUG) {
Slog.d(TAG, "onWakefulnessChangeStarted: wakefulness=" + wakefulness
+ ", reason=" + reason + ", interactive=" + interactive);
}

// Tell the activity manager about changes in wakefulness, not just interactivity.
// It needs more granularity than other components.
mHandler.post(new Runnable() {
@Override
public void run() {
mActivityManagerInternal.onWakefulnessChanged(wakefulness);
}
});

// Handle any early interactive state changes.
// Finish pending incomplete ones from a previous cycle.
//亮屏操作 mInteractive=false != interactive=true
if (mInteractive != interactive) {
// Finish up late behaviors if needed.
//最开始进来这个方法的时候,mInteractiveChanging的值为false,会往下做一些交互状态改变的早期工作
if (mInteractiveChanging) {
handleLateInteractiveChange();//处理交互状态改变后的操作
}

// Start input as soon as we start waking up or going to sleep.
mInputManagerInternal.setInteractive(interactive);
mInputMethodManagerInternal.setInteractive(interactive);

// Notify battery stats.
try {
mBatteryStats.noteInteractive(interactive);
} catch (RemoteException ex) { }
StatsLog.write(StatsLog.INTERACTIVE_STATE_CHANGED,
interactive ? StatsLog.INTERACTIVE_STATE_CHANGED__STATE__ON :
StatsLog.INTERACTIVE_STATE_CHANGED__STATE__OFF);

// Handle early behaviors.
//更新交互状态信息
mInteractive = interactive;
mInteractiveChangeReason = reason;
mInteractiveChangeStartTime = eventTime;
//后面再进来这个方法的时候,由于mInteractiveChanging的值被置为true,就会进入上面的handleLateInteractiveChange方法去执行一些交互状态改变的后期工作
mInteractiveChanging = true;

handleEarlyInteractiveChange();//开始做交互状态改变的早期工作
}
}

综上分析,首先判断系统是否可交互,即是否处于Dream或Awake状态,如果是则interactive为true。如果是亮屏场景,则在执行到该方法时,在 setWakeFulnessLocked() 方法中将 wakefulness 设置为了 WAKEFULNESS_AWAKE,所以 interactive 为 true,mInteractive 是 false。因此,会先执行 handleEarlyInteractiveChange(),之后再执行handleLateInteractiveChange()方法。

handleEarlyInteractiveChange()方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
private void handleEarlyInteractiveChange() {
synchronized (mLock) {
//mInteractive值为true时,说明在进行亮屏操作,进入如下流程
if (mInteractive) {
// Waking up...
mHandler.post(new Runnable() {
@Override
public void run() {
final int why = translateOnReason(mInteractiveChangeReason);
mPolicy.startedWakingUp(why);////mPolicy.startedWakingUp(why)这行代码就会调到PhonewindowManager类中的startedWakingUp()方法。印我们常常在亮屏日志里看到的Started waking up...(why=...)
}
});

// Send interactive broadcast.
//准备发送亮屏广播
mPendingInteractiveState = INTERACTIVE_STATE_AWAKE;
mPendingWakeUpBroadcast = true;
updatePendingBroadcastLocked();
} else {
// Going to sleep...
// Tell the policy that we started going to sleep.
final int why = translateOffReason(mInteractiveChangeReason);
mHandler.post(new Runnable() {
@Override
public void run() {
mPolicy.startedGoingToSleep(why);
}
});
}
}
}

接下来执行userActivityNoUpdateLocked()方法,该方法负责更新用户和系统最后交互时间,计算的时间在updateUserActivitySummary()方法中用于判断何时灭屏。

最后回到wakeUpInternal()方法,可以看到,当wakeUpNoUpdateLocked()执行完毕并返回true后,又会执行updatePowerStateLocked()方法来更新全部的状态,这个方法中会进行亮屏的最关键的操作updateDisplayPowerStateLocked(),该方法将power中所有的和显示状态、亮度有关的数据封装到DisplayPowerRequest对象中,向DisplayManagerService中发起请求,于是在DisplayPowerController中将开始设置显示状态、亮度等操作,并在这些操作完成后,通知PMS再次请求,并返回true,表示请求处理成功。

2、Notifier类

Notifier类是PMS的帮助类,它里面的一些逻辑不会在PMS线程中执行,而是在system_server主线程中执行,因此,PMS中需要异步与其他组件进行交互的工作就交给了Notifier类。如通知PhoneWindowManager亮灭屏进度、发送亮灭屏广播。

onWakefulnessChangeStarted()

该方法用于亮屏或者灭屏时逻辑的处理,和onWakefulnessChangeFinished()方法对应,分别负责操作开始和结束的逻辑处理,当wakefulness改变时进行回调,因此当亮屏、灭屏、进入Doze模式时都会调用这个方法。相关代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public void onWakefulnessChangeStarted(final int wakefulness, int reason, long eventTime) {
// 当前系统状态是否可交互,awake或dream时为true,灭屏/Doze场景下时为false。
final boolean interactive = PowerManagerInternal.isInteractive(wakefulness);
mHandler.post(new Runnable() {
@Override
public void run() {
// 通知AMS系统状态发生变化
mActivityManagerInternal.onWakefulnessChanged(wakefulness);
}
});
//表示交互状态发生改变,即从亮屏/屏保到灭屏或者从灭屏到亮屏
if (mInteractive != interactive) {
// 表示交互状态快速发生过两次变化,此时只做收尾工作
// 这个逻辑会在下面场景中执行:快速灭(亮)屏->亮(灭)屏,提前结束上一个交互状态变化后的逻辑。
if (mInteractiveChanging) {
handleLateInteractiveChange();//处理交互改变后的任务
}
// 通知InputMS交互状态
mInputManagerInternal.setInteractive(interactive);
mInputMethodManagerInternal.setInteractive(interactive); // 通知InputMethodMS交互状态

try {
mBatteryStats.noteInteractive(interactive); // BatteryStatsService中进行统计
} catch (RemoteException ex) { }

mInteractive = interactive; // 更新交互状态
mInteractiveChangeReason = reason; // 更新交互状态改变原因
mInteractiveChangeStartTime = eventTime; // 交互状态改变时间
mInteractiveChanging = true; // 表示交互状态正在改变中
handleEarlyInteractiveChange(); // 处理交互状态改变后的早期逻辑
}
}

handleEarlyInteractiveChange()方法:处理交互状态改变后的早期逻辑,如通知状态栏设备开始亮灭屏,发送亮灭屏广播。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
private void handleEarlyInteractiveChange() {
synchronized (mLock) {
// 如果是可交互状态,进行wake up操作
if (mInteractive) {
// 在system_server main线程进行,通知PhoneWindowManager开始亮屏
mHandler.post(new Runnable() {
@Override
public void run() {
final int why = translateOnReason(mInteractiveChangeReason);
mPolicy.startedWakingUp(why);
}
});

// 发送广播
mPendingInteractiveState = INTERACTIVE_STATE_AWAKE; // 表示即将要发送的广播,INTERACTIVE_STATE_AWAKE表示亮屏广播
mPendingWakeUpBroadcast = true; // 表示是否发送亮屏广播
updatePendingBroadcastLocked(); // 更新亮灭屏广播队列
} else { // 说明不可交互状态,进行灭屏操作
final int why = translateOffReason(mInteractiveChangeReason);
// 在system_server main线程进行,通知PhoneWindowManager开始灭屏
mHandler.post(new Runnable() {
@Override
public void run() {
mPolicy.startedGoingToSleep(why);
}
});
}
}
}

onWakefulnessChangeFinished()

该方法用以屏幕状态切换完成后,做wakefulness改变完成后的工作。

1
2
3
4
5
6
7
8
public void onWakefulnessChangeFinished() {
if (mInteractiveChanging) {
// 重置mInteractiveChanging,说明交互状态改变完成
mInteractiveChanging = false;
// 开始处理交互状态改变后的后期工作
handleLateInteractiveChange();
}
}

handleLateInteractiveChange()方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
private void handleLateInteractiveChange() {
synchronized (mLock) {
// 如果可交互状态
if (mInteractive) {
// Finished waking up...
final int why = translateOnReason(mInteractiveChangeReason);
mHandler.post(new Runnable() {
@Override
public void run() {
// 通知PhoneWindowManager完成亮屏
mPolicy.finishedWakingUp(why);
}
});
} else {

// 取消PhoneWindowManager的用户活动更新通知
if (mUserActivityPending) {
mUserActivityPending = false;
mHandler.removeMessages(MSG_USER_ACTIVITY);
}

final int why = translateOffReason(mInteractiveChangeReason);
mHandler.post(new Runnable() {
@Override
public void run() {
// 通知PhoneWindowManager完成灭屏
mPolicy.finishedGoingToSleep(why);
}
});
// 发送灭屏广播
mPendingInteractiveState = INTERACTIVE_STATE_ASLEEP; // 表示即将要发送的广播,INTERACTIVE_STATE_ASLEEP表示灭屏广播
mPendingGoToSleepBroadcast = true; // 表示即将要发送灭屏广播
updatePendingBroadcastLocked(); // 发送广播
}
}
}

handleLateInteractiveChange()方法中,如果是亮屏,则调用 PhoneWindowManager 的 finishedWakingUp() 表示亮屏处理成功。如果是灭屏,则调用 PhoneWindowManager 的 finishedGoingToSleep()

updatePendingBroadcaseLocked()

该方法用于交互状态改变时发送广播。如亮屏时,在handlerEarlyInteractiveChang()方法中调用该方法发送广播,灭屏时,在handlerLateInteractiveChang()中调用该方法发送广播。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
private void updatePendingBroadcastLocked() {
/**
* 广播没有进行中&&要发送的广播状态!= UNKNOW
* && (发送亮屏广播||发送灭屏广播||发送广播状态!=当前广播交互状态)
* mBroadcastedInteractiveState值实际上是上次发送广播交互状态的值
*/
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);
}
}
//注:
// 代表即将发送广播的状态值:INTERACTIVE_STATE_UNKNOWN为默认值,INTERACTIVE_STATE_AWAKE表示亮屏广播,INTERACTIVE_STATE_ASLEEP表示灭屏广播
private int mPendingInteractiveState;
// 即将发送的广播是否为亮屏广播
private boolean mPendingWakeUpBroadcast;
// 即将发送的广播是否为灭屏广播
private boolean mPendingGoToSleepBroadcast;
// 代表当前广播的状态值
private int mBroadcastedInteractiveState;
// 是否正在进行广播发送
private boolean mBroadcastInProgress;

在进入updatePendingBroadcaseLocked()方法时,首先会申请一个SuspendBlocker锁,这个锁是通过在PMS中创建Notifier对象时创建传入的,目的是避免在发送广播时系统休眠而导致广播发送失败,该锁在广播发送完成后释放,之后通过mHandler.obtainMessage(MSG_BROADCAST)调用sendNextBroadcast()方法发送广播。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
private final class NotifierHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
//...
case MSG_BROADCAST:
sendNextBroadcast();
break;
//...
}
}
}

private void sendNextBroadcast() {
final int powerState;
synchronized (mLock) {
// 如果mBroadcastedInteractiveState为初始状态,说明刚开始,按照亮屏流程进行,会发送亮屏广播
if (mBroadcastedInteractiveState == INTERACTIVE_STATE_UNKNOWN) {
mPendingWakeUpBroadcast = false;
mBroadcastedInteractiveState = INTERACTIVE_STATE_AWAKE; // 更新广播状态设置为awake
} else if (mBroadcastedInteractiveState == INTERACTIVE_STATE_AWAKE) { // 如果当前广播状态为awake,可能会发送灭屏广播
// 广播亮屏||广播灭屏||最终要广播的交互状态为灭屏
if (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast
|| mPendingInteractiveState == INTERACTIVE_STATE_ASLEEP) {
mPendingGoToSleepBroadcast = false;
mBroadcastedInteractiveState = INTERACTIVE_STATE_ASLEEP;
} else {
finishPendingBroadcastLocked(); //完成此次广播发送,释放mSuspendBlocker锁
return;
}
} else { // 如果当前广播状态为灭屏
if (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast
|| mPendingInteractiveState == INTERACTIVE_STATE_AWAKE) {
mPendingWakeUpBroadcast = false;
mBroadcastedInteractiveState = INTERACTIVE_STATE_AWAKE;
} else {
finishPendingBroadcastLocked();
return;
}
}
mBroadcastStartTime = SystemClock.uptimeMillis();
powerState = mBroadcastedInteractiveState;
}

if (powerState == INTERACTIVE_STATE_AWAKE) {
sendWakeUpBroadcast(); // 发送亮屏广播
} else {
sendGoToSleepBroadcast(); // 发送灭屏广播
}
}

以亮屏为例,在进入该方法之前时,mPendingWakeUpBroadcast会设置为true,mPendingInteractiveState会设置为INTERACTIVE_STATE_AWAKE,此时mBroadcastedInteractiveStateINTERACTIVE_STATE_ASLEEP,当执行到这个方法后,进入else代码块当中,更新mBroadcastedInteractiveState变量为true,然后将调用sendWakeUpBroadcast()方法发送亮屏广播:

1
2
3
4
5
6
7
private void sendWakeUpBroadcast() {
// 发送Intent.ACTION_SCREEN_ON广播
if (mActivityManagerInternal.isSystemReady()) {
mContext.sendOrderedBroadcastAsUser(mScreenOnIntent, UserHandle.ALL, null,
mWakeUpBroadcastDone, mHandler, 0, null, null);
} else {}
}

这里指定了一个mWakeUpBroadcastDone,会在广播发送后,作为最后一个广播接收器,因此会在这里进行广播发送完毕后的工作:

1
2
3
4
5
6
7
private final BroadcastReceiver mWakeUpBroadcastDone = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
//又调用了sendNextBroadcast()方法,这次执行该方法,根据判断条件,将会执行else if 代码块中的else代码块,于是执行finishPendingBroadcastLocked()方法
sendNextBroadcast();
}
};
1
2
3
4
private void finishPendingBroadcastLocked() {
mBroadcastInProgress = false; // 重置mBroadcastInProgress,表示当前没有正在进行发送的广播
mSuspendBlocker.release(); // 释放SuspendBlocker锁
}

于是亮屏广播就发送完成了。而灭屏广播,则是通过sendGoToSleepBroadcast()来发送,逻辑类似。

3、灭屏流程

PMS模块同样提供了灭屏接口goToSleep(),下面分析具体流程。

3.1、Power按键灭屏

当按Power键灭屏时,会在PhoneWindowManager中处理按键事件后调用PMS的goToSleep()方法进行灭屏处理。

goToSleep()方法:

1
2
3
4
5
6
7
//frameworks/base/core/java/android/os/PowerManager.java

public void goToSleep(long time, int reason, int flags) {
try {
mService.goToSleep(time, reason, flags);
} catch (RemoteException e) { }
}

在PMS中开始向下Binder调用goToSleep()方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
/**
evenTime:灭屏时间
reason:灭屏原因
flags:标识是否直接进入灭屏。一般的灭屏流程先进入Doze状态再进入Sleep状态;如果置为1则直接进入Sleep状态。
**/
@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 {
//调用 gotToSleepInternal
goToSleepInternal(eventTime, reason, flags, uid);
} finally {
Binder.restoreCallingIdentity(ident);
}
}

goToSleep()方法中,检查权限之后,开始调用goToSleepInternal()方法。

goToSleepInternal()方法:

1
2
3
4
5
6
7
8
9
//frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java

private void goToSleepInternal(long eventTime, int reason, int flags, int uid) {
synchronized (mLock) {
if (goToSleepNoUpdateLocked(eventTime, reason, flags, uid)) {
updatePowerStateLocked();//更新电源状态
}
}
}

goToSleepInternal()方法中,先是调用了goToSleepNoUpdateLocked()方法,并根据方法返回值决定是否调用updatePowerStateLocked()方法。

goToSleepNoUpdateLocked()方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
//frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java

@SuppressWarnings("deprecation")
private boolean goToSleepNoUpdateLocked(long eventTime, int reason, int flags, int uid) {
if (eventTime < mLastWakeTime
|| mWakefulness == WAKEFULNESS_ASLEEP
|| mWakefulness == WAKEFULNESS_DOZING
|| !mBootCompleted || !mSystemReady) {
return false;
}

try {
switch (reason) {
case PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN:
Slog.i(TAG, "Going to sleep due to device administration policy "
+ "(uid " + uid +")...");
break;
case PowerManager.GO_TO_SLEEP_REASON_TIMEOUT:
Slog.i(TAG, "Going to sleep due to screen timeout (uid " + uid +")...");
break;
case PowerManager.GO_TO_SLEEP_REASON_LID_SWITCH:
Slog.i(TAG, "Going to sleep due to lid switch (uid " + uid +")...");
break;
case PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON:
Slog.i(TAG, "Going to sleep due to power button (uid " + uid +")...");
break;
case PowerManager.GO_TO_SLEEP_REASON_SLEEP_BUTTON:
Slog.i(TAG, "Going to sleep due to sleep button (uid " + uid +")...");
break;
case PowerManager.GO_TO_SLEEP_REASON_HDMI:
Slog.i(TAG, "Going to sleep due to HDMI standby (uid " + uid +")...");
break;
default:
Slog.i(TAG, "Going to sleep by application request (uid " + uid +")...");
reason = PowerManager.GO_TO_SLEEP_REASON_APPLICATION;
break;
}

//标记最后一次灭屏时间
mLastSleepTime = eventTime;
//用于判定是否进入屏保
mSandmanSummoned = true;
//设置 wakefulness 值为 WAKEFULNESS_DOZING,
//因此先进入 Doze 状态
setWakefulnessLocked(WAKEFULNESS_DOZING, reason);

// Report the number of wake locks that will be cleared by going to sleep.
//灭屏时,将清楚以下三种使得屏幕保持亮屏的 wakelock 锁,numWakeLocksCleared 统计下个数
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;
}
}

// Skip dozing if requested.
//如果带有 PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE 的 flag,则直接进入 Sleep 状态,不再进入 Doze 状态
if ((flags & PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE) != 0) {
//该方法才会真正地进入睡眠
reallyGoToSleepNoUpdateLocked(eventTime, uid);
}
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
return true;
}

goToSleepNoUpdateLocked()方法中,使用setWakefulnessLocked()来设置wakefulness值,同时会调用Notifier中的wakefulness相关的逻辑。

1
2
3
4
5
6
7
8
9
10
11
12
//frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java

private void setWakefulnessLocked(int wakefulness, int reason) {
if (mWakefulness != wakefulness) {
//设置 mWakefulness
mWakefulness = wakefulness;
mWakefulnessChanging = true;
mDirty |= DIRTY_WAKEFULNESS;
//调用 Notifier 中的方法,做 wakefulness 改变开始时的工作
mNotifier.onWakefulnessChangeStarted(wakefulness, reason);
}
}

setWakefulnessLocked()方法中,调用Notifier中的方法onWakefulnessChangeStarted()做wakefulness改变开始时的工作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
//frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java

public void onWakefulnessChangeStarted(final int wakefulness, int reason) {
//由于 wakefulness 为 Doze,故 interactive 为 false
final boolean interactive = PowerManagerInternal.isInteractive(wakefulness);
//...
// Handle any early interactive state changes.
// Finish pending incomplete ones from a previous cycle.
if (mInteractive != interactive) {
// Finish up late behaviors if needed.
if (mInteractiveChanging) {
handleLateInteractiveChange();
}

// Start input as soon as we start waking up or going to sleep.
mInputManagerInternal.setInteractive(interactive);
mInputMethodManagerInternal.setInteractive(interactive);

// Notify battery stats.
try {
mBatteryStats.noteInteractive(interactive);
} catch (RemoteException ex) { }

// Handle early behaviors.
mInteractive = interactive;
mInteractiveChangeReason = reason;
mInteractiveChanging = true;
handleEarlyInteractiveChange();
}
}

onWakefulnessChangeStarted()方法中根据wakefulness值判断了系统当前的交互状态,Awake/Dream状态为可交互,Doze/Asleep状态为不可交互。由于在setWakefulnessLocked()中设置了wakefulness为Doze状态,因此此刻处于不可交互状态,接下来开始执行handleEarlyInteractiveChange()方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
//frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java

private void handleEarlyInteractiveChange() {
synchronized (mLock) {
if (mInteractive) {//此时为 false
// Waking up...
mHandler.post(new Runnable() {
@Override
public void run() {
// Note a SCREEN tron event is logged in PowerManagerService.
mPolicy.startedWakingUp();
}
});

// Send interactive broadcast.
mPendingInteractiveState = INTERACTIVE_STATE_AWAKE;
mPendingWakeUpBroadcast = true;
updatePendingBroadcastLocked();
} else {
// Going to sleep...
// Tell the policy that we started going to sleep.
final int why = translateOffReason(mInteractiveChangeReason);
mHandler.post(new Runnable() {
@Override
public void run() {//通过 PhoneWindowManager 设置锁屏
mPolicy.startedGoingToSleep(why);
}
});
}
}
}

handleEarlyInteractiveChange()方法中,由于mInteractive为false,将执行else部分调用mPolicy.startedGoingToSleep(why)

进行锁屏流程。

继续回到goToSleepNoUpdateLocked()方法,由于没有指定跳过Doze状态直接进入Sleep,所以不会立即执行reallyGoToSleepNoUpdateLocked()方法,此时 goToSleepNoUpdateLocked() 方法完毕并返回 true。

之后开始执行 updatePowerStateLocked() 方法了,在这里我们只看其灭屏时的一些处理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
//frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java

private void updatePowerStateLocked() {
//...
try {
//...

// Phase 2: Update display power state.
//更新屏幕状态
//updateDisplayPowerStateLocked() 将会向 DisplayPowerController 请求新的屏幕状态,完成屏幕的更新;
boolean displayBecameReady = updateDisplayPowerStateLocked(dirtyPhase2);

// Phase 3: Update dream state (depends on display ready signal).
//更新屏保信息
//updateDreamLocked() 方法用来更新屏保信息,除此之外还有一个任务——调用 reallyGoToSleep() 方法进入休眠,即由 DOZE 状态进入 Sleep 状态。
updateDreamLocked(dirtyPhase2, displayBecameReady);

// Phase 4: Send notifications, if needed.
// 收尾
finishWakefulnessChangeIfNeededLocked();

// Phase 5: 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);
}
}

updateDreamLocked()中更新屏保状态时,如果此时处于Doze状态且屏保没有进行,则将调用reallyGoToSleepNoUpdateLocked()方法,将wakefulness值设置为Sleep。相关代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java

private void handleSandman() { // runs on handler thread
//...
synchronized (mLock) {
//...
//决定是否继续 Dream
if (wakefulness == WAKEFULNESS_DREAMING) {
//...
} else if (wakefulness == WAKEFULNESS_DOZING) {
if (isDreaming) {
return; // continue dozing
}

//进入 asleep 状态
reallyGoToSleepNoUpdateLocked(SystemClock.uptimeMillis(), Process.SYSTEM_UID);
updatePowerStateLocked();
}
}
//...
}

reallyGoToSleepNoUpdateLocked()方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java

// Done dozing, drop everything and go to sleep.
private boolean reallyGoToSleepNoUpdateLocked(long eventTime, int uid) {
if (eventTime < mLastWakeTime || mWakefulness == WAKEFULNESS_ASLEEP
|| !mBootCompleted || !mSystemReady) {
return false;
}

try {
//设置为 ASLEEP 状态
setWakefulnessLocked(WAKEFULNESS_ASLEEP, PowerManager.GO_TO_SLEEP_REASON_TIMEOUT);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
return true;
}

至此Power按键灭屏过程结束,相关流程如图:

3.2、自动灭屏

自动灭屏由用户设置的休眠时间或用户活动影响,用户活动即最近一次用户和设备交互的时间,以此为起点达到休眠时间后开始执行灭屏流程。

userActivityNoUpdateLocked():

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
//frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java

private boolean userActivityNoUpdateLocked(long eventTime, int event, int flags, int uid) {
if (eventTime < mLastSleepTime || eventTime < mLastWakeTime
|| !mBootCompleted || !mSystemReady) {
return false;
}

try {
if (eventTime > mLastInteractivePowerHintTime) {
powerHintInternal(PowerHint.INTERACTION, 0);
mLastInteractivePowerHintTime = eventTime;
}
// 通知Notifier更新用户活动状态
mNotifier.onUserActivity(event, uid);

// 重置该值,该值表示WindowManager中是否有覆盖了下次灭屏的时间
if (mUserInactiveOverrideFromWindowManager) {
mUserInactiveOverrideFromWindowManager = false;
mOverriddenTimeout = -1;
}

//如果 wakefulness 为 Asleep 或 Doze,不再计算超时时间,直接返回
if (mWakefulness == WAKEFULNESS_ASLEEP
|| mWakefulness == WAKEFULNESS_DOZING
|| (flags & PowerManager.USER_ACTIVITY_FLAG_INDIRECT) != 0) {
return false;
}

//如果带有该 flag,则会小亮一会儿再灭屏
if ((flags & PowerManager.USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS) != 0) {
if (eventTime > mLastUserActivityTimeNoChangeLights
&& eventTime > mLastUserActivityTime) {
// 更新最后一次活动时间给mLastUserActivityTimeNoChangeLights
mLastUserActivityTimeNoChangeLights = eventTime;
mDirty |= DIRTY_USER_ACTIVITY;
if (event == PowerManager.USER_ACTIVITY_EVENT_BUTTON) {
mDirty |= DIRTY_QUIESCENT;
}

return true;
}
} else {
if (eventTime > mLastUserActivityTime) {
//将当前时间赋值给 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;
}

在这个方法中,如果传入的参数 flag 为 PowerManager.USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS,则将事件时间赋值给 mLastUserActivityTimeNoChangeLights,否则将事件时间赋值给 mLastUserActivityTime。这个 flag 标志用于延长亮屏或 Dim 的时长一小会儿。

当这个方法执行之后,就得到了 mLastUserActivityTime 或者 mLastUserActivityTimeNoChangeLights 的值,然后经过一些调用后,又会进入 updatePowerStateLocked() 方法中。在这个方法中,与超时灭屏直接相关的就是 for 循环部分.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java

private void updatePowerStateLocked() {
//...
try {
//...
for (;;) {
int dirtyPhase1 = mDirty;
dirtyPhase2 |= dirtyPhase1;
mDirty = 0;

updateWakeLockSummaryLocked(dirtyPhase1);//统计Wakelock
updateUserActivitySummaryLocked(now, dirtyPhase1);
if (!updateWakefulnessLocked(dirtyPhase1)) {
break;
}
}
//...
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
}

updateUserActivitySummaryLocked()方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
//frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java

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) {
//获取睡眠时长,为 Settings.Secure.SLEEP_TIMEOUT 的值和最小休眠时间的最大值,
//Settings.Secure.SLEEP_TIMEOUT 一般为 -1,表示禁用,因此该值默认为 -1
final int sleepTimeout = getSleepTimeoutLocked();
//获取休眠时长,在 Settings 中设置的值
final int screenOffTimeout = getScreenOffTimeoutLocked(sleepTimeout);
//获取 Dim 时长,由休眠时长剩 Dim 百分比得到
final int screenDimDuration = getScreenDimDurationLocked(screenOffTimeout);
//用户活动是否由 Window 覆盖
final boolean userInactiveOverride = mUserInactiveOverrideFromWindowManager;

//该值用来统计用户活动状态,每次进入该方法,置为 0
mUserActivitySummary = 0;
//上次用户活动时间 >= 上次唤醒时间
if (mLastUserActivityTime >= mLastWakeTime) {
//下次超时时间为上次用户活动时间 + 休眠时间 - Dim 时间
//到达这个时间后,将进入 Dim 状态
nextTimeout = mLastUserActivityTime
+ screenOffTimeout - screenDimDuration;
//如果当前时间 < nextTimeout,则此时处于亮屏状态,
//标记 mUserActivitySummary 为 USER_ACTIVITY_SCREEN_BRIGHT
if (now < nextTimeout) {
mUserActivitySummary = USER_ACTIVITY_SCREEN_BRIGHT;
} else {
//如果当前时间 > nextTimeout,此时有两种情况,要么进入 Dim 要么进入 Sleep
//将上次用户活动时间 + 灭屏时间赋值给 nextTimeout,
//如果该值大于当前时间,则说明此时应该处于 Dim 状态
//因此将标记 mUserActivitySummary 为 USER_ACTIVITY_SCREEN_DIM
nextTimeout = mLastUserActivityTime + screenOffTimeout;
if (now < nextTimeout) {
mUserActivitySummary = USER_ACTIVITY_SCREEN_DIM;
}
}
}
//判断和 USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS 标记相关,如果带有此标记,才会进入该 if
if (mUserActivitySummary == 0
&& mLastUserActivityTimeNoChangeLights >= mLastWakeTime) {
//下次超时时间 = 上次用户活动时间 + 灭屏时间
nextTimeout = mLastUserActivityTimeNoChangeLights + screenOffTimeout;
//根据当前时间和 nextTimeout 设置 mUserActivitySummary
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;
}
}
}

//不满足以上条件时,此时 mUserActivitySummary 为 0,
//这种情况应该为当 mUserActivitySummary 经历了 USER_ACTIVITY_SCREEN_BRIGHT
//和 USER_ACTIVITY_SCREEN_DIM 之后才会执行到这里
if (mUserActivitySummary == 0) {
if (sleepTimeout >= 0) {
//获取上次用户活动时间的最后一次时间
final long anyUserActivity = Math.max(mLastUserActivityTime,
mLastUserActivityTimeNoChangeLights);
if (anyUserActivity >= mLastWakeTime) {
nextTimeout = anyUserActivity + sleepTimeout;
//将 mUserActivitySummary 值置为 USER_ACTIVITY_SCREEN_DREAM,表示屏保
if (now < nextTimeout) {
mUserActivitySummary = USER_ACTIVITY_SCREEN_DREAM;
}
}
} else {
//将 mUserActivitySummary 值置为 USER_ACTIVITY_SCREEN_DREAM,表示屏保
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 != 0 && nextTimeout >= 0) {
//发送一个异步 Handler 定时消息
Message msg = mHandler.obtainMessage(MSG_USER_ACTIVITY_TIMEOUT);
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, nextTimeout);
}
} else {//当 wakefulness = Sleep 的时候,直接将 mUserActivitySummary 置为 0
mUserActivitySummary = 0;
}
}
}

MSG_USER_ACTIVITY_TIMEOUT的handler调用逻辑如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java

@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_USER_ACTIVITY_TIMEOUT:
handleUserActivityTimeout();
break;
}
}

private void handleUserActivityTimeout() { // runs on handler thread
synchronized (mLock) {
mDirty |= DIRTY_USER_ACTIVITY;
updatePowerStateLocked();
}
}

回到updatePowerStateLocked(),执行updateWakefulnessLocked()方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java

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) {
//isItBedTimeYetLocked() 判断是否需要"睡觉"了
if (mWakefulness == WAKEFULNESS_AWAKE && isItBedTimeYetLocked()) {
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;
}

isItBedTimeYetLocked()方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java

private boolean isItBedTimeYetLocked() {
return mBootCompleted && !isBeingKeptAwakeLocked();
}

private boolean isBeingKeptAwakeLocked() {
return mStayOn//是否需要保持常亮
|| mProximityPositive//PSensor 是否靠近
|| (mWakeLockSummary & WAKE_LOCK_STAY_AWAKE) != 0//当前是否有 Wakelock 类型为屏幕相关的锁
|| (mUserActivitySummary & (USER_ACTIVITY_SCREEN_BRIGHT
| USER_ACTIVITY_SCREEN_DIM)) != 0//当前用户活动状态是否为 Dream 或者 0
|| mScreenBrightnessBoostInProgress;//是否处于亮度增强过程中
}

shouldNapAtBedTimeLocked()方法:返回true,则开始屏保,否则直接休眠。

1
2
3
4
5
6
7
//frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java

private boolean shouldNapAtBedTimeLocked() {
return mDreamsActivateOnSleepSetting
|| (mDreamsActivateOnDockSetting
&& mDockState != Intent.EXTRA_DOCK_STATE_UNDOCKED);
}

当开始休眠时,则调用goToSleepNoUpdateLocked()方法,于是走休眠流程,之后的逻辑和Power键灭屏类似。整体流程如下: