亮屏、滅屏流程整個流程涉及的模塊比較多,包括PowerManagerService、DisplayPowerControl、WMS、AMS。因此在分析完WMS之後,我們把這塊也分析下。
DisplayPowerControl
我們知道滅屏流程的發起是在PowerManagerService中,會通過updatePowerState函數調用updateDisplayPowerStateLocked函數,再調用DisplayPowerControl的requestPowerState函數,到DisplayPowerControl中。DisplayPowerControl中後面會調用updatePowerState函數,我們也主要從這個函數開始分析:
updatePowerState會根據PowerManagerService傳過來的顯示狀態,然後調用animateScreenStateChange函數。
animateScreenStateChange(state, performScreenOffTransition);
下面我們先來看animateScreenStateChange函數:
- private void animateScreenStateChange(int target, boolean performScreenOffTransition) {
- // If there is already an animation in progress, don't interfere with it.
- if (mColorFadeOnAnimator.isStarted()
- || mColorFadeOffAnimator.isStarted()) {
- return;
- }
-
- // If we were in the process of turning off the screen but didn't quite
- // finish. Then finish up now to prevent a jarring transition back
- // to screen on if we skipped blocking screen on as usual.
- if (mPendingScreenOff && target != Display.STATE_OFF) {
- setScreenState(Display.STATE_OFF);
- mPendingScreenOff = false;
- mPowerState.dismissColorFadeResources();
- }
-
- if (target == Display.STATE_ON) {//亮屏處理
- // Want screen on. The contents of the screen may not yet
- // be visible if the color fade has not been dismissed because
- // its last frame of animation is solid black.
- if (!setScreenState(Display.STATE_ON)) {
- return; // screen on blocked
- }
- if (USE_COLOR_FADE_ON_ANIMATION && mPowerRequest.isBrightOrDim()) {//亮屏動畫
- // Perform screen on animation.
- if (mPowerState.getColorFadeLevel() == 1.0f) {
- mPowerState.dismissColorFade();
- } else if (mPowerState.prepareColorFade(mContext,
- mColorFadeFadesConfig ?
- ColorFade.MODE_FADE :
- ColorFade.MODE_WARM_UP)) {
- mColorFadeOnAnimator.start();
- } else {
- mColorFadeOnAnimator.end();
- }
- } else {//跳過亮屏動畫
- // Skip screen on animation.
- mPowerState.setColorFadeLevel(1.0f);
- mPowerState.dismissColorFade();
- }
- } else if (target == Display.STATE_DOZE) {
- // Want screen dozing.
- // Wait for brightness animation to complete beforehand when entering doze
- // from screen on to prevent a perceptible jump because brightness may operate
- // differently when the display is configured for dozing.
- ......
- } else if (target == Display.STATE_DOZE_SUSPEND) {
- // Want screen dozing and suspended.
- // Wait for brightness animation to complete beforehand unless already
- // suspended because we may not be able to change it after suspension.
- ......
- } else {//滅屏處理
- // Want screen off.
- mPendingScreenOff = true;
- if (mPowerState.getColorFadeLevel() == 0.0f) {//滅屏動畫結束
- // Turn the screen off.
- // A black surface is already hiding the contents of the screen.
- setScreenState(Display.STATE_OFF);
- mPendingScreenOff = false;
- mPowerState.dismissColorFadeResources();
- } else if (performScreenOffTransition
- && mPowerState.prepareColorFade(mContext,
- mColorFadeFadesConfig ?
- ColorFade.MODE_FADE : ColorFade.MODE_COOL_DOWN)
- && mPowerState.getScreenState() != Display.STATE_OFF) {
- // Perform the screen off animation.
- mColorFadeOffAnimator.start();//開啓滅屏動畫
- } else {
- // Skip the screen off animation and add a black surface to hide the
- // contents of the screen.
- mColorFadeOffAnimator.end();//關閉滅屏動畫
- }
- }
- }
animateScreenStateChange在亮屏的處理的時候,先會調用setScreenState(Display.STATE_ON),然後根據USE_COLOR_FADE_ON_ANIMATION 判斷是否要開啓亮屏動畫,這裏我們是沒有設置的。因此直接跳過亮屏動畫。滅屏的處理的話,會有一個滅屏動畫(也是註冊一個VSync信號回調函數處理的,這裏我們不分析了),當動畫結束後,直接就調用setScreenState(Display.STATE_OFF)結束。
我們再來看看setScreenState函數
- private boolean setScreenState(int state) {
- if (mPowerState.getScreenState() != state) {
- final boolean wasOn = (mPowerState.getScreenState() != Display.STATE_OFF);
- mPowerState.setScreenState(state);
- ......
- }
-
- // Tell the window manager policy when the screen is turned off or on unless it's due
- // to the proximity sensor. We temporarily block turning the screen on until the
- // window manager is ready by leaving a black surface covering the screen.
- // This surface is essentially the final state of the color fade animation and
- // it is only removed once the window manager tells us that the activity has
- // finished drawing underneath.
- final boolean isOff = (state == Display.STATE_OFF);
- if (isOff && mReportedScreenStateToPolicy != REPORTED_TO_POLICY_SCREEN_OFF
- && !mScreenOffBecauseOfProximity) {
- mReportedScreenStateToPolicy = REPORTED_TO_POLICY_SCREEN_OFF;
- unblockScreenOn();
- mWindowManagerPolicy.screenTurnedOff();//調用PhoneWindowManager的screenTurnedOff
- } else if (!isOff && mReportedScreenStateToPolicy == REPORTED_TO_POLICY_SCREEN_OFF) {
- mReportedScreenStateToPolicy = REPORTED_TO_POLICY_SCREEN_TURNING_ON;
- if (mPowerState.getColorFadeLevel() == 0.0f) {
- blockScreenOn();
- } else {
- unblockScreenOn();
- }
- mWindowManagerPolicy.screenTurningOn(mPendingScreenOnUnblocker);//調用PhoneWindowManager的screenTurningOn函數
- }
-
- // Return true if the screen isn't blocked.
- return mPendingScreenOnUnblocker == null;
- }
setScreenState函數,先是調用了DisplayPowerState的setScreenState函數,然後根據屏幕是滅屏還是亮屏調用PhoneWindowManager的相關函數。
PhoneWindowManager的screenTurnedOff和screenTurningOn函數
PhoneWindowManager的screenTurnedOff函數主要是通知kerguard,屏幕滅屏了。
- @Override
- public void screenTurnedOff() {
- if (DEBUG_WAKEUP) Slog.i(TAG, "Screen turned off...");
-
- updateScreenOffSleepToken(true);
- synchronized (mLock) {
- mScreenOnEarly = false;
- mScreenOnFully = false;
- mKeyguardDrawComplete = false;
- mWindowManagerDrawComplete = false;
- mScreenOnListener = null;
- updateOrientationListenerLp();
-
- if (mKeyguardDelegate != null) {
- mKeyguardDelegate.onScreenTurnedOff();
- }
- }
- }
我們再來看PhoneWindowManager的screenTurningOn函數。當有keyguard時,我們會先發一個延時的MSG_KEYGUARD_DRAWN_TIMEOUT信號,並且會調用keyguard的onScreenTurningOn函數,當完成會調用mKeyguardDrawnCallback回調函數。我們這裏還要注意下有一個屏幕點亮後的回調。
- @Override
- public void screenTurningOn(final ScreenOnListener screenOnListener) {
- if (DEBUG_WAKEUP) Slog.i(TAG, "Screen turning on...");
-
- updateScreenOffSleepToken(false);
- synchronized (mLock) {
- mScreenOnEarly = true;
- mScreenOnFully = false;
- mKeyguardDrawComplete = false;
- mWindowManagerDrawComplete = false;
- mScreenOnListener = screenOnListener;//屏幕點亮後的回調
-
- if (mKeyguardDelegate != null) {
- if (DEBUG_WAKEUP) Slog.d(TAG,
- "send delay message MSG_KEYGUARD_DRAWN_TIMEOUT");
- mHandler.removeMessages(MSG_KEYGUARD_DRAWN_TIMEOUT);
- mHandler.sendEmptyMessageDelayed(MSG_KEYGUARD_DRAWN_TIMEOUT, 1000);
- mKeyguardDelegate.onScreenTurningOn(mKeyguardDrawnCallback);
- } else {
- if (DEBUG_WAKEUP) Slog.d(TAG,
- "null mKeyguardDelegate: setting mKeyguardDrawComplete.");
- finishKeyguardDrawn();
- }
- }
- }
我們先看下mKeyguardDrawnCallback 回調,就是發送MSG_KEYGUARD_DRAWN_COMPLETE(keyguard繪製完的消息)
- final DrawnListener mKeyguardDrawnCallback = new DrawnListener() {
- @Override
- public void onDrawn() {
- if (DEBUG_WAKEUP) Slog.d(TAG, "mKeyguardDelegate.ShowListener.onDrawn.");
- mHandler.sendEmptyMessage(MSG_KEYGUARD_DRAWN_COMPLETE);
- }
- };
我們再來看看MSG_KEYGUARD_DRAWN_COMPLETE以及MSG_KEYGUARD_DRAWN_TIMEOUT信號的處理,都會調用finishKeyguardDrawn函數。
- case MSG_KEYGUARD_DRAWN_COMPLETE:
- if (DEBUG_WAKEUP) Slog.w(TAG, "Setting mKeyguardDrawComplete");
- finishKeyguardDrawn();
- break;
- case MSG_KEYGUARD_DRAWN_TIMEOUT:
- Slog.w(TAG, "Keyguard drawn timeout. Setting mKeyguardDrawComplete");
- finishKeyguardDrawn();
- break;
我們再來看看finishKeyguardDrawn函數,會先去除隊列中的MSG_KEYGUARD_DRAWN_TIMEOUT消息(因爲之前發的MSG_KEYGUARD_DRAWN_TIMEOUT消息,可能keyguard結束髮送MSG_KEYGUARD_DRAWN_COMPLETE消息調用的finishKeyguardDrawn就要把MSG_KEYGUARD_DRAWN_TIMEOUT去除了)。然後會調用
- private void finishKeyguardDrawn() {
- synchronized (mLock) {
- if (!mScreenOnEarly || mKeyguardDrawComplete) {
- return; // We are not awake yet or we have already informed of this event.
- }
-
- mKeyguardDrawComplete = true;
- if (mKeyguardDelegate != null) {
- mHandler.removeMessages(MSG_KEYGUARD_DRAWN_TIMEOUT);
- }
- mWindowManagerDrawComplete = false;
- }
-
- // ... eventually calls finishWindowsDrawn which will finalize our screen turn on
- // as well as enabling the orientation change logic/sensor.
- mWindowManagerInternal.waitForAllWindowsDrawn(mWindowManagerDrawCallback,
- WAITING_FOR_DRAWN_TIMEOUT);
- }
最後我們再看看WMS的waitForAllWindowsDrawn函數,以及兩個參數mWindowManagerDrawCallback和一個WAITING_FOR_DRAWN_TIMEOUT(1秒)。
WMS的waitForAllWindowsDrawn函數
我們先來看看WMS的waitForAllWindowsDrawn函數,會把傳進來的回調保存在mWaitingForDrawnCallback 。然後遍歷所有的windows,把需要顯示或者已經顯示的窗口全部加入到mWaitingForDrawn,然後調用requestTraversalLocked這個函數我們之前分析過,就是發送一個消息,重新刷新UI佈局。然後我們繼續分析這個函數,如果mWaitingForDrawn爲空,代表沒啥顯示的直接調用回調函數,如果mWaitingForDrawn有要顯示的窗口,就要會先發送一個WAITING_FOR_DRAWN_TIMEOUT,這個timeout之前傳進來的是1秒。然後調用checkDrawnWindowsLocked函數。
- @Override
- public void waitForAllWindowsDrawn(Runnable callback, long timeout) {
- synchronized (mWindowMap) {
- mWaitingForDrawnCallback = callback;//回調保存在mWaitingForDrawnCallback
- final WindowList windows = getDefaultWindowListLocked();
- for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
- final WindowState win = windows.get(winNdx);
- final boolean isForceHiding = mPolicy.isForceHiding(win.mAttrs);
- Slog.i(TAG,"In the function waitForAllWindowsDrawn");
- if (win.isVisibleLw()
- && (win.mAppToken != null || isForceHiding)) {
- Slog.i(TAG,"In the function win.isVisibleLw()");
- win.mWinAnimator.mDrawState = WindowStateAnimator.DRAW_PENDING;
- // Force add to mResizingWindows.
- win.mLastContentInsets.set(-1, -1, -1, -1);
- mWaitingForDrawn.add(win);
-
- // No need to wait for the windows below Keyguard.
- if (isForceHiding) {
- break;
- }
- }
- }
- requestTraversalLocked();
- }
- mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT);
- if (mWaitingForDrawn.isEmpty()) {
- callback.run();
- Slog.i(TAG,"In the function mWaitingForDrawn.isEmpty()");
- } else {
- mH.sendEmptyMessageDelayed(H.WAITING_FOR_DRAWN_TIMEOUT, timeout);
- checkDrawnWindowsLocked();
- Slog.i(TAG,"In the function checkDrawnWindowsLocked()");
- }
- }
我們先來看下checkDrawnWindowsLocked函數,這個函數。遍歷之前加入的mWaitingForDrawn(要顯示的窗口),這個時候我們把已經去除的,不需要顯示的,沒有surface的窗口從mWaitingForDrawn去除,還有已經繪製好的也去除。然後再當mWaitingForDrawn爲空時,就發送ALL_WINDOWS_DRAWN消息。
- void checkDrawnWindowsLocked() {
- if (mWaitingForDrawn.isEmpty() || mWaitingForDrawnCallback == null) {
- return;
- }
- for (int j = mWaitingForDrawn.size() - 1; j >= 0; j--) {
- WindowState win = mWaitingForDrawn.get(j);
- if (win.mRemoved || !win.mHasSurface || !win.mPolicyVisibility) {
- // Window has been removed or hidden; no draw will now happen, so stop waiting.
- if (DEBUG_SCREEN_ON) Slog.w(TAG, "Aborted waiting for drawn: " + win);
- mWaitingForDrawn.remove(win);
- } else if (win.hasDrawnLw()) {
- // Window is now drawn (and shown).
- if (DEBUG_SCREEN_ON) Slog.d(TAG, "Window drawn win=" + win);
- mWaitingForDrawn.remove(win);
- }
- }
- if (mWaitingForDrawn.isEmpty()) {
- if (DEBUG_SCREEN_ON) Slog.d(TAG, "All windows drawn!");
- mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT);
- mH.sendEmptyMessage(H.ALL_WINDOWS_DRAWN);
- }
- }
ALL_WINDOWS_DRAWN消息的處理就是清除mWaitingForDrawnCallback ,然後調用回調。
- case ALL_WINDOWS_DRAWN: {
- Runnable callback;
- synchronized (mWindowMap) {
- callback = mWaitingForDrawnCallback;
- mWaitingForDrawnCallback = null;
- }
- if (callback != null) {
- callback.run();
- }
- }
還有當我們調用waitForAllWindowsDrawn一般都是有需要顯示的窗口,但是我們直接調用checkDrawnWindowsLocked函數,發現有的窗口還沒繪製完成。那麼我們就要等,會在刷新的核心函數中performLayoutAndPlaceSurfacesLockedInner有如下代碼,這個時候如果之前還沒繪製完成的窗口,繪製好了。會再調用checkDrawnWindowsLocked函數,如果mWaitingForDrawn中的窗口繪製好了,會在mWaitingForDrawn中去除這個窗口。然後mWaitingForDrawn爲空了,之後會發送ALL_WINDOWS_DRAWN消息,還調用mWaitingForDrawnCallback回調函數。
- if (mWaitingForDrawnCallback != null ||
- (mInnerFields.mOrientationChangeComplete && !defaultDisplay.layoutNeeded &&
- !mInnerFields.mUpdateRotation)) {
- checkDrawnWindowsLocked();
- }
當然如果我們之前沒有把mWaitingForDrawn中的窗口清空,最後在WAITING_FOR_DRAWN_TIMEOUT(這裏是1秒)時間到了也會調用回調的。
- case WAITING_FOR_DRAWN_TIMEOUT: {
- Runnable callback = null;
- synchronized (mWindowMap) {
- Slog.w(TAG, "Timeout waiting for drawn: undrawn=" + mWaitingForDrawn);
- mWaitingForDrawn.clear();
- callback = mWaitingForDrawnCallback;
- mWaitingForDrawnCallback = null;
- }
- if (callback != null) {
- callback.run();
- }
- break;
- }
PhoneWindowManager窗口繪製完成的回調函數
那下面我們就要繼續看PhoneWindowManager中窗口繪製完成之後的回調函數。代碼如下就是發送了一個消息。
- final Runnable mWindowManagerDrawCallback = new Runnable() {
- @Override
- public void run() {
- if (DEBUG_WAKEUP) Slog.i(TAG, "All windows ready for display!");
- mHandler.sendEmptyMessage(MSG_WINDOW_MANAGER_DRAWN_COMPLETE);
- }
- };
我們來看這個消息的處理
- case MSG_WINDOW_MANAGER_DRAWN_COMPLETE:
- if (DEBUG_WAKEUP) Slog.w(TAG, "Setting mWindowManagerDrawComplete");
- finishWindowsDrawn();
- break;
finishWindowsDrawn就是把mWindowManagerDrawComplete 置爲true,然後調用finishScreenTurningOn函數。
- private void finishWindowsDrawn() {
- synchronized (mLock) {
- if (!mScreenOnEarly || mWindowManagerDrawComplete) {
- return; // Screen is not turned on or we did already handle this case earlier.
- }
-
- mWindowManagerDrawComplete = true;
- }
-
- finishScreenTurningOn();
- }
finishScreenTurningOn函數調用了之前在DisplayPowerControl中調用screenTurningOn傳入的回調,然後再調用WMS的enableScreenIfNeeded函數。
- private void finishScreenTurningOn() {
- synchronized (mLock) {
- updateOrientationListenerLp();
- }
- final ScreenOnListener listener;
- final boolean enableScreen;
- synchronized (mLock) {
-
- if (mScreenOnFully || !mScreenOnEarly || !mWindowManagerDrawComplete
- || (mAwake && !mKeyguardDrawComplete)) {
- return; // spurious or not ready yet
- }
-
- listener = mScreenOnListener;
- mScreenOnListener = null;
- mScreenOnFully = true;
- ......
- }
-
- if (listener != null) {
- listener.onScreenOn();
- }
-
- if (enableScreen) {
- try {
- mWindowManager.enableScreenIfNeeded();
- } catch (RemoteException unhandled) {
- }
- }
- }
我們先分析下WMS的enableScreenIfNeeded函數,然後再看DisplayPowerControl的回調onScreenOn函數。
WMS的enableScreenIfNeeded函數
WMS的enableScreenIfNeeded函數就是調用了enableScreenIfNeededLocked函數
- @Override
- public void enableScreenIfNeeded() {
- synchronized (mWindowMap) {
- enableScreenIfNeededLocked();
- }
- }
enableScreenIfNeededLocked這個函數僅僅是保證mDisplayEnabled爲true,如果爲true直接結束。
- void enableScreenIfNeededLocked() {
- if (mDisplayEnabled) {
- return;
- }
- if (!mSystemBooted && !mShowingBootMessages) {
- return;
- }
- mH.sendEmptyMessage(H.ENABLE_SCREEN);
- }
mDisplayEnabled不爲true,發送ENABLE_SCREEN消息
- case ENABLE_SCREEN: {
- performEnableScreen();
- break;
performEnableScreen函數會讓SurfaceFlinger去停止開機動畫等,也會把mDisplayEnabled置爲true。當然performEnableScreen在開機的時候會AMS中調用WMS的enableScreenAfterBoot函數來調用performEnableScreen函數。這個我們在博客http://blog.csdn.net/kc58236582/article/details/52921978分析過了。
- public void performEnableScreen() {
- synchronized(mWindowMap) {
- if (mDisplayEnabled) {
- return;
- }
- if (!mSystemBooted && !mShowingBootMessages) {
- return;
- }
-
- // Don't enable the screen until all existing windows have been drawn.
- if (!mForceDisplayEnabled && checkWaitingForWindowsLocked()) {
- return;
- }
-
- if (!mBootAnimationStopped) {
- // Do this one time.
- try {//停止開機動畫
- IBinder surfaceFlinger = ServiceManager.getService("SurfaceFlinger");
- if (surfaceFlinger != null) {
- //Slog.i(TAG, "******* TELLING SURFACE FLINGER WE ARE BOOTED!");
- Parcel data = Parcel.obtain();
- data.writeInterfaceToken("android.ui.ISurfaceComposer");
- surfaceFlinger.transact(IBinder.FIRST_CALL_TRANSACTION, // BOOT_FINISHED
- data, null, 0);
- data.recycle();
- }
- } catch (RemoteException ex) {
- Slog.e(TAG, "Boot completed: SurfaceFlinger is dead!");
- }
- mBootAnimationStopped = true;
- }
-
- if (!mForceDisplayEnabled && !checkBootAnimationCompleteLocked()) {
- if (DEBUG_BOOT) Slog.i(TAG, "performEnableScreen: Waiting for anim complete");
- return;
- }
-
- mDisplayEnabled = true;//置爲true
- if (DEBUG_SCREEN_ON || DEBUG_BOOT) Slog.i(TAG, "******************** ENABLING SCREEN!");
-
- // Enable input dispatch.
- mInputMonitor.setEventDispatchingLw(mEventDispatchingEnabled);
- }
-
- try {
- mActivityManager.bootAnimationComplete();
- } catch (RemoteException e) {
- }
-
- mPolicy.enableScreenAfterBoot();
-
- // Make sure the last requested orientation has been applied.
- updateRotationUnchecked(false, false);
- }
窗口繪製完成後調用DisplayPowerControl中的回調
當WMS窗口繪製完成後,會在PhoneWindowManager中的finishScreenTurningOn函數調用DisplayPowerControl的回調函數。最後我們再來看看DisplayPowerControl中的回調的onScreenOn函數。只是發送了一個MSG_SCREEN_ON_UNBLOCKED消息。
- private final class ScreenOnUnblocker implements WindowManagerPolicy.ScreenOnListener {
- @Override
- public void onScreenOn() {
- Message msg = mHandler.obtainMessage(MSG_SCREEN_ON_UNBLOCKED, this);
- msg.setAsynchronous(true);
- mHandler.sendMessage(msg);
- }
- }
MSG_SCREEN_ON_UNBLOCKED的處理先是調用了unblockScreenOn函數,然後再調用updatePowerState更新狀態。
- case MSG_SCREEN_ON_UNBLOCKED:
- if (mPendingScreenOnUnblocker == msg.obj) {
- unblockScreenOn();
- updatePowerState();
- }
- break;
unblockScreenOn函數,只是打印下從調用screenTurningOn開始,到窗口繪製完成在PhoneWindowManager中回調這個函數的時間差打印。
- private void unblockScreenOn() {
- if (mPendingScreenOnUnblocker != null) {
- mPendingScreenOnUnblocker = null;
- long delay = SystemClock.elapsedRealtime() - mScreenOnBlockStartRealTime;
- Slog.i(TAG, "Unblocked screen on after " + delay + " ms");
- Trace.asyncTraceEnd(Trace.TRACE_TAG_POWER, SCREEN_ON_BLOCKED_TRACE_NAME, 0);
- }
- }