前言
Power按键灭屏、 双击亮屏,本文阐述了power灭屏事件从上报到framework的处理到灭屏流程,对其他项目中存在的power亮灭屏问题有借鉴意义。
初步分析
此问题在user版本上报出,user版本日志较少且改问题复现概率极低,导致问题分析难度加大,在此前提背景下我们不妨先梳理一下power按键的灭屏代码流程 。 梳理代码得知power灭屏最终的keyevent处理是在PhoneWindowManager的interceptKeyBeforeQueueing方法中。Android12中对power按键的处理流程有做大的改动, 增加了Gesture概念,统一从原有的case KeyEvent.KEYCODE_POWER处理移到handleKeyGesture(event, interactiveAndOn)分支中进行power的长按双击单击以及其他组合手势的处理。
日志分析
从现有日志结合代码逻辑入手分析了解到 interceptKeyBeforeQueueing方法入口日志有keyevent的code类型打印, 以及我们查看代码得知power按键对应的键值是KEYCODE_POWER 26,那么我们根据测试提供的日志以及问题时间点搜索日志如下:
Line 105756: 03-12 03:47:30.693800 1288 1405 D WindowManager: KeyEvent:26
Line 105758: 03-12 03:47:30.817735 1288 1405 D WindowManager: KeyEvent:245
Line 105763: 03-12 03:47:30.867104 1288 1405 D WindowManager: KeyEvent:245
Line 105765: 03-12 03:47:30.895917 1288 1405 D WindowManager: KeyEvent:26
发现出问题的power按下抬起事件中间穿插了245的事件上报,查看245是驱动同事新增的sar事件上报,具体功能不用去纠结,查看代码也是我们interceptKeyBeforeQueueing方法中处理了。
由此我抓了一次power按下正常灭屏的日志发现 keyEvent 26的打印 down up事件中间并无其他事件的上报处理,
由此大胆怀疑是否是power 按键的down 与 up之间有其他事件的上报处理,影响power down时记录的一些状态导致power up不能正常被识别导致无法调用灭屏流程呢? 我们不妨来写一个bat脚本,模拟驱动上报keyEvent事件,10ms来循环发送keyEvent 245事件,同时进行power按键的亮灭屏动作。
验证问题
运行bat脚本之后进行power灭屏动作,发现power不灭屏概率增大到70%左右,由此实验得知我们的猜想已经被证实了90%,接着我们结合power灭屏的代码进行分析如下:
private void handleKeyGesture(KeyEvent event, boolean interactive)方法中会调用SingleKeyGestureDetector.java 中的void interceptKey(KeyEvent event, boolean interactive)
方法来记录down事件,记录down时会检测是否是power事件,如果是则记录按下的时间、以及ActiveRule等信息,
等到power up事件进入后去执行ActiveRule中的powerPress进行灭屏,
此次未灭屏是因为power down之后 给SingleKeyGestureDetector中又传入了keyEvent 245的key dwon事件,
interceptKeyDown中发现不是power按键就把ActiveRule进行了reset处理,导致后续的power up进来后无法处理。
解决方案
咨询驱动同事,power 与 sar事件是从不同的event上报的,并且无法做到互斥、顺序上报或延迟上报进行规避,此问题只能从软件层面进行规避解决。 那么我们在处理power事件的时候可以增加sar事件上报处理的过滤,不让sar事件reset我们power down事件的ActiveRule赋值,继续向下传递sar事件即可,这样既不影响sar的处理,也不影响power的响应,最终修改代码如下: PhoneWindowManager的private void handleKeyGesture(KeyEvent event, boolean interactive)方法中进行规避处理:
private void handleKeyGesture(KeyEvent event, boolean interactive) {
if (event.getKeyCode() == KeyEvent.KEYCODE_SAR_NEAR
|| event.getKeyCode() == KeyEvent.KEYCODE_SAR_CLOSE
|| event.getKeyCode() == KeyEvent.KEYCODE_SAR_FAR) {
Log.i(TAG, "Key code is not power, is sar, so not handle gesture!!!");
return;
}
if (mKeyCombinationManager.interceptKey(event, interactive)) {
// handled by combo keys manager.
mSingleKeyGestureDetector.reset();
return;
}
if (event.getKeyCode() == KEYCODE_POWER && event.getAction() == KeyEvent.ACTION_DOWN) {
mPowerKeyHandled = handleCameraGesture(event, interactive);
if (mPowerKeyHandled) {
// handled by camera gesture.
mSingleKeyGestureDetector.reset();
return;
}
}
mSingleKeyGestureDetector.interceptKey(event, interactive);
}
总结
通过问题,我们大致分析了power的按键处理流程,此问题的出现是我们增加sar事件上处理引入的问题, 没有考虑到事件并行上报处理时、对于谷歌AOSP设计处理按键流程存在的风险,通过该问题的分析解决也给我们后续项目增加keyEvent事件需求提供了思路, 做需求的同事要考虑是否有引入其他问题的风险以及影响原有流程的可能。