本文主要跟踪分析通过按松power键来唤醒,熄灭屏幕的逻辑。下面是一些相关类的介绍
PowerManagerService.java:简称PMS,负责Andorid系统中电源管理方面的工作。作为系统核心服务之一,主要处理系统中与power相关的计算,然后决策系统该如何反应。同时PowerManagerService与其他服务及HAL层等都有交互关系,协调power如何与系统其他模块的交互,比如没有用户活动时屏幕变暗等。
DisplayPowerController.java:简称DPC管理Display设备的电源状态。仅在PowerManagerService中实例化了一个对象,它算是PowerManagerService的一部分,只不过是独立出来了而已。主要处理和距离传感器,
灯光传感器,以及包括关屏在内的一些动画,通过异步回调的方式来通知PowerManagerService某些事情发生了变化。
DisplayPowerState.java:简称DPS,在本质上类似于View,只不过用来描述一个display的属性,当这些属性发生变化时,可以通过一个序列化的命令,让这些和display电源状态的属性一起产生变化。
这个类的对象只能被DispalyPowerController的Looper持有。而这个Looper应该就是PowerManagerService中新建的一个HandlerThread中的Looper。和PowerManager相关的,
包括DisplayPowerState和DisplayPowerController相关的消息处理应该都可以通过这个HandlerThread进行运转的
Notifier.java:将power状态的重要变化,通过广播发送出去,并且参与了与AMS,WMS,IMP的交互。
ColorFade.java:负责屏幕由关到开,由开到关的一些GL动画,由DPC进行控制。
AutomaticBrightnessController.java:主要处理光传感器,将底层上传的参数进行处理计算,将计算的新的亮度值传给DPC。
RampAnimator.java:处理屏幕亮度渐变动画。
正常我们按下power键后,出触发Kernel关于该事件的中断。然后inputReader通过EventHub获取该事件,并做出事件处理,之后由inputdispatch进行事件分发。
因为power事件是key事件,会调用interceptKeyBeforeQueueing进行处理,通过如果流程
InputDispatcher.cpp
->com_android_server_input_InputManagerService.cpp
->InputManagerService.java
->InputMonitor.java
->WindowManagerPolicy.java
->PhoneWindowManager.java
最终由PhoneWindowManager.java的interceptKeyBeforeQueueing方法对该次事件进行处理,对power键以及屏幕状态进行判断,来决定亮屏还是灭屏等操作。当需要亮屏时,会调用PowerMangerService中的wakeup函数进行处理。
主要代码如下:
首先定义以下几个布尔值,主要是按键属性和屏幕状态
//是否亮屏状态,代码是否可以与用户交互
final boolean interactive = (policyFlags & FLAG_INTERACTIVE) != 0;
//按键事件是否为down事件
final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
//事件是否被取消
final boolean canceled = event.isCanceled();
//按键的keycode,不同按键 keycode不同,一般power 116
final int keyCode = event.getKeyCode();
//是否是输入事件
final boolean isInjected = (policyFlags & WindowManagerPolicy.FLAG_INJECTED) != 0;
//锁屏界面状态
final boolean keyguardActive = (mKeyguardDelegate == null ? false :(interactive ?isKeyguardShowingAndNotOccluded() :mKeyguardDelegate.isShowing()));
//flags有wake标记,或者按键(isWakeKey函数)为KEYCODE_BACK, KEYCODE_MENU, KEYCODE_WAKEUP, KEYCODE_PAIRING, KEYCODE_STEM_1, KEYCODE_STEM_2, KEYCODE_STEM_3设置isWakeKey为true
boolean isWakeKey = (policyFlags & WindowManagerPolicy.FLAG_WAKE) != 0 || event.isWakeKey();
if (isValidGlobalKey(keyCode)//有效的全局按键 (KEYCODE_POWER:KEYCODE_WAKEUP:KeyEvent.KEYCODE_SLEEP:),
&& mGlobalKeyManager.shouldHandleGlobalKey(keyCode, event)) {//在com.android.internal.R.xml.global_keys 有定义
if (isWakeKey) {
wakeUp(event.getEventTime(), mAllowTheaterModeWakeFromKey, "android.policy:KEY");唤醒屏幕
}
return result;
}
接下来是对特殊按键的处理,这里只关注power键
switch (keyCode) {
case KeyEvent.KEYCODE_POWER: {
result &= ~ACTION_PASS_TO_USER;
isWakeKey = false; // wake-up will be handled separately
if (down) {
interceptPowerKeyDown(event, interactive);//处理power按下
} else {
interceptPowerKeyUp(event, interactive, canceled);//处理power松开
}
break;
}
power down 键的处理
private void interceptPowerKeyDown(KeyEvent event, boolean interactive) {
// 获取wakelock,报错CPU唤醒状态
if (!mPowerKeyWakeLock.isHeld()) {
mPowerKeyWakeLock.acquire();
}
// 取消多次按下超时监测
if (mPowerKeyPressCounter != 0) {
mHandler.removeMessages(MSG_POWER_DELAYED_PRESS);
}
// Detect user pressing the power button in panic when an application has
// taken over the whole screen.
boolean panic = mImmersiveModeConfirmation.onPowerKeyDown(interactive,
SystemClock.elapsedRealtime(), isImmersiveMode(mLastSystemUiFlags),
isNavBarEmpty(mLastSystemUiFlags));
if (panic) {
mHandler.post(mHiddenNavPanic);
}
// Latch power key state to detect screenshot chord.
if (interactive && !mScreenshotChordPowerKeyTriggered
&& (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
mScreenshotChordPowerKeyTriggered = true;
mScreenshotChordPowerKeyTime = event.getDownTime();
interceptScreenshotChord();//屏幕截屏
interceptDisableTouchModeChord(); //添加口袋模式
}
// 当power键按下,停止电话响铃或者结束通话
TelecomManager telecomManager = getTelecommService();
boolean hungUp = false;
if (telecomManager != null) {
if (telecomManager.isRinging()) {
停止响铃
telecomManager.silenceRinger();
} else if ((mIncallPowerBehavior
& Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP) != 0
&& telecomManager.isInCall() && interactive) {
Setting数据库读取设置,如果开了挂断电话
hungUp = telecomManager.endCall();
}
}
SprdGestureLauncherService gestureService = LocalServices.getService(
SprdGestureLauncherService.class);
boolean gesturedServiceIntercepted = false;
if (gestureService != null) {
gesturedServiceIntercepted = gestureService.interceptPowerKeyDown(event, interactive,
mTmpBoolean);
if (mTmpBoolean.value && mGoingToSleep) {
mCameraGestureTriggeredDuringGoingToSleep = true;
}
}
// If the power key has still not yet been handled, then detect short
// 如果power键还没有被处理,判断是短按,多按,长按等场景并做出对应处理
mPowerKeyHandled = hungUp || mScreenshotChordVolumeDownKeyTriggered
|| mA11yShortcutChordVolumeUpKeyTriggered || gesturedServiceIntercepted;
if (!mPowerKeyHandled) {
if (interactive) {
//如果屏幕是亮的,长按动作处理对应的长按动作
if (hasLongPressOnPowerBehavior()) {
Message msg = mHandler.obtainMessage(MSG_POWER_LONG_PRESS);
msg.setAsynchronous(true);
mHandler.sendMessageDelayed(msg,
ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
}
} else {//屏幕休眠的状态,唤醒屏幕
wakeUpFromPowerKey(event.getDownTime());
if (mSupportLongPressPowerWhenNonInteractive && hasLongPressOnPowerBehavior()) {
Message msg = mHandler.obtainMessage(MSG_POWER_LONG_PRESS);
msg.setAsynchronous(true);
mHandler.sendMessageDelayed(msg,//如果长按动作继续执行长按操作
ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
mBeganFromNonInteractive = true;
} else {
final int maxCount = getMaxMultiPressPowerCount();
if (maxCount <= 1) {
mPowerKeyHandled = true;
} else {
mBeganFromNonInteractive = true;
......
power up 键的处理
private void interceptPowerKeyUp(KeyEvent event, boolean interactive, boolean canceled) {
final boolean handled = canceled || mPowerKeyHandled; //power键是否被处理了
mScreenshotChordPowerKeyTriggered = false;
cancelPendingScreenshotChordAction();
cancelPendingPowerKeyAction();
if (!handled) {
// power press 加1
mPowerKeyPressCounter += 1;
final int maxCount = getMaxMultiPressPowerCount();//多按的次数
final long eventTime = event.getDownTime();//press power 时间
if (mPowerKeyPressCounter < maxCount) {
// 这种情况可能是一个多次按键事件,等待一会做确认处理
Message msg = mHandler.obtainMessage(MSG_POWER_DELAYED_PRESS,
interactive ? 1 : 0, mPowerKeyPressCounter, eventTime);
msg.setAsynchronous(true);
mHandler.sendMessageDelayed(msg, ViewConfiguration.getDoubleTapTimeout());
return;
}
// 没有其他action,继续处理power按下事件
powerPress(eventTime, interactive, mPowerKeyPressCounter);
}
// Done. Reset our state.
finishPowerKeyPress();//power按键处理结束
}
private void finishPowerKeyPress() {
mBeganFromNonInteractive = false;
mPowerKeyPressCounter = 0;
if (mPowerKeyWakeLock.isHeld()) {
mPowerKeyWakeLock.release();//释放wakelock
}
}
下面继续跟踪powerPress函数
private void powerPress(long eventTime, boolean interactive, int count) {
if (mScreenOnEarly && !mScreenOnFully) {
Slog.i(TAG, "Suppressed redundant power key press while "
+ "already in the process of turning the screen on.");
return;
}
if (count == 2) {//按两次power事件
powerMultiPressAction(eventTime, interactive, mDoublePressOnPowerBehavior);
} else if (count == 3) {//按三次power事件
powerMultiPressAction(eventTime, interactive, mTriplePressOnPowerBehavior);
} else if (interactive && !mBeganFromNonInteractive) {//屏幕如果亮着而且mBeganFromNonInteractive为false会执行下面操作
switch (mShortPressOnPowerBehavior) {//根据配置om.android.internal.R.integer.config_shortPressOnPowerBehavior 决定对应值 此处为1
case SHORT_PRESS_POWER_NOTHING:
break;
case SHORT_PRESS_POWER_GO_TO_SLEEP:
mPowerManager.goToSleep(eventTime,
PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, 0);//执行灭屏操作
break;
......
}
我们继续跟踪亮屏操作,从power down事件处理可知,调用wakeUpFromPowerKey点亮屏幕
private void wakeUpFromPowerKey(long eventTime) {
Slog.d(TAG, "wake Up From Power Key"); // 此处会打印这句log,可作为分析问题是注意点
wakeUp(eventTime, mAllowTheaterModeWakeFromPowerKey, "android.policy:POWER");//调用wakeup继续执行亮屏操作,注意调用mPowerManager.wakeUp操作
}
下面我们看下PowerManager.wakeUp的相关处理
public void wakeUp(long time) {
try {
mService.wakeUp(time, "wakeUp", mContext.getOpPackageName());//调用到PWM.wakeUpInternal->PWM.wakeUpNoUpdateLocked
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
当power接收到亮灭屏调用后,会先进行设置手机wakefullness状态. 之后发送亮灭屏广播通知其他应用手机处于亮屏还是灭屏状态。
private boolean wakeUpNoUpdateLocked(long eventTime, String reason, int reasonUid,
String opPackageName, int opUid) {
//mWakefulness标识系统当前状态共有四种定义:
WAKEFULNESS_ASLEEP:表示系统当前处于休眠状态,只能被wakeUp()调用唤醒。
WAKEFULNESS_AWAKE:表示系统目前处于正常运行状态。
WAKEFULNESS_DREAMING:表示系统当前正处于互动屏保的状态。
WAKEFULNESS_DOZING:表示系统正处于“doze”状态
if (eventTime < mLastSleepTime || mWakefulness == WAKEFULNESS_AWAKE
|| !mBootCompleted || !mSystemReady) {//按键时间在睡下去之前,屏幕是正常状态,没有完成开机流程,系统没有准备完成,这四种情况不继续执行唤醒流程
return false;
}
try {//系统不是点亮状态,打出相关log
switch (mWakefulness) {
case WAKEFULNESS_ASLEEP:
case WAKEFULNESS_DREAMING:
case WAKEFULNESS_DOZING:
Slog.i(TAG, "Waking up from dozing due to"+opPackageName+" "+reason+" (uid " + reasonUid +")...");
break;
}
mLastWakeTime = eventTime;//更新wake时间
setWakefulnessLocked(WAKEFULNESS_AWAKE, 0);//更新mWakefulness,并调用Notifier.onWakefulnessChangeStarted发送亮屏广播
mNotifier.onWakeUp(reason, reasonUid, opPackageName, opUid);//调用Notifier通知battery处理
userActivityNoUpdateLocked(eventTime, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, reasonUid);//更新最后一次用户事件的时间
} finally {
}
return true;
}
然后主要就是在Notifier.java中与AMS,window,input进行交互,通知各模块手机状态发生了改变,根据屏幕状态各自进行处理, 最后发送亮灭屏广播, 通知相关的模块.
private void setWakefulnessLocked(int wakefulness, int reason) {
if (mWakefulness != wakefulness) {
mWakefulness = wakefulness;//更新mWakefulness变量
mWakefulnessChanging = true;
mDirty |= DIRTY_WAKEFULNESS;
mNotifier.onWakefulnessChangeStarted(wakefulness, reason);//调用Notify的函数onWakefulnessChangeStarted 发广播通知
}
}
public void onWakefulnessChangeStarted(final int wakefulness, int reason) {
//获取交互模式变量,亮屏为true, 灭屏为false
final boolean interactive = PowerManagerInternal.isInteractive(wakefulness);
通知AMS wakefulness状态的变化
mHandler.post(new Runnable() {
@Override
public void run() {
mActivityManagerInternal.onWakefulnessChanged(wakefulness);
}
});
//interactive 变化时才会执行里面的逻辑
if (mInteractive != interactive) {
// Finish up late behaviors if needed.
if (mInteractiveChanging) {
handleLateInteractiveChange();
}
//在input中记录现在的屏幕状态
mInputManagerInternal.setInteractive(interactive);
mInputMethodManagerInternal.setInteractive(interactive);
//唤醒battery状态
try {
mBatteryStats.noteInteractive(interactive);
} catch (RemoteException ex) { }
// Handle early behaviors.
mInteractive = interactive;
mInteractiveChangeReason = reason;
mInteractiveChanging = true;
handleEarlyInteractiveChange();//处理交互模式改变
}
}
private void handleEarlyInteractiveChange() {
synchronized (mLock) {
if (mInteractive) {//mInteractive 为true代表要执行亮屏逻辑
// Waking up...
mHandler.post(new Runnable() {
@Override
public void run() {
// Note a SCREEN tron event is logged in PowerManagerService.
mPolicy.startedWakingUp();//调用PhoneWindowManager 方法开始亮屏流程
}
});
// 更新亮屏广播
mPendingInteractiveState = INTERACTIVE_STATE_AWAKE;
mPendingWakeUpBroadcast = true;
updatePendingBroadcastLocked();//mSuspendBlocker.acquire();持有partial 锁
} else {//mInteractive 为false代表要执行灭屏逻辑
final int why = translateOffReason(mInteractiveChangeReason);
mHandler.post(new Runnable() {
@Override
public void run() {
mPolicy.startedGoingToSleep(why);//调用PhoneWindowManager 方法开始灭屏流程
}
});
}
}
}
调用updatePendingBroadcastLocked函数发出handle msg 消息
Message msg = mHandler.obtainMessage(MSG_BROADCAST);
msg.setAsynchronous(true);
mHandler.sendMessage(msg);
然后handle收到后执行sendNextBroadcast函数
case MSG_BROADCAST:
sendNextBroadcast();
break;
private void sendNextBroadcast() {
final int powerState;
//mBroadcastedInteractiveState 这个变量记录当前的系统亮灭屏情况
synchronized (mLock) {
if (mBroadcastedInteractiveState == INTERACTIVE_STATE_UNKNOWN) {
// 当前状态位置更新为唤醒状态
mPendingWakeUpBroadcast = false;
mBroadcastedInteractiveState = INTERACTIVE_STATE_AWAKE;
} else if (mBroadcastedInteractiveState == INTERACTIVE_STATE_AWAKE) {
// 当前是唤醒状态,更新为灭屏状态
if (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast
|| mPendingInteractiveState == INTERACTIVE_STATE_ASLEEP) {
mPendingGoToSleepBroadcast = false;
mBroadcastedInteractiveState = INTERACTIVE_STATE_ASLEEP;
} else {
finishPendingBroadcastLocked();//释放partial 锁
return;
}
} else {
// 当前是灭屏状态,更新为唤醒状态
if (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast
|| mPendingInteractiveState == INTERACTIVE_STATE_AWAKE) {
mPendingWakeUpBroadcast = false;
mBroadcastedInteractiveState = INTERACTIVE_STATE_AWAKE;
} else {
finishPendingBroadcastLocked();
return;
}
}
//记录下当前系统时间为广播开始时间
mBroadcastStartTime = SystemClock.uptimeMillis();
powerState = mBroadcastedInteractiveState;
}
EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_SEND, 1);//打出event log
if (powerState == INTERACTIVE_STATE_AWAKE) {//根据powerState的值决定发亮屏还是灭屏广播
sendWakeUpBroadcast();
} else {
sendGoToSleepBroadcast();
}
}
广播都是前台广播,然后其他模块收到广播后作出对应处理
mScreenOnIntent.addFlags(
Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND
| Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS);
mScreenOffIntent.addFlags(
Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND
| Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS);
Notify 收到这个广播后会,继续调用sendNextBroadcast,因为mPendingWakeUpBroadcast值变化,会调用finishPendingBroadcastLocked();释放partial 锁
private final BroadcastReceiver mWakeUpBroadcastDone = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_DONE, 1,
SystemClock.uptimeMillis() - mBroadcastStartTime, 1);
sendNextBroadcast();
}
};
总结:当power接收到亮灭屏调用后,会先进行设置手机wakefullness状态,之后发送亮灭屏广播通知其他模块手机处于亮屏还是灭屏状态。并且在发送广播过程中power也与AMS,window,input进行交互,通知各模块手机状态发生了改变,根据屏幕状态各自进行处理。其中发送亮灭屏广播的主要实现在Notifier.java中。
当wakefulness状态发生改变,AMS收到通知。如果亮屏操作,AMS就会通过函数comeOutOfSleepIfNeedLocked调用到ActivityStackSupervisor中,将sleep超时消息移除,最后将在栈顶的activity显示出来。
power是通过WindowManagerPolicy与PhoneWindowManager进行交互,当屏幕在唤醒时需要通知window进行更新手势监听,更新方向监听,更新锁屏超时时间。最后通知keyguard屏幕点亮了,进行刷新锁屏界面时间,之后通过回调接口,回调回PhoneWindowManager的onShown函数,通知window keyguard准备完成。
当亮屏时通过InputManagerService将当前屏幕状态传入JNI中进行记录,当再次发生power键事件可以方便确认该事件是需要亮屏还是灭屏。
当广播处理完毕后就会调用PMS的内部函数updatePowerStateLocked来更新全局电源状态。其实在PMS中很多函数都只是对一些必须的属性进行赋值,大部分最终都会调用到updatePowerStateLocked函数中进行功能执行,其中更新电源状态主要依据就是变量mDirty。mDirty就是用来记录power state的变化的标记位,这样的状态变化在系统中一共定义了12个,每一个状态对应一个固定的数字,都是2的倍数。这样,若有多个状态一块变化,进行按位取或这样结果既是唯一的,又能准确标记出各个状态的变化。在updatePowerStateLocked中主要做了如下事情:
- 首先判断手机是否处于充电状态,如果标记位DIRTY_BATTERY_STATE发生改变时就证明电池状态发生了改变,然后通过对比判断(通过电池前后变化与充电状态的变化),确认手机是否处于充电状态。如果手机处于充电状态会将表示充电的标记位记入mDirty中。当有USB插拔时我们也可以通过配置信息来决定是否需要点亮屏幕。并且是否在充电或者充电方式发生改变,系统都会认为发生了一次用户事件进行更新最后用户操作时间,以此来重新计算屏幕超时时间。
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 (wasPowered != mIsPowered || oldPlugType != mPlugType) {
mDirty |= DIRTY_IS_POWERED;//如果充电中设置mDirty
/* < Bug#696466 optimization for sceenoff */
if (wasPowered != mIsPowered)
SystemProperties.set("sys.sprd.power.ispowered", (mIsPowered? "1": "0"));//设置属性sys.sprd.power.ispowered
/* Bug#696466 optimization for sceenoff > */
//无线充电
final boolean dockedOnWirelessCharger = mWirelessChargerDetector.update(
mIsPowered, mPlugType, mBatteryLevel);
final long now = SystemClock.uptimeMillis();
if (shouldWakeUpWhenPluggedOrUnpluggedLocked(wasPowered, oldPlugType,
dockedOnWirelessCharger)) {//插拔USB是否要点亮屏幕
wakeUpNoUpdateLocked(now, "android.server.power:POWER", Process.SYSTEM_UID,
mContext.getOpPackageName(), Process.SYSTEM_UID);
}
userActivityNoUpdateLocked(//插拔USB算一次用户事件,重新设置最后一次用户事件的时间点
now, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, Process.SYSTEM_UID);
// Tell the notifier whether wireless charging has started so that
// it can provide feedback to the user.
if (dockedOnWirelessCharger) {
mNotifier.onWirelessChargingStarted();
}
}
if (wasPowered != mIsPowered || oldLevelLow != mBatteryLevelLow) {//低电模式
if (oldLevelLow != mBatteryLevelLow && !mBatteryLevelLow) {
mAutoLowPowerModeSnoozing = false;
}
updateLowPowerModeLocked();//更新低电模式
}
}
}
- 更新wakefulness
for (;;) {
int dirtyPhase1 = mDirty;
dirtyPhase2 |= dirtyPhase1;
mDirty = 0;
updateWakeLockSummaryLocked(dirtyPhase1);
updateUserActivitySummaryLocked(now, dirtyPhase1);
if (!updateWakefulnessLocked(dirtyPhase1)) {
break;
}
}
updateWakeLockSummaryLocked函数将wakeLock的类型用mWakeLockSummary进行记录,最后与Wakefulness状态结合重新算出新的mWakeLockSummary值,再判断是否需要睡眠时会使用。
之后updateUserActivitySummaryLocked就会更新屏幕超时时间,根据最后一次的用户事件与屏幕超时时间与dim持续时间来计算屏幕超时的时间,然后与现在的时间进行对比,来决定屏幕要继续高亮,还是要变为dim状态。
PowerManagerHandler接收屏幕超时的消息, 并且调用handleUserActivityTimeout进行处理, 该函数之后就在Handler线程中运行
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;
}
}
}
private void handleUserActivityTimeout() { // runs on handler thread
synchronized (mLock) {
if (DEBUG_SPEW) {
Slog.d(TAG, "handleUserActivityTimeout");
}
mDirty |= DIRTY_USER_ACTIVITY; //设置有用户活动的mDirty值
updatePowerStateLocked(); //更新电源状态, 最后去判断是否要睡眠
}
}
根据前面流程图可以看出更新wakefulness过程是通过一个死循环来执行的,只有调用函数updateWakefulnessLocked返回false时才会跳出循环。在循环中对wakeLockSummary进行更新,并且更新自动灭屏时间后,进行判断系统是否该睡眠了,是否可以跳出循环。
在updateWakefulnessLocked中主要根据是否存在wakeLock,用户活动进行判断设备是否需要进入睡眠状态。从函数isBeingKeptAwakeLocked可以看出当device拿着一个wake lock,有用户事件,有距离传感器等都不会灭屏进行睡眠状态。如果需要睡眠就会往下面调用,最后跳出循环。
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()) { //mWakefulness为AWAKE, 并且到了睡觉时间, 就去睡觉
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;
}
[java] view plain copy
private boolean isItBedTimeYetLocked() {// 对所有该唤醒的情况取反, 就是该休眠了
return mBootCompleted && !isBeingKeptAwakeLocked();
}
private boolean isBeingKeptAwakeLocked() {
return mStayOn //设置了stay on
|| mProximityPositive //距离传感器返回一个positive结果,保持唤醒
|| (mWakeLockSummary & WAKE_LOCK_STAY_AWAKE) != 0 //当有wake lock时保持唤醒
|| (mUserActivitySummary & (USER_ACTIVITY_SCREEN_BRIGHT
| USER_ACTIVITY_SCREEN_DIM)) != 0 //有user activity时保持唤醒
|| mScreenBrightnessBoostInProgress;
}
[java] view plain copy
mDreamsActivateOnSleepSetting = (Settings.Secure.getIntForUser(resolver,
Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP,
mDreamsActivatedOnSleepByDefaultConfig ? 1 : 0,
UserHandle.USER_CURRENT) != 0); //从settings数据库获取对应值
mDreamsActivateOnDockSetting = (Settings.Secure.getIntForUser(resolver,
Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK,
mDreamsActivatedOnDockByDefaultConfig ? 1 : 0,
UserHandle.USER_CURRENT) != 0);
private boolean shouldNapAtBedTimeLocked() { //当返回true, 设备自动nap
return mDreamsActivateOnSleepSetting
|| (mDreamsActivateOnDockSetting
&& mDockState != Intent.EXTRA_DOCK_STATE_UNDOCKED);
}
[java] view plain copy
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); //设置WAKEFULNESS_DREAMING
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
return true;
}
调用goToSleepNoUpdateLocked进行睡眠, 当按power键灭屏是也会调用该函数.
[java] view plain copy
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 {
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;
setWakefulnessLocked(WAKEFULNESS_DOZING, reason);
// 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++) { //遍历所有的wakeLocks, 将FULL, BRIGHT, DIM Locks,计入numWakeLocksCleared中
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;
}
}
EventLog.writeEvent(EventLogTags.POWER_SLEEP_REQUESTED, numWakeLocksCleared);
// Skip dozing if requested.
if ((flags & PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE) != 0) {
reallyGoToSleepNoUpdateLocked(eventTime, uid); //如果没有doze流程,直接设置WAKEFULNESS_ASLEEP
}
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
return true; //返回true
}
当第一个for循环中将所有的状态都设置好了, 并且此时也没有重要的mDirty发生变化, 在下一次循环中mDirty的值为0, updateWakefulnessLocked返回false,就会跳出循环.
当跳出循环之后在函数updateDisplayPowerStateLocked中进行获取需要请求的设备电源状态是亮还是灭或者dim,判断是否开启了自动调节亮度开关,是否使用了距离传感器,并经过一系列的计算获取亮度值等,最终都记录到DisplayPowerRequest中,经过DMS传入DPC中,进行处理。
在PowerManagerService中对各种状态进行判断后,将其数值封装进DisplayPowerRequest中传入DisplayPowerController中进一步处理。在亮屏过程中DisplayPowerController会根据传过来的数值来设置新的电源状态为亮屏,然后调用DisplayPowerState来对状态进行设置。由于此时ColorFade level(就是在手机屏幕的一层surface,当level为0是为一层黑帧,level为1.0时为透明)的值为0,表示屏幕还没有绘制好,所以此时需要block screen直到window界面绘制完成。当需要亮屏时调用PhoneWindowManager的screenTurningOn函数,通知window屏幕就要点亮了。然后调用WMS中函数waitForAllWindowsDrawn函数等待将所有需要绘制的window绘制完成后回调回来,超时时间为1000ms。在WMS中获取需要绘制的window将其加入mWaitingForDrawn中等待绘制,通过检查mWaitingForDrawn是否为空来判断,window是否绘制完成。此时screenTurningOn函数就执行完了,剩下的就是等待windows绘制完成。