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

前言

"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 提前消费
相关推荐
irving同学462386 小时前
TypeORM 列装饰器完整总结
前端·后端·nestjs
彭于晏爱编程6 小时前
你真的了解 Map、Set 嘛
前端
崔璨6 小时前
详解Vue3的响应式系统
前端·vue.js
摸鱼的鱼lv6 小时前
🔥 Vue.js组件通信全攻略:从父子传值到全局状态管理,一篇搞定所有场景!🚀
前端·vue.js
IT_陈寒6 小时前
Java性能优化:10个让你的Spring Boot应用提速300%的隐藏技巧
前端·人工智能·后端
whysqwhw6 小时前
Hippy 跨平台框架扩展原生自定义组件的完整实现方案对比
前端
dasseinzumtode7 小时前
nestJS 使用ExcelJS 实现数据的excel导出功能
前端·后端·node.js
子兮曰7 小时前
🔥C盘告急!WSL磁盘暴增?三招秒清20GB+空间
前端·windows·docker
Jinuss7 小时前
Vue3源码reactivity响应式篇之EffectScope
前端·vue3