邯鄲建設(shè)網(wǎng)站的公司接廣告推廣
該系列文章總綱鏈接:專題分綱目錄 Android SystemUI組件
本章關(guān)鍵點總結(jié) & 說明:
說明:本章節(jié)持續(xù)迭代之前章節(jié)的思維導(dǎo)圖,主要關(guān)注左側(cè)上方鎖屏分析部分 睡眠滅屏 即可。
Power按鍵的處理邏輯最終是由PhoneWindowManager來完成。想了解更多可參考輸入子系統(tǒng)的相關(guān)文章。整理如下:
Android Framework 輸入子系統(tǒng)(01)核心機制 inotify和epoll
Android Framework 輸入子系統(tǒng)(02)核心機制 雙向通信(socketpair+binder)
Android Framework 輸入子系統(tǒng)(03)輸入系統(tǒng)框架
Android Framework 輸入子系統(tǒng)(04)InputReader解讀
Android Framework 輸入子系統(tǒng)(05)InputDispatcher解讀
Android Framework 輸入子系統(tǒng)(06)Global Key 一鍵啟動 應(yīng)用程序案例
Android Framework 輸入子系統(tǒng)(07)APP建立聯(lián)系
Android Framework 輸入子系統(tǒng)(08)View基礎(chǔ)(activity window decor view)
Android Framework 輸入子系統(tǒng)(09)InputStage解讀
Android Framework 輸入子系統(tǒng)(10)Input命令解讀
Android Framework 輸入子系統(tǒng)(11)sendevent與getevent命令解讀
本章我們只關(guān)注與Power按鍵相關(guān)的內(nèi)容,InputManagerService處理的按鍵事件,最終會傳遞到PhoneWindowManager的interceptKeyBeforeQueueing方法中處理。我們就從這里入手逐步分析。
1 從PhoneWindowManager到PowerManagerService的處理
public class PhoneWindowManager implements WindowManagerPolicy {static final String TAG = "WindowManager";static final boolean DEBUG = false;//...//關(guān)鍵流程step1public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {//...//表示屏幕是否點亮final boolean interactive = (policyFlags & FLAG_INTERACTIVE) != 0;final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;final boolean canceled = event.isCanceled();//獲取按鍵編碼final int keyCode = event.getKeyCode();final boolean keyguardActive = (mKeyguardDelegate == null ? false :(interactive ?isKeyguardShowingAndNotOccluded() :mKeyguardDelegate.isShowing()));boolean isWakeKey = (policyFlags & WindowManagerPolicy.FLAG_WAKE) != 0|| event.isWakeKey();//...// Handle special keys.switch (keyCode) {//...case KeyEvent.KEYCODE_POWER: {result &= ~ACTION_PASS_TO_USER;isWakeKey = false; // wake-up will be handled separatelyif (down) {//亮屏 step1 按下power按鍵,亮屏流程interceptPowerKeyDown(event, interactive);} else {//抬起power按鍵interceptPowerKeyUp(event, interactive, canceled);}break;}case KeyEvent.KEYCODE_SLEEP: {result &= ~ACTION_PASS_TO_USER;if (!mPowerManager.isInteractive()) {useHapticFeedback = false; // suppress feedback if already non-interactive}mPowerManager.goToSleep(event.getEventTime(),PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, 0);isWakeKey = false;break;}case KeyEvent.KEYCODE_WAKEUP: {result &= ~ACTION_PASS_TO_USER;isWakeKey = true;break;}//...}//...if (isWakeKey) {wakeUp(event.getEventTime(), mAllowTheaterModeWakeFromKey);}return result;}//...//關(guān)鍵流程step2private void interceptPowerKeyUp(KeyEvent event, boolean interactive, boolean canceled) {final boolean handled = canceled || mPowerKeyHandled;mScreenshotChordPowerKeyTriggered = false;cancelPendingScreenshotChordAction();cancelPendingPowerKeyAction();if (!handled) {// Figure out how to handle the key now that it has been released.mPowerKeyPressCounter += 1;final int maxCount = getMaxMultiPressPowerCount();final long eventTime = event.getDownTime();if (mPowerKeyPressCounter < maxCount) {// This could be a multi-press. Wait a little bit longer to confirm.// Continue holding the wake lock.Message msg = mHandler.obtainMessage(MSG_POWER_DELAYED_PRESS,interactive ? 1 : 0, mPowerKeyPressCounter, eventTime);msg.setAsynchronous(true);mHandler.sendMessageDelayed(msg, ViewConfiguration.getDoubleTapTimeout());return;}// No other actions. Handle it immediately.powerPress(eventTime, interactive, mPowerKeyPressCounter);}// Done. Reset our state.finishPowerKeyPress();}//...//關(guān)鍵流程step3private void powerPress(long eventTime, boolean interactive, int count) {if (mScreenOnEarly && !mScreenOnFully) {return;}if (count == 2) {powerMultiPressAction(eventTime, interactive, mDoublePressOnPowerBehavior);} else if (count == 3) {powerMultiPressAction(eventTime, interactive, mTriplePressOnPowerBehavior);} else if (interactive && !mBeganFromNonInteractive) {//關(guān)鍵流程step4 除了無效處理意外,都會調(diào)用到PowerManagerService中的goToSleep方法switch (mShortPressOnPowerBehavior) {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;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;}}}//...
}
2 從PowerManagerService到Notifier的處理
從PhoneWindowManager的interceptKeyBeforeQueueing方法入口開始分析,最終會到達PowerManagerService的gotoSleep方法(從PowerManager到PowerManagerService的調(diào)用就不在分析了,這個屬于binder通信的范疇),對應(yīng)的代碼實現(xiàn)如下:
public final class PowerManagerService extends SystemServiceimplements Watchdog.Monitor {private static final String TAG = "PowerManagerService";private static final boolean DEBUG = false;//...//關(guān)鍵流程step1private final class BinderService extends IPowerManager.Stub {@Override // Binder callpublic 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 {goToSleepInternal(eventTime, reason, flags, uid);} finally {Binder.restoreCallingIdentity(ident);}}//...}//...//關(guān)鍵流程step2private void goToSleepInternal(long eventTime, int reason, int flags, int uid) {synchronized (mLock) {if (goToSleepNoUpdateLocked(eventTime, reason, flags, uid)) {updatePowerStateLocked();}}}//...//關(guān)鍵流程step3private boolean goToSleepNoUpdateLocked(long eventTime, int reason, int flags, int uid) {if (eventTime < mLastWakeTime|| mWakefulness == WAKEFULNESS_ASLEEP|| mWakefulness == WAKEFULNESS_DOZING|| !mBootCompleted || !mSystemReady) {return false;}try {//...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++) {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.if ((flags & PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE) != 0) {reallyGoToSleepNoUpdateLocked(eventTime, uid);}} return true;}//...//關(guān)鍵流程step4private boolean reallyGoToSleepNoUpdateLocked(long eventTime, int uid) {if (eventTime < mLastWakeTime || mWakefulness == WAKEFULNESS_ASLEEP|| !mBootCompleted || !mSystemReady) {return false;}try {mDirty |= DIRTY_WAKEFULNESS;mWakefulness = WAKEFULNESS_ASLEEP;setInteractiveStateLocked(false, PowerManager.GO_TO_SLEEP_REASON_TIMEOUT);}return true;}//關(guān)鍵流程step5private void setInteractiveStateLocked(boolean interactive, int reason) {if (mInteractive != interactive) {finishInteractiveStateChangeLocked();mInteractive = interactive;mInteractiveChanging = true;mNotifier.onInteractiveStateChangeStarted(interactive, reason);}}//...//關(guān)鍵流程step6private void finishInteractiveStateChangeLocked() {if (mInteractiveChanging) {mNotifier.onInteractiveStateChangeFinished(mInteractive);mInteractiveChanging = false;}}//...
}
3 Notifier的處理
Notifier的處理包含2個層面,一個是發(fā)送SCREEN_OFF的廣播,通知其他子系統(tǒng)亮屏的消息。一個是通過PhoneWindowManager的處理來逐層執(zhí)行對應(yīng)回調(diào)onScreenTurnedOff方法。
3.1 從Notifier最終發(fā)送SCREEN_OFF廣播
針對發(fā)送廣播的邏輯處理流程,代碼邏輯流程如下:
//Notifier
final class Notifier {private static final String TAG = "PowerManagerNotifier";private static final boolean DEBUG = false;//...//關(guān)鍵流程step1public void onInteractiveStateChangeFinished(boolean interactive) {synchronized (mLock) {if (!interactive) {if (mActualPowerState != POWER_STATE_ASLEEP) {mActualPowerState = POWER_STATE_ASLEEP;mPendingGoToSleepBroadcast = true;if (mUserActivityPending) {mUserActivityPending = false;mHandler.removeMessages(MSG_USER_ACTIVITY);}mHandler.post(new Runnable() {@Overridepublic void run() {int why = WindowManagerPolicy.OFF_BECAUSE_OF_USER;switch (mLastGoToSleepReason) {case PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN:why = WindowManagerPolicy.OFF_BECAUSE_OF_ADMIN;break;case PowerManager.GO_TO_SLEEP_REASON_TIMEOUT:why = WindowManagerPolicy.OFF_BECAUSE_OF_TIMEOUT;break;}EventLog.writeEvent(EventLogTags.POWER_SCREEN_STATE, 0, why, 0, 0);mPolicy.goingToSleep(why);mActivityManagerInternal.goingToSleep();}});updatePendingBroadcastLocked();}}}}//...//關(guān)鍵流程step2private void updatePendingBroadcastLocked() {if (!mBroadcastInProgress&& mActualInteractiveState != INTERACTIVE_STATE_UNKNOWN&& (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast|| mActualInteractiveState != mBroadcastedInteractiveState)) {mBroadcastInProgress = true;mSuspendBlocker.acquire();Message msg = mHandler.obtainMessage(MSG_BROADCAST);msg.setAsynchronous(true);mHandler.sendMessage(msg);}}//...//關(guān)鍵流程step3private final class NotifierHandler extends Handler {public NotifierHandler(Looper looper) {super(looper, null, true /*async*/);}@Overridepublic void handleMessage(Message msg) {switch (msg.what) {case MSG_BROADCAST:sendNextBroadcast();break;//...}}}//消息處理:當(dāng)設(shè)備從睡眠狀態(tài)喚醒時,會發(fā)送 ACTION_SCREEN_ON 廣播;當(dāng)設(shè)備準(zhǔn)備進入睡眠狀態(tài)時,會發(fā)送 ACTION_SCREEN_OFF 廣播。private void sendNextBroadcast() {final int powerState;synchronized (mLock) {//mBroadcastedInteractiveState相關(guān)處理//...mBroadcastStartTime = SystemClock.uptimeMillis();powerState = mBroadcastedInteractiveState;}EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_SEND, 1);// 根據(jù)電源狀態(tài)發(fā)送相應(yīng)的廣播if (powerState == INTERACTIVE_STATE_AWAKE) {sendWakeUpBroadcast(); //發(fā)送喚醒廣播} else {sendGoToSleepBroadcast(); //發(fā)送睡眠廣播}}//...//消息處理:發(fā)送有序廣播private void sendGoToSleepBroadcast() {if (ActivityManagerNative.isSystemReady()) {// 發(fā)送廣播關(guān)鍵API,參數(shù)解讀如下:// mScreenOnIntent 是一個 Intent,包含了喚醒屏幕的信息// UserHandle.ALL 表示這個廣播會發(fā)送給所有用戶// mWakeUpBroadcastDone 是一個 BroadcastReceiver,用于在廣播完成后接收回調(diào)// mHandler 是一個 Handler,用于處理廣播完成后的回調(diào)// 0 是一個 flags,表示廣播的權(quán)限// 最后的 null, null 是額外的參數(shù),這里沒有使用mContext.sendOrderedBroadcastAsUser(mScreenOffIntent, UserHandle.ALL, null,mGoToSleepBroadcastDone, mHandler, 0, null, null);} else {EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_STOP, 3, 1);sendNextBroadcast();}}//...
}
這條邏輯的處理主要是發(fā)送睡眠廣播為主。接下來分析從mPolicy.goingToSleep(why);出發(fā)的滅屏回調(diào)處理流程。
3.2 PhoneWindowManager的goingToSleep方法處理滅屏回調(diào)方法
這里主要是從到PhoneWindowManager的wakingUp(policy.goingToSleep)方法,再到各層的onScreenTurnedOff方法的處理邏輯流程,從onInteractiveStateChangeFinished處開始,代碼實現(xiàn)如下:
//Notifier
final class Notifier {private static final String TAG = "PowerManagerNotifier";private static final boolean DEBUG = false;//...public void onInteractiveStateChangeFinished(boolean interactive) {synchronized (mLock) {if (!interactive) {if (mActualPowerState != POWER_STATE_ASLEEP) {mActualPowerState = POWER_STATE_ASLEEP;mPendingGoToSleepBroadcast = true;if (mUserActivityPending) {mUserActivityPending = false;mHandler.removeMessages(MSG_USER_ACTIVITY);}mHandler.post(new Runnable() {@Overridepublic void run() {int why = WindowManagerPolicy.OFF_BECAUSE_OF_USER;switch (mLastGoToSleepReason) {case PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN:why = WindowManagerPolicy.OFF_BECAUSE_OF_ADMIN;break;case PowerManager.GO_TO_SLEEP_REASON_TIMEOUT:why = WindowManagerPolicy.OFF_BECAUSE_OF_TIMEOUT;break;}EventLog.writeEvent(EventLogTags.POWER_SCREEN_STATE, 0, why, 0, 0);mPolicy.goingToSleep(why);mActivityManagerInternal.goingToSleep();}});updatePendingBroadcastLocked();}}}}//...
}
這里會調(diào)用到PhoneWindowManager的goingToSleep方法。代碼實現(xiàn)如下:
//phonewindowmanager@Overridepublic void goingToSleep(int why) {EventLog.writeEvent(70000, 0);synchronized (mLock) {mAwake = false;mKeyguardDrawComplete = false;updateWakeGestureListenerLp();updateOrientationListenerLp();updateLockScreenTimeout();}if (mKeyguardDelegate != null) {mKeyguardDelegate.onScreenTurnedOff(why);}}
這里會調(diào)用到KeyguardDelegate的onScreenTurnedOff方法。代碼實現(xiàn)如下:
?
//KeyguardDelegatepublic void onScreenTurnedOff(int why) {if (mKeyguardService != null) {mKeyguardService.onScreenTurnedOff(why);}mKeyguardState.offReason = why;mKeyguardState.screenIsOn = false;}
這里會調(diào)用到KeyguardServiceWrapper的onScreenTurnedOff方法。代碼實現(xiàn)如下:
//wrapper@Override // Binder interfacepublic void onScreenTurnedOff(int reason) {try {mService.onScreenTurnedOff(reason);} catch (RemoteException e) {Slog.w(TAG , "Remote Exception", e);}}
這里會調(diào)用到KeyguardService的onScreenTurnedOff方法。代碼實現(xiàn)如下:
//KeyguardService//binder@Override // Binder interfacepublic void onScreenTurnedOff(int reason) {checkPermission();mKeyguardViewMediator.onScreenTurnedOff(reason);}
這里會調(diào)用到KeyguardViewMediator的onScreenTurnedOff方法。這里才是真正的邏輯實現(xiàn),代碼實現(xiàn)如下:
//KeyguardViewMediatorpublic void onScreenTurnedOff(int why) {synchronized (this) {// 將屏幕狀態(tài)設(shè)置為關(guān)閉mScreenOn = false;// 重置關(guān)鍵的鎖屏完成等待狀態(tài)resetKeyguardDonePendingLocked();// 標(biāo)記未運行隱藏動畫mHideAnimationRun = false;// 判斷是否需要立即鎖屏// 如果設(shè)置為按下電源鍵立即鎖屏,或者設(shè)備沒有設(shè)置安全措施,則立即鎖屏final boolean lockImmediately =mLockPatternUtils.getPowerButtonInstantlyLocks() || !mLockPatternUtils.isSecure();// 通知屏幕已關(guān)閉notifyScreenOffLocked();// 如果存在退出安全模式的回調(diào),執(zhí)行回調(diào)并設(shè)置為nullif (mExitSecureCallback != null) {// 執(zhí)行回調(diào)以通知鎖屏退出的結(jié)果try {mExitSecureCallback.onKeyguardExitResult(false);} catch (RemoteException e) {// 如果遠程調(diào)用失敗,記錄錯誤Slog.w(TAG, "Failed to call onKeyguardExitResult(false)", e);}mExitSecureCallback = null;// 如果鎖屏沒有被外部啟用,隱藏鎖屏if (!mExternallyEnabled) {hideLocked();}} else if (mShowing) {// 如果鎖屏當(dāng)前正在顯示,重置鎖屏狀態(tài)resetStateLocked();} else if (why == WindowManagerPolicy.OFF_BECAUSE_OF_TIMEOUT ||(why == WindowManagerPolicy.OFF_BECAUSE_OF_USER && !lockImmediately)){// 如果屏幕是因為超時關(guān)閉,或者用戶主動關(guān)閉但不需要立即鎖屏,// 則計劃延遲顯示鎖屏doKeyguardLaterLocked();} else {// 否則,立即顯示鎖屏doKeyguardLocked(null);}}// 通知更新監(jiān)控器屏幕已關(guān)閉,并傳遞關(guān)閉的原因KeyguardUpdateMonitor.getInstance(mContext).dispatchScreenTurndOff(why);}
這里總結(jié)下,onScreenTurnedOff 關(guān)鍵邏輯解讀如下:
- 當(dāng)屏幕關(guān)閉時,這個方法會被調(diào)用。
- 如果設(shè)備設(shè)置為按下電源鍵立即鎖定,或者設(shè)備沒有設(shè)置安全措施(如PIN、密碼、圖案),則變量?lockImmediately?會被設(shè)置為?true。
- 根據(jù)?why?參數(shù)的值(表示屏幕關(guān)閉的原因),決定是否立即調(diào)用?doKeyguardLocked?或者延遲調(diào)用?doKeyguardLaterLocked(也會調(diào)用doKeyguardLocked?)。
接下來關(guān)于doKeyguardLocked的處理,可以參考如下文章:
Android SystemUI組件(07)鎖屏KeyguardViewMediator分析
參考其第二部分2.2 即可。