亮屏有很多种方式,如Power键亮屏、插拔USB亮屏、来电亮屏......,虽然方式不同,但只要发起亮屏,其流程都是一样的。PowerManager中提供了 wakeUp() 方法给其他组件或应用来点亮屏幕,下面就从这个方法开始分析亮屏流程。

* @param time 亮屏时间 * @param reason 亮屏原因 * @param details 细节描述 public void wakeUp ( long time, @WakeReason int reason, String details) { try { mService.wakeUp(time, reason, details, mContext.getOpPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer();

调用PowerManager的wakeUp()后,将直接调用PMS#wakeUp()方法,在进行权限检查后,调用wakeUpInternal()进入到PMS内部流程:

// frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
private void wakeUpInternal(long eventTime, @WakeReason int reason, String details, int uid,
        String opPackageName, int opUid) {
    synchronized (mLock) {
        // 进行亮屏流程
        if (wakeUpNoUpdateLocked(eventTime, reason, details, uid, opPackageName, opUid)) {
            // 更新全部状态
            updatePowerStateLocked();

这个方法中:

  • 首先,调用wakeUpNoUpdateLocked()方法;
  • 然后,根据调用返回值确定是否更新全局状态;
  • 1.wakeUpNoUpdateLocked()验证和亮屏状态更新

    此方法是进行亮屏的主要方法,如果亮屏成功,该方法返回true,并更新全局状态,如果因不满足亮屏条件,则返回false,说明亮屏失败:

    // frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
    private boolean wakeUpNoUpdateLocked(long eventTime, @WakeReason int reason, String details,
            int reasonUid, String opPackageName, int opUid) {
        // 此次亮屏时间小于最近一次灭屏时间、已经处于亮屏、系统未启动完成或强制suspend,不会进行亮屏
        if (eventTime < mLastSleepTime || mWakefulness == WAKEFULNESS_AWAKE
                || !mBootCompleted || !mSystemReady || mForceSuspendActive) {
            return false;
        try {
            mLastWakeTime = eventTime;  // 更新最后一次亮屏时间
            mLastWakeReason = reason;   // 更新亮屏原因
            // 更新mWakefulness值
            setWakefulnessLocked(WAKEFULNESS_AWAKE, reason, eventTime);
            // 通知其他组件亮屏动作
            mNotifier.onWakeUp(reason, details, reasonUid, opPackageName, opUid);
            // 更新用户活动时间
            userActivityNoUpdateLocked(
                    eventTime, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, reasonUid);
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_POWER);
        return true;
    

    首先,进行亮屏时间和状态的验证,如果满足以下三个条件之一,则亮屏不会成功,返回false,验证完成后,开始执行亮屏流程:

  • 此次亮屏时间小于最近一次灭屏时间;
  • 唤醒状态已经处于亮屏;
  • 系统未启动完成或强制suspend。
  • 接下来,会更新mLastWakeTime和mLastWakeReason,表示最后一次亮屏时间和原因。
    然后,调用setWakefulnessLocked()方法来设置表示PMS唤醒状态mWakefulness的值。
    最后,执行userActivityNoUpdateLocked()方法更新用户活动时间。

    1.1.setWakefulnessLocked()更新唤醒状态

    // frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
    void setWakefulnessLocked(int wakefulness, int reason, long eventTime) {
        if (getWakefulnessLocked() != wakefulness) {
            // 更新mWakefulness
            mWakefulnessRaw = wakefulness;
            mWakefulnessChanging = true;
            mDirty |= DIRTY_WAKEFULNESS;
            mDozeStartInProgress &= (getWakefulnessLocked() == WAKEFULNESS_DOZING);
            // mNotifier中做mWakefuless转变的开始工作
            if (mNotifier != null) {
                mNotifier.onWakefulnessChangeStarted(wakefulness, reason, eventTime);
            // 通知mAttentionDetector系统状态的改变
            mAttentionDetector.onWakefulnessChangeStarted(wakefulness);
    

    这里会将mWakefulnessRaw的值设置为WAKEFULNESS_AWAKE,表示屏幕状态为Awake。然后通过Notifier#onWakefulnessChangeStarted()方法进行屏幕状态开始改变但未完成切断的工作(如亮灭屏广播)。

    1.2.Notifier#onWakefulnessChangeStarted()

    // frameworks/base/services/core/java/com/android/server/power/Notifier.java
        public void onWakefulnessChangeStarted(final int wakefulness, int reason, long eventTime) {
            // 是否为可交互状态
            final boolean interactive = PowerManagerInternal.isInteractive(wakefulness);
            ......
            if (mInteractive != interactive) {
                // Finish up late behaviors if needed.
                if (mInteractiveChanging) {
                    handleLateInteractiveChange();
                .......
                // 更新交互状态
                mInteractive = interactive;
                mInteractiveChangeReason = reason;
                mInteractiveChangeStartTime = eventTime;
                // 交互状态开始变化
                mInteractiveChanging = true;
                // 进行交状态变化早期任务
                handleEarlyInteractiveChange();
    

    首先更新mInteractive值,表示系统是否可交互,并将交互状态设置给Input模块。当PMS唤醒状态为Awake和Dreaming时,认为是可交互状态。然后调用handleEarlyInteractiveChange()方法,进行交状态变化后的早期任务。

    1.3.handleEarlyInteractiveChange()进行交互状态变化后的早期任务

    // frameworks/base/services/core/java/com/android/server/power/Notifier.java
        private void handleEarlyInteractiveChange() {
            synchronized (mLock) {
                if (mInteractive) {  // 可交互状态
                    // 在system_server主线程进行
                    mHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            final int why = translateOnReason(mInteractiveChangeReason);
                            // 通知PhoneWindowManager开始亮屏
                            mPolicy.startedWakingUp(why);
                    // 表示处于哪种交互状态变化过程中
                    mPendingInteractiveState = INTERACTIVE_STATE_AWAKE;
                    // 表示将要发送亮屏广播
                    mPendingWakeUpBroadcast = true;
                    // 发送亮屏广播
                    updatePendingBroadcastLocked();
                } else {
                    // Going to sleep...
                    ......
    

    亮屏时属于可交互状态,mInteractive此时为true,因此调用PhoneWindowManager#startedWakingUp()方法,该方法中将会通知锁屏等组件进行相应操作,需要注意的是,这个调用是在system_server主线程进行。然后通过updatePendingBroadcastLocked()方法发送亮屏广播。

    1.4.updatePendingBroadcastLocked()发送亮屏广播

    该方法负责亮灭屏广播的发送:

    // frameworks/base/services/core/java/com/android/server/power/Notifier.java
        private void updatePendingBroadcastLocked() {
            if (!mBroadcastInProgress
                    && mPendingInteractiveState != INTERACTIVE_STATE_UNKNOWN
                    && (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast
                            || mPendingInteractiveState != mBroadcastedInteractiveState)) {
                mBroadcastInProgress = true;                         // 表示处于广播发送过程中
                mSuspendBlocker.acquire();                           // 申请SuspendBlocker,防止CPU休眠
                Message msg = mHandler.obtainMessage(MSG_BROADCAST); // system_server中进行发送亮屏广播流程
                msg.setAsynchronous(true);
                mHandler.sendMessage(msg);
    

    这里会先进行条件判断,确认是否满足发送广播条件,这几个条件含义如下:

  • mBroadcastInProgress:是否正在进行广播发送;
  • mPendingInteractiveState:即将发送广播的状态值:INTERACTIVE_STATE_UNKNOWN为默认值,INTERACTIVE_STATE_AWAKE表示亮屏广播,INTERACTIVE_STATE_ASLEEP表示灭屏广播;
  • mBroadcastedInteractiveState:表示当前广播的状态值;
  • mPendingWakeUpBroadcast:表示将要发送亮屏广播;
  • mPendingGoToSleepBroadcast:表示将要发送灭屏广播。
  • 进入此方法后,首先申请一个SuspendBlocker锁,目的是避免在发送广播过程中出现CPU进入休眠状态导致广播发送失败。之后通过Handler中调用sendNextBroadcaset()方法发送广播:

    // frameworks/base/services/core/java/com/android/server/power/Notifier.java
        private void sendNextBroadcast() {
            final int powerState;
            synchronized (mLock) {
                // 首次执行
                if (mBroadcastedInteractiveState == INTERACTIVE_STATE_UNKNOWN) {
                    ......
                } else if (mBroadcastedInteractiveState == INTERACTIVE_STATE_AWAKE) {
                    //如果当前广播状态为INTERACTIVE_STATE_AWAKE,可能会发送灭屏广播
                    if (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast
                            || mPendingInteractiveState == INTERACTIVE_STATE_ASLEEP) {
                        mPendingGoToSleepBroadcast = false;
                        mBroadcastedInteractiveState = INTERACTIVE_STATE_ASLEEP;
                    } else {
                        // 结束亮屏广播发送
                        finishPendingBroadcastLocked();
                        return;
                } else {// 如果当前广播状态为INTERACTIVE_STATE_ASLEEP送亮屏广播
                    if (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast
                            || mPendingInteractiveState == INTERACTIVE_STATE_AWAKE) {
                        mPendingWakeUpBroadcast = false;
                        // 更新mBroadcastedInteractiveState值
                        mBroadcastedInteractiveState = INTERACTIVE_STATE_AWAKE;
                    } else {
                        // 结束灭屏广播发送
                        finishPendingBroadcastLocked();
                        return;
                powerState = mBroadcastedInteractiveState;
            if (powerState == INTERACTIVE_STATE_AWAKE) {
                // 发送亮屏广播
                sendWakeUpBroadcast();
            } else {
                // 发送灭屏广播
                sendGoToSleepBroadcast();
    

    最终,通过sendWakeUpBroadcast()方法,发送亮屏广播:

    // frameworks/base/services/core/java/com/android/server/power/Notifier.java
    private void sendWakeUpBroadcast() {
        // 发送Intent.ACTION_SCREEN_ON广播
        if (mActivityManagerInternal.isSystemReady()) {
            mContext.sendOrderedBroadcastAsUser(mScreenOnIntent, UserHandle.ALL, null,
                    mWakeUpBroadcastDone, mHandler, 0, null, null);
        ......
    

    这里指定了一个mWakeUpBroadcastDone,会在广播发送后,作为最后一个广播接收器接收该广播,进行广播发送完毕后的工作。mWakeUpBroadcastDone中则继续执行sendNextBroadcast()方法,在这次执行时,根据条件会执行inishPendingBroadcastLocked()方法:

    private void finishPendingBroadcastLocked() {
        // 重置mBroadcastInProgress,表示当前没有正在进行发送的广播
        mBroadcastInProgress = false;  
        // 释放SuspendBlocker锁
        mSuspendBlocker.release();  
    

    从而完成亮屏广播的发送。

    1.5.userActivityNoUpdateLocked()更新用户交互时间

    回到wakeUpNoUpdateLocked()方法中,setWakefulnessLocked()执行完毕后,执行 userActivityNoUpdateLocked()方法,此方法用来更新系统和用户最后的交互时间,根据这个时间可以决定何时自动休眠。详细内容在自动灭屏流程中分析。

    此时wakeUpNoUpdateLocked()执行完毕并返回true,接下来执行updatePowerStateLocked()方法。

    2.updatePowerStateLocked()更新PMS全局状态

    此方法在第一篇已进行了分析,这里只看进行亮屏的最关键操作——执行updateDisplayPowerStateLocked()方法。

    2.1.updateDisplayPowerStateLocked()向DMS发起请求

    PMS中所有请求数据会封装到DisplayPowerRequest对象中,向DMS中发起请求。DMS中收到请求后,在DisplayPowerController中更新Display状态和亮度,并将请求结果返回给PMS。DisplayPowerController中处理请求逻辑如下:

    public boolean requestPowerState(DisplayPowerRequest request,
            boolean waitForNegativeProximity) {
        synchronized (mLock) {
            boolean changed = false;
             // 是否需要等待PSensor上报远离事件
            if (waitForNegativeProximity
                    && !mPendingWaitForNegativeProximityLocked) {
                mPendingWaitForNegativeProximityLocked = true;
                changed = true;
            // 判断是否是新的请求
            if (mPendingRequestLocked == null) {
                mPendingRequestLocked = new DisplayPowerRequest(request);
                changed = true;
            } else if (!mPendingRequestLocked.equals(request)) {
                mPendingRequestLocked.copyFrom(request);
                changed = true;
            if (changed) {
                mDisplayReadyLocked = false;
            // 开始处理请求
            if (changed && !mPendingRequestChangedLocked) {
                mPendingRequestChangedLocked = true;
                sendUpdatePowerStateLocked();
            // 返回给PMS,表示请求是否处理完成
    
    
    
    
        
    
            return mDisplayReadyLocked;
    

    这个方法中,会判断请求时携带的DisplayPowerRequest对象是否和上一次发生请求的DisplayRequest对象相同,如果不同表示发生了的请求,则开始处理这次新请求,并向PMS返回mDisplayReadyLocked,该值表示DMS中是否处理完毕请求。

    当请求处理完毕后,会将mDisplayReadyLocked值置为true,同时回调PMS#onStateChanged()方法通知PMS更新完成。 经过这一步后,会将系统的亮度、显示状态全部设置完毕,此时屏幕已经亮了。关于亮度和显示状态的详细分析,见 Android R DisplayManagerService模块(3) DMS部分亮灭屏流程

    2.2.finishWakefulnessChangeIfNeededLocked()进行唤醒状态变化完成时任务

    回到updatePowerStateLocked()方法中,当DMS处理请求完成,并且返回请求结果后,执行finishWakefulnessChangeIfNeededLocked()方法,进行屏幕状态改变完成后的操作:

        private void finishWakefulnessChangeIfNeededLocked() {
            // 通过Notifier进行系统状态wakefulness改变后的处理
            if (mWakefulnessChanging && mDisplayReady) {
                if (getWakefulnessLocked() == WAKEFULNESS_DOZING
                        && (mWakeLockSummary & WAKE_LOCK_DOZE) == 0) {
                    return; 
                } else {
                    mDozeStartInProgress = false;
                // 唤醒状态变化完成
                mWakefulnessChanging = false;
                mNotifier.onWakefulnessChangeFinished();
    

    这里会执行Notifier#onWakefulnessChangeFinished()方法,通知Notifier做唤醒状态改变完成后,交互状态相关的一些任务。

    2.3.Notifier#onWakefulnessChangeFinished()

    // frameworks/base/services/core/java/com/android/server/power/Notifier.java
        public void onWakefulnessChangeFinished() {
            // 将mInteractiveChanging设置为false,表示交互状态也改变完成
            if (mInteractiveChanging) {
                mInteractiveChanging = false;
                // 处理进行交互状态变化完成后的任务
                handleLateInteractiveChange();
    

    这里将mInteractiveChanging值重置为false,表示交互状态的变化已经完成,接下来执行handleLateInteractiveChange()方法。

    2.4.handleLateInteractiveChange()进行交互状态变化完成后的任务

    handleLateInteractiveChange()方法和handleEarlyInteractiveChange()方法相对应,一个处理交互状态改变后的早期工作,一个处理交互状态改变后的后期工作:

    // frameworks/base/services/core/java/com/android/server/power/Notifier.java
        private void handleLateInteractiveChange() {
            synchronized (mLock) {
                if (mInteractive) {
                    mHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            // 通知PhoneWindowManager完成亮屏
                            mPolicy.finishedWakingUp(why);
                } else {
                    // 不可交互状态时流程
                    ......
    

    在system_server主线程中,通知PhoneWindowManager完成亮屏。

    亮屏过程中,关键步骤如下:

  • 更新PMS唤醒状态;
  • 更新交互状态;
  • system_server主线程执行PhoneWindowManager#startedWakingUp()方法,通知WMS开始亮屏;
  • system_server主线程发送亮屏广播;
  • 向DMS请求Display状态和亮度;
  • DMS返回请求状态后,system_server主线程执行PhoneWindowManager#finishedWakingUp()通知WMS模块完成亮屏。
  • 整个过程时序图如下:

    Android
    私信