记一次从“按钮点不动”到“窗口派发缺失”的排查过程

前言

"xx机型 进入待支付页面之后,【<】按钮点击没反应"

------ 这是测试同事最初的反馈。很多时候,我们会下意识把它当成:按钮被遮挡 / 没绑定监听 / 点击区域偏移 / 压力测试后状态异常。

但当我接手复测后,发现问题并不只是"一个按钮点不了",而是"整个上半屏(Dialog 之外的背景区域)完全没有触摸响应"。

这个"问题再界定"过程,直接决定了后续排查维度:从"控件级"转向"窗口输入命中级"。

最终根因是:一个看似纯视觉效果的窗口 Flag ------ FLAG_DIM_BEHIND ------ 在特定 ROM 上被策略层放大为"模态化处理",导致外部区域触摸事件被系统直接吞掉,没有分发进应用。下面详细展开全过程,并总结出可复用的输入排查方法论。

现象精确描述

场景:订单待支付页面,底部弹出一个自定义 Dialog(类似 Bottom Sheet 样式)。

  • Dialog 内部:按钮、列表项点击全部正常
  • 上半屏(Dialog 之外的可见 Activity 背景区域):完全无触摸响应(点击不触发埋点、也不触发全局触摸监控)
  • 预期:点击背景区域应允许关闭弹层或继续交互(例如点击返回)
  • 复现范围:特定 OEM(定制 ROM)出现;其他主流品牌正常
  • 伴随现象:无异常崩溃日志;无明显 ANR;

分层排查策略总览

Android 输入链路(简化):

sql 复制代码
物理触摸 → InputReader(读取设备事件)→ InputDispatcher(命中并派发)→ 应用 Window → DecorView / ViewGroup 分发 → 具体控件

目标:判断事件卡在哪一层。我们采用"自外向内"策略:先确认系统是否把事件派发给应用,再看应用内部是否消费/拦截。

事件是否进入应用窗口(系统派发层)

推荐 Perfetto 手指在本该响应的触摸区域,按下 滑动,抬起,重复多次,抓取 trace

  • Outbound(俗称 oq):InputDispatcher 针对目标窗口的派发队列事件

发现 没有对应oq分配到 app的 Window

查看APP 对应window 属性

adb shell dumpsys window

xml 复制代码
  Window #9 Window{11b6259 u0 xxx.xxx.xxx.xx/xxx.xxx.xxx.xx.ui.runningorder.OrderActivity}:
    mDisplayId=0 rootTaskId=462 mSession=Session{894b5d8 1199:u0a10560} mClient=android.os.BinderProxy@fde26a0
    mOwnerUid=10560 showForAllUsers=false package=xxx.xxx.xxx.xx appop=NONE
    mAttrs={(0,0)(fillxwrap) gr=BOTTOM CENTER_VERTICAL sim={adjust=pan} ty=APPLICATION fmt=TRANSPARENT wanim=0x7f120322 surfaceInsets=Rect(93, 93 - 93, 93) mSaturation=-2.0
    // DIM_BEHIND 这个 FLAG : 猜测某机型 会把带 DIM_BEHIND 的窗口仍当成"模态"对待,外区域不下发触摸(或被直接丢弃)
      fl=DIM_BEHIND NOT_TOUCH_MODAL SPLIT_TOUCH HARDWARE_ACCELERATED
      ...
    Requested w=1080 h=918 mLayoutSeq=5622
  Window #10 Window{344f9c2 u0 xxx.xxx.xxx.xx/xxx.xxx.xxx.xx.ui.runningorder.OrderActivity}:
    mDisplayId=0 rootTaskId=462 mSession=Session{894b5d8 1199:u0a10560} mClient=android.os.BinderProxy@125460d
    mOwnerUid=10560 showForAllUsers=false package=xxx.xxx.xxx.xx appop=NONE
    mAttrs={(0,0)(fillxfill) sim={state=always_hidden adjust=resize forwardNavigation} layoutInDisplayCutoutMode=always ty=BASE_APPLICATION wanim=0x1030309 mSaturation=-2.0
      fl=LAYOUT_IN_SCREEN LAYOUT_INSET_DECOR SPLIT_TOUCH HARDWARE_ACCELERATED DRAWS_SYSTEM_BAR_BACKGROUNDS
      ...

11b6259 (dialog 弹窗) ->

344f9c2 背景Activity ->

修改验证

java 复制代码
// dialog window设置
...
//增加这一行: 手动清除 FLAG_DIM_BEHIND ,目前项目中有设置展开Dialog时,显示背景,所以这个属性,是不需要的
window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
window.setFlags(
                    WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
                    WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
            );
...

验证

adb shell dumpsys window

xml 复制代码
// 弹窗
Window #11 Window{682c4ff u0 xxx.xxx.xxx.xx/xxx.xxx.xxx.xx.ui.runningorder.OrderActivity}:
    mDisplayId=0 rootTaskId=467 mSession=Session{f6119c4 1473:u0a10560} mClient=android.os.BinderProxy@72c741e
    mOwnerUid=10560 showForAllUsers=false package=xxx.xxx.xxx.xx appop=NONE
    mAttrs={(0,0)(fillxwrap) gr=BOTTOM CENTER_VERTICAL sim={adjust=pan} ty=APPLICATION fmt=TRANSPARENT wanim=0x7f120322 surfaceInsets=Rect(93, 93 - 93, 93) mSaturation=-2.0
    // fl 已经没有那个属性了
      fl=NOT_TOUCH_MODAL SPLIT_TOUCH HARDWARE_ACCELERATED
     ...
    //背景层
  Window #12 Window{acf7b41 u0 xxx.xxx.xxx.xx/xxx.xxx.xxx.xx.ui.runningorder.OrderActivity}:
    mDisplayId=0 rootTaskId=467 mSession=Session{f6119c4 1473:u0a10560} mClient=android.os.BinderProxy@670f228
    mOwnerUid=10560 showForAllUsers=false package=xxx.xxx.xxx.xx appop=NONE
    mAttrs={(0,0)(fillxfill) sim={state=always_hidden adjust=resize forwardNavigation} layoutInDisplayCutoutMode=always ty=BASE_APPLICATION wanim=0x1030309 mSaturation=-2.0
      fl=LAYOUT_IN_SCREEN LAYOUT_INSET_DECOR SPLIT_TOUCH HARDWARE_ACCELERATED DRAWS_SYSTEM_BAR_BACKGROUNDS
     ...

问题解决:尝试滑动,点击先前无响应的该区域,可以正常响应。

排查思路总结

  1. 先界定范围:单控件?一块区域?全局?(区域性 → 优先怀疑 Window 命中 / 策略)
  2. 抓 trace(Perfetto):
    • 有 outbound(派发到目标窗口)吗?
  3. 无 outbound:
    • 用 dumpsys window 看目标窗口 flags / type / Z 序
    • 用 dumpsys input 看 FocusedWindow、touchableRegion
    • 检查是否被其他高层窗口/遮罩/系统策略截走
  4. 有 outbound 但应用没反应:
    • Activity.dispatchTouchEvent 是否触发?
    • View 层是否被透明遮挡 / intercept / clickable=false
    • 是否被 GestureDetector / OnTouchListener 提前消费
相关推荐
IT_陈寒4 分钟前
Python项目实战经验分享:为什么你的多进程日志会丢失?
前端·人工智能·后端
柳杉12 分钟前
让 AI 学会审美、建模和剪片:我收藏夹里的 14 个仓库
前端·ai编程·three.js
前端架构师-老李17 分钟前
HTML与CSS基础第七课—HTML 中的a标签(跳转链接)
前端·css·html
陈随易1 小时前
一个网吧网管,做了个网页,卖了 5000 万
前端·后端·程序员
jktantan9 小时前
Vue keep-alive 切标签后滚动位置回顶?因为 onDeactivated 里读到的 scrollTop 是 0
前端·javascript·vue.js
2601_9628857210 小时前
quotes 字段全解:涨跌幅、振幅、换手率的口径与单位
java·前端·spring
excel10 小时前
encodeURI 和 encodeURIComponent 有什么区别?
前端
前端精髓11 小时前
调用openrouter的免费API模型
java·前端·javascript
赛博守夜人11 小时前
AI安全攻防与治理之十四:AI 安全测试不能脱离传统安全,Web、API、移动端与模型攻击面的组合拳
前端·人工智能·安全
开开心心_Every11 小时前
快速隐藏程序工具自定义快捷键一键切换
java·开发语言·前端·spring·智能手机·word·intellij-idea