当前位置 : 主页 > 手机开发 > android >

PowerManagerService之亮屏流程示例分析

来源:互联网 收集:自由互联 发布时间:2023-02-01
目录 前言 Power键亮屏 1. 更新 wakefulness 1.1 更新 PMS 的 wakefulness 1.2 保存用户行为时间 1.3 更新 wakefulness 小结 2. 更新电源状态 2.1 更新用户行为 2.2 更新显示屏的电源状态 2.3 处理屏幕状态
目录
  • 前言
  • Power键亮屏
  • 1. 更新 wakefulness
    • 1.1 更新 PMS 的 wakefulness
    • 1.2 保存用户行为时间
    • 1.3 更新 wakefulness 小结
  • 2. 更新电源状态
    • 2.1 更新用户行为
    • 2.2 更新显示屏的电源状态
    • 2.3 处理屏幕状态的更新
    • 2.4 小结
  • 总结

    前言

    亮屏的方式有很多,其中最常用的是 Power 键亮屏,这个流程比较简单,本文希望通过分析这个流程,从而理清操作屏幕的能用流程,为后面的文章打下基础。

    Power键亮屏

    本文以 Power 键亮屏为例进行分析,它会调用 PowerManagerService#wakeUp()

    // PowerManagerService.java
    @Override // Binder call
    public void wakeUp(long eventTime, @WakeReason int reason, String details,
            String opPackageName) {
        // ...
        try {
            // 只能唤醒 default display group 下的显示屏
            wakeDisplayGroup(Display.DEFAULT_DISPLAY_GROUP, eventTime, reason, details, uid,
                    opPackageName, uid);
        } finally {
            Binder.restoreCallingIdentity(ident);
        }
    }  
    private void wakeDisplayGroup(int groupId, long eventTime, @WakeReason int reason,
            String details, int uid, String opPackageName, int opUid) {
        synchronized (mLock) {
            // 1. 更新 wakefulness 为 WAKEFULNESS_AWAKE
            // 包括更新 PowerManagerService 和 DisplayGroupPowerStateMapper 的 wakefulness
            if (wakeDisplayGroupNoUpdateLocked(groupId, eventTime, reason, details, uid,
                    opPackageName, opUid)) {
                // 2. 更新电源状态
                updatePowerStateLocked();
            }
        }
    } 
    

    注意,PowerManagerService#wakeUp() 只能操作默认分组下的屏幕。

    Android 不知何时起,对多屏幕添加了一个分组功能,手机通常只有一个屏幕,它属于默认分组。

    亮屏的过程有两步

    • 更新 wakefulness 为 WAKEFULNESS_AWAKE。主要是更新 PowerManagerService 和 DisplayGroupPowerStateMapper 的 wakefulness。
    • 更新电源状态。亮屏的过程就是在这里处理的。

    1. 更新 wakefulness

    private boolean wakeDisplayGroupNoUpdateLocked(int groupId, long eventTime,
            @WakeReason int reason, String details, int uid, String opPackageName, int opUid) {
        // ...
        try {
            // ...
            // 设置 wakefulness 为 WAKEFULNESS_AWAKE
            setWakefulnessLocked(groupId, WAKEFULNESS_AWAKE, eventTime, uid, reason, opUid,
                    opPackageName, details);
            // 更新分组显示屏的信息
            mDisplayGroupPowerStateMapper.setLastPowerOnTimeLocked(groupId, eventTime);
            mDisplayGroupPowerStateMapper.setPoweringOnLocked(groupId, true);
        } 
        return true;
    }
    void setWakefulnessLocked(int groupId, int wakefulness, long eventTime, int uid, int reason,
            int opUid, String opPackageName, String details) {
        // 1. 更新 DisplayGroupPowerStateMapper 的 wakefulness
        if (mDisplayGroupPowerStateMapper.setWakefulnessLocked(groupId, wakefulness)) {
            // display group wakefulness 改变了
            mDirty |= DIRTY_DISPLAY_GROUP_WAKEFULNESS;
            // 2. 更新 PMS 的 wakefulness
            // 注意第一个参数取所有 display group 的最大的 wakefulness,优先级如下
            //  PowerManagerInternal#WAKEFULNESS_AWAKE
            //  PowerManagerInternal#WAKEFULNESS_DREAMING
            //  PowerManagerInternal#WAKEFULNESS_DOZING
            //  PowerManagerInternal#WAKEFULNESS_ASLEEP
            // TODO: 为何 PMS 的 wakefulness 要设置为所有 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.
                // 3. 保存用户行为的时间
                userActivityNoUpdateLocked(
                        groupId, eventTime, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, uid);
            }
        }
    }    
    

    更新 wakefulness 为 WAKEFULNESS_AWAKE 过程如下

    • 更新 DisplayGroupPowerStateMapper 的 wakefulness 为 WAKEFULNESS_AWAKE。
    • 更新 PMS 的 wakefulness 为 WAKEFULNESS_AWAKE。这里还会通知其它系统组件,wakefulness/交互状态 改变了。详见【1.1 更新 PMS 的 wakefulness
    • 保存用户行为的时间。这个时间用来决定自动灭屏的时间。详见【1.2 保存用户行为时间

    1.1 更新 PMS 的 wakefulness

    // PowerManagerService.java
    private void setGlobalWakefulnessLocked(int wakefulness, long eventTime, int reason, int uid,
            int opUid, String opPackageName, String details) {
        if (getWakefulnessLocked() == wakefulness) {
            return;
        }
        // Phase 1: Handle pre-wakefulness change bookkeeping.
        final String traceMethodName;
        switch (wakefulness) {
            // ...
            case WAKEFULNESS_AWAKE:
                // 保存唤醒设备的时间
                // 这个时间,后面在更新用户行为的时候会用到
                mLastWakeTime = eventTime;
                mLastWakeReason = reason;
                break;
            // ...
        }
        try {
            // Phase 2: Handle wakefulness change and bookkeeping.
            // Under lock, invalidate before set ensures caches won't return stale values.
            mInjector.invalidateIsInteractiveCaches();
            // 更新 PMS 的 wakefulness 相关变量
            mWakefulnessRaw = wakefulness;
            mWakefulnessChanging = true;
            // mDirty 设置 DIRTY_WAKEFULNESS,表示 PMS 的 wakefulness 改变了
            mDirty |= DIRTY_WAKEFULNESS;
            mDozeStartInProgress &= (getWakefulnessLocked() == WAKEFULNESS_DOZING);
            // 通知其它组件,wakefulness改变 或者 交互状态改变
            if (mNotifier != null) {
                mNotifier.onWakefulnessChangeStarted(wakefulness, reason, eventTime);
            }
            mAttentionDetector.onWakefulnessChangeStarted(wakefulness);
            // Phase 3: Handle post-wakefulness change bookkeeping.
            switch (wakefulness) {
                case WAKEFULNESS_AWAKE:
                    // 记录并检测是否有权限
                    mNotifier.onWakeUp(reason, details, uid, opPackageName, opUid);
                    if (sQuiescent) {
                        mDirty |= DIRTY_QUIESCENT;
                    }
                    break;
                // ...
            }
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_POWER);
        }
    }
    

    根据英文注释,更新 PMS 的 wakefulness 过程分为三个阶段,最主要的是在第二个阶段,更新 wakefulness 相关变量,然后 Notifier 通知其它组件并发送亮屏通知,过程如下,大家看一下就行,这不是重点。

    // Notifier.java
    public void onWakefulnessChangeStarted(final int wakefulness, int reason, long eventTime) {
        // 判断新的 wakefulness 是否是交互状态
        // WAKEFULNESS_AWAKE 是可交互状态
        final boolean interactive = PowerManagerInternal.isInteractive(wakefulness);
        // 1. 通知 AMS wakefulness 改变了
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                mActivityManagerInternal.onWakefulnessChanged(wakefulness);
            }
        });
        // 2. 处理交互状态改变
        // Handle any early interactive state changes.
        // Finish pending incomplete ones from a previous cycle.
        // 处理早期交互状态改变
        if (mInteractive != interactive) {
            // Finish up late behaviors if needed.
            // mInteractiveChanging 为 true,表示上一次的处理流程还没有执行完
            // 这里会先执行上一次的流程
            if (mInteractiveChanging) {
                handleLateInteractiveChange();
            }
            // 2.1 更新系统组件的交互状态
            // Start input as soon as we start waking up or going to sleep.
            mInputManagerInternal.setInteractive(interactive);
            mInputMethodManagerInternal.setInteractive(interactive);
            // ...
            // Handle early behaviors.
            // 2.2 更新关于交互状态的变量
            mInteractive = interactive;
            mInteractiveChangeReason = reason;
            mInteractiveChangeStartTime = eventTime;
            // 交互状态正在改变
            mInteractiveChanging = true;
            // 2.3 处理早期的交互状态改变任务
            handleEarlyInteractiveChange();
        }
    }
    private void handleEarlyInteractiveChange() {
        synchronized (mLock) {
            if (mInteractive) {
                // 通知 PhoneWindowManager,PhoneWindowManager再通知 SystemUI keyguard
                mHandler.post(() -> mPolicy.startedWakingUp(mInteractiveChangeReason));
                // 发送亮屏广播
                mPendingInteractiveState = INTERACTIVE_STATE_AWAKE;
                mPendingWakeUpBroadcast = true;
                updatePendingBroadcastLocked();
            } else {
                // ...
            }
        }
    }    
    

    1.2 保存用户行为时间

    // PowerManagerService.java
    private boolean userActivityNoUpdateLocked(int groupId, long eventTime, int event, int flags,
            int uid) {
        if (eventTime < mLastSleepTime || eventTime < mLastWakeTime || !mSystemReady) {
            return false;
        }
        Trace.traceBegin(Trace.TRACE_TAG_POWER, "userActivity");
        try {
            if (eventTime > mLastInteractivePowerHintTime) {
                setPowerBoostInternal(Boost.INTERACTION, 0);
                mLastInteractivePowerHintTime = eventTime;
            }
            // 1. 通知系统组件,有用户行为发生
            mNotifier.onUserActivity(event, uid);
            mAttentionDetector.onUserActivity(eventTime, event);
            if (mUserInactiveOverrideFromWindowManager) {
                mUserInactiveOverrideFromWindowManager = false;
                mOverriddenTimeout = -1;
            }
            final int wakefulness = mDisplayGroupPowerStateMapper.getWakefulnessLocked(groupId);
            if (wakefulness == WAKEFULNESS_ASLEEP
                    || wakefulness == WAKEFULNESS_DOZING
                    || (flags & PowerManager.USER_ACTIVITY_FLAG_INDIRECT) != 0) {
                return false;
            }
            maybeUpdateForegroundProfileLastActivityLocked(eventTime);
            if ((flags & PowerManager.USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS) != 0) {
                // 这里处理延长亮屏的时间的逻辑 ...
            } else {
                if (eventTime > mDisplayGroupPowerStateMapper.getLastUserActivityTimeLocked(
                        groupId)) {
                    // 2. 保存用户活动时间
                    mDisplayGroupPowerStateMapper.setLastUserActivityTimeLocked(groupId, eventTime);
                    // 3. mDirty 设置 DIRTY_USER_ACTIVITY 标志位,
                    // 表示用户活动有更新
                    mDirty |= DIRTY_USER_ACTIVITY;
                    if (event == PowerManager.USER_ACTIVITY_EVENT_BUTTON) {
                        mDirty |= DIRTY_QUIESCENT;
                    }
                    return true;
                }
            }
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_POWER);
        }
        return false;
    }
    

    PMS 更新用户行为的过程

    • 通过 Notifier 通知其它组件有用户行为。
    • DisplayGroupPowerStateMapper 保存用户行为的时间。这个时间会用于决定自动灭屏的时间。
    • mDirty 设置 DIRTY_USER_ACTIVITY 标志位,表示用户活动有更新,后面更新电源状态会用到。

    简单看下第一步的过程,如下

        private void sendUserActivity(int event) {
            synchronized (mLock) {
                if (!mUserActivityPending) {
                    return;
                }
                mUserActivityPending = false;
            }
            // 这里暂时不知道做了什么
            TelephonyManager tm = mContext.getSystemService(TelephonyManager.class);
            tm.notifyUserActivity();
            // PhoneWindowManger 会通知 SystemUI
            mPolicy.userActivity();
            // 如果 FaceDownDetector 正在执行翻转灭屏任务,此时有用户行为,取消这个任务
            mFaceDownDetector.userActivity(event);
        }
    

    1.3 更新 wakefulness 小结

    通过上面的分析,我们应该看到一个本质,更新 wakefulness 流程大致如下

    • 更新 DisplayGroupPowerStateMapper 的 wakefulness,mDirty 设置标志位 DIRTY_DISPLAY_GROUP_WAKEFULNESS。
    • 更新 PowerManagerService 的 wakefulness,mDirty 设置标志位 DIRTY_WAKEFULNESS.
    • Notifier 通知其它组件 wakefulness/交互状态 改变了,并发送亮屏/灭屏的广播。

    2. 更新电源状态

    // PowerManagerService.java
    private void updatePowerStateLocked() {
        if (!mSystemReady || mDirty == 0) {
            return;
        }
        // 注意这里的技术,线程可以判断是否获取了某个锁
        if (!Thread.holdsLock(mLock)) {
            Slog.wtf(TAG, "Power manager lock was not held when calling updatePowerStateLocked");
        }
        Trace.traceBegin(Trace.TRACE_TAG_POWER, "updatePowerState");
        try {
            // Phase 0: Basic state updates.
            // 省电模式功能
            updateIsPoweredLocked(mDirty);
            // 设置中"充电常亮功能"
            updateStayOnLocked(mDirty);
            // 亮度增加功能
            updateScreenBrightnessBoostLocked(mDirty);
            // Phase 1: Update wakefulness.
            // Loop because the wake lock and user activity computations are influenced
            // by changes in wakefulness.
            final long now = mClock.uptimeMillis();
            int dirtyPhase2 = 0;
            for (;;) {
                int dirtyPhase1 = mDirty;
                dirtyPhase2 |= dirtyPhase1;
                mDirty = 0;
                // 把所有的唤醒锁归纳到 mWakeLockSummary
                updateWakeLockSummaryLocked(dirtyPhase1);
                // 1. 更新用户行为
                updateUserActivitySummaryLocked(now, dirtyPhase1);
                updateAttentiveStateLocked(now, dirtyPhase1);
                // 决定是否进入休眠/dream/doze状态
                // 如果进入某一种状态,会更新 wakefulness,因此这里要通过循环再来更新上面的东西
                if (!updateWakefulnessLocked(dirtyPhase1)) {
                    break;
                }
            }
            // Phase 2: Lock profiles that became inactive/not kept awake.
            updateProfilesLocked(now);
            // Phase 3: Update display power state.
            // 2. 更新显示屏的电源状态
            final boolean displayBecameReady = updateDisplayPowerStateLocked(dirtyPhase2);
            // Phase 4: Update dream state (depends on display ready signal).
            updateDreamLocked(dirtyPhase2, displayBecameReady);
            // Phase 5: Send notifications, if needed.
            finishWakefulnessChangeIfNeededLocked();
            // Phase 6: Update suspend blocker.
            // Because we might release the last suspend blocker here, we need to make sure
            // we finished everything else first!
            updateSuspendBlockerLocked();
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_POWER);
        }
    }
    

    PowerManagerService 的所有功能都集中在这个函数中,但是与亮屏相关的主要有两步

    • updateUserActivitySummaryLocked() 更新用户行为。这个用户行为会决定屏幕的最终亮度。详见【2.1 更新用户行为
    • updateDisplayPowerStateLocked() 更新显示屏的电源状态,它会对 DisplayManagerService 发起电源请求,从而决定屏幕屏的亮度。详见【2.2 更新显示屏的电源状态

    2.1 更新用户行为

    // PowerManagerService.java
    private void updateUserActivitySummaryLocked(long now, int dirty) {
        // Update the status of the user activity timeout timer.
        if ((dirty & (DIRTY_DISPLAY_GROUP_WAKEFULNESS | DIRTY_WAKE_LOCKS
                | DIRTY_USER_ACTIVITY | DIRTY_WAKEFULNESS | DIRTY_SETTINGS)) == 0) {
            return;
        }
        mHandler.removeMessages(MSG_USER_ACTIVITY_TIMEOUT);
        // 默认为 -1
        final long attentiveTimeout = getAttentiveTimeoutLocked();
        // 休眠超时时间,默认为 -1
        final long sleepTimeout = getSleepTimeoutLocked(attentiveTimeout);
        // 屏幕超时时间
        long screenOffTimeout = getScreenOffTimeoutLocked(sleepTimeout,
                attentiveTimeout);
        // dim duration = 20 % screen off timeout
        final long screenDimDuration = getScreenDimDurationLocked(screenOffTimeout);
        screenOffTimeout =
                getScreenOffTimeoutWithFaceDownLocked(screenOffTimeout, screenDimDuration);
        final boolean userInactiveOverride = mUserInactiveOverrideFromWindowManager;
        long nextTimeout = -1;
        boolean hasUserActivitySummary = false;
        // 遍历 display group id
        for (int groupId : mDisplayGroupPowerStateMapper.getDisplayGroupIdsLocked()) {
            int groupUserActivitySummary = 0;
            long groupNextTimeout = 0;
            // 注意,休眠状态是无法决定用户行为的
            if (mDisplayGroupPowerStateMapper.getWakefulnessLocked(groupId) != WAKEFULNESS_ASLEEP) {
                final long lastUserActivityTime =
                        mDisplayGroupPowerStateMapper.getLastUserActivityTimeLocked(groupId);
                final long lastUserActivityTimeNoChangeLights =
                        mDisplayGroupPowerStateMapper.getLastUserActivityTimeNoChangeLightsLocked(
                                groupId);
                // 1. 获取用户行为与超时时间
                // 上一次用户行为的时间 >= 上一次唤醒屏幕的时间
                if (lastUserActivityTime >= mLastWakeTime) {
                    groupNextTimeout = lastUserActivityTime + screenOffTimeout - screenDimDuration;
                    if (now < groupNextTimeout) { // 没有到 dim 时间
                        groupUserActivitySummary = USER_ACTIVITY_SCREEN_BRIGHT;
                    } else {
                        groupNextTimeout = lastUserActivityTime + screenOffTimeout;
                        if (now < groupNextTimeout) { // 处于 dim 时间段
                            groupUserActivitySummary = USER_ACTIVITY_SCREEN_DIM;
                        }
                    }
                }
                // 超时了,但是由于释放了某一个锁,需要延长亮屏时间
                if (groupUserActivitySummary == 0
                        && lastUserActivityTimeNoChangeLights >= mLastWakeTime) {
                    // ...
                }
                // 一般的超时情况,
                if (groupUserActivitySummary == 0) {
                    // ...
                }
                // PhoneWindowManager 处理 KeyEvent.KEYCODE_SOFT_SLEEP 时,userInactiveOverride 为 true
                // KeyEvent.KEYCODE_SOFT_SLEEP 这个软件的休眠按键 ?
                if (groupUserActivitySummary != USER_ACTIVITY_SCREEN_DREAM
                        && userInactiveOverride) {
                    // ...
                }
                // 用户行为是点亮屏幕,并且WakeLock没有保持屏幕常亮,用AttentionDetector再次计算屏幕超时时间
                if ((groupUserActivitySummary & USER_ACTIVITY_SCREEN_BRIGHT) != 0
                        && (mDisplayGroupPowerStateMapper.getWakeLockSummaryLocked(groupId)
                        & WAKE_LOCK_STAY_AWAKE) == 0) {
                    // ...
                }
                hasUserActivitySummary |= groupUserActivitySummary != 0;
                if (nextTimeout == -1) {
                    nextTimeout = groupNextTimeout;
                } else if (groupNextTimeout != -1) {
                    // 这里表示 nextTimeout != -1 的情况,也说明有多个 display group 的情况
                    // 从这里可以看出,多个 display group 的超时时间是相同的
                    nextTimeout = Math.min(nextTimeout, groupNextTimeout);
                }
            }
            // 2. DisplayGroupPowerStateMapper 保存用户行为
            mDisplayGroupPowerStateMapper.setUserActivitySummaryLocked(groupId,
                    groupUserActivitySummary);
            }
        } // 遍历 display group id 结束
        final long nextProfileTimeout = getNextProfileTimeoutLocked(now);
        if (nextProfileTimeout > 0) {
            nextTimeout = Math.min(nextTimeout, nextProfileTimeout);
        }
        // 3. 定时更新电源状态
        // 这一步决定自动灭屏
        if (hasUserActivitySummary && nextTimeout >= 0) {
            scheduleUserInactivityTimeout(nextTimeout);
        }
    }
    

    这个函数不单单是用于更新用户行为,还更新了屏幕超时时间,并且以这个时间来定时更新电源状态,以实现自动灭屏的功能。

    更新用户行为在第1步,前面分析更新 wakefulness 时,PMS 保存了唤醒的时间 mLastWakeTime,以及 DisplayGroupPowerStateMapper 保存了用户行为时间。因此,对于从灭屏状态到亮屏状态这一过程来说,用户行为的值现在是 USER_ACTIVITY_SCREEN_BRIGHT,表示用户行为是亮屏。

    2.2 更新显示屏的电源状态

    // PowerManagerService.java
    private boolean updateDisplayPowerStateLocked(int dirty) {
        final boolean oldDisplayReady = mDisplayGroupPowerStateMapper.areAllDisplaysReadyLocked();
        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_VR_MODE_CHANGED |
                DIRTY_QUIESCENT | DIRTY_DISPLAY_GROUP_WAKEFULNESS)) != 0) {
            if ((dirty & DIRTY_QUIESCENT) != 0) {
                // ...
            }
            // 遍历 display group
            for (final int groupId : mDisplayGroupPowerStateMapper.getDisplayGroupIdsLocked()) {
                // 1. 获取 display group 的请求
                final DisplayPowerRequest displayPowerRequest =
                        mDisplayGroupPowerStateMapper.getPowerRequestLocked(groupId);
                // 2. 更新请求的各种参数
                // 更新请求的策略参数,所谓的策略,就是亮屏,还是灭屏,或者使屏幕变暗,等等
                displayPowerRequest.policy = getDesiredScreenPolicyLocked(groupId);
                // ...省略更新其它请求参数的过程...
                // 3. 向 DisplayManagerService 发起请求
                // 如果此次请求与上一次的请求不同,那么这个请求的处理是一个异步处理过程,此时返回 false。
                // 否则,不用处理,直接返回 true。
                final boolean ready = mDisplayManagerInternal.requestPowerState(groupId,
                        displayPowerRequest, mRequestWaitForNegativeProximity);
                // 更新 DisplayGroupPowerStateMapper 的 ready 状态
                final boolean displayReadyStateChanged =
                        mDisplayGroupPowerStateMapper.setDisplayGroupReadyLocked(groupId, ready);
                // 如果异步请求处理完毕,DMS 会回调通知 PMS,PMS 再更新状态走到这里
                // 如果点亮屏幕时间过长,那么用log记录下来
                final boolean poweringOn =
                        mDisplayGroupPowerStateMapper.isPoweringOnLocked(groupId);
                if (ready && displayReadyStateChanged && poweringOn
                        && mDisplayGroupPowerStateMapper.getWakefulnessLocked(
                        groupId) == WAKEFULNESS_AWAKE) {
                    mDisplayGroupPowerStateMapper.setPoweringOnLocked(groupId, false);
                    Trace.asyncTraceEnd(Trace.TRACE_TAG_POWER, TRACE_SCREEN_ON, groupId);
                    final int latencyMs = (int) (mClock.uptimeMillis()
                            - mDisplayGroupPowerStateMapper.getLastPowerOnTimeLocked(groupId));
                    if (latencyMs >= SCREEN_ON_LATENCY_WARNING_MS) {
                        Slog.w(TAG, "Screen on took " + latencyMs + " ms");
                    }
                }
            }
            mRequestWaitForNegativeProximity = false;
        }
        // 返回值表示是否从非ready状态变为ready状态
        return mDisplayGroupPowerStateMapper.areAllDisplaysReadyLocked() && !oldDisplayReady;
    }
    

    更新屏幕电源状态的很清晰,如下

    • 首先获取请求,并更新请求参数。请求参数中,主要关心的是策略参数,它决定了屏幕的状态,也就是到底是亮屏还是灭屏。
    • 向 DisplayManagerService 发起请求。注意,如果当前的请求与上一次请求不同,那么处理过程是异步的,并且返回的 ready 状态为 false。否则,处理过程是同步的,返回的 ready 为 true。

    我们来看下如何更新请求的策略

    // PowerManagerService.java
     int getDesiredScreenPolicyLocked(int groupId) {
        final int wakefulness = mDisplayGroupPowerStateMapper.getWakefulnessLocked(groupId);
        final int wakeLockSummary = mDisplayGroupPowerStateMapper.getWakeLockSummaryLocked(groupId);
        if (wakefulness == WAKEFULNESS_ASLEEP || sQuiescent) {
            return DisplayPowerRequest.POLICY_OFF;
        } else if (wakefulness == WAKEFULNESS_DOZING) {
            // ...
        }
        if (mIsVrModeEnabled) {
            return DisplayPowerRequest.POLICY_VR;
        }
        // 由于此时的 UserActivity 为 USER_ACTIVITY_SCREEN_BRIGHT,因此策略为 DisplayPowerRequest.POLICY_BRIGHT
        if ((wakeLockSummary & WAKE_LOCK_SCREEN_BRIGHT) != 0
                || !mBootCompleted
                || (mDisplayGroupPowerStateMapper.getUserActivitySummaryLocked(groupId)
                & USER_ACTIVITY_SCREEN_BRIGHT) != 0
                || mScreenBrightnessBoostInProgress) {
            return DisplayPowerRequest.POLICY_BRIGHT;
        }
        return DisplayPowerRequest.POLICY_DIM;
    }
    

    我们刚才分析的用户行为是 USER_ACTIVITY_SCREEN_BRIGHT,因此策略最终为 DisplayPowerRequest.POLICY_BRIGHT。当向 DisplayManagerService 发起请求时,最终会导致屏幕点亮。

    2.3 处理屏幕状态的更新

    前面我们刚提到过,处理屏幕请求的过程可能是一个异步,也可能是一个同步。如果从灭屏到亮屏,这个过程一定是一个异步的,那么 PowerManagerService 是如何得知 DisplayManagerService 已经处理完成了呢? 其实 PowerManagerService 向 DisplayManagerService 注册过回调

    // PowerManagerService.java
    public void systemReady(IAppOpsService appOps) {
        synchronized (mLock) {
            mDisplayManagerInternal.initPowerManagement(
                    mDisplayPowerCallbacks, mHandler, sensorManager);                 
        }
    }
    private final DisplayManagerInternal.DisplayPowerCallbacks mDisplayPowerCallbacks =
            new DisplayManagerInternal.DisplayPowerCallbacks() {
        @Override
        public void onStateChanged() {
            synchronized (mLock) {
                // 表示屏幕状态更新了
                mDirty |= DIRTY_ACTUAL_DISPLAY_POWER_STATE_UPDATED;
                updatePowerStateLocked();
            }
        }
    }    
    

    当 PowerManagerService 通过回调得知 DisplayManagerService 已经处理完屏幕请求,于是再次更新电源状态。

    此时,updateDisplayPowerStateLocked() 再向 DisplayManagerService 发起请求,由于与上一次请求相同,因此 DisplayManagerService 不做处理,返回的 ready 状态为 true。

    更新电源状态剩下的过程,就是收尾,我们大致看下

    // PowerManagerService.java
    private void finishWakefulnessChangeIfNeededLocked() {
        // 注意,其中一个条件就是所有 display group 要 ready
        if (mWakefulnessChanging && mDisplayGroupPowerStateMapper.areAllDisplaysReadyLocked()) {
            // ...
            // 显示屏 ready 了, PMS 的 wakefulness 改变的工作才算处理完
            mWakefulnessChanging = false;
            // Notier 通知 wakefulness 的改变已经完成
            mNotifier.onWakefulnessChangeFinished();
        }
    }
    
    // Notifier.java
    public void onWakefulnessChangeFinished() {
        if (mInteractiveChanging) {
            mInteractiveChanging = false;
            // 处理交互状态的后期任务
            handleLateInteractiveChange();
        }
    }
    private void handleLateInteractiveChange() {
        synchronized (mLock) {
            final int interactiveChangeLatency =
                    (int) (SystemClock.uptimeMillis() - mInteractiveChangeStartTime);
            if (mInteractive) {
                // Finished waking up...
                mHandler.post(() -> {
                    // 通知 PhoneWindowManager 完成设备唤醒工作
                    mPolicy.finishedWakingUp(mInteractiveChangeReason);
                });
            } else {
                // ...
            }
        }
    }
    

    2.4 小结

    我们分析的是从灭屏到亮屏的过程,但是我们应该看到一个本质的问题,它其实就是向 DislayManagerService 发起请求,来更新屏幕状态(例如 亮屏,灭屏)。

    请求的策略最终决定了屏幕在状态,但是影响请求策略的因素有很多,例如系统状态(指的是PMS的wakefulness),用户行为,唤醒锁,等等。我们将在后面的文章中看到更多决定请求策略的情况。

    总结

    本文虽然分析的是从灭屏到亮屏的流程,但是我们要看到一个本质的过程,其实只有两步

    • 更新 wakefulness.
    • 向 DisplayManagerService 发起请求,更新屏幕状态。

    以上就是PowerManagerService之亮屏流程示例分析的详细内容,更多关于PowerManagerService 亮屏流程的资料请关注自由互联其它相关文章!

    上一篇:微前端架构ModuleFederationPlugin源码解析
    下一篇:没有了
    网友评论