PowerManagerService之亮屏流程分析_powermanagerservice display(2)

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

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

// 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() 更新用户行为。这个用户行为会决定屏幕的最终亮度。
updateDisplayPowerStateLocked() 更新显示屏的电源状态,它会对 DisplayManagerService 发起电源请求,从而决定屏幕屏的亮度。

###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,

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

owerStateMapper 保存用户行为
mDisplayGroupPowerStateMapper.setUserActivitySummaryLocked(groupId,

[外链图片转存中…(img-LpmxUdDh-1715314773702)]
[外链图片转存中…(img-rTWqLPpC-1715314773702)]

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 7
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值