本文转载自:Android R DisplayManagerService(5) Proximity Sensor灭屏原理
本文基于Android 11.0源码分析
1.概述
在PMS灭屏流程中可以通过距离传感器的灭屏,它和正常灭屏原理上不同。像按Power键灭屏这类正常灭屏来说,会将PMS部分的系统状态和DMS中整体状态全部更新(PMS中唤醒状态mWakefulness会设置为ASLEEP、DOZING,DMS中display状态会设置为STATE_OFF、STATE_DOZING、STATE_DOZING_SUSPEND)。而如果是PSensor灭屏,只会将Display状态设置为STATE_OFF,同时关闭屏幕亮度,PMS中的系统状态依旧保持Awake状态。这篇文章就对PSensor亮灭屏流程和原理进行分析。
2.注册PSensor
DMS中,通过申请PROXIMITY_SCREEN_OFF_WAKE_LOCK类型WakeLock锁来注册PSensor:
mPowerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
mWakeLock = mPowerManager.newWakeLock(PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK,"TAG");
mWakeLock.acquire(); // 申请
mWakeLock.release(/*PowerManager.RELEASE_FLAG_WAIT_FOR_NO_PROXIMITY*/); // 释放
当PMS中申请该类型WakeLock后,在向DisplayMS发起请求时,DisplayPowerRequest.useProximitySensor 属性将会设置为true,表示需要使用PSensor。DisplayPowerController中收到请求后,将在updatePowerState()方法中,将针对该属性进行处理PSensor注册:
// frameworks/base/services/core/java/com/android/server/display/DisplayPowerController.java
private void updatePowerState() {
......
// Apply the proximity sensor.
if (mProximitySensor != null) {
// 如果持有PROXIMITY_SCREEN_OFF_WAKE_LOCK类型WakeLock锁,且请求Display状态不为OFF
if (mPowerRequest.useProximitySensor && state != Display.STATE_OFF) {
// 注册PSensor
setProximitySensorEnabled(true);
// PSensor收到靠近事件时,设置mScreenOffBecauseOfProximity为true,表示由于PSensor导致的灭屏
if (!mScreenOffBecauseOfProximity
&& mProximity == PROXIMITY_POSITIVE) {
mScreenOffBecauseOfProximity = true;
// 回调通知PMS收到靠近事件
sendOnProximityPositiveWithWakelock();
}
// 如果mWaitingForNegativeProximity为true,且此时PSensor状态为靠近,继续保持PSensor监听
} else if (mWaitingForNegativeProximity
&& mScreenOffBecauseOfProximity
&& mProximity == PROXIMITY_POSITIVE
&& state != Display.STATE_OFF) {
setProximitySensorEnabled(true);
// 解除PSensor监听
} else {
setProximitySensorEnabled(false);
mWaitingForNegativeProximity = false;
}
// 表示收到远离事件,重置mScreenOffBecauseOfProximity
if (mScreenOffBecauseOfProximity
&& mProximity != PROXIMITY_POSITIVE) {
mScreenOffBecauseOfProximity = false;
// 回调通知PMS收到远离事件
sendOnProximityNegativeWithWakelock();
}
} else {
mWaitingForNegativeProximity = false;
}
// 如果PSensor收到上报靠近事件,将Display状态设置为OFF进行灭屏
if (mScreenOffBecauseOfProximity) {
state = Display.STATE_OFF;
}
.......
// 设置状态
animateScreenStateChange(state, performScreenOffTransition);
......
在DisplayPowerController#updatePowerState()方法的以上代码片段中,处理PSensor相关逻辑,包括PSensor监听的注册、解除、事件处理:
-
当请求对象mPowerRequest.useProximitySensor为true,且当前Display状态处于非OFF时,通过setProximitySensorEnabled()方法设置PSensor监听;
-
当PSensor上报靠近事件时,将mScreenOffBecauseOfProximity设置为true,并执行sendOnProximityPositiveWithWakelock()方法通知PMS收到靠近事件;
-
当请求对象mPowerRequest.useProximitySensor为false,说明PMS中相关WakeLock已经释放,如果释放时带有RELEASE_FLAG_WAIT_FOR_NO_PROXIMITY标记,则mWaitingForNegativeProximity变量为true,若此时PSensor监听状态依然处于靠近状态,则不会立即解除PSensor监听;
-
如果释放WakeLock时,不带有RELEASE_FLAG_WAIT_FOR_NO_PROXIMITY标记,则解除PSensor监听,并将将mScreenOffBecauseOfProximity重置;
-
当PSensor上报远离事件时,将mScreenOffBecauseOfProximity重置为false,并执行sendOnProximityNegativeWithWakelock()方法通知PMS收到远离事件;
通过setProximitySensorEnabled()方法进行PSensor监听的注册与解除:
// frameworks/base/services/core/java/com/android/server/display/DisplayPowerController.java
private void setProximitySensorEnabled(boolean enable) {
if (enable) {
// 注册
if (!mProximitySensorEnabled) {
mProximitySensorEnabled = true;
mSensorManager.registerListener(mProximitySensorListener, mProximitySensor,
SensorManager.SENSOR_DELAY_NORMAL, mHandler);
}
// 解除
} else {
if (mProximitySensorEnabled) {
mProximitySensorEnabled = false;
// 重置PSensor监听状态
mProximity = PROXIMITY_UNKNOWN;
mPendingProximity = PROXIMITY_UNKNOWN;
mHandler.removeMessages(MSG_PROXIMITY_SENSOR_DEBOUNCED);
mSensorManager.unregisterListener(mProximitySensorListener);
//
clearPendingProximityDebounceTime();
}
}
}
3.PSensor事件处理
注册成功后,mProximitySensorListener将用来接收PSensor上报的数据:
// frameworks/base/services/core/java/com/android/server/display/DisplayPowerController.java
private final SensorEventListener mProximitySensorListener = new SensorEventListener() {
@Override
public void onSensorChanged(SensorEvent event) {
if (mProximitySensorEnabled) {
final long time = SystemClock.uptimeMillis();
// 获取上报值
final float distance = event.values[0];
// 判断是否是靠近事件
boolean positive = distance >= 0.0f && distance < mProximityThreshold;
// 处理上报事件
handleProximitySensorEvent(time, positive);
}
}
};
这个方法中,会得到PSensor上报的事件值,如果 0.0f <= distance < mProximityThreshold,说明上报了靠近事件,distance >= mProximityThreshold则说明上报了远离事件。然后调用handleProximitySensorEvent()方法,根据上报事件值来进行灭屏和亮屏流程:
// frameworks/base/services/core/java/com/android/server/display/DisplayPowerController.java
private void handleProximitySensorEvent(long time, boolean positive) {
if (mProximitySensorEnabled) {
// 两次上报事件均为远离事件时,不做处理
if (mPendingProximity == PROXIMITY_NEGATIVE && !positive) {
return; // no change
}
// 两次上报事件均为靠近事件时,不做处理
if (mPendingProximity == PROXIMITY_POSITIVE && positive) {
return; // no change
}
mHandler.removeMessages(MSG_PROXIMITY_SENSOR_DEBOUNCED);
// 上报靠近事件
if (positive) {
// 表示接下来设置靠近事件
mPendingProximity = PROXIMITY_POSITIVE;
// 设置防抖动时长,PROXIMITY_SENSOR_POSITIVE_DEBOUNCE_DELAY为0
setPendingProximityDebounceTime(
time + PROXIMITY_SENSOR_POSITIVE_DEBOUNCE_DELAY); // acquire wake lock
// 上报远离事件
} else {
mPendingProximity = PROXIMITY_NEGATIVE;
setPendingProximityDebounceTime(
time + PROXIMITY_SENSOR_NEGATIVE_DEBOUNCE_DELAY); // acquire wake lock
}
// 防抖动操作
debounceProximitySensor();
}
}
这个方法中,首先设置mPendingProximity变量,然后调用setPendingProximityDebounceTime()方法,设置PSensor事件的防抖动时长:
// frameworks/base/services/core/java/com/android/server/display/DisplayPowerController.java
private void setPendingProximityDebounceTime(long debounceTime) {
if (mPendingProximityDebounceTime < 0) {
// 向PMS中申请一个SuspendBlocker锁
mCallbacks.acquireSuspendBlocker();
}
// 更新防抖动时长
mPendingProximityDebounceTime = debounceTime;
}
最后执行debounceProximitySensor()方法,进行防抖动处理,原生流程中靠近事件和远离时间的防抖时长分别为0ms和250ms,也就是说,如果是靠近事件则立即处理,如果是远离时间,则在250ms后处理,避免由于频繁的靠近远离操作而频繁地亮灭屏。该方法如下:
// frameworks/base/services/core/java/com/android/server/display/DisplayPowerController.java
private void debounceProximitySensor() {
if (mProximitySensorEnabled
&& mPendingProximity != PROXIMITY_UNKNOWN
&& mPendingProximityDebounceTime >= 0) {
final long now = SystemClock.uptimeMillis();
// 说明当前时间已经超过规定去抖动时间
if (mPendingProximityDebounceTime <= now) {
// 更新Psensor监听状态
mProximity = mPendingProximity;
// 更新全局状态
updatePowerState();
// 清除防抖动时长,并释放SuspendBlcoker锁
clearPendingProximityDebounceTime();
// 说明还到达规定的防抖动时间
} else {
Message msg = mHandler.obtainMessage(MSG_PROXIMITY_SENSOR_DEBOUNCED);
mHandler.sendMessageAtTime(msg, mPendingProximityDebounceTime);
}
}
}
如果当前时间还不满足规定去抖动时长,则会用Handler设置一个定时操作,到达时间后再执行一次debounceProximitySensor(),完成mProximity属性的更新,然后调用updatePowerState()开始进行全局更新。
在这次更新时,将根据PSensor监听状态mProximity的值进行判断,靠近时,设置Display状态为Display.STATE_OFF,亮度也会被设置为0。
4.PMS中的工作
当PSensor监听状态发生变化时,会调用sendOnProximityPositiveWithWakelock()方法和sendOnProximityNegativeWithWakelock()方法,回调到PMS中:
// frameworks/base/services/core/java/com/android/server/display/DisplayPowerController.java
private void sendOnProximityPositiveWithWakelock() {
// 申请SuspendBlocker锁
mCallbacks.acquireSuspendBlocker();
mHandler.post(mOnProximityPositiveRunnable);
}
private final Runnable mOnProximityPositiveRunnable = new Runnable() {
@Override
public void run() {
// 回调PMS.onProximityPositive()
mCallbacks.onProximityPositive();
// 释放SuspendBlocker
mCallbacks.releaseSuspendBlocker();
}
};
private void sendOnProximityNegativeWithWakelock() {
// 申请SuspendBlocker
mCallbacks.acquireSuspendBlocker();
mHandler.post(mOnProximityNegativeRunnable);
}
private final Runnable mOnProximityNegativeRunnable = new Runnable() {
@Override
public void run() {
// 回调PMS.onProximityNegative()
mCallbacks.onProximityNegative();
// 释放SuspendBlocker
mCallbacks.releaseSuspendBlocker();
}
};
mCallbacks对象来自PMS中,所以接下来将执行到PMS中以下两个回调方法:
// frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
@Override
public void onProximityPositive() {
synchronized (mLock) {
// 表示接收到靠近事件
mProximityPositive = true;
mDirty |= DIRTY_PROXIMITY_POSITIVE;
// 更新全局Power状态
updatePowerStateLocked();
}
}
@Override
public void onProximityNegative() {
synchronized (mLock) {
// 表示接收到远离事件
mProximityPositive = false;
mDirty |= DIRTY_PROXIMITY_POSITIVE;
// 更新用户活动时间
userActivityNoUpdateLocked(SystemClock.uptimeMillis(),
PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, Process.SYSTEM_UID);
// 更新全局Power状态
updatePowerStateLocked();
}
}
当DisplayPowerController中PSensor状态发生变化时,会通知PMS中更新mProximityPositive,而且如果是远离事件,还会更新用户活动时间。这个值有何作用?发现在下面isBeingKeptAwakeLocked()方法中用到了:
private boolean isBeingKeptAwakeLocked() {
return mStayOn
|| mProximityPositive
|| (mWakeLockSummary & WAKE_LOCK_STAY_AWAKE) != 0
|| (mUserActivitySummary & (USER_ACTIVITY_SCREEN_BRIGHT
| USER_ACTIVITY_SCREEN_DIM)) != 0
|| mScreenBrightnessBoostInProgress;
}
只要任意条件为ture,那么就不会进行自动灭屏。因此,在PSensor收到靠近事件灭屏后,PMS中会一直保持唤醒状态,即使到达自动休眠时间,也不会执行自动灭屏流程。
5.总结
从整个分析来看,相比正常亮灭屏有几个特点:
-
PSensor亮灭屏,仅仅是修改display状态和亮度,PMS中会保持系统唤醒;
-
PSensor亮灭屏,不会向PhoneWindowManger报告屏幕状态;
-
PSensor灭屏后,PMS中不会自动灭屏,在收到远离事件后,会作为用户活动事件,更新用户活动时间。
以上流程时序图如下:

网友评论