背景:
近来有有个学员朋友在锁屏画面自动息屏有一些疑问求助马哥这边,大致情况描述如下:
问题1、锁屏画面不停的点击触摸发现锁屏画面会一直常亮,这里他知道锁屏这个window比较特殊,正常其他window在InputDispatcher进行事件传递时候都会进行userActivity时间的更新,但是锁屏画面是有屏蔽userActivity操作,所以认为锁屏画面哪怕一直点击也不应该阻止息屏
问题2、锁屏画面有时候一直触摸按着界面发现也会自动的息屏,认为这个是不是一个bug
首先大家得有一点预备知识:
那就是手机为了整体功耗,其实是有对手机设置一个自动进入息屏的时间,就是手机在一段时间没有任何触摸等操作时候,手机会进行变暗,灭屏。这样目的就是为了节省功耗延迟手机的使用时间。一旦亮屏时候有用户触摸手机屏幕,那么肯定进入息屏的时间就需要从手机最后触摸时间开始计算,这里手机触摸后就会触发userActivity方法,跨进程到pms中进行统计时间的更新。
有了上面的知识背景后接下来在开始对学员提出的问题进行挨个解释分析。
问题1剖析
锁屏画面window相比普通的window有啥不一样么?这里的对于手机自动息屏部分有啥差异呢?
要查看window之间在input部分的差异最好就是看dumpsys input相关输出:
这里输出太多,就拿NotificationShade锁屏窗口和状态栏窗口StatusBar来进行对比看看
bash
1: name='728a9f0 NotificationShade', id=663, displayId=0, inputConfig=TRUSTED_OVERLAY | WATCH_OUTSIDE_TOUCH | DISABLE_USER_ACTIVITY, alpha=1.00, frame=[0,0][1080,1920], globalScale=1.000000, applicationInfo.name=, applicationInfo.token=<null>, touchableRegion=[-1080,-1920][2160,3840], ownerPid=12201, ownerUid=10143, dispatchingTimeout=5000ms, hasToken=0x7702fa8350, touchOcclusionMode=BLOCK_UNTRUSTED
transform (ROT_0) (IDENTITY)
2: name='8fb1249 StatusBar', id=285, displayId=0, inputConfig=NOT_FOCUSABLE | TRUSTED_OVERLAY, alpha=1.00, frame=[0,0][1080,74], globalScale=1.000000, applicationInfo.name=, applicationInfo.token=<null>, touchableRegion=[0,0][1080,74], ownerPid=12201, ownerUid=10143, dispatchingTimeout=5000ms, hasToken=0x7702fa8490, touchOcclusionMode=BLOCK_UNTRUSTED
transform (ROT_0) (IDENTITY)
明显可以NotificationShade的inputConfig有一个DISABLE_USER_ACTIVITY属性,这个属性就是它的特别之处相比于其他window,grep DISABLE_USER_ACTIVITY寻找相关线索:
可以大致看出在这个DISABLE_USER_ACTIVITY在java层面创建window其实是INPUT_FEATURE_DISABLE_USER_ACTIVITY这个属性进行配置和设置。
frameworks/base/core/java/android/view/WindowManager.java
cpp
/**
* When this window has focus, does not call user activity for all input events so
* the application will have to do it itself. Should only be used by
* the keyguard and phone app.
* <p>
* Should only be used by the keyguard and phone app.
* </p>
*
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public static final int INPUT_FEATURE_DISABLE_USER_ACTIVITY = 1 << 1;
注释可以看出了,当window有焦点时候,所有输入事件都不会调用userActivity方法来更新最后的活跃时间,需要app自己来控制这个活跃时间。使用该flag也只能是keyguard和phone app。
那么对应InputDispatcher部分对这个flag处理如下:
那么问题来了,既然NotificationShade输入事件是不会进行调用userActivity到power更新时间,那么为啥不停的点击时候,手机不会自动息屏?
这个问题要解答就需要去userActivity方法中打印日志堆栈,或者抓取trace来分析:
到userActivity方法加入堆栈如下:
发现在点击NotificationShade确实有调用这个userActivity方法
bash
09-27 00:28:18.947 12201 12201 I PowerManagerSerivce: java.lang.Exception
09-27 00:28:18.947 12201 12201 I PowerManagerSerivce: at android.os.PowerManager.userActivity(PowerManager.java:1482)
09-27 00:28:18.947 12201 12201 I PowerManagerSerivce: at android.os.PowerManager.userActivity(PowerManager.java:1447)
09-27 00:28:18.947 12201 12201 I PowerManagerSerivce: at com.android.systemui.keyguard.KeyguardViewMediator.userActivity(go/retraceme 82fd227f7994cdb56e784cec6bfccc2f9340b959741c421f19a58b2a7c6f0476:13)
09-27 00:28:18.947 12201 12201 I PowerManagerSerivce: at com.android.systemui.shade.NotificationPanelViewController$TouchHandler.onInterceptTouchEvent(go/retraceme 82fd227f7994cdb56e784cec6bfccc2f9340b959741c421f19a58b2a7c6f0476:978)
09-27 00:28:18.947 12201 12201 I PowerManagerSerivce: at com.android.systemui.shade.NotificationPanelView.onInterceptTouchEvent(go/retraceme 82fd227f7994cdb56e784cec6bfccc2f9340b959741c421f19a58b2a7c6f0476:3)
09-27 00:28:18.947 12201 12201 I PowerManagerSerivce: at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2657)
09-27 00:28:18.947 12201 12201 I PowerManagerSerivce: at com.android.systemui.shade.NotificationPanelView.dispatchTouchEvent(go/retraceme 82fd227f7994cdb56e784cec6bfccc2f9340b959741c421f19a58b2a7c6f0476:1)
09-27 00:28:18.947 12201 12201 I PowerManagerSerivce: at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3123)
09-27 00:28:18.947 12201 12201 I PowerManagerSerivce: at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2747)
09-27 00:28:18.947 12201 12201 I PowerManagerSerivce: at com.android.systemui.shade.NotificationShadeWindowView.dispatchTouchEvent(go/retraceme 82fd227f7994cdb56e784cec6bfccc2f9340b959741c421f19a58b2a7c6f0476:824)
09-27 00:28:18.947 12201 12201 I PowerManagerSerivce: at android.view.View.dispatchPointerEvent(View.java:15928)
根据堆栈查看到相关方法:
frameworks/base/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
这里其实就能理解上面的注释,InputDispatcher中虽然已经屏蔽了userActivity,但是app可以自己根据情况控制userActivity的调用。这里发现确实只在down事件有调用,但是其他move等事件没有调用,所以这里可以解释清楚,锁屏画面时候一定要不停地点击画面才可以保持不会自动进行息屏。
问题2剖析
有了问题1的结论,即NotificationShade窗口只会在down事件时候发送userActivity,那么意味着其他事件不会发送userActivity,所以经过测试结果如下:
只要触摸按下后一直停留在NotificationShade窗口进行移动,移动事件根本不会调用userActivity,所以到了自动息屏时间后一样会进行息屏,因为除了down事件,其他事件根本不会对进行userActivity更新自动息屏时间。
更多framework详细代码和资料参考如下链接
投屏专题部分:
https://mp.weixin.qq.com/s/IGm6VHMiAOPejC_H3N_SNg
hal+perfetto+surfaceflinger
https://mp.weixin.qq.com/s/LbVLnu1udqExHVKxd74ILg
其他课程七件套专题:
点击这里
https://mp.weixin.qq.com/s/Qv8zjgQ0CkalKmvi8tMGaw
视频试看:
https://www.bilibili.com/video/BV1wc41117L4/
参考相关链接:
https://blog.csdn.net/zhimokf/article/details/137958615
更多framework假威风耗:androidframework007