PowerManagerService之亮屏流程示例分析
前言
亮屏的方式有很多,其中最常用的是 Power 鍵亮屏,這個(gè)流程比較簡(jiǎn)單,本文希望通過(guò)分析這個(gè)流程,從而理清操作屏幕的能用流程,為后面的文章打下基礎(chǔ)。
Power鍵亮屏
本文以 Power 鍵亮屏為例進(jìn)行分析,它會(huì)調(diào)用 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. 更新電源狀態(tài) updatePowerStateLocked(); } } }
注意,PowerManagerService#wakeUp() 只能操作默認(rèn)分組下的屏幕。
Android 不知何時(shí)起,對(duì)多屏幕添加了一個(gè)分組功能,手機(jī)通常只有一個(gè)屏幕,它屬于默認(rèn)分組。
亮屏的過(guò)程有兩步
- 更新 wakefulness 為 WAKEFULNESS_AWAKE。主要是更新 PowerManagerService 和 DisplayGroupPowerStateMapper 的 wakefulness。
- 更新電源狀態(tài)。亮屏的過(guò)程就是在這里處理的。
1. 更新 wakefulness
private boolean wakeDisplayGroupNoUpdateLocked(int groupId, long eventTime, @WakeReason int reason, String details, int uid, String opPackageName, int opUid) { // ... try { // ... // 設(shè)置 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 // 注意第一個(gè)參數(shù)取所有 display group 的最大的 wakefulness,優(yōu)先級(jí)如下 // PowerManagerInternal#WAKEFULNESS_AWAKE // PowerManagerInternal#WAKEFULNESS_DREAMING // PowerManagerInternal#WAKEFULNESS_DOZING // PowerManagerInternal#WAKEFULNESS_ASLEEP // TODO: 為何 PMS 的 wakefulness 要設(shè)置為所有 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. 保存用戶行為的時(shí)間 userActivityNoUpdateLocked( groupId, eventTime, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, uid); } } }
更新 wakefulness 為 WAKEFULNESS_AWAKE 過(guò)程如下
- 更新 DisplayGroupPowerStateMapper 的 wakefulness 為 WAKEFULNESS_AWAKE。
- 更新 PMS 的 wakefulness 為 WAKEFULNESS_AWAKE。這里還會(huì)通知其它系統(tǒng)組件,wakefulness/交互狀態(tài) 改變了。詳見(jiàn)【1.1 更新 PMS 的 wakefulness】
- 保存用戶行為的時(shí)間。這個(gè)時(shí)間用來(lái)決定自動(dòng)滅屏的時(shí)間。詳見(jiàn)【1.2 保存用戶行為時(shí)間】
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: // 保存喚醒設(shè)備的時(shí)間 // 這個(gè)時(shí)間,后面在更新用戶行為的時(shí)候會(huì)用到 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 相關(guān)變量 mWakefulnessRaw = wakefulness; mWakefulnessChanging = true; // mDirty 設(shè)置 DIRTY_WAKEFULNESS,表示 PMS 的 wakefulness 改變了 mDirty |= DIRTY_WAKEFULNESS; mDozeStartInProgress &= (getWakefulnessLocked() == WAKEFULNESS_DOZING); // 通知其它組件,wakefulness改變 或者 交互狀態(tài)改變 if (mNotifier != null) { mNotifier.onWakefulnessChangeStarted(wakefulness, reason, eventTime); } mAttentionDetector.onWakefulnessChangeStarted(wakefulness); // Phase 3: Handle post-wakefulness change bookkeeping. switch (wakefulness) { case WAKEFULNESS_AWAKE: // 記錄并檢測(cè)是否有權(quán)限 mNotifier.onWakeUp(reason, details, uid, opPackageName, opUid); if (sQuiescent) { mDirty |= DIRTY_QUIESCENT; } break; // ... } } finally { Trace.traceEnd(Trace.TRACE_TAG_POWER); } }
根據(jù)英文注釋,更新 PMS 的 wakefulness 過(guò)程分為三個(gè)階段,最主要的是在第二個(gè)階段,更新 wakefulness 相關(guān)變量,然后 Notifier 通知其它組件并發(fā)送亮屏通知,過(guò)程如下,大家看一下就行,這不是重點(diǎn)。
// Notifier.java public void onWakefulnessChangeStarted(final int wakefulness, int reason, long eventTime) { // 判斷新的 wakefulness 是否是交互狀態(tài) // WAKEFULNESS_AWAKE 是可交互狀態(tài) final boolean interactive = PowerManagerInternal.isInteractive(wakefulness); // 1. 通知 AMS wakefulness 改變了 mHandler.post(new Runnable() { @Override public void run() { mActivityManagerInternal.onWakefulnessChanged(wakefulness); } }); // 2. 處理交互狀態(tài)改變 // Handle any early interactive state changes. // Finish pending incomplete ones from a previous cycle. // 處理早期交互狀態(tài)改變 if (mInteractive != interactive) { // Finish up late behaviors if needed. // mInteractiveChanging 為 true,表示上一次的處理流程還沒(méi)有執(zhí)行完 // 這里會(huì)先執(zhí)行上一次的流程 if (mInteractiveChanging) { handleLateInteractiveChange(); } // 2.1 更新系統(tǒng)組件的交互狀態(tài) // Start input as soon as we start waking up or going to sleep. mInputManagerInternal.setInteractive(interactive); mInputMethodManagerInternal.setInteractive(interactive); // ... // Handle early behaviors. // 2.2 更新關(guān)于交互狀態(tài)的變量 mInteractive = interactive; mInteractiveChangeReason = reason; mInteractiveChangeStartTime = eventTime; // 交互狀態(tài)正在改變 mInteractiveChanging = true; // 2.3 處理早期的交互狀態(tài)改變?nèi)蝿?wù) handleEarlyInteractiveChange(); } } private void handleEarlyInteractiveChange() { synchronized (mLock) { if (mInteractive) { // 通知 PhoneWindowManager,PhoneWindowManager再通知 SystemUI keyguard mHandler.post(() -> mPolicy.startedWakingUp(mInteractiveChangeReason)); // 發(fā)送亮屏廣播 mPendingInteractiveState = INTERACTIVE_STATE_AWAKE; mPendingWakeUpBroadcast = true; updatePendingBroadcastLocked(); } else { // ... } } }
1.2 保存用戶行為時(shí)間
// 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. 通知系統(tǒng)組件,有用戶行為發(fā)生 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) { // 這里處理延長(zhǎng)亮屏的時(shí)間的邏輯 ... } else { if (eventTime > mDisplayGroupPowerStateMapper.getLastUserActivityTimeLocked( groupId)) { // 2. 保存用戶活動(dòng)時(shí)間 mDisplayGroupPowerStateMapper.setLastUserActivityTimeLocked(groupId, eventTime); // 3. mDirty 設(shè)置 DIRTY_USER_ACTIVITY 標(biāo)志位, // 表示用戶活動(dòng)有更新 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 更新用戶行為的過(guò)程
- 通過(guò) Notifier 通知其它組件有用戶行為。
- DisplayGroupPowerStateMapper 保存用戶行為的時(shí)間。這個(gè)時(shí)間會(huì)用于決定自動(dòng)滅屏的時(shí)間。
- mDirty 設(shè)置 DIRTY_USER_ACTIVITY 標(biāo)志位,表示用戶活動(dòng)有更新,后面更新電源狀態(tài)會(huì)用到。
簡(jiǎn)單看下第一步的過(guò)程,如下
private void sendUserActivity(int event) { synchronized (mLock) { if (!mUserActivityPending) { return; } mUserActivityPending = false; } // 這里暫時(shí)不知道做了什么 TelephonyManager tm = mContext.getSystemService(TelephonyManager.class); tm.notifyUserActivity(); // PhoneWindowManger 會(huì)通知 SystemUI mPolicy.userActivity(); // 如果 FaceDownDetector 正在執(zhí)行翻轉(zhuǎn)滅屏任務(wù),此時(shí)有用戶行為,取消這個(gè)任務(wù) mFaceDownDetector.userActivity(event); }
1.3 更新 wakefulness 小結(jié)
通過(guò)上面的分析,我們應(yīng)該看到一個(gè)本質(zhì),更新 wakefulness 流程大致如下
- 更新 DisplayGroupPowerStateMapper 的 wakefulness,mDirty 設(shè)置標(biāo)志位 DIRTY_DISPLAY_GROUP_WAKEFULNESS。
- 更新 PowerManagerService 的 wakefulness,mDirty 設(shè)置標(biāo)志位 DIRTY_WAKEFULNESS.
- Notifier 通知其它組件 wakefulness/交互狀態(tài) 改變了,并發(fā)送亮屏/滅屏的廣播。
2. 更新電源狀態(tài)
// PowerManagerService.java private void updatePowerStateLocked() { if (!mSystemReady || mDirty == 0) { return; } // 注意這里的技術(shù),線程可以判斷是否獲取了某個(gè)鎖 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); // 設(shè)置中"充電常亮功能" 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); // 決定是否進(jìn)入休眠/dream/doze狀態(tài) // 如果進(jìn)入某一種狀態(tài),會(huì)更新 wakefulness,因此這里要通過(guò)循環(huán)再來(lái)更新上面的東西 if (!updateWakefulnessLocked(dirtyPhase1)) { break; } } // Phase 2: Lock profiles that became inactive/not kept awake. updateProfilesLocked(now); // Phase 3: Update display power state. // 2. 更新顯示屏的電源狀態(tài) 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 的所有功能都集中在這個(gè)函數(shù)中,但是與亮屏相關(guān)的主要有兩步
- updateUserActivitySummaryLocked() 更新用戶行為。這個(gè)用戶行為會(huì)決定屏幕的最終亮度。詳見(jiàn)【2.1 更新用戶行為】
- updateDisplayPowerStateLocked() 更新顯示屏的電源狀態(tài),它會(huì)對(duì) DisplayManagerService 發(fā)起電源請(qǐng)求,從而決定屏幕屏的亮度。詳見(jiàn)【2.2 更新顯示屏的電源狀態(tài)】
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); // 默認(rèn)為 -1 final long attentiveTimeout = getAttentiveTimeoutLocked(); // 休眠超時(shí)時(shí)間,默認(rèn)為 -1 final long sleepTimeout = getSleepTimeoutLocked(attentiveTimeout); // 屏幕超時(shí)時(shí)間 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; // 注意,休眠狀態(tài)是無(wú)法決定用戶行為的 if (mDisplayGroupPowerStateMapper.getWakefulnessLocked(groupId) != WAKEFULNESS_ASLEEP) { final long lastUserActivityTime = mDisplayGroupPowerStateMapper.getLastUserActivityTimeLocked(groupId); final long lastUserActivityTimeNoChangeLights = mDisplayGroupPowerStateMapper.getLastUserActivityTimeNoChangeLightsLocked( groupId); // 1. 獲取用戶行為與超時(shí)時(shí)間 // 上一次用戶行為的時(shí)間 >= 上一次喚醒屏幕的時(shí)間 if (lastUserActivityTime >= mLastWakeTime) { groupNextTimeout = lastUserActivityTime + screenOffTimeout - screenDimDuration; if (now < groupNextTimeout) { // 沒(méi)有到 dim 時(shí)間 groupUserActivitySummary = USER_ACTIVITY_SCREEN_BRIGHT; } else { groupNextTimeout = lastUserActivityTime + screenOffTimeout; if (now < groupNextTimeout) { // 處于 dim 時(shí)間段 groupUserActivitySummary = USER_ACTIVITY_SCREEN_DIM; } } } // 超時(shí)了,但是由于釋放了某一個(gè)鎖,需要延長(zhǎng)亮屏?xí)r間 if (groupUserActivitySummary == 0 && lastUserActivityTimeNoChangeLights >= mLastWakeTime) { // ... } // 一般的超時(shí)情況, if (groupUserActivitySummary == 0) { // ... } // PhoneWindowManager 處理 KeyEvent.KEYCODE_SOFT_SLEEP 時(shí),userInactiveOverride 為 true // KeyEvent.KEYCODE_SOFT_SLEEP 這個(gè)軟件的休眠按鍵 ? if (groupUserActivitySummary != USER_ACTIVITY_SCREEN_DREAM && userInactiveOverride) { // ... } // 用戶行為是點(diǎn)亮屏幕,并且WakeLock沒(méi)有保持屏幕常亮,用AttentionDetector再次計(jì)算屏幕超時(shí)時(shí)間 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 的情況,也說(shuō)明有多個(gè) display group 的情況 // 從這里可以看出,多個(gè) display group 的超時(shí)時(shí)間是相同的 nextTimeout = Math.min(nextTimeout, groupNextTimeout); } } // 2. DisplayGroupPowerStateMapper 保存用戶行為 mDisplayGroupPowerStateMapper.setUserActivitySummaryLocked(groupId, groupUserActivitySummary); } } // 遍歷 display group id 結(jié)束 final long nextProfileTimeout = getNextProfileTimeoutLocked(now); if (nextProfileTimeout > 0) { nextTimeout = Math.min(nextTimeout, nextProfileTimeout); } // 3. 定時(shí)更新電源狀態(tài) // 這一步?jīng)Q定自動(dòng)滅屏 if (hasUserActivitySummary && nextTimeout >= 0) { scheduleUserInactivityTimeout(nextTimeout); } }
這個(gè)函數(shù)不單單是用于更新用戶行為,還更新了屏幕超時(shí)時(shí)間,并且以這個(gè)時(shí)間來(lái)定時(shí)更新電源狀態(tài),以實(shí)現(xiàn)自動(dòng)滅屏的功能。
更新用戶行為在第1步,前面分析更新 wakefulness 時(shí),PMS 保存了喚醒的時(shí)間 mLastWakeTime,以及 DisplayGroupPowerStateMapper 保存了用戶行為時(shí)間。因此,對(duì)于從滅屏狀態(tài)到亮屏狀態(tài)這一過(guò)程來(lái)說(shuō),用戶行為的值現(xiàn)在是 USER_ACTIVITY_SCREEN_BRIGHT,表示用戶行為是亮屏。
2.2 更新顯示屏的電源狀態(tài)
// 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 的請(qǐng)求 final DisplayPowerRequest displayPowerRequest = mDisplayGroupPowerStateMapper.getPowerRequestLocked(groupId); // 2. 更新請(qǐng)求的各種參數(shù) // 更新請(qǐng)求的策略參數(shù),所謂的策略,就是亮屏,還是滅屏,或者使屏幕變暗,等等 displayPowerRequest.policy = getDesiredScreenPolicyLocked(groupId); // ...省略更新其它請(qǐng)求參數(shù)的過(guò)程... // 3. 向 DisplayManagerService 發(fā)起請(qǐng)求 // 如果此次請(qǐng)求與上一次的請(qǐng)求不同,那么這個(gè)請(qǐng)求的處理是一個(gè)異步處理過(guò)程,此時(shí)返回 false。 // 否則,不用處理,直接返回 true。 final boolean ready = mDisplayManagerInternal.requestPowerState(groupId, displayPowerRequest, mRequestWaitForNegativeProximity); // 更新 DisplayGroupPowerStateMapper 的 ready 狀態(tài) final boolean displayReadyStateChanged = mDisplayGroupPowerStateMapper.setDisplayGroupReadyLocked(groupId, ready); // 如果異步請(qǐng)求處理完畢,DMS 會(huì)回調(diào)通知 PMS,PMS 再更新?tīng)顟B(tài)走到這里 // 如果點(diǎn)亮屏幕時(shí)間過(guò)長(zhǎng),那么用log記錄下來(lái) 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狀態(tài)變?yōu)閞eady狀態(tài) return mDisplayGroupPowerStateMapper.areAllDisplaysReadyLocked() && !oldDisplayReady; }
更新屏幕電源狀態(tài)的很清晰,如下
- 首先獲取請(qǐng)求,并更新請(qǐng)求參數(shù)。請(qǐng)求參數(shù)中,主要關(guān)心的是策略參數(shù),它決定了屏幕的狀態(tài),也就是到底是亮屏還是滅屏。
- 向 DisplayManagerService 發(fā)起請(qǐng)求。注意,如果當(dāng)前的請(qǐng)求與上一次請(qǐng)求不同,那么處理過(guò)程是異步的,并且返回的 ready 狀態(tài)為 false。否則,處理過(guò)程是同步的,返回的 ready 為 true。
我們來(lái)看下如何更新請(qǐng)求的策略
// 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; } // 由于此時(shí)的 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。當(dāng)向 DisplayManagerService 發(fā)起請(qǐng)求時(shí),最終會(huì)導(dǎo)致屏幕點(diǎn)亮。
2.3 處理屏幕狀態(tài)的更新
前面我們剛提到過(guò),處理屏幕請(qǐng)求的過(guò)程可能是一個(gè)異步,也可能是一個(gè)同步。如果從滅屏到亮屏,這個(gè)過(guò)程一定是一個(gè)異步的,那么 PowerManagerService 是如何得知 DisplayManagerService 已經(jīng)處理完成了呢? 其實(shí) PowerManagerService 向 DisplayManagerService 注冊(cè)過(guò)回調(diào)
// 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) { // 表示屏幕狀態(tài)更新了 mDirty |= DIRTY_ACTUAL_DISPLAY_POWER_STATE_UPDATED; updatePowerStateLocked(); } } }
當(dāng) PowerManagerService 通過(guò)回調(diào)得知 DisplayManagerService 已經(jīng)處理完屏幕請(qǐng)求,于是再次更新電源狀態(tài)。
此時(shí),updateDisplayPowerStateLocked() 再向 DisplayManagerService 發(fā)起請(qǐng)求,由于與上一次請(qǐng)求相同,因此 DisplayManagerService 不做處理,返回的 ready 狀態(tài)為 true。
更新電源狀態(tài)剩下的過(guò)程,就是收尾,我們大致看下
// PowerManagerService.java private void finishWakefulnessChangeIfNeededLocked() { // 注意,其中一個(gè)條件就是所有 display group 要 ready if (mWakefulnessChanging && mDisplayGroupPowerStateMapper.areAllDisplaysReadyLocked()) { // ... // 顯示屏 ready 了, PMS 的 wakefulness 改變的工作才算處理完 mWakefulnessChanging = false; // Notier 通知 wakefulness 的改變已經(jīng)完成 mNotifier.onWakefulnessChangeFinished(); } }
// Notifier.java public void onWakefulnessChangeFinished() { if (mInteractiveChanging) { mInteractiveChanging = false; // 處理交互狀態(tài)的后期任務(wù) handleLateInteractiveChange(); } } private void handleLateInteractiveChange() { synchronized (mLock) { final int interactiveChangeLatency = (int) (SystemClock.uptimeMillis() - mInteractiveChangeStartTime); if (mInteractive) { // Finished waking up... mHandler.post(() -> { // 通知 PhoneWindowManager 完成設(shè)備喚醒工作 mPolicy.finishedWakingUp(mInteractiveChangeReason); }); } else { // ... } } }
2.4 小結(jié)
我們分析的是從滅屏到亮屏的過(guò)程,但是我們應(yīng)該看到一個(gè)本質(zhì)的問(wèn)題,它其實(shí)就是向 DislayManagerService 發(fā)起請(qǐng)求,來(lái)更新屏幕狀態(tài)(例如 亮屏,滅屏)。
請(qǐng)求的策略最終決定了屏幕在狀態(tài),但是影響請(qǐng)求策略的因素有很多,例如系統(tǒng)狀態(tài)(指的是PMS的wakefulness),用戶行為,喚醒鎖,等等。我們將在后面的文章中看到更多決定請(qǐng)求策略的情況。
總結(jié)
本文雖然分析的是從滅屏到亮屏的流程,但是我們要看到一個(gè)本質(zhì)的過(guò)程,其實(shí)只有兩步
- 更新 wakefulness.
- 向 DisplayManagerService 發(fā)起請(qǐng)求,更新屏幕狀態(tài)。
以上就是PowerManagerService之亮屏流程示例分析的詳細(xì)內(nèi)容,更多關(guān)于PowerManagerService 亮屏流程的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
android中AutoCompleteTextView的簡(jiǎn)單用法(實(shí)現(xiàn)搜索歷史)
本篇文章主要介紹了android中AutoCompleteTextView的簡(jiǎn)單用法(自動(dòng)提示),有需要的可以了解一下。2016-11-11Android圖片加載利器之Picasso擴(kuò)展功能
這篇文章主要為大家詳細(xì)介紹了Android圖片加載利器之Picasso擴(kuò)展功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-03-03分享Android平板電腦上開(kāi)發(fā)應(yīng)用程序不能全屏顯示的問(wèn)題解決
在一個(gè)8寸屏的Android平板電腦上開(kāi)發(fā)應(yīng)用程序(游戲程序),開(kāi)始的時(shí)候,總是不能全屏顯示,也不知道怎么設(shè)置才可以2013-05-05非常詳細(xì)的android so庫(kù)逆向調(diào)試教程
這篇文章主要給大家介紹了關(guān)于android so庫(kù)逆向調(diào)試的相關(guān)資料,文中通過(guò)示例代碼以及圖文介紹的非常詳細(xì),對(duì)各位Android開(kāi)發(fā)者具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2021-08-08Android編程實(shí)現(xiàn)創(chuàng)建,刪除,判斷快捷方式的方法
這篇文章主要介紹了Android編程實(shí)現(xiàn)創(chuàng)建,刪除,判斷快捷方式的方法,結(jié)合實(shí)例形式分析了Android編程針對(duì)快捷方式的常用操作技巧,需要的朋友可以參考下2017-02-02Android自定義星星可滑動(dòng)評(píng)分控件
這篇文章主要介紹了Android自定義星星可滑動(dòng)評(píng)分控件,通過(guò)線性布局結(jié)合ImageView實(shí)現(xiàn)評(píng)分控件,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-03-03Android開(kāi)發(fā)入門(mén)之Notification用法分析
這篇文章主要介紹了Android中Notification用法,較為詳細(xì)的分析了Notification的功能、使用步驟與相關(guān)注意事項(xiàng),需要的朋友可以參考下2016-07-07Android下錄制App操作生成Gif動(dòng)態(tài)圖的全過(guò)程
這篇文章主要為大家分享了Android下錄制App操作生成Gif動(dòng)態(tài)圖的全過(guò)程,感興趣的小伙伴們可以參考一下2016-01-01