android google 分屏 多窗口 popup无法显示故障分析

原创无极限,欢迎加微信公众号 code_gg_home ,关注更多内容

问题描述
[Message][Input method]Display is wrong when message at split mode.
分屏模式下短信界面显示不正确

操作步骤
1.打开message然后退出
2.打开一个app如Call,然后长按recent键进入分屏模式
3.让message在分屏模式中处于底部,然后在message中编辑一些字符
4.长按这些字符串,不能显示出”CUT COPY SHARE”这3项  
–KO

环境描述
 android7.0.1
 屏幕分辨率 720*1280
 手机:eng版本

首先
按照bug描述,此时无法弹出pop框(cut copy…),我们第一步方向,去跟踪代码,追到此框弹出路径。(根据log分析, 使用调试工具Eclipse打断,跟踪流程),得到一条调用栈信息:

Editor.java 
—>startSelectionActionModeInternal
—>mTextView.startActionMode

DecorView.java 
—>startActionModeForChild
—>startActionMode
—>createFloatingActionMode
—>FloatingActionMode

FloatingActionMode.java
—>repositionToolbar
—>updateViewLocationInWindow
—>repositionToolbar
结论

确定位置FloatingActionMode.java  的 repositionToolbar方法上,此处 if (isContentRectWithinBounds()) 判断上:

android google 分屏 多窗口 popup无法显示故障分析_第1张图片
分析

前面的结论,写的非常粗糙,只是给出了大致结果,没有给出如何处理此问题的,如下我们慢慢展开。

01
使用hierarchyviewer 工具,我们全屏下操作出来copy 对话框,去看它的视图信息。
android google 分屏 多窗口 popup无法显示故障分析_第2张图片

展看后我们看到了:

android google 分屏 多窗口 popup无法显示故障分析_第3张图片

看下cut copy这个框中的元素,发现最终类为:FloatingActionMode.java,因此直接定位在了这个类。

大致去阅读下这个类,同时工程下搜索下这个类,很快可以看到一条轨迹。在轨迹路途加入断点,快速定位流程,搜索内容如下:

android google 分屏 多窗口 popup无法显示故障分析_第4张图片
我们可以排除StatusBarWindowView.java(因为我们不属于这里),我们忽略本身的FloatingActionMode.java ,来到了DecorView.java位置,(一看代码,有戏)
android google 分屏 多窗口 popup无法显示故障分析_第5张图片
于是我们上断点,定位出来流程。

02
通过跟踪,对比全屏和分屏下出错的流程,发现问题点在于updateToolbarVisibility 函数的调用上,全屏下会调用这个show,而出错的在分屏下的底部时,没有调用。

android google 分屏 多窗口 popup无法显示故障分析_第6张图片

于是我们继续定位,去找谁调用了这个函数。再次筛选,我们需要调用到show方法上。寻着这个路径,我们看到了本文件里面的调用关系:mMovingOff调用了updateToolbarVisibility方法

android google 分屏 多窗口 popup无法显示故障分析_第7张图片

继续找mMovingOff的调用位置,可以得到如下

android google 分屏 多窗口 popup无法显示故障分析_第8张图片

两个条件,最终确定是第一个条件出现问题,出现点为:

android google 分屏 多窗口 popup无法显示故障分析_第9张图片
这里代码的意思为:
mContentRectOnScreen 弹出框在全屏的显示区域
mScreenRect  全屏区域  (错误点在这里)
mViewRectOnScreen view在全屏的显示区域

此段代码做了校验,判断popup框是否在屏幕外,如果在,就不要画了(画了你也看不见)

错误是因为:此段代码判断结论为,popup不在可见范围,不用画。(我擦,有没搞错,我在编辑框上选个内容,需要复制,粘贴,怎么会不在可见范围,哭晕..)
然而错误的原因你会泪奔的,原因是
mContext.getResources().getDisplayMetrics().heightPixels 的值为558,而popup的位置是579(系统判断579>558 ,所以在屏幕外?OMG,我觉得是在开玩笑),郁闷的是我们手机屏幕是720*1280的,(579<1280,应该要画的)。于是我们愤怒转移到了getDisplayMetrics().heightPixels方法,此方法取出来的不是屏幕高,是不是有些崩溃,那么为什么不是呢?
03
让我们停止怀疑人生,继续来追踪
mContext.getResources().getDisplayMetrics().heightPixels 为什么会给错呢?
最终

我们发现:
  系统getDisplayMetrics().heightPixels此方法给出的是当前task的高度值,并非屏幕的高度值。
  由于之前我们没有分屏机制,所以task就是全屏的,这两个值一致,没有问题。当分屏产生时,此值大小则不是屏幕的高度了。这个属于分屏开发暴露的问题。
  至于为什么分屏在上面时候,pop能弹出来,留个疑问给大家。

我们现在来查询heightPixels从何处来。此过程太过漫长,喝杯茶,容我慢慢道来。

mContext.getResources() 找到这个方法实现的地方,通过断点,找到此处的mContext在ContextImpl.java里面

getResources() 返回mResources ,于是我们要去找mResources的赋值地方,发现在ContextImpl的构造里面:

android google 分屏 多窗口 popup无法显示故障分析_第10张图片
于是在ContextImpl的构造函数设置断点,发现确实此处传递的overrideConfiguration参数中有我们需要的错误值。
因此可以断定,此处之前已经有问题啦。

android google 分屏 多窗口 popup无法显示故障分析_第11张图片

通过栈信息,我们可以看到,此时传递的路径为WindowManagerService.java的 handle里面的ADD_STARTING case里面,调用了addStartingWindow 方法

android google 分屏 多窗口 popup无法显示故障分析_第12张图片

于是乎,我们看到了wtoken.mTask.mOverrideConfig 这个值决定了此处的overrideConfig。

如何去找哪里触发的这个case,我们搜索ADD_STARTING 

android google 分屏 多窗口 popup无法显示故障分析_第13张图片

在调用地方设置断点,如此可以找到调用路径。

android google 分屏 多窗口 popup无法显示故障分析_第14张图片

于是我们发现setAppStartingWindow 里面调用了,我们向上去找,发现了此处的wtoken里面的值已经出错(此处为279,densityDpi值为2,和之前的558对应上了),于是我们的方向便是去找这个值从哪里来的。

通过栈信息,我们找到了ActivityStarter.java 里面的 startActivityUnchecked方法,看到了此处的mStartActivity.task值已经出错,于是我们需要在此处确认此值的来源。

android google 分屏 多窗口 popup无法显示故障分析_第15张图片

于是我们向上跟踪,发现修改地方在setTaskFromReuseOrCreateNewTask函数里面,继续跟进去看:

android google 分屏 多窗口 popup无法显示故障分析_第16张图片

android google 分屏 多窗口 popup无法显示故障分析_第17张图片

结论已经出现:
由于我们的task的isResizeable()返回true,使得方法进入task.updateOverrideConfiguration(mBounds);此处task处在分屏时候,此时task的大小需要使用activity的边界值做覆盖,覆盖之后,使得我们最终调用mContext.getResources().getDisplayMetrics().heightPixels拿到的是task的高,并非屏幕的高。

等等,我们好像发现了什么?

这里我们再去细分析,发现此处逻辑没有问题,当前task如果是isResizeable的,那么我们是需要覆盖这个值的,因此这里值没有问题,此处逻辑追踪的只是想确定错误值的来源。通过看完,发现此值本身没有疑问,是task的大小,没有问题。

我们错了?why??

那我们再返回到我们定位的起点,此处判断错误,引起没有去显示popup框

android google 分屏 多窗口 popup无法显示故障分析_第18张图片

mContentRectOnScreen 弹出框在全屏的显示区域
mScreenRect  全屏区域  (错误点在这里)
mViewRectOnScreen view在全屏的显示区域

mScreenRect 系统期望拿到的是屏幕大小,(task默认不分屏下是等于屏幕大小)而此处因为分屏了,task的大小不等于屏幕大小了。

而此段代码认为mContext.getResources().getDisplayMetrics().heightPixels拿到还是系统屏幕大小,导致出错的。

结论
mContext.getResources().getDisplayMetrics().heightPixels 真正意义上是task的大小,在不分屏下,和屏幕大小相等(当然这里屏幕大小不是真正物理屏幕大小,因为还有状态栏和虚拟按键不在task的范围内,具体就不扩展了)

  于是我们的修改思路便是,需要找到此处可以拿到屏幕大小的方法,解决此问题。

修复
FloatingActionMode.java 里面,修改isContentRectWithinBounds的方法实现,具体修改为:

  修改前:
android google 分屏 多窗口 popup无法显示故障分析_第19张图片
修改后:
android google 分屏 多窗口 popup无法显示故障分析_第20张图片
编译版本,验证OK。

扫描下方二维码,关注代码GG ,或者微信搜索 code_gg_home

android google 分屏 多窗口 popup无法显示故障分析_第21张图片

你可能感兴趣的:(android,android,系统分析,android,bug与系统源码分析)