我的编程空间,编程开发者的网络收藏夹
学习永远不晚

PowerManagerService之亮屏流程示例分析

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

PowerManagerService之亮屏流程示例分析

前言

亮屏的方式有很多,其中最常用的是 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 亮屏流程的资料请关注编程网其它相关文章!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

PowerManagerService之亮屏流程示例分析

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

PowerManagerService之亮屏流程示例分析

这篇文章主要为大家介绍了PowerManagerService之亮屏流程示例分析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2022-11-13

PowerManagerService之手动灭屏流程示例分析

这篇文章主要为大家介绍了PowerManagerService之手动灭屏流程的示例解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2022-11-13

PowerManagerService之自动灭屏流程解析

这篇文章主要为大家介绍了PowerManagerService之自动灭屏流程解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2022-11-13

HDFS读流程的示例分析

这篇文章给大家分享的是有关HDFS读流程的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。1.客户端或者用户通过调用FileSystem对象的Open()方法打开需要读取的文件,这时就是HDSF分布式系统所
2023-06-02

Java流程控制之顺序结构的示例分析

这篇文章主要介绍了Java流程控制之顺序结构的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。Java中的流程控制语句可以这样分类:顺序结构,选择结构,循环结构。1.关
2023-06-22

web开发之网站制作流程的示例分析

这篇文章主要介绍了web开发之网站制作流程的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。  1、关于网站的页面设计  对于网站的页面设计这一部分主要是由设计师完成,
2023-06-10

Java流程控制之选择结构的示例分析

这篇文章主要介绍Java流程控制之选择结构的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!布尔表达式:布尔表达式(Boolean expression)是一段代码声明,它最终只有true(真)和false(假
2023-06-22

linux启动流程的示例分析

这篇文章将为大家详细讲解有关linux启动流程的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。linux启动流程简介我们都知道,由于linux的稳定性,通常被作为服务器系统,要想称为一个PHP的高
2023-06-09

网站开发流程的示例分析

这篇文章主要介绍了网站开发流程的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。一、必不可少的准备工作开发网站的目的在于吸引大量的客流量,所以以提高网站的访问量为网站开
2023-06-10

HDFS文件读流程的示例分析

这篇文章主要介绍了HDFS文件读流程的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。用图来理解:详解HDFS读的过程:1.Client客户端发出请求open到Dist
2023-06-03

HDFS文件写流程的示例分析

小编给大家分享一下HDFS文件写流程的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!图理解:详解HDFS写的过程:1.Client客户端发出请求open到
2023-06-03

Java基础之三大控制流程结构的示例分析

这篇文章给大家分享的是有关Java基础之三大控制流程结构的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。常用的java框架有哪些1.SpringMVC,Spring Web MVC是一种基于Java的实现
2023-06-14

Android编程之自定义锁屏实例分析

本文实例讲述了Android编程之自定义锁屏。分享给大家供大家参考,具体如下: 花了半天时间研究下了自定义锁屏,发现其实实现并不是很神秘。不过有些地方还是值得注意。 首先说流程,锁屏界面一般是在关闭屏幕时启用,打开屏幕时展现在我们面前,所以
2022-06-06

Html5之webcoekt播放JPEG图片流的示例分析

这篇文章给大家分享的是有关Html5之webcoekt播放JPEG图片流的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。一、简介既然webcoekt是基于tcp连接的,理论上讲所有的浏览器是可以私有协议处
2023-06-09

编程热搜

  • Android:VolumeShaper
    VolumeShaper(支持版本改一下,minsdkversion:26,android8.0(api26)进一步学习对声音的编辑,可以让音频的声音有变化的播放 VolumeShaper.Configuration的三个参数 durati
    Android:VolumeShaper
  • Android崩溃异常捕获方法
    开发中最让人头疼的是应用突然爆炸,然后跳回到桌面。而且我们常常不知道这种状况会何时出现,在应用调试阶段还好,还可以通过调试工具的日志查看错误出现在哪里。但平时使用的时候给你闹崩溃,那你就欲哭无泪了。 那么今天主要讲一下如何去捕捉系统出现的U
    Android崩溃异常捕获方法
  • android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
    系统的设置–>电池–>使用情况中,统计的能耗的使用情况也是以power_profile.xml的value作为基础参数的1、我的手机中power_profile.xml的内容: HTC t328w代码如下:
    android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
  • Android SQLite数据库基本操作方法
    程序的最主要的功能在于对数据进行操作,通过对数据进行操作来实现某个功能。而数据库就是很重要的一个方面的,Android中内置了小巧轻便,功能却很强的一个数据库–SQLite数据库。那么就来看一下在Android程序中怎么去操作SQLite数
    Android SQLite数据库基本操作方法
  • ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
    工作的时候为了方便直接打开编辑文件,一些常用的软件或者文件我们会放在桌面,但是在ubuntu20.04下直接直接拖拽文件到桌面根本没有效果,在进入桌面后发现软件列表中的软件只能收藏到面板,无法复制到桌面使用,不知道为什么会这样,似乎并不是很
    ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
  • android获取当前手机号示例程序
    代码如下: public String getLocalNumber() { TelephonyManager tManager =
    android获取当前手机号示例程序
  • Android音视频开发(三)TextureView
    简介 TextureView与SurfaceView类似,可用于显示视频或OpenGL场景。 与SurfaceView的区别 SurfaceView不能使用变换和缩放等操作,不能叠加(Overlay)两个SurfaceView。 Textu
    Android音视频开发(三)TextureView
  • android获取屏幕高度和宽度的实现方法
    本文实例讲述了android获取屏幕高度和宽度的实现方法。分享给大家供大家参考。具体分析如下: 我们需要获取Android手机或Pad的屏幕的物理尺寸,以便于界面的设计或是其他功能的实现。下面就介绍讲一讲如何获取屏幕的物理尺寸 下面的代码即
    android获取屏幕高度和宽度的实现方法
  • Android自定义popupwindow实例代码
    先来看看效果图:一、布局
  • Android第一次实验
    一、实验原理 1.1实验目标 编程实现用户名与密码的存储与调用。 1.2实验要求 设计用户登录界面、登录成功界面、用户注册界面,用户注册时,将其用户名、密码保存到SharedPreference中,登录时输入用户名、密码,读取SharedP
    Android第一次实验

目录