PowerManager学习笔记-Power键亮屏流程

4,735 阅读13分钟

本文基于Android S源码进行梳理。

学习目标

结合AOSP源码了解按下Power键后亮屏的系统流程。

系列回顾

PowerManager学习笔记-Power键灭屏流程

PowerManager学习笔记-超时灭屏流程

Power键亮屏简介

简要概括一下Power键亮屏的流程,当用户按下power键后,InputReader从EventHub中读取到事件,交由InputDispatcher进行分发,通知PhoneWindowManager对此事件进行处理,PhoneWindowManager处理后,通知PowerManagerService进行wakeUp处理,随后PowerManagerService在内部更新wakefulness并发出亮屏广播之后,再通知DisplayPowerController进行亮屏状态更新,在此期间DisplayPowerController会根据Window绘制状态进行阻塞亮屏,待绘制完毕后,进行亮屏动画和设置屏幕亮度的操作。

下面是整个Power键亮屏的时序图:

TODO:这里可能还缺一张类图,以后补上^_^。

到这里,如果只是对Power键亮屏流程了解一下的同学,可以不用往下看了,下面就是具体业务中重要环节的详细介绍。

业务梳理

相关类

  • frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java
  • frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
  • frameworks/base/services/core/java/com/android/server/power/Notifier.java
  • frameworks/base/services/core/java/com/android/server/display/DisplayPowerController.java
  • frameworks/base/services/core/java/com/android/server/display/RampAnimator.java
  • frameworks/base/services/core/java/com/android/server/display/ColorFade.java
  • frameworks/base/services/core/java/com/android/server/display/DisplayPowerState.java
  • frameworks/base/services/core/java/com/android/server/display/DisplayManagerService.java
  • frameworks/base/services/core/java/com/android/server/display/LocalDisplayAdapter.java
  • frameworks/base/services/core/java/com/android/server/lights/LightsService.java

部分类名解释与缩写

类名作用缩写
PowerManagerServicePower状态管理PMS
DisplayPowerController管理设备Display状态,主要处理近距sensor,亮灭屏DPC
NotifierPower侧用于通知其他系统模块
RampAnimatorDisplay侧亮度动画
ColorFade高端机器用于亮灭屏的蒙层

1. Power键事件处理

本章所讲的就是Power键按下亮屏的流程,对系统有一定了解的同学肯定知晓,按下power键后,kernel会将此事件进行中断,InputReader从EventHub中读取到事件后,InputDispatcher会callback给PhoneWindowManager,callback方法是interceptKeyBeforeQueueing:

frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java

// TODO(b/117479243): handle it in InputPolicy
 /** {  @inheritDoc } */
@Override
public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
    ...
     // 处理长按、连击事件, 灭屏流程
    if ((event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
        handleKeyGesture(event, interactiveAndOn);
    }
    ...
    // Handle special keys.
    switch (keyCode) {
        ...
         // 处理Power键 down和up事件
        case KeyEvent.KEYCODE_POWER: {
            EventLogTags.writeInterceptPower(
                    KeyEvent.actionToString(event.getAction()),
                    mPowerKeyHandled ? 1 : 0,
                    mSingleKeyGestureDetector.getKeyPressCounter(KeyEvent.KEYCODE_POWER));
            // Any activity on the power button stops the accessibility shortcut
            result &= ~ACTION_PASS_TO_USER;
            isWakeKey = false; // wake-up will be handled separately
            if (down) {
                interceptPowerKeyDown(event, interactiveAndOn);
            } else {
                interceptPowerKeyUp(event, canceled);
            }
            break;
        }
    ...
}

按下power键,其实是分为down和up事件,而亮屏流程触发再其down事件处理方法中:

frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java

private void interceptPowerKeyDown(KeyEvent event, boolean interactive) {
    // 获取一个wakelock,防止cpu在此流程期间休眠
    // Hold a wake lock until the power key is released.
    if (!mPowerKeyWakeLock.isHeld()) {
        mPowerKeyWakeLock.acquire();
    }
    mWindowManagerFuncs.onPowerKeyDown(interactive);
    // 对于来电场景下,按下power键的处理
    // Stop ringing or end call if configured to do so when power is pressed.
    TelecomManager telecomManager = getTelecommService();
    boolean hungUp = false;
    if (telecomManager != null) {
        if (telecomManager.isRinging()) {
            // Pressing Power while there's a ringing incoming
            // call should silence the ringer.
            telecomManager.silenceRinger();
        } else if ((mIncallPowerBehavior
                & Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP) != 0
                && telecomManager.isInCall() && interactive) {
            // Otherwise, if "Power button ends call" is enabled,
            // the Power button will hang up any current active call.
            hungUp = telecomManager.endCall();
        }
    }
    ...

    // If the power key has still not yet been handled, then detect short
    // press, long press, or multi press and decide what to do.
    mPowerKeyHandled = mPowerKeyHandled || hungUp
            || handledByPowerManager || mKeyCombinationManager.isPowerKeyIntercepted();
    if (!mPowerKeyHandled) {
        if (!interactive) {
             // wake up start
            wakeUpFromPowerKey(event.getDownTime());
        }
    } else {
        // handled by another power key policy.
        if (!mSingleKeyGestureDetector.isKeyIntercepted(KEYCODE_POWER)) {
            mSingleKeyGestureDetector.reset();
        }
    }
}

private void wakeUpFromPowerKey(long eventTime) {
    ...
    if (wakeUp(eventTime, mAllowTheaterModeWakeFromPowerKey,
            PowerManager.WAKE_REASON_POWER_BUTTON, "android.policy:POWER")) {
        // Start HOME with "reason" extra if sleeping for more than mWakeUpToLastStateTimeout
        if (shouldWakeUpWithHomeIntent()) {
            startDockOrHome(DEFAULT_DISPLAY, /*fromHomeKey*/ false, /*wakenFromDreams*/ true,
                    PowerManager.wakeReasonToString(PowerManager.WAKE_REASON_POWER_BUTTON));
        }
    }
}

private boolean wakeUp(long wakeTime, boolean wakeInTheaterMode, @WakeReason int reason,
        String details) {
    ...
     // call powermanagerservice wakeup
    mPowerManager.wakeUp(wakeTime, reason, details);
    return true;
}

总结一下down事件的业务流程,当收到KEYCODE_POWER之后,在其down事件中,首先判断是否持有mPowerKeyWakeLock,如果没有的话就申请一个wakelock,这样可以防止在此业务期间,CPU进入休眠,通过一系列的条件判断,调用PowerManager的wakeUp接口。

而up事件就相对简单,主要是收尾工作和释放wakelock:

private void interceptPowerKeyUp(KeyEvent event, boolean canceled) {
    final boolean handled = canceled || mPowerKeyHandled;
    if (!handled) {
        if ((event.getFlags() & KeyEvent.FLAG_LONG_PRESS) == 0) {
            // Abort possibly stuck animations only when power key up without long press case.
            mHandler.post(mWindowManagerFuncs::triggerAnimationFailsafe);
        }
    } else {
        // handled by single key or another power key policy.
        if (!mSingleKeyGestureDetector.isKeyIntercepted(KEYCODE_POWER)) {
            mSingleKeyGestureDetector.reset();
        }
    }
    finishPowerKeyPress();
}

private void finishPowerKeyPress() {
    mPowerKeyHandled = false;
    if (mPowerKeyWakeLock.isHeld()) {
        mPowerKeyWakeLock.release();
    }
}

2. PMS侧处理

本节中主要介绍PMS侧处理,梳理在PMS中如何处理亮屏请求,如何通知DPC处理亮屏请求。

2.1 wakeUp

上一节中,最后PhoneWindowManager通过PowerManager接口wakeUp方法调用,通知PowerManager模块执行亮屏动作,这里最终响应是在PowerManagerService中的wakeUp方法:

frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java

@Override // Binder call
public void wakeUp(long eventTime, @WakeReason int reason, String details,
        String opPackageName) {
    if (eventTime > mClock.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 {
        wakeDisplayGroup(Display.DEFAULT_DISPLAY_GROUP, eventTime, reason, details, uid,
                opPackageName, uid);
    } finally {
        Binder.restoreCallingIdentity(ident);
    }
}

这里重点说下以下两点:

1. reason参数

可以看到此函数中有一个reason参数,PMS定义了若干种reason:

WAKE_REASON_UNKNOWN // 未知原因
WAKE_REASON_POWER_BUTTON // 按power键唤醒
WAKE_REASON_APPLICATION // 应用唤醒
WAKE_REASON_PLUGGED_IN // 插入唤醒
WAKE_REASON_GESTURE // 手势唤醒
WAKE_REASON_CAMERA_LAUNCH // 相机启动
WAKE_REASON_WAKE_KEY // 唤醒键
WAKE_REASON_WAKE_MOTION // 唤醒操作触发
WAKE_REASON_HDMI // HDMI唤醒
WAKE_REASON_DISPLAY_GROUP_ADDED // 其他Display区域增加
WAKE_REASON_DISPLAY_GROUP_TURNED_ON // 其他Display区域点亮

2. R和S变化

在R上,PMS的wakeUp中是wakeUpInternal,而在S上变更成wakeDisplayGroup,具体的变化是增加了参数DisplayGroupId,这个是为了增加对多屏设备亮屏的处理。

2.2 wakeDisplayGroup

在wakeUp中,PMS调用了内部方法wakeDisplayGroup:

frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java

private void wakeDisplayGroup(int groupId, long eventTime, @WakeReason int reason,
        String details, int uid, String opPackageName, int opUid) {
    synchronized (mLock) {
         // 判断是否可以进行亮屏,设置Wakefulness以及相关参数,发送亮屏广播
        if (wakeDisplayGroupNoUpdateLocked(groupId, eventTime, reason, details, uid,
                opPackageName, opUid)) {
             // 更新PMS中状态参数,通知DPC处理亮屏操作
            updatePowerStateLocked();
        }
    }
}

这里面有两个非常重要的方法:wakeDisplayGroupNoUpdateLockedupdatePowerStateLocked

2.3 亮屏广播

"android.intent.action.SCREEN_ON"这个很多开发者肯定不会陌生,这个是在屏幕即将点亮的时候发出的广播,整个亮屏广播的发送时序图如下:

2.3.1 wakeDisplayGroupNoUpdateLocked

此函数主要作用就是判断当前是否具备亮屏的条件,设置Wakefulness以及相关参数:

frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java

private boolean wakeDisplayGroupNoUpdateLocked(int groupId, long eventTime,
        @WakeReason int reason, String details, int uid, String opPackageName, int opUid) {
    ...
     // 判断触发时间是否正确,系统是否挂起或者是否还在开机状态
    if (eventTime < mLastSleepTime || mForceSuspendActive || !mSystemReady) {
        return false;
    }
    ...
     // 根据Wakefulness,判断是否已亮屏
    final int currentState = mDisplayGroupPowerStateMapper.getWakefulnessLocked(groupId);
    if (currentState == WAKEFULNESS_AWAKE) {
         // 对非系统启动完毕场景进行特殊处理
        if (!mBootCompleted && sQuiescent) {
            mDirty |= DIRTY_QUIESCENT;
            return true;
        }
        return false;
    }
    ...
    try {
        Slog.i(TAG, "Powering on display group from"
                + PowerManagerInternal.wakefulnessToString(currentState)
                + " (groupId=" + groupId
                + ", uid=" + uid
                + ", reason=" + PowerManager.wakeReasonToString(reason)
                + ", details=" + details
                + ")...");
        Trace.asyncTraceBegin(Trace.TRACE_TAG_POWER, TRACE_SCREEN_ON, groupId);
         // 设置Wakefulness
        setWakefulnessLocked(groupId, WAKEFULNESS_AWAKE, eventTime, uid, reason, opUid,
                opPackageName, details);
         // 设置亮屏时间和状态到mDisplayGroupPowerStateMapper,DisplayGroupPowerStateMapper是S新增解决多屏Power管理的方案
        mDisplayGroupPowerStateMapper.setLastPowerOnTimeLocked(groupId, eventTime);
        mDisplayGroupPowerStateMapper.setPoweringOnLocked(groupId, true);
    } finally {
        Trace.traceEnd(Trace.TRACE_TAG_POWER);
    }

    return true;
}

此函数中有一个很重要的变量Wakefulness,PMS定义了四种状态:

WAKEFULNESS_ASLEEP //灭屏
WAKEFULNESS_AWAKE  //亮屏
WAKEFULNESS_DREAMING //屏保
WAKEFULNESS_DOZING //doze模式

2.3.2 setWakefulnessLocked

frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java

@VisibleForTesting
void setWakefulnessLocked(int groupId, int wakefulness, long eventTime, int uid, int reason,
        int opUid, String opPackageName, String details) {
    if (mDisplayGroupPowerStateMapper.setWakefulnessLocked(groupId, wakefulness)) {
        // 引入mDirty参数,用于判断当前Power State是否发生变化
        mDirty |= DIRTY_DISPLAY_GROUP_WAKEFULNESS;
         // 设置全局参数状态,并对亮屏工作进行准备
        setGlobalWakefulnessLocked(mDisplayGroupPowerStateMapper.getGlobalWakefulnessLocked(),
                eventTime, reason, uid, opUid, opPackageName, details);
        if (wakefulness == WAKEFULNESS_AWAKE) {
            // Kick user activity to prevent newly awake group from timing out instantly.
            userActivityNoUpdateLocked(
                    groupId, eventTime, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, uid);
        }
    }
}

此函数中最重要的就是参数mDirty,这个是PMS中一个非常重要的标志位,通过对它的位运算,可以知晓当前power状态是否发生变化,根据变化的位置可以进行对应的业务操作。

PMS中定义了以下DirtyState:

// Dirty bit: mWakeLocks changed
private static final int DIRTY_WAKE_LOCKS = 1 << 0;
// Dirty bit: mWakefulness changed
private static final int DIRTY_WAKEFULNESS = 1 << 1;
// Dirty bit: user activity was poked or may have timed out
private static final int DIRTY_USER_ACTIVITY = 1 << 2;
// Dirty bit: actual display power state was updated asynchronously
private static final int DIRTY_ACTUAL_DISPLAY_POWER_STATE_UPDATED = 1 << 3;
// Dirty bit: mBootCompleted changed
private static final int DIRTY_BOOT_COMPLETED = 1 << 4;
// Dirty bit: settings changed
private static final int DIRTY_SETTINGS = 1 << 5;
// Dirty bit: mIsPowered changed
private static final int DIRTY_IS_POWERED = 1 << 6;
// Dirty bit: mStayOn changed
private static final int DIRTY_STAY_ON = 1 << 7;
// Dirty bit: battery state changed
private static final int DIRTY_BATTERY_STATE = 1 << 8;
// Dirty bit: proximity state changed
private static final int DIRTY_PROXIMITY_POSITIVE = 1 << 9;
// Dirty bit: dock state changed
private static final int DIRTY_DOCK_STATE = 1 << 10;
// Dirty bit: brightness boost changed
private static final int DIRTY_SCREEN_BRIGHTNESS_BOOST = 1 << 11;
// Dirty bit: sQuiescent changed
private static final int DIRTY_QUIESCENT = 1 << 12;
// Dirty bit: VR Mode enabled changed
private static final int DIRTY_VR_MODE_CHANGED = 1 << 13;
// Dirty bit: attentive timer may have timed out
private static final int DIRTY_ATTENTIVE = 1 << 14;
// Dirty bit: display group wakefulness has changed
private static final int DIRTY_DISPLAY_GROUP_WAKEFULNESS = 1 << 16;

2.3.3 setGlobalWakefulnessLocked

frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java

private void setGlobalWakefulnessLocked(int wakefulness, long eventTime, int reason, int uid,
        int opUid, String opPackageName, String details) {
        ...
         // 通知系统中其他模块Wakefulness开始变化,发送亮屏广播
        if (mNotifier != null) {
            mNotifier.onWakefulnessChangeStarted(wakefulness, reason, eventTime);
        }
        ...
}

在这个方法中,用到了PMS中另外一个重要的成员变量mNotifier,其主要功能就是告知系统其他核心服务或者模块,当前Power State。

2.3.4 Notifier.onWakefulnessChangeStarted

frameworks/base/services/core/java/com/android/server/power/Notifier.java

 /**
 * Notifies that the device is changing wakefulness.
 * This function may be called even if the previous change hasn't finished in
 * which case it will assume that the state did not fully converge before the
 * next transition began and will recover accordingly.
 */
public void onWakefulnessChangeStarted(final int wakefulness, int reason, long eventTime) {
    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.
    // 通知AMS Wakefulness 变化
    mHandler.post(new Runnable() {
        @Override
        public void run() {
            mActivityManagerInternal.onWakefulnessChanged(wakefulness);
        }
    });
    ...
        // 触发广播消息发送
        handleEarlyInteractiveChange();
    }
}

 /**
 * Handle early interactive state changes such as getting applications or the lock
 * screen running and ready for the user to see (such as when turning on the screen).
 */
private void handleEarlyInteractiveChange() {
    synchronized (mLock) {
        if (mInteractive) {
            // Waking up...
             // 通知WMS正在亮屏
            mHandler.post(() -> mPolicy.startedWakingUp(mInteractiveChangeReason));

            // Send interactive broadcast.
            mPendingInteractiveState = INTERACTIVE_STATE_AWAKE;
            mPendingWakeUpBroadcast = true;
             // 发送广播
            updatePendingBroadcastLocked();
        } else {
            // Going to sleep...
            // Tell the policy that we started going to sleep.
            mHandler.post(() -> mPolicy.startedGoingToSleep(mInteractiveChangeReason));
        }
    }
}

private void updatePendingBroadcastLocked() {

    if (!mBroadcastInProgress
            && mPendingInteractiveState != INTERACTIVE_STATE_UNKNOWN
 && (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast
                    || mPendingInteractiveState != mBroadcastedInteractiveState)) {
        mBroadcastInProgress = true;
         // 为了避免发送广播的时候,为了避免CPU还在休眠,申请SuspendBlocker
        mSuspendBlocker.acquire();
        Message msg = mHandler.obtainMessage(MSG_BROADCAST);
        msg.setAsynchronous(true);
        mHandler.sendMessage(msg);
    }
}

这里最后通过消息机制触发了亮屏广播的发送,由于业务单一,这里就不贴代码了。

3. DPC侧处理

3.1 PMS.updatePowerStateLocked

上一节中,在PMS. wakeDisplayGroup执行完wakeDisplayGroupNoUpdateLocked之后,在updatePowerStateLocked中进行DPC侧业务处理的发起:

frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java

 /**
 * Updates the global power state based on dirty bits recorded in mDirty.
 *
 * This is the main function that performs power state transitions.
 * We centralize them here so that we can recompute the power state completely
 * each time something important changes, and ensure that we do it the same
 * way each time.  The point is to gather all of the transition logic here.
 */
private void updatePowerStateLocked() {
        ...
        // Phase 3: Update display power state.
        final boolean displayBecameReady = updateDisplayPowerStateLocked(dirtyPhase2);
        ...
}



 /**
 * Updates the display power state asynchronously.
 * When the update is finished, the ready state of the displays will be updated.  The display
 * controllers post a message to tell us when the actual display power state
 * has been updated so we come back here to double-check and finish up.
 *
 * This function recalculates the display power state each time.
 *
 *  @return {  @code true} if all displays became ready; {  @code false} otherwise
 */
private boolean updateDisplayPowerStateLocked(int dirty) {
   ...
   final boolean ready = mDisplayManagerInternal.requestPowerState(groupId,
        displayPowerRequest, mRequestWaitForNegativeProximity);
   ...
}

这里最后调用了mDisplayManagerInternal的requestPowerState方法,DisplayManagerInternal是一个抽象类,其具体实现的类是DisplayManagerService,在其重写的方法中发起了对DPC的调用。感兴趣的可以去看下源码,这里就不贴了。

3.2 阻塞亮屏

在DPC中,最主要的一个业务就是进行亮屏前的最后准备,为什么说是亮屏前呢?因为里面有一个非常重要的环节就是阻塞亮屏,试想如果直接点亮屏幕,可能会出现什么情况,首先可能出现窗口还没有绘制,用户会观看到整个窗口绘制的过程,或者锁屏没有绘制,这样用户体验很差,所以在点亮屏幕前,我们需要进行一个阻塞亮屏的流程。

frameworks/base/services/core/java/com/android/server/display/DisplayPowerController.java

/**
 * Requests a new power state.
 * The controller makes a copy of the provided object and then
 * begins adjusting the power state to match what was requested.
 *
 *  @param request The requested power state.
 *  @param waitForNegativeProximity If true, issues a request to wait for
 * negative proximity before turning the screen back on, assuming the screen
 * was turned off by the proximity sensor.
 *  @return True if display is ready, false if there are important changes that must
 * be made asynchronously (such as turning the screen on), in which case the caller
 * should grab a wake lock, watch for {  @link DisplayPowerCallbacks#onStateChanged()}
 * then try the request again later until the state converges.
 */
public boolean requestPowerState(DisplayPowerRequest request,
        boolean waitForNegativeProximity) {
    ...
        if (changed) {
            mDisplayReadyLocked = false;
            if (!mPendingRequestChangedLocked) {
                mPendingRequestChangedLocked = true;
                sendUpdatePowerStateLocked();
            }
        }
        return mDisplayReadyLocked;
    }
}

private void sendUpdatePowerStateLocked() {
    if (!mStopped && !mPendingUpdatePowerStateLocked) {
        mPendingUpdatePowerStateLocked = true;
        // 发送MSG_UPDATE_POWER_STATE
        Message msg = mHandler.obtainMessage(MSG_UPDATE_POWER_STATE);
        mHandler.sendMessage(msg);
    }
}

private void updatePowerState() {
    ...
    // Animate the screen state change unless already animating.
    // The transition may be deferred, so after this point we will use the
    // actual state instead of the desired one.
    final int oldState = mPowerState.getScreenState();

    // 准备执行屏幕变化动画,这里也可以认为是发起亮屏动画
    animateScreenStateChange(state, performScreenOffTransition);
    state = mPowerState.getScreenState();
}

private void animateScreenStateChange(int target, boolean performScreenOffTransition) {
    ...
    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.
        // 阻塞亮屏,如果当前不满足亮屏,那么直接return
        if (!setScreenState(Display.STATE_ON)) {
            return; // screen on blocked
        }

        if (USE_COLOR_FADE_ON_ANIMATION && mColorFadeEnabled && 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();
        }
    }
    ...
}

从最后animateScreenStateChange可以看到,如果setScreenState不满足要求的话,就会直接return,这并不是表示流程结束了,而是阻塞亮屏的开始:

frameworks/base/services/core/java/com/android/server/display/DisplayPowerController.java

private boolean setScreenState(int state, boolean reportOnly) {
    ...
    if (!isOff
            && (mReportedScreenStateToPolicy == REPORTED_TO_POLICY_SCREEN_OFF
 || mReportedScreenStateToPolicy == REPORTED_TO_POLICY_UNREPORTED)) {
        setReportedScreenState(REPORTED_TO_POLICY_SCREEN_TURNING_ON);
        if (mPowerState.getColorFadeLevel() == 0.0f) {
            // 阻塞亮屏
            blockScreenOn();
        } else {
            unblockScreenOn();
        }

        // 向PhoneWindowManager传入mPendingScreenOnUnblocker
        mWindowManagerPolicy.screenTurningOn(mDisplayId, mPendingScreenOnUnblocker);
    }
    ...
}

private void blockScreenOn() {
    if (mPendingScreenOnUnblocker == null) {
        Trace.asyncTraceBegin(Trace.TRACE_TAG_POWER, SCREEN_ON_BLOCKED_TRACE_NAME, 0);
        mPendingScreenOnUnblocker = new ScreenOnUnblocker();
        mScreenOnBlockStartRealTime = SystemClock.elapsedRealtime();
        Slog.i(TAG, "Blocking screen on until initial contents have been drawn.");
    }
}

private final class ScreenOnUnblocker implements WindowManagerPolicy.ScreenOnListener {
    @Override
    public void onScreenOn() {
        Message msg = mHandler.obtainMessage(MSG_SCREEN_ON_UNBLOCKED, this);
        mHandler.sendMessage(msg);
    }
}

可以看到,在blockScreenOn中,创建了一个ScreenUnblocker的实例mPendingScreenOnUnblocker,并通过WindowManagerPolicy传给了PhoneWindowMangaer:

frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java

// Called on the DisplayManager's DisplayPowerController thread.
@Override
public void screenTurningOn(int displayId, final ScreenOnListener screenOnListener) {
    if (DEBUG_WAKEUP) Slog.i(TAG, "Display " + displayId + " turning on...");

    if (displayId == DEFAULT_DISPLAY) {
        Trace.asyncTraceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "screenTurningOn",
                0 /* cookie */);
        updateScreenOffSleepToken(false);
        mDefaultDisplayPolicy.screenTurnedOn(screenOnListener);
        mBootAnimationDismissable = false;

        synchronized (mLock) {
            if (mKeyguardDelegate != null && mKeyguardDelegate.hasKeyguard()) {
                mHandler.removeMessages(MSG_KEYGUARD_DRAWN_TIMEOUT);
                // 发送消息,通知锁屏绘制完毕
                mHandler.sendEmptyMessageDelayed(MSG_KEYGUARD_DRAWN_TIMEOUT,
                        getKeyguardDrawnTimeout());
                mKeyguardDelegate.onScreenTurningOn(mKeyguardDrawnCallback);
            } else {
                if (DEBUG_WAKEUP) Slog.d(TAG,
                        "null mKeyguardDelegate: setting mKeyguardDrawComplete.");
                mHandler.sendEmptyMessage(MSG_KEYGUARD_DRAWN_COMPLETE);
            }
        }
    } else {
        mScreenOnListeners.put(displayId, screenOnListener);
        mWindowManagerInternal.waitForAllWindowsDrawn(() -> {
            if (DEBUG_WAKEUP) Slog.i(TAG, "All windows ready for display: " + displayId);
            mHandler.sendMessage(mHandler.obtainMessage(MSG_WINDOW_MANAGER_DRAWN_COMPLETE,
                    displayId, 0));
        }, WAITING_FOR_DRAWN_TIMEOUT, displayId);
    }
}

正常在Keyguard绘制完毕后,PhoneWindowManager会调用onScreenOn callback通知到DPC。当DPC中收到onScreenOn,会发送消息进行unblock,消息中就执行了两个函数unblockScreenOn和updatePowerState:

frameworks/base/services/core/java/com/android/server/display/DisplayPowerController.java

private void unblockScreenOn() {
    if (mPendingScreenOnUnblocker != null) {
        // 这里将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);
    }
}

然后又再次执行了updatePowerState-animateScreenStateChange-setScreenState,在setScreenState中最后因为mPendingScreenOnUnblocker = null,所以返回了true,这样animateScreenStateChange就可以继续执行下去,阻塞亮屏的流程也就全部执行完毕了。

3.3 亮屏动画

在上一节最后提到,当阻塞亮屏流程结束,那么原本DPC中animateScreenStateChange就可以继续执行下去了:

frameworks/base/services/core/java/com/android/server/display/DisplayPowerController.java

private void animateScreenStateChange(int target, boolean performScreenOffTransition) {
    ...
    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 && mColorFadeEnabled && 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();
        }
    } 
    ...
}

这里有个对象ColorFade,这是什么呢?在高端的机器上,为了让用户亮灭屏体验更加,有一个蒙层会在亮灭屏的时候,盖在最上面,通过设置其alpha值,可以实现亮灭屏的时候的渐变动效。

在DPC.updatePowerState中完成阻塞亮屏,并执行ColorFade的渐变动效后,就到了亮屏的最后一个环节,设置屏幕的亮度,在updatePowerState中最后调用了animateScreenBrightness:

frameworks/base/services/core/java/com/android/server/display/DisplayPowerController.java

private void animateScreenBrightness(float target, float sdrTarget, float rate) {
    if (DEBUG) {
        Slog.d(TAG, "Animating brightness: target=" + target + ", sdrTarget=" + sdrTarget
                + ", rate=" + rate);
    }

    if (mScreenBrightnessRampAnimator.animateTo(target, sdrTarget, rate)) {
        Trace.traceCounter(Trace.TRACE_TAG_POWER, "TargetScreenBrightness", (int) target);
        // TODO(b/153319140) remove when we can get this from the above trace invocation
        SystemProperties.set("debug.tracing.screen_brightness", String.valueOf(target));
        noteScreenBrightness(target);
    }
}

通过mScreenBrightnessRampAnimator进行一个亮度动画,mScreenBrightnessRampAnimator是由DualRampAnimator实例化的,在DPC初始化的时候创建:

frameworks/base/services/core/java/com/android/server/display/DisplayPowerController.java

private void initialize(int displayState) {
    ...
    mScreenBrightnessRampAnimator = new DualRampAnimator<>(mPowerState,
            DisplayPowerState.SCREEN_BRIGHTNESS_FLOAT,
            DisplayPowerState.SCREEN_SDR_BRIGHTNESS_FLOAT);
    mScreenBrightnessRampAnimator.setListener(mRampAnimatorListener);
    ...
}

这里有两个很重要的参数:DisplayPowerState.SCREEN_BRIGHTNESS_FLOAT, DisplayPowerState.SCREEN_SDR_BRIGHTNESS_FLOAT。这是两个参数中,会通过其setValue的方法设置亮度。这里就从mScreenBrightnessRampAnimator的animateTo为入口来进一步分析:

frameworks/base/services/core/java/com/android/server/display/RampAnimator.java

 /**
 * Starts animating towards the specified values.
 *
 * If this is the first time the property is being set or if the rate is 0,
 * the value jumps directly to the target.
 *
 *  @param firstTarget The first target value.
 *  @param secondTarget The second target value.
 *  @param rate The convergence rate in units per second, or 0 to set the value immediately.
 *  @return True if either target differs from the previous target.
 */

public boolean animateTo(float firstTarget, float secondTarget, float rate) {
    final boolean firstRetval = mFirst.animateTo(firstTarget, rate);
    final boolean secondRetval = mSecond.animateTo(secondTarget, rate);
    return firstRetval && secondRetval;
}

 /**
 * Starts animating towards the specified value.
 *
 * If this is the first time the property is being set or if the rate is 0,
 * the value jumps directly to the target.
 *
 *  @param target The target value.
 *  @param rate The convergence rate in units per second, or 0 to set the value immediately.
 *  @return True if the target differs from the previous target.
 */

public boolean animateTo(float target, float rate) {
    // Immediately jump to the target the first time.
    if (mFirstTime || rate <= 0) {
        if (mFirstTime || target != mCurrentValue) {

            mFirstTime = false;
            mRate = 0;
            mTargetValue = target;
            mCurrentValue = target;
            mProperty.setValue(mObject, target);
            
            if (mAnimating) {
                mAnimating = false;
                cancelAnimationCallback();
            }

            if (mListener != null) {
                mListener.onAnimationEnd();
            }
            return true;
        }
        return false;
    }

    // Adjust the rate based on the closest target.
    // If a faster rate is specified, then use the new rate so that we converge
    // more rapidly based on the new request.
    // If a slower rate is specified, then use the new rate only if the current
    // value is somewhere in between the new and the old target meaning that
    // we will be ramping in a different direction to get there.
    // Otherwise, continue at the previous rate.
    if (!mAnimating
            || rate > mRate
            || (target <= mCurrentValue && mCurrentValue <= mTargetValue)
            || (mTargetValue <= mCurrentValue && mCurrentValue <= target)) {
        mRate = rate;
    }

    final boolean changed = (mTargetValue != target);
    mTargetValue = target;

    // Start animating.
    if (!mAnimating && target != mCurrentValue) {
        mAnimating = true;
        mAnimatedValue = mCurrentValue;
        mLastFrameTimeNanos = System.nanoTime();
        postAnimationCallback();
    }

    return changed;
}

这里的mFirst和mSecond就是前面提到的DisplayPowerState.SCREEN_BRIGHTNESS_FLOAT, DisplayPowerState.SCREEN_SDR_BRIGHTNESS_FLOAT。根据代码中注释来看,最终调用了postAnimationCallback:

frameworks/base/services/core/java/com/android/server/display/RampAnimator.java

private void postAnimationCallback() {
    mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, mAnimationCallback, null);

}

private final Runnable mAnimationCallback = new Runnable() {
    @Override // Choreographer callback
    public void run() {

        final long frameTimeNanos = mChoreographer.getFrameTimeNanos();
        final float timeDelta = (frameTimeNanos - mLastFrameTimeNanos)
                * 0.000000001f;

        mLastFrameTimeNanos = frameTimeNanos;

        // Advance the animated value towards the target at the specified rate
        // and clamp to the target. This gives us the new current value but
        // we keep the animated value around to allow for fractional increments
        // towards the target.
        final float scale = ValueAnimator.getDurationScale();

        if (scale == 0) {
            // Animation off.
            mAnimatedValue = mTargetValue;

        } else {
            final float amount = timeDelta * mRate / scale;
            if (mTargetValue > mCurrentValue) {
                mAnimatedValue = Math.min(mAnimatedValue + amount, mTargetValue);
            } else {
                mAnimatedValue = Math.max(mAnimatedValue - amount, mTargetValue);
            }
        }

        final float oldCurrentValue = mCurrentValue;
        mCurrentValue = mAnimatedValue;

        // 判断是否满足亮度,如果不满足再次设置亮度,直到满足位置
        if (oldCurrentValue != mCurrentValue) {
            mProperty.setValue(mObject, mCurrentValue);
        }

        if (mTargetValue != mCurrentValue) {
            postAnimationCallback();
        } else {
            mAnimating = false;
            if (mListener != null) {
                mListener.onAnimationEnd();
            }
        }
    }
};

这一段,最终在mScreenUpdateRunnable中结束,这里引入了mPhotonicModulator,这个是在DisplayPowerState的一个内部类,其继承于Thread,那么不用深思,具体实现肯定在其的run方法中:

frameworks/base/services/core/java/com/android/server/display/DisplayPowerState.java 

 /**
 * Updates the state of the screen and backlight asynchronously on a separate thread.
 */
 
private final class PhotonicModulator extends Thread {
    ...

    public boolean setState(int state, float brightnessState, float sdrBrightnessState) {
        synchronized (mLock) {
            ...
                boolean changeInProgress = mStateChangeInProgress || mBacklightChangeInProgress;
                mStateChangeInProgress = stateChanged || mStateChangeInProgress;
                mBacklightChangeInProgress = backlightChanged || mBacklightChangeInProgress;

                // 唤醒wait
                if (!changeInProgress) {
                    mLock.notifyAll();
                }
            }
            return !mStateChangeInProgress;
        }
    }
    ...
    @Override
    public void run() {
        for (;;) {
            // Get pending change.
            final int state;
            final boolean stateChanged;
            final float brightnessState;
            final float sdrBrightnessState;
            final boolean backlightChanged;
            
            synchronized (mLock) {
                ...
                // 死循环等待变化
                if (!stateChanged && !backlightChanged) {
                    try {
                        mLock.wait();
                    } catch (InterruptedException ex) {
                        if (mStopped) {
                            return;
                        }
                    }
                    continue;
                }
                ...
            }
            ...
            mBlanker.requestDisplayState(mDisplayId, state, brightnessState,
                    sdrBrightnessState);
        }
    }
}

可以看到最终在线程的run方法中调用了mBlanker.requestDisplayState,这个mBlanker其实是接口DisplayBlanker的实例,其最终callback到了DisplayManagerService中:

frameworks/base/services/core/java/com/android/server/display/DisplayManagerService.java

 /** {  @link DisplayBlanker} used by all {  @link DisplayPowerController}s. */
private final DisplayBlanker mDisplayBlanker = new DisplayBlanker() {
    // Synchronized to avoid race conditions when updating multiple display states.
    @Override
    public synchronized void requestDisplayState(int displayId, int state, float brightness,
            float sdrBrightness) {
        ...

        if (state != Display.STATE_OFF) {
            requestDisplayStateInternal(displayId, state, brightness, sdrBrightness);
        }
    }
};

private void requestDisplayStateInternal(int displayId, int state, float brightnessState,
        float sdrBrightnessState) {
    ...

    // Update the display state within the lock.
    // Note that we do not need to schedule traversals here although it
    // may happen as a side-effect of displays changing state.
    final Runnable runnable;
    final String traceMessage;

    synchronized (mSyncRoot) {
        ...
        runnable = updateDisplayStateLocked(mLogicalDisplayMapper.getDisplayLocked(displayId)
                .getPrimaryDisplayDeviceLocked());
    }

    // Setting the display power state can take hundreds of milliseconds
    // to complete so we defer the most expensive part of the work until
    // after we have exited the critical section to avoid blocking other
    // threads for a long time.
    if (runnable != null) {
        runnable.run();
    }
    ...
}

private Runnable updateDisplayStateLocked(DisplayDevice device) {
    ...
        // Only send a request for display state if display state has already been initialized.
        if (state != Display.STATE_UNKNOWN) {
            final BrightnessPair brightnessPair = mDisplayBrightnesses.get(displayId);
            return device.requestDisplayStateLocked(state, brightnessPair.brightness,
                    brightnessPair.sdrBrightness);
        }
    }
    ...
}

在最后面,其实是通过updateDisplayStateLocked创建了一个runnable,那么设置屏幕亮度的业务也将会在此中进行,通过DisplayDevice的requestDisplayStateLocked进行创建runnable,但是DisplayDevice是一个抽象类,真正的实现是在LocalDisplayAdapter中:

frameworks/base/services/core/java/com/android/server/display/LocalDisplayAdapter.java

@Override
public Runnable requestDisplayStateLocked(final int state, final float brightnessState,
        final float sdrBrightnessState) {
        ...
        
        // Defer actually setting the display state until after we have exited
        // the critical section since it can take hundreds of milliseconds
        // to complete.
        return new Runnable() {
            @Override
            public void run() {
                    ...
                    // 设置屏幕亮度
                    setDisplayBrightness(brightnessState, sdrBrightnessState);
                    ...
           }

            private void setDisplayBrightness(float brightnessState,
                    float sdrBrightnessState) {
                        ...
                        mBacklightAdapter.setBacklight(sdrBacklight, sdrNits, backlight, nits);
                        ...
}

// Set backlight within min and max backlight values
void setBacklight(float sdrBacklight, float sdrNits, float backlight, float nits) {
     if (mUseSurfaceControlBrightness || mForceSurfaceControl) {
        if (BrightnessSynchronizer.floatEquals(
                sdrBacklight, PowerManager.BRIGHTNESS_INVALID_FLOAT)) {
            mSurfaceControlProxy.setDisplayBrightness(mDisplayToken, backlight);
        } else {
            mSurfaceControlProxy.setDisplayBrightness(mDisplayToken, sdrBacklight, sdrNits,
                    backlight, nits);
        }
    } else if (mBacklight != null) {
        mBacklight.setBrightness(backlight);
    }
}

前面提到在DisplayManagerService中最终执行了一个runnable,根据代码的走读,在runnable中最终执行到了LocalDisplayAdapter中mBacklight.setBrightness,这个最终响应是在LightsService中:

frameworks/base/services/core/java/com/android/server/lights/LightsService.java

@Override
public void setBrightness(float brightness) {
    setBrightness(brightness, BRIGHTNESS_MODE_USER);
}

@Override
public void setBrightness(float brightness, int brightnessMode) {
        ...
        setLightLocked(color, LIGHT_FLASH_NONE, 0, 0, brightnessMode);
        ...
}

private void setLightLocked(int color, int mode, int onMS, int offMS, int brightnessMode) {
    ...
        setLightUnchecked(color, mode, onMS, offMS, brightnessMode);
    ...
}

private void setLightUnchecked(int color, int mode, int onMS, int offMS,
        int brightnessMode) {
    Trace.traceBegin(Trace.TRACE_TAG_POWER, "setLightState(" + mHwLight.id + ", 0x"
            + Integer.toHexString(color) + ")");

    try {
        if (mVintfLights != null) {
            HwLightState lightState = new HwLightState();
            lightState.color = color;
            lightState.flashMode = (byte) mode;
            lightState.flashOnMs = onMS;
            lightState.flashOffMs = offMS;
            lightState.brightnessMode = (byte) brightnessMode;
            mVintfLights.get().setLightState(mHwLight.id, lightState);
        } else {
            setLight_native(mHwLight.id, color, mode, onMS, offMS, brightnessMode);
        }
    } catch (RemoteException | UnsupportedOperationException ex) {
        Slog.e(TAG, "Failed issuing setLightState", ex);
    } finally {
        Trace.traceEnd(Trace.TRACE_TAG_POWER);
    }
}

可以看到,在LightsService中,最终完成了对底层亮屏的JNI调用。到这里上层的Power键亮屏流程全部梳理完毕。