PowerManagerService 亮屏流程
大胃粥 人气:0前言
亮屏的方式有很多,其中最常用的是 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 发起请求,更新屏幕状态。
加载全部内容