【问题分析】放大镜影响权限弹窗接收事件【Android14】

在这里插入图片描述

1 问题描述

在这里插入图片描述

如图,打开google的放大镜功能,然后将该放大镜和权限弹窗部分重合,会发现权限弹窗的按钮如“Allow”,点击无响应。

顺便一提,如果放大镜和权限弹窗完全重合或者完全不重合,是没问题的。

2 问题分析

2.1 分析1

首先权限弹窗View层级结构为:

在这里插入图片描述

对应的按钮为“SecureButton”。

打开一些log开关,首先是正常的log:

在这里插入图片描述

MotionEvent传到“SecureButton”并且也被这个Buttion处理了。

再看异常log为:

在这里插入图片描述

这里的很多log信息都是MTK的log打印的,能知道的信息是,MotionEvent已经传到“SecureButton”了,但是“SecureButton”没有处理,最终处理MotionEvent的是一个父View,LinearLayout。

2.2 分析2

既然事件已经传到了SecureButton了,那么再看具体的View类处理MotionEvent的代码,View.dispatchTouchEvent:

在这里插入图片描述

很值得怀疑的一个点就是View.onFilterTouchEventForSecurity是不是拦截了MotionEvent发给onTouch以及onTouchEvent来处理事件,打个断点看看:

在这里插入图片描述

果然,这里的View.onFilterTouchEventForSecurity走进了“SecureButton”自己重写的onFilterTouchEventForSecurity方法中,并且返回了false,导致MotionEvent没有被“SecureButton”处理。

反编译apk看到“SecureButton”重写的onFilterTouchEventForSecurity方法为:

在这里插入图片描述

看下这里的MotionEvent的flag:

在这里插入图片描述

FLAG_WINDOW_IS_OBSCURED和FLAG_WINDOW_IS_PARTIALLY_OBSCURED都表示接收MotionEvent的窗口被另外一个位于它之上的可见窗口遮挡了,但是不同点的是:

1)、FLAG_WINDOW_IS_OBSCURED表示MotionEvent落在了被遮挡的区域。

2)、FLAG_WINDOW_IS_PARTIALLY_OBSCURED表示MotionEvent落在了被遮挡区域以外的区域,也就是没被遮挡的区域。

那么回头再看看异常的log,果然:

在这里插入图片描述

这里的MotionEvent的flag为0x2,那么也就是包含了FLAG_WINDOW_IS_PARTIALLY_OBSCURED这个flag,所以传入“SecureButton”自己重写的onFilterTouchEventForSecurity方法后会返回false。

2.3 分析3

最后看下FLAG_WINDOW_IS_PARTIALLY_OBSCURED这个flag是在哪里添加的。

在InputDispatcher.findTouchedWindowTargetsLocked:

在这里插入图片描述

如果InputDispatcher.isWindowObscuredLocked返回true,那么就表示找个窗口被遮挡,就要为找个窗口对应的WindowInfo添加WINDOW_IS_PARTIALLY_OBSCURED标志位。

在这里插入图片描述

这里的逻辑也比较简单,从上到下找能够遮挡当前Window的WindowInfoHandle,找到当前窗口的时候就结束。

根据我添加的log,看到遮挡的WindowInfoHandle为请求权限弹窗的那个界面窗口克隆出的窗口,被遮挡的自然就是权限弹窗:

在这里插入图片描述

符合我们dumpsys input的信息:

在这里插入图片描述

input大概示意图为:

在这里插入图片描述

1)、开启放大镜后,会为每一个Layer克隆一个Layer出来,并且这些克隆体的层级整体都比真身高。

2)、根据InputDispatcher.canBeObscuredBy的逻辑,如果WindowInfo包含以下信息,则不遮挡:

  • NOT_VISIBLE的窗口不遮挡。
  • NOT_TOUCHABLE的窗口不遮挡。
  • TRUSTED_OVERLAY的窗口不遮挡。
  • 相同uid的窗口不遮挡。
  • 相同token的窗口不遮挡。
  • 不同displayId的窗口不遮挡。

排除以上条件的WindowInfoHandle后,第一个遮挡的窗口就是申请权限弹窗的那个界面的窗口的克隆窗口。

但是pixel没有问题,查看信息后发现,pixel似乎对每一个克隆出来的InputWindowHandle都添加了TRUSTED_OVERLAY这个flag:

在这里插入图片描述

下一步需要继续查找这个差异。

2.4 分析4

搜索代码,查看为WindowInfo添加TRUSTED_OVERLAY的位置主要是两处:

1)、一个是旧的流程:在Layer.fillInputInfo中:

在这里插入图片描述

2)、一个是新的流程:在LayerSnapshotBuilder.updateInput中:

在这里插入图片描述

具体走哪个流程,则是和SurfaceFlinger.commit的以下逻辑有关,受SurfaceFlinger.mLayerLifecycleManagerEnabled的控制:

在这里插入图片描述

如果SurfaceFlinger.mLayerLifecycleManagerEnabled为true,那么走新流程,否则走旧流程。

从目前的信息来看:

1)、我们的Android14的机器走的是SurfaceFlinger的旧流程,有问题。

2)、Android14的pixel走的是SurfaceFlinger的新流程,没问题。

3)、我们的Android15的机器走的是SurfaceFlinger的新流程,没问题。

根据是SurfaceFlinger.dumpAll中,可以输出SurfaceFlinger.mLayerLifecycleManagerEnabled的值:

在这里插入图片描述

并且Android14的pixel的SF是有这个信息的:

在这里插入图片描述

而我们的机器则没有。

因此这个问题应该是原生问题。

2.5 小延伸一下

现在已经知道了权限弹窗没有办法响应MotionEvent是因为,它被请求权限弹窗的那个Activity的窗口的克隆窗口盖住了,即我们刚刚的示意图:

在这里插入图片描述

另外如我们最开始提到的,如果放大镜和权限弹窗完全重合或者完全不重合,是没问题的。

完全不重合没问题,这个很好理解,既然不重合了,那就不存在遮挡的情况了,那完全重合为啥也没问题呢?

打印了log后发现其实原理很简单,完全重合后,点击的区域就是权限弹窗的克隆窗口,这个克隆窗口同样也能接收事件,因此事件直接被权限弹窗的克隆窗口接收了:

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值