息屏与亮屏时, Keyguard绘制的基本流程
手机的Power键在灭屏是会加载keyguard, 保证用户在亮屏时,第一时间看到锁屏界面,以保证用户的良好体验.
在亮屏过程中涉及到了两条主要的线程: PowerManager Thread 和DisplayManager Thread
> PowerManager: 主要是Power的按键事件(PhoneWindowManager.java)传递到PowerManagerService.java, 然后进行一系列的操作.> DisplayManager: 会负责进行屏幕状态的设置以及屏幕的熄灭与点亮(与屏幕有关),此外跟屏幕相关的一些可见性操作. 显示操作.
根据上面所述, 找到power按键的事件, 手机的实体按键基本都是在PhoneWindowManaer.java 被处理的.找到入口:
# PhoneWindowManger
private void powerPress(long eventTime, boolean interactive, int count) {
...
if (interactive && !mBeganFromNonInteractive) {
switch (mShortPressOnPowerBehavior) {
...
case SHORT_PRESS_POWER_GO_TO_SLEEP:
mPowerManager.goToSleep(eventTime,
PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, 0);
break;
case SHORT_PRESS_POWER_REALLY_GO_TO_SLEEP:
mPowerManager.goToSleep(eventTime,
PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON,
PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE);
break;
case SHORT_PRESS_POWER_REALLY_GO_TO_SLEEP_AND_GO_HOME:
mPowerManager.goToSleep(eventTime,
PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON,
PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE);
launchHomeFromHotKey();
break;
case SHORT_PRESS_POWER_GO_HOME://进入home界面,应该是亮屏操作
launchHomeFromHotKey(true /* awakenFromDreams */, false /*respectKeyguard*/);
break;
}
}
}
息屏操作的入口在: mPowerManager.goToSleep(), 这是强制手机进入休眠状态.
# PowerManager
public void goToSleep(long time, int reason, int flags) {
try {
mService.goToSleep(time, reason, flags);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
mService是一个Ipowermanager对象, 其使用的aidl机制进行数据共享, 其AIDL Service为 PowerMangerService.java
# PowerManagerService$BinderService
public void goToSleep(long eventTime, int reason, int flags) {
...
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.DEVICE_POWER, null);
final int uid = Binder.getCallingUid();
final long ident = Binder.clearCallingIdentity();
try {
goToSleepInternal(eventTime, reason, flags, uid);
} finally {
Binder.restoreCallingIdentity(ident);//恢复远程调用端的uid和pid信息
}
}
private void goToSleepInternal(long eventTime, int reason, int flags, int uid) {
synchronized (mLock) {
...//判断与sensor有关的息屏
if (goToSleepNoUpdateLocked(eventTime, reason, flags, uid)) {
updatePowerStateLocked();
}
}
}
//全局更新power状态. 主要告知手机即将息屏.
private void updatePowerStateLocked() {
...
try {
...
for (;;) {
...
if (!updateWakefulnessLocked(dirtyPhase1)) {
break;
}
}
...
}
}
private boolean updateWakefulnessLocked(int dirty) {
...//多重判断
if (shouldNapAtBedTimeLocked()) {
changed = napNoUpdateLocked(time, Process.SYSTEM_UID);
} else {
changed = goToSleepNoUpdateLocked(time,
PowerManager.GO_TO_SLEEP_REASON_TIMEOUT, 0, Process.SYSTEM_UID);
}
//多重判断结束
return changed;
}
通过分析: goToSleepNoUpdateLocked() 和 napNoUpdateLocked() 最终会调用:
# PowerManagerService.java
private void setWakefulnessLocked(int wakefulness, int reason) {
if (mWakefulness != wakefulness) {
mWakefulness = wakefulness;
mWakefulnessChanging = true;
mDirty |= DIRTY_WAKEFULNESS;
mNotifier.onWakefulnessChangeStarted(wakefulness, reason);
}
}
只是这两个方法的区别是: 是否是自动去息屏操作.
Notifier 主要是用来发送 Power 状态的广播. 在这里边经过一些列的判断操作, 直接调用了 handleEarlyInteractiveChange() -> mPolicy.startedGoingToSleep(why), 此时PhoneWindowManager开始事件分发:
# PhoneWindowManager.java
public void startedGoingToSleep(int why) {
...
mGoingToSleep = true;
if (mKeyguardDelegate != null) {
mKeyguardDelegate.onStartedGoingToSleep(why);
}
}
这里就不看KeyguardServiceDelegate.java 与 KeyguardService.java, 只要了解他们之间的aidl的跨进程服务. Keyguard.java 是
服务端. KeyguardServiceWrapper.java 是客户端.
息屏操作, 此时进入到了SystemUI, 通知SystemUI的手机进入息屏状态.
# KeyguardViewMediator.java
public void onStartedGoingToSleep(int why) {
...
synchronized (this) {
...
if (mShowing) {
mPendingReset = true;
} else if ((why == WindowManagerPolicy.OFF_BECAUSE_OF_TIMEOUT && timeout > 0)
|| (why == WindowManagerPolicy.OFF_BECAUSE_OF_USER && !lockImmediately/*keyguard的状态,非wipe状态*/)
&& !mIsIPOShutDown/*非关机*/) {
doKeyguardLaterLocked(timeout);
mLockLater = true;
}
...
}
KeyguardUpdateMonitor.getInstance(mContext).dispatchStartedGoingToSleep(why);//稍后分析
notifyStartedGoingToSleep(); //通知息屏结束,锁屏了.
}
private void doKeyguardLaterLocked(long timeout) {
long when = SystemClock.elapsedRealtime() + timeout;
Intent intent = new Intent(DELAYED_KEYGUARD_ACTION);
intent.putExtra("seq", mDelayedShowingSequence);
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
//发送一个广播,调用锁屏函数.
PendingIntent sender = PendingIntent.getBroadcast(mContext,
0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP, when, sender);
doKeyguardLaterForChildProfilesLocked();
}
//DELAYED_KEYGUARD_ACTION 作为广播信息
private final BroadcastReceiver mBroadcastReceiver = new roadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (DELAYED_KEYGUARD_ACTION.equals(action)) {
final int sequence = intent.getIntExtra("seq", 0);
...
synchronized (KeyguardViewMediator.this) {
if (mDelayedShowingSequence == sequence) {
mSuppressNextLockSound = true;
doKeyguardLocked(null); //锁屏路径
}
}
}
...
}
};
总这里看出: 其实在息屏操作中, KeyguardViewMediator最终通过广播调用了 doKeyguardLocked(null), 这个函数应该有印象, 在开机的时候就被调用过. 不过调用它的函数为 onSystemReady(). 这样,我们就不用再通过这条路径往下走了, 其结果应该差不多. 也就证明了keyguard 是在息屏时, 被创建的.
> 在开机状态中, Keyguar是在息屏时被创建.
> 息屏下创建Keyguard, 与是否是主动息屏这个行为无关.
<br/>
屏幕的亮与灭
在点击 Power 按键进行亮屏时:
# PhoneWindowManager
void launchHomeFromHotKey(final boolean awakenFromDreams, final boolean respectKeyguard) {
if (respectKeyguard) {
if (isKeyguardShowingAndNotOccluded()) {
// don't launch home if keyguard showing
return;
}
...
}
...
}
这里仅仅是判断是有 keyguard 这个界面. 如果有, 将停留在这个 keyguard 的界面,; 如果没有, 将进行后续其他的处理.
屏幕的亮起与熄灭,主要在 DisplayPowerController 中驱动. 之前已经说了 Power 的
的控制主要在 Powermanager.
# PowerMnagerService
private void goToSleepInternal(long eventTime, int reason, int flags, int uid) {
synchronized (mLock) {
if (mProximityPositive && reason == PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON) {
...
updatePowerStateLocked();
return;
}
if (goToSleepNoUpdateLocked(eventTime, reason, flags, uid)) {
updatePowerStateLocked();
}
}
}
private void updatePowerStateLocked() {
...
try {
...
// Phase 2: Update display power state.
boolean displayBecameReady = updateDisplayPowerStateLocked(dirtyPhase2);
...
}
}
private boolean updateDisplayPowerStateLocked(int dirty) {
final boolean oldDisplayReady = mDisplayReady;
if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_USER_ACTIVITY | DIRTY_WAKEFULNESS
| DIRTY_ACTUAL_DISPLAY_POWER_STATE_UPDATED | DIRTY_BOOT_COMPLETED
| DIRTY_SETTINGS | DIRTY_SCREEN_BRIGHTNESS_BOOST | DIRTY_BOOT_IPO)) != 0) {
...
mDisplayReady = mDisplayManagerInternal.requestPowerState(mDisplayPowerRequest,
mRequestWaitForNegativeProximity);
...
}
return mDisplayReady && !oldDisplayReady;
}
上述可以看出, 在息屏的时候, PowerManager服务通过一定的操作, 调用了 DisplayPowerController, 来进行显示操作. DisplayManagerInternal 和DisplayManagerService$LocalService作为中间类来进行处理.
首先从requestPowerState()方法开始分析.
# DisplayPowerController.java
public boolean requestPowerState(DisplayPowerRequest request,
boolean waitForNegativeProximity) {
synchronized (mLock) {
boolean changed = false;
...
if (changed && !mPendingRequestChangedLocked) {
mPendingRequestChangedLocked = true;
sendUpdatePowerStateLocked(); //屏幕发生变化
}
...
return mDisplayReadyLocked;
}
}
private void sendUpdatePowerStateLocked() {
if (!mPendingUpdatePowerStateLocked) {
...
Message msg = mHandler.obtainMessage(MSG_UPDATE_POWER_STATE);//发送到Handler子线程去执行.
msg.setAsynchronous(true);
mHandler.sendMessage(msg);
}
}
private void updatePowerState() {//一系列的更新操作.
...
//驱动屏幕状态变化.
animateScreenStateChange(state, performScreenOffTransition);
state = mPowerState.getScreenState();
}
}
private void animateScreenStateChange(int target, boolean performScreenOffTransition) {
...
//息屏操作, 指向了setScreenState();
if (mPendingScreenOff && target != Display.STATE_OFF) {
setScreenState(Display.STATE_OFF);
mPendingScreenOff = false;
...
}
//亮屏操作, 指向了setScreenState()
if (target == Display.STATE_ON) {
if (!setScreenState(Display.STATE_ON)) {
return; // screen on blocked
}
}
...
}
//从上述可以看出,亮屏操作与息屏操作都是需要走setScreenState()方法的.
private boolean setScreenState(int state) {
...
//告诉窗体管理WindowManagerPolicy的屏幕状态.
final boolean isOff = (state == Display.STATE_OFF);
if (isOff && mReportedScreenStateToPolicy != REPORTED_TO_POLICY_SCREEN_OFF
&& !mScreenOffBecauseOfProximity) {
unblockScreenOn();
mWindowManagerPolicy.screenTurnedOff();
} else if (!isOff && mReportedScreenStateToPolicy == REPORTED_TO_POLICY_SCREEN_OFF) {
if (mPowerState.getColorFadeLevel() == 0.0f) {//控制显示状态
blockScreenOn(); //阻止屏幕亮
} else {
unblockScreenOn();//解除阻止屏幕状态.
}
mWindowManagerPolicy.screenTurningOn(mPendingScreenOnUnblocker);
}
// Return true if the screen isn't blocked.
return mPendingScreenOnUnblocker == null;
}
可以看出, 息屏与亮屏过程都会触发WindowManagerPolicy进行一系列事件的操作. 在 PhoneWindowManagerPolicy.java 中, 亮屏与息屏这个消息都会触发 keyguard 代理进行处理.
# PhoneWindowManagerPolicy
//息屏时
public void screenTurnedOff() {
...
synchronized (mLock) {
...
if (mKeyguardDelegate != null) {
mKeyguardDelegate.onScreenTurnedOff();
}
}
}
//亮屏时
public void screenTurningOn(final ScreenOnListener screenOnListener) {
...
synchronized (mLock) {
...
if (mKeyguardDelegate != null) {
mHandler.removeMessages(MSG_KEYGUARD_DRAWN_TIMEOUT);
mHandler.sendEmptyMessageDelayed(MSG_KEYGUARD_DRAWN_TIMEOUT, 1000);
mKeyguardDelegate.onScreenTurningOn(mKeyguardDrawnCallback);
} else {
...
finishKeyguardDrawn();
}
}
}
接着对 KeyguardServiceDelegate 的对象进行判断.如果为空, 即表示未进行keyguard的设置;如果为非空,即表明:keyguard设置了某一 model 形式.
# KeyguardServiceDelegate.java
//息屏
public void onScreenTurnedOff() {
if (mKeyguardService != null) {
mKeyguardService.onScreenTurnedOff();
}
mKeyguardState.screenState = SCREEN_STATE_OFF;
}
//亮屏
public void onScreenTurningOn(final DrawnListener drawnListener) {
if (mKeyguardService != null) {
//当手机在息状态时,必然是开启了keyguard的服务.如果设置了keyguard.
mKeyguardService.onScreenTurningOn(new KeyguardShowDelegate(drawnListener));
} else {
mDrawnListenerWhenConnect = drawnListener;
showScrim();
}
mKeyguardState.screenState = SCREEN_STATE_TURNING_ON;
}
public void screenTurnedOn() {
synchronized (mLock) {
if (mKeyguardDelegate != null) {
mKeyguardDelegate.onScreenTurnedOn();
}
}
}
接着进入到SystemUI,开启Keyguard服务,KeyguardService.java.我们可以发现KeyguardServiceWrapper这个类对象是启动KeyguardService的一个中间类,代理分派任务到Systemui.
# KeyguardService.java
private final IKeyguardService.Stub mBinder = new IKeyguardService.Stub() {
//息屏
public void onScreenTurnedOff() {
checkPermission();
mKeyguardViewMediator.onScreenTurnedOff();
}
//亮屏
...
@Override // Binder interface
public void onScreenTurningOn(IKeyguardDrawnCallback callback) {
checkPermission();
mKeyguardViewMediator.onScreenTurningOn(callback);
}
...
}
Keyguard服务开启后,也是先检查权限,然后再将事件分派出去.
#KeyguardViewMediator.java
//息屏
public void onScreenTurnedOff() {
notifyScreenTurnedOff();
mUpdateMonitor.dispatchScreenTurnedOff();
}
//> 息屏做了两件事:
//1. notifyScreenTurnedOff()将事件交由StatusBarKeyguardViewManager处理
//2. dispatchScreenTurnedOff()将事件交于KeyguardUpdateMonitor处理.
//亮屏
public void onScreenTurningOn(IKeyguardDrawnCallback callback) {
notifyScreenOn(callback);
}
先看看息屏状态时, 流程走向
notifyScreenTurnedOff(): 通知StatusBarKeyguardViewManager去进行处理
# StatusBarKeyguardViewManager.java
public void onScreenTurnedOff() {
mScreenTurnedOn = false;
mPhoneStatusBar.onScreenTurnedOff();
}
# PhoneStatusBar.java
public void onScreenTurnedOff() {
mFalsingManager.onScreenOff();
}
# FalsingManager.jva
public void onScreenOff() {
mDataCollector.onScreenOff();
mScreenOn = false;
sessionExitpoint(false /* force */); //传感器接触注册, 停止传感器的使用
}
# DataCollector.java
public void onScreenOff() {
addEvent(PhoneEvent.ON_SCREEN_OFF); //传感器log日志手机
sessionExitpoint(Session.FAILURE); //touch事件收集器
}
dispatchScreenTurnedOff() 通知 KeyguardUpdateMonitor进行处理
# KeyguardUpdateMonitor.java
private void handleScreenTurnedOff() {
final int count = mCallbacks.size();
for (int i = 0; i < count; i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
cb.onScreenTurnedOff();
}
}
}
看看cb的实现体
# KeyguardHostView.java
public void onScreenTurnedOff() {
mSecurityContainer.onScreenTurnedOff(); //空实现
}
对于亮屏的这个过程, 其余息屏的方式是一样的.都是需要经过
# KeyguardViewMediator.java
private void handleNotifyScreenTurningOn(IKeyguardDrawnCallback callback) {
synchronized (KeyguardViewMediator.this) {
//更新notification的时间和传感器注册, 以及事件的收集.
mStatusBarKeyguardViewManager.onScreenTurningOn();
if (callback != null) {
if (mWakeAndUnlocking) {//判断锁的形式.
mDrawnCallback = callback;
} else {
//回调一个接口对象进行回调绘制.
notifyDrawn(callback);
}
}
}
}
可以看出, "息屏"与"正在亮屏"最后都会调用接口对象实现其息屏与亮屏的操作.
,那么也存在"完成开机"这个实现, 再次回到原点.直接看 StatusBarKeyguardViewManager.java
# StatusBarKeyguardViewManager.java
public void onScreenTurnedOn() {
mScreenTurnedOn = true;
if (mDeferScrimFadeOut) {
mDeferScrimFadeOut = false;
animateScrimControllerKeyguardFadingOut(0, WAKE_AND_UNLOCK_SCRIM_FADEOUT_DURATION_MS,
true /* skipFirstFrame */);
updateStates();
}
if (mPhoneStatusBar != null) {
mPhoneStatusBar.onScreenTurnedOn();//后续操作, 也是一层一层的通知
}
}
---
> 在亮屏与灭屏阶段, keyguard的绘制其实在灭屏阶段.
> 屏幕的显示亮屏与灭屏, 与keyguard的并无直接关系.