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. 更新電源狀態(tài)
updatePowerStateLocked();
}
}
}
注意,PowerManagerService#wakeUp() 只能操作默認分組下的屏幕。
Android 不知何時起,對多屏幕添加了一個分組功能,手機通常只有一個屏幕,它屬于默認分組。
亮屏的過程有兩步
- 更新 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 {
// ...
// 設置 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,優(yōu)先級如下
// 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。這里還會通知其它系統(tǒng)組件,wakefulness/交互狀態(tài) 改變了。詳見【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改變 或者 交互狀態(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:
// 記錄并檢測是否有權限
mNotifier.onWakeUp(reason, details, uid, opPackageName, opUid);
if (sQuiescent) {
mDirty |= DIRTY_QUIESCENT;
}
break;
// ...
}
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
}
根據英文注釋,更新 PMS 的 wakefulness 過程分為三個階段,最主要的是在第二個階段,更新 wakefulness 相關變量,然后 Notifier 通知其它組件并發(fā)送亮屏通知,過程如下,大家看一下就行,這不是重點。
// 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í)行完
// 這里會先執(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 更新關于交互狀態(tài)的變量
mInteractive = interactive;
mInteractiveChangeReason = reason;
mInteractiveChangeStartTime = eventTime;
// 交互狀態(tài)正在改變
mInteractiveChanging = true;
// 2.3 處理早期的交互狀態(tài)改變任務
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 保存用戶行為時間
// 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) {
// 這里處理延長亮屏的時間的邏輯 ...
} 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 標志位,表示用戶活動有更新,后面更新電源狀態(tài)會用到。
簡單看下第一步的過程,如下
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 正在執(zhí)行翻轉滅屏任務,此時有用戶行為,取消這個任務
mFaceDownDetector.userActivity(event);
}
1.3 更新 wakefulness 小結
通過上面的分析,我們應該看到一個本質,更新 wakefulness 流程大致如下
- 更新 DisplayGroupPowerStateMapper 的 wakefulness,mDirty 設置標志位 DIRTY_DISPLAY_GROUP_WAKEFULNESS。
- 更新 PowerManagerService 的 wakefulness,mDirty 設置標志位 DIRTY_WAKEFULNESS.
- Notifier 通知其它組件 wakefulness/交互狀態(tài) 改變了,并發(fā)送亮屏/滅屏的廣播。
2. 更新電源狀態(tài)
// 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狀態(tài)
// 如果進入某一種狀態(tài),會更新 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 的所有功能都集中在這個函數中,但是與亮屏相關的主要有兩步
- updateUserActivitySummaryLocked() 更新用戶行為。這個用戶行為會決定屏幕的最終亮度。詳見【2.1 更新用戶行為】
- updateDisplayPowerStateLocked() 更新顯示屏的電源狀態(tài),它會對 DisplayManagerService 發(fā)起電源請求,從而決定屏幕屏的亮度。詳見【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);
// 默認為 -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;
// 注意,休眠狀態(tài)是無法決定用戶行為的
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. 定時更新電源狀態(tài)
// 這一步決定自動滅屏
if (hasUserActivitySummary && nextTimeout >= 0) {
scheduleUserInactivityTimeout(nextTimeout);
}
}
這個函數不單單是用于更新用戶行為,還更新了屏幕超時時間,并且以這個時間來定時更新電源狀態(tài),以實現自動滅屏的功能。
更新用戶行為在第1步,前面分析更新 wakefulness 時,PMS 保存了喚醒的時間 mLastWakeTime,以及 DisplayGroupPowerStateMapper 保存了用戶行為時間。因此,對于從滅屏狀態(tài)到亮屏狀態(tài)這一過程來說,用戶行為的值現在是 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 的請求
final DisplayPowerRequest displayPowerRequest =
mDisplayGroupPowerStateMapper.getPowerRequestLocked(groupId);
// 2. 更新請求的各種參數
// 更新請求的策略參數,所謂的策略,就是亮屏,還是滅屏,或者使屏幕變暗,等等
displayPowerRequest.policy = getDesiredScreenPolicyLocked(groupId);
// ...省略更新其它請求參數的過程...
// 3. 向 DisplayManagerService 發(fā)起請求
// 如果此次請求與上一次的請求不同,那么這個請求的處理是一個異步處理過程,此時返回 false。
// 否則,不用處理,直接返回 true。
final boolean ready = mDisplayManagerInternal.requestPowerState(groupId,
displayPowerRequest, mRequestWaitForNegativeProximity);
// 更新 DisplayGroupPowerStateMapper 的 ready 狀態(tài)
final boolean displayReadyStateChanged =
mDisplayGroupPowerStateMapper.setDisplayGroupReadyLocked(groupId, ready);
// 如果異步請求處理完畢,DMS 會回調通知 PMS,PMS 再更新狀態(tài)走到這里
// 如果點亮屏幕時間過長,那么用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)的很清晰,如下
- 首先獲取請求,并更新請求參數。請求參數中,主要關心的是策略參數,它決定了屏幕的狀態(tài),也就是到底是亮屏還是滅屏。
- 向 DisplayManagerService 發(fā)起請求。注意,如果當前的請求與上一次請求不同,那么處理過程是異步的,并且返回的 ready 狀態(tài)為 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 發(fā)起請求時,最終會導致屏幕點亮。
2.3 處理屏幕狀態(tài)的更新
前面我們剛提到過,處理屏幕請求的過程可能是一個異步,也可能是一個同步。如果從滅屏到亮屏,這個過程一定是一個異步的,那么 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) {
// 表示屏幕狀態(tài)更新了
mDirty |= DIRTY_ACTUAL_DISPLAY_POWER_STATE_UPDATED;
updatePowerStateLocked();
}
}
}
當 PowerManagerService 通過回調得知 DisplayManagerService 已經處理完屏幕請求,于是再次更新電源狀態(tài)。
此時,updateDisplayPowerStateLocked() 再向 DisplayManagerService 發(fā)起請求,由于與上一次請求相同,因此 DisplayManagerService 不做處理,返回的 ready 狀態(tài)為 true。
更新電源狀態(tài)剩下的過程,就是收尾,我們大致看下
// 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;
// 處理交互狀態(tài)的后期任務
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 發(fā)起請求,來更新屏幕狀態(tài)(例如 亮屏,滅屏)。
請求的策略最終決定了屏幕在狀態(tài),但是影響請求策略的因素有很多,例如系統(tǒng)狀態(tài)(指的是PMS的wakefulness),用戶行為,喚醒鎖,等等。我們將在后面的文章中看到更多決定請求策略的情況。
總結
本文雖然分析的是從滅屏到亮屏的流程,但是我們要看到一個本質的過程,其實只有兩步
- 更新 wakefulness.
- 向 DisplayManagerService 發(fā)起請求,更新屏幕狀態(tài)。
以上就是PowerManagerService之亮屏流程示例分析的詳細內容,更多關于PowerManagerService 亮屏流程的資料請關注腳本之家其它相關文章!
相關文章
android中AutoCompleteTextView的簡單用法(實現搜索歷史)
本篇文章主要介紹了android中AutoCompleteTextView的簡單用法(自動提示),有需要的可以了解一下。2016-11-11
分享Android平板電腦上開發(fā)應用程序不能全屏顯示的問題解決
在一個8寸屏的Android平板電腦上開發(fā)應用程序(游戲程序),開始的時候,總是不能全屏顯示,也不知道怎么設置才可以2013-05-05
Android編程實現創(chuàng)建,刪除,判斷快捷方式的方法
這篇文章主要介紹了Android編程實現創(chuàng)建,刪除,判斷快捷方式的方法,結合實例形式分析了Android編程針對快捷方式的常用操作技巧,需要的朋友可以參考下2017-02-02
Android開發(fā)入門之Notification用法分析
這篇文章主要介紹了Android中Notification用法,較為詳細的分析了Notification的功能、使用步驟與相關注意事項,需要的朋友可以參考下2016-07-07
Android下錄制App操作生成Gif動態(tài)圖的全過程
這篇文章主要為大家分享了Android下錄制App操作生成Gif動態(tài)圖的全過程,感興趣的小伙伴們可以參考一下2016-01-01

