【问题分析】InputDispatcher无焦点窗口ANR问题【Android 14】

在这里插入图片描述

1 问题描述

Monkey跑出的无焦点窗口的ANR问题。

特点:

1)、上层WMS有焦点窗口,为Launcher。

2)、native层InputDispacher无焦点窗口,上层为”recents_animation_input_consumer“请求了焦点,但是”recents_animation_input_consumer“最终没有成为焦点窗口,原因是”NO_WINDOW“。

2 log分析

在这里插入图片描述

3 复现ANR

从log分析中可以看到发生ANR的场景的上下文:

1)、首先是SystemUI主线程比较卡顿的情况下,这种的我们要复现问题可能需要给SystemUI的绘制加点延迟。

2)、先启动了一个Activity,“com.tct.nxtvision_ui/.LauncherActivity”。

3)、随后屏幕转为了180度,即ROTATION_2。

4)、输入KeyEvent.KEYCODE_RECENT_APPS(312),切换到Launcher的Recents,并且屏幕转为0度,即ROTATION_0。

5)、接着在焦点App切换到Launcher之前,又输入了一个KeyEvent.KEYCODE_BACK(4),并且是第一步启动Activity接收到了,并且调用了finish —— KO!!!后续native层的InputDispacher出现了无焦点窗口的情况。

4 原因分析

4.1 NO_WINDOW代码分析

回到当时看log时,分析ANR出现的直接原因:

在这里插入图片描述

这里InputDispatcher侧的焦点窗口从“recents_animation_input_consumer”切走,直接原因为“NO_WINDOW”,查看到具体代码位置,FocusResolver.setInputWindows:

在这里插入图片描述

关键的地方有:

大概的内容为,局部变量currentFocus代表的是存储的焦点窗口,而windows代表的是从SurfaceFlinger处传入的最新的可接收输入事件的输入窗口列表,这里继续调用FocusResolver.getResolvedFocusWindow去寻找一个焦点窗口,并且调用FocusResolver.updateFocusedWindow来更新焦点窗口。

继续看FocusResolver.getResolvedFocusWindow:

在这里插入图片描述

这里的逻辑主要是调用FocusResolver.isTokenFocusable来判断某一个窗口是否能够作为焦点窗口:

在这里插入图片描述

这里要遍历的windows是从SurfaceFlinger发来的最新的输入窗口列表,而token是之前设置的焦点窗口,这个函数的大意是根据最新的输入窗口信息判断之前设置的焦点窗口是否有效。

那么可能有几种情况,即对应Focusability的4个值:

在这里插入图片描述

1)、返回NO_WINDOW,说明之前设置的焦点窗口已经不在最新的输入窗口列表里了,即该输入窗口的Layer已经被移除了,或者不满足Layer.needsInputInfo的条件。

2)、返回NOT_FOCUSABLE,说明之前设置的焦点窗口还在最新的输入窗口列表里,但是被设置了NOT_FOCUSABLE这个标志位,不满足作为焦点窗口的条件了。

3)、返回NOT_FOCUSABLE,说明之前设置的焦点窗口还在最新的输入窗口列表里,但是被设置了NOT_VISIBLE,即该Layer已经不可见了,所以不能再作为焦点窗口了。

4)、返回OK,找到了一个符合条件的窗口作为焦点窗口,并且将该窗口保存在传参outFocusableWindow中。

从上面的代码分析可知,焦点窗口从“recents_animation_input_consumer”切走的原因为它对应的Layer已经被移除了,或者不满足Layer.needsInputInfo的条件,继续打开DebugConfig.DEBUG_FOCUS这个开关继续看看log,发现有:

在这里插入图片描述

原因为“Window went away”,是该Layer被移除了。

4.2 recents_animation_input_consumer分析

首先看下正常情况下这个Layer的信息为:

在这里插入图片描述

它的zOrderRelativeOf就是被transientHide的那个Task。

该Layer(SurfaceControl)在创建INPUT_CONSUMER_RECENTS_ANIMATION对应的Input ConsumerImpl对象中创建:

在这里插入图片描述

显示、隐藏和移除的逻辑为:

在这里插入图片描述

4.3 “Window went away”原因分析

复现问题后,dumpsys SF的信息,发现:

在这里插入图片描述

“recents_animation_input_consumer”对应的Layer仍然存在,那为什么没有遍历到呢?

查看SurfaceFlinger向InputDispatcher更新输入窗口的地方,SurfaceFlinger.updateInputFlinger:

在这里插入图片描述

1)、SurfaceFlinger.updateInputFlinger方法的逻辑比较简单,调用SurfaceFlinger.buildWindowInfos构建一个输入窗口列表,然后发给InputDispatcher,那么关键的地方就在于SurfaceFlinger.buildWindowInfos了,它是如果选择哪个Layer可以作为输入窗口的?

2)、SurfaceFlinger.buildWindowInfos的逻辑也很简单,主要是通过Layer.needsInputInfo来判断一个Layer是否能够作为输入窗口的:

在这里插入图片描述

应该是主要是判断Layer.hasInputInfo,而“recents_animation_input_consumer”在show的时候已经设置了一个InputWindowInfo了,所以原因应该不是这个。

继续添加log,发现的确如此,“recents_animation_input_consumer”没有发送给InputDispatcher的原因是“recents_animation_input_consumer”这个Layer根本就没有遍历到!

原因则是:

在这里插入图片描述

“recents_animation_input_consumer”的相对层级的那个Task已经从Layer层级结构中被移除了,这个Task都遍历不到了,自然“recents_animation_input_consumer”也遍历不到了。

所以这个问题的根本原因是:

1)、在native层,“recents_animation_input_consumer”已经不能作为焦点窗口了,因为transientHide的那个Task已经被移除了。

2)、在上层WMS处,“recents_animation_input_consumer”仍然可以作为一个焦点窗口去请求焦点,没有考虑到transientHide的Task此时是否已经被移除。

再看下WMS处为“recents_animation_input_consumer”请求焦点的逻辑:

在这里插入图片描述

主要就是这个成员变量mActiveRecentsActivity:

在这里插入图片描述

当Recents界面被调起,就为mActiveRecentsActivity为Launcher对应的ActivityRecord,并且激活“recents_animation_input_consumer”来作为焦点窗口。

比如,当我们点击Recents的时候,会启动一个Transition:

1)、在Transition.onTransactionReady阶段,会调用Transition.handleLegacyRecentsStartBehavior来设置InputMonitor.mActiveRecentsActivity为Launcher对应的ActivityRecord。

2)、在Transition.finishTransition阶段,会将InputMonitor.mActiveRecentsActivity置为null。

在我们复现ANR的场景:

1)、在native层SF,由于和“recents_animation_input_consumer”绑定的那个transientHide的那个Task已经被移除了,所以“recents_animation_input_consumer”就不能作为焦点窗口了。

2)、在上层WMS,因为仍然处于Recents界面,这个Transition一直都不会finish,那么InputMonitor.mActiveRecentsActivity就一直不为空,那么每次走到InputMonitor.updateInputFocusRequest的时候,就会为“recents_animation_input_consumer”请求焦点。

这么看来是InputMonitor.updateInputFocusRequest为“recents_animation_input_consumer”请求焦点的这段逻辑有点问题。

5 在pixel上复现ANR

那我们如何在pixel上复现呢?从以上分析可知这个问题似乎是google原生问题,SystemUI卡顿并非复现该场景的必要条件,毕竟本题中SystemUI卡顿带来的效果的本质是,推迟Launcher称为焦点App的时间,从而让输入KEYCODE_RECENT_APPS后再次输入的KEYCODE_BACK能够被“com.tct.nxtvision_ui/.LauncherActivity”接收到做finish的操作。

那么我们需要让我们模拟的App,在输入KEYCODE_RECENT_APPS切换到Launcher后自动finish,不需要为SystemUI增加延迟,似乎也可以复现“recents_animation_input_consumer”请求不到焦点的情况。

最终果然可行,pixel的Launcher,“com.google.android.apps.nexuslauncher/.NexusLauncherActivity”也可以复现:

在这里插入图片描述

finish的代码为:

    @Overridepublic void onTopResumedActivityChanged(boolean isTopResumedActivity) {super.onTopResumedActivityChanged(isTopResumedActivity);if (!isTopResumedActivity) {Handler handler = new Handler();handler.postDelayed(new Runnable() {@Overridepublic void run() {finish();}}, 4000);}}

可以看到复现问题的路径更简单了,再次总结一下:

1)、首先是SystemUI主线程比较卡顿的情况下,这种的我们要复现问题可能需要给SystemUI的绘制加点延迟。

2)、写一个Demo App,启动“com.example.demoapp/.MainActivity”,为其设置方向android:screenOrientation=“reversePortrait”,这样它一启动屏幕就转为ROTATION_180(当然用adb命令让屏幕转成180也行,monkey应该就是这么做的,没什么区别)。

3)、输入KeyEvent.KEYCODE_RECENT_APPS(312),这将切换到Launcher的Recents,并且屏幕转为0度,即ROTATION_0。

4)、让“com.example.demoapp/.MainActivity”在切换到Launcher的4s后调用finish —— KO!!!后续native层的InputDispacher出现了无焦点窗口的情况,如果再发一个KeyEvent,我一般发KeyEvent.KEYCODE_BUTTON_C(98),比如就会复现ANR,log就如上面的贴的所示。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/779529.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

整理git上的模板框架

vite-vue3.0-ts-pinia-uni-app 技术栈的app框架 功能:基于 uni-app,一端发布多端通用,目前已经适配 H5、微信小程序、QQ小程序、Ios App、Android App。 taro3vue3tsnutuipinia taro3 框架小程序跨端平台 vue3.0-element-vite-qiankun 后台…

HarmonyOS实战开发-如何构建多种样式弹窗

介绍 本篇Codelab将介绍如何使用弹窗功能,实现四种类型弹窗。分别是:警告弹窗、自定义弹窗、日期滑动选择器弹窗、文本滑动选择器弹窗。需要完成以下功能: 点击左上角返回按钮展示警告弹窗。点击出生日期展示日期滑动选择器弹窗。点击性别展…

计算机xinput1_3.dll丢失的解决方法,分享5种有效的解决方法

在计算机系统的运行过程中,当用户或应用程序试图访问某个特定功能时,可能会遇到“找不到xinput1_3.dll”这一错误提示。这个问题通常是由于系统文件缺失或损坏导致的。许多依赖于“xinput1_3.dll”文件的游戏、软件或工具在启动时会立即遭遇阻碍。由于该…

rust使用Command库调用cmd命令或者shell命令,并支持多个参数和指定文件夹目录

想要在不同的平台上运行flutter doctor命令,就需要知道对应的平台是windows还是linux,如果是windows就需要调用cmd命令,如果是linux平台,就需要调用sh命令,所以可以通过cfg!实现不同平台的判断,然后调用不同…

Excel·VBA数组分组问题

看到一个帖子《excel吧-数据分组问题》,对一组数据分成4组,使每组的和值相近 目录 代码思路1,分组形式、可分组数代码1代码2代码2举例 2,数组所有分组形式举例 这个问题可以转化为2步:第1步,获取一组数据…

QT 控件有突出感,定义控件边框

QT 控件有突出感,定义控件边框 1.设计师页面 在flat部分选中 这个时候按钮会失去边框如下图: 然后在.cpp文件中写入代码: ui->pushButton->setStyleSheet("border: 1px solid gray;");按钮就有了新的边框:

C++11入门手册第一节,学完直接上手Qt(共两节)

入门 hello.cpp #include <iostream>int main() { std::cout << "Hello Quick Reference\n"<<endl; return 0;} 编译运行 $ g hello.cpp -o hello$ ./hello​Hello Quick Reference 变量 int number 5; // 整数float f 0.95; //…

快排(六大排序)

快速排序 快速排序是Hoare于1962年提出的一种二叉树结构的交换排序方法&#xff0c;其基本思想为&#xff1a;任取待排序元素序列中的某元素作为基准值&#xff0c;按照该排序码将待排序集合分割成两子序列&#xff0c;左子序列中所有元素均小于基准值&#xff0c;右子序列中所…

yolov8本地、autodl环境配置、训练

目录 搭建本地环境安装miniconda3创建一个新的环境安装包 安装pycharm下载汉化导入解释器测试终端终端运行代码 YOLOv8本地训练数据集制作训练文件 YOLOv8 autodl训练流程注册账号充值选则服务器jupyterlab创建训练环境上传文件训练使用vscode SSH使用pycharm专业版SSH下载文件…

最大子序列(蓝桥杯,acwing,单调队列)

题目描述&#xff1a; 输入一个长度为 n 的整数序列&#xff0c;从中找出一段长度不超过 m 的连续子序列&#xff0c;使得子序列中所有数的和最大。 注意&#xff1a; 子序列的长度至少是 1。 输入格式&#xff1a; 第一行输入两个整数 n,m。 第二行输入 n 个数&#xff0…

Matlab|电动汽车充放电V2G模型

目录 1 主要内容 1.1 模型背景 1.2 目标函数 1.3 约束条件 2 部分代码 3 效果图 4 下载链接 1 主要内容 本程序主要建立电动汽车充放电V2G模型&#xff0c;采用粒子群算法&#xff0c;在保证电动汽车用户出行需求的前提下&#xff0c;为了使工作区域电动汽车尽可能多的消…

Mojo与Python——wsl安装mojo

文章目录 前言一、wsl设置二、安装步骤三、mojo初体验四、vscode联合开发总结 前言 此课程为系列课程&#xff0c;借助python语言来学习python语言的超集mojo。可以持续关注。 一、wsl设置 powershell查看wsl的版本&#xff0c;如果版本是1需要修改为2。 二、安装步骤 1.安装m…

浅试Kimi

最近KIMI大模型挺火的&#xff0c;擅长处理中文文本&#xff0c;咱也来试试吧&#xff01; 测试问题&#xff1a; 写一篇800字以上的短片小说&#xff1a;主要故事是以一位上进但其他方面表现平平的大男孩小贱&#xff0c;刚到公司不久&#xff0c;就被一位名叫大弟的女同事看…

HarmonyOS 应用开发之多端协同

多端协同流程 多端协同流程如下图所示。 图1 多端协同流程图 约束限制 由于“多端协同任务管理”能力尚未具备&#xff0c;开发者当前只能通过开发系统应用获取设备列表&#xff0c;不支持三方应用接入。 多端协同需遵循 分布式跨设备组件启动规则。 为了获得最佳体验&…

数据分析之Power BI

POWER QUERY 获取清洗 POWER PIVOT建模分析 如何加载power pivot 文件-选项-加载项-com加载项-转到 POWER VIEW 可视呈现 如何加载power view 文件-选项-自定义功能区-不在功能区中的命令-新建组-power view-添加-确定 POWER MAP可视地图

知识图谱与大数据:区别、联系与应用

目录 前言1 知识图谱1.1 定义1.2 特点1.3 应用 2 大数据2.1 定义2.2 应用 3. 区别与联系3.1 区别3.2 联系 结语 前言 在当今信息爆炸的时代&#xff0c;数据成为了我们生活和工作中不可或缺的资源。知识图谱和大数据是两个关键概念&#xff0c;它们在人工智能、数据科学和信息…

保护电路设计 —(2)过温保护

保护电路设计 —&#xff08;2&#xff09;过温保护 上一讲讲到自锁电路设计&#xff0c;但有的同学还不太清楚怎么去复位这个电路&#xff0c;在这里给出一个例子&#xff0c;去复位这个电路。复位电路也非常简单&#xff0c;使用以下电路即可。如图1所示。 图1:复位电路 为…

HarmonyOS 应用开发之UIAbility组件间交互(设备内)

UIAbility是系统调度的最小单元。在设备内的功能模块之间跳转时&#xff0c;会涉及到启动特定的UIAbility&#xff0c;该UIAbility可以是应用内的其他UIAbility&#xff0c;也可以是其他应用的UIAbility&#xff08;例如启动三方支付UIAbility&#xff09;。 本文将从如下场景…

深入理解指针(7)函数指针变量及函数数组(文章最后放置本文所有原码)

一、函数指针变量 什么是函数指针变量呢&#xff1f; 既然是指针变量&#xff0c;那么它指向的一定是地址&#xff0c;而且我们可以通过地址来调用函数的。 函数是否有地址呢&#xff1f;地址是什么&#xff1f; 经过上面的测试可以看到函数也是有地址的&#xff0c;而且其地…

每日一练 两数相加问题(leetcode)

原题如下&#xff1a; 这道题目是一道链表题&#xff0c;我们对于这种链表类&#xff0c;很显然我们最后输出的是初始节点&#xff0c;所以我们要保留我们的初始头指针&#xff0c;那么我们的第一步一定是把头指针保留一份&#xff0c;然后再让头指针往后进行操作。那么我们进行…