PowerManagerService之亮屏流程示例分析
前言
亮屏的方式有很多,其中最常用的是 Power 鍵亮屏,這個(gè)流程比較簡(jiǎn)單,本文希望通過分析這個(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)分組。
亮屏的過程有兩步
- 更新 wakefulness 為 WAKEFULNESS_AWAKE。主要是更新 PowerManagerService 和 DisplayGroupPowerStateMapper 的 wakefulness。
- 更新電源狀態(tài)。亮屏的過程就是在這里處理的。
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 過程如下
- 更新 DisplayGroupPowerStateMapper 的 wakefulness 為 WAKEFULNESS_AWAKE。
- 更新 PMS 的 wakefulness 為 WAKEFULNESS_AWAKE。這里還會(huì)通知其它系統(tǒng)組件,wakefulness/交互狀態(tài) 改變了。詳見【1.1 更新 PMS 的 wakefulness】
- 保存用戶行為的時(shí)間。這個(gè)時(shí)間用來決定自動(dòng)滅屏的時(shí)間。詳見【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 過程分為三個(gè)階段,最主要的是在第二個(gè)階段,更新 wakefulness 相關(guān)變量,然后 Notifier 通知其它組件并發(fā)送亮屏通知,過程如下,大家看一下就行,這不是重點(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,表示上一次的處理流程還沒有執(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 更新用戶行為的過程
- 通過 Notifier 通知其它組件有用戶行為。
- DisplayGroupPowerStateMapper 保存用戶行為的時(shí)間。這個(gè)時(shí)間會(huì)用于決定自動(dòng)滅屏的時(shí)間。
- mDirty 設(shè)置 DIRTY_USER_ACTIVITY 標(biāo)志位,表示用戶活動(dòng)有更新,后面更新電源狀態(tài)會(huì)用到。
簡(jiǎn)單看下第一步的過程,如下
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é)
通過上面的分析,我們應(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,因此這里要通過循環(huán)再來更新上面的東西
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ì)決定屏幕的最終亮度。詳見【2.1 更新用戶行為】
- updateDisplayPowerStateLocked() 更新顯示屏的電源狀態(tài),它會(huì)對(duì) DisplayManagerService 發(fā)起電源請(qǐng)求,從而決定屏幕屏的亮度。詳見【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)是無法決定用戶行為的
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) { // 沒有到 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沒有保持屏幕常亮,用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 的情況,也說明有多個(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í)間來定時(shí)更新電源狀態(tài),以實(shí)現(xiàn)自動(dòng)滅屏的功能。
更新用戶行為在第1步,前面分析更新 wakefulness 時(shí),PMS 保存了喚醒的時(shí)間 mLastWakeTime,以及 DisplayGroupPowerStateMapper 保存了用戶行為時(shí)間。因此,對(duì)于從滅屏狀態(tài)到亮屏狀態(tài)這一過程來說,用戶行為的值現(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ù)的過程...
// 3. 向 DisplayManagerService 發(fā)起請(qǐng)求
// 如果此次請(qǐng)求與上一次的請(qǐng)求不同,那么這個(gè)請(qǐng)求的處理是一個(gè)異步處理過程,此時(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ài)走到這里
// 如果點(diǎn)亮屏幕時(shí)間過長(zhǎng),那么用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狀態(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)求不同,那么處理過程是異步的,并且返回的 ready 狀態(tài)為 false。否則,處理過程是同步的,返回的 ready 為 true。
我們來看下如何更新請(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)的更新
前面我們剛提到過,處理屏幕請(qǐng)求的過程可能是一個(gè)異步,也可能是一個(gè)同步。如果從滅屏到亮屏,這個(gè)過程一定是一個(gè)異步的,那么 PowerManagerService 是如何得知 DisplayManagerService 已經(jīng)處理完成了呢? 其實(shí) PowerManagerService 向 DisplayManagerService 注冊(cè)過回調(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 通過回調(diào)得知 DisplayManagerService 已經(jīng)處理完屏幕請(qǐng)求,于是再次更新電源狀態(tài)。
此時(shí),updateDisplayPowerStateLocked() 再向 DisplayManagerService 發(fā)起請(qǐng)求,由于與上一次請(qǐng)求相同,因此 DisplayManagerService 不做處理,返回的 ready 狀態(tài)為 true。
更新電源狀態(tài)剩下的過程,就是收尾,我們大致看下
// 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é)
我們分析的是從滅屏到亮屏的過程,但是我們應(yīng)該看到一個(gè)本質(zhì)的問題,它其實(shí)就是向 DislayManagerService 發(fā)起請(qǐng)求,來更新屏幕狀態(tài)(例如 亮屏,滅屏)。
請(qǐng)求的策略最終決定了屏幕在狀態(tài),但是影響請(qǐng)求策略的因素有很多,例如系統(tǒng)狀態(tài)(指的是PMS的wakefulness),用戶行為,喚醒鎖,等等。我們將在后面的文章中看到更多決定請(qǐng)求策略的情況。
總結(jié)
本文雖然分析的是從滅屏到亮屏的流程,但是我們要看到一個(gè)本質(zhì)的過程,其實(shí)只有兩步
- 更新 wakefulness.
- 向 DisplayManagerService 發(fā)起請(qǐng)求,更新屏幕狀態(tài)。
以上就是PowerManagerService之亮屏流程示例分析的詳細(xì)內(nèi)容,更多關(guān)于PowerManagerService 亮屏流程的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Android使用WebView實(shí)現(xiàn)離線閱讀功能
這篇文章主要介紹了Android使用WebView實(shí)現(xiàn)離線閱讀功能,幫助大家更好的理解和學(xué)習(xí)使用Android,感興趣的朋友可以了解下2021-04-04
android的got表HOOK實(shí)現(xiàn)代碼
對(duì)于android的so文件的hook根據(jù)ELF文件特性分為:Got表hook、Sym表hook和inline hook等。今天通過本文給大家介紹android HOOK實(shí)現(xiàn)got表的實(shí)例代碼,需要的朋友參考下吧2021-08-08
Android自定義ScrollView實(shí)現(xiàn)放大回彈效果
這篇文章主要為大家詳細(xì)介紹了Android自定義ScrollView實(shí)現(xiàn)放大回彈效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-05-05
android實(shí)現(xiàn)加載動(dòng)畫對(duì)話框
這篇文章主要為大家詳細(xì)介紹了android實(shí)現(xiàn)加載動(dòng)畫對(duì)話框,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-10-10
基于SurfaceView實(shí)現(xiàn)可拖動(dòng)視頻控件
這篇文章主要為大家詳細(xì)介紹了基于SurfaceView的可拖動(dòng)視頻控件,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-04-04
Android模仿知乎的回答詳情頁(yè)的動(dòng)畫效果
這篇文章主要介紹了Android模仿“知乎”的回答詳情頁(yè)的動(dòng)畫效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-02-02
Android開發(fā)之ListView列表刷新和加載更多實(shí)現(xiàn)方法
這篇文章主要介紹了Android開發(fā)之ListView列表刷新和加載更多實(shí)現(xiàn)方法,實(shí)例分析了ListView列表操作的相關(guān)技巧,需要的朋友可以參考下2015-06-06
Mac中Eclipse連不上Android手機(jī)的解決方法
這篇文章主要介紹了Mac中Eclipse連不上Android手機(jī)的解決方法,本文方法同樣適用其它的移動(dòng)設(shè)備,需要的朋友可以參考下2015-06-06

