微信号:code_gg_home

介绍:分享技术干货,分享最新新闻动态,分享开心段子,让大家轻松愉快的成长.

google 进入分屏后在横屏模式按home键界面错乱( 四)

2017-03-25 12:18 陆晓明

google 进入分屏后在横屏模式按home键界面错乱( 四)


你确定你了解分屏的整个流程?



代码阅读,请到此处http://androidxref.com 查看原生代码


google 分屏 横屏模式 按home键界面错乱故障分析(三)

google 分屏 横屏模式 按home键界面错乱故障分析(二)

google 分屏 横屏模式 按home键界面错乱故障分析(一)

Android 关机对话框概率没有阴影故障分析

android recent key长按事件弹起触发最近列表故障分析

google 分屏 popup无法显示故障分析


前情回顾:

google 分屏 横屏模式 按home键界面错乱故障分析(三)

上一节我们主要围绕了分屏的退出过程,我们从suystemui的长按recent key开始,追踪整个退出流程,分析了在此过程中,系统调整task的动作,处理是否需要relauncher acitivty的判断,是否判断已经退出了分屏。

最后,我们延伸了一个分割线在退出的时候处理流程。

为了我们分屏整个系列的完整性,我们这节开始研究,分屏下的转屏过程。


00

我们先看下WMS的启动过程,看下PhoneWindowManager.java的初始化流程,因为PhoneWindowManager.java这个是我们分析转屏的切入位置,因此我们顺着学习(此章节没有用倒着思维,主要是自己从逆向去讲,有些绕,我们就正常顺着讲完这一节即可)


system_server进程,是我们android的核心进程,提供了了上层app所需要的大部分服务,我们开发使用的BT WIFI POWER AMS WMS都是在system_server进程里面,以线程的方式存在,系统其他app进程通过binder(一种跨进程通信方式),来进行交互。

于是,我们这里关注WMS的服务的启动过程。


我们从SystemServer.java文件开始走起:

runtimeinit里面,通过抛出异常,执行 调用此处的main,进行SystemServer的进程初始化过程。

main走入本文件的run方法:

继续startOtherServices方法:(去掉无关代码)

这里我们看到,使用main初始化构造了一个WindowManagerService,然后调用了wm.systemReady,我们关心这里的systemReady:

于是我们看下mPolicy是什么?

是个PhoneWindowManager,于是我们这里需要看PhoneWindowManager里面的systemReady方法。我们先看下WMS这边对于mPolicy的初始化地方:

WindowManagerService的构造函数里面有

我们看下这里的initPolicy方法,完成了初始化动作。

这里init方法,完成了一个关键的初始化

mOrientationListener 是注册转屏的关键监听,我们先说这里,转回去看下mPolicy 的systemReady 方法:

这里关键的就是updateOrientationListenerLp 和updateSettings两个方法,完成旋转屏的监听注册,以及更新设置动作。

由于我们不去详细讲解这里具体的设置过程,我们只是给出信息位置。此处会根据当前的设置值,如果当前开启了屏幕旋转,则会enable这个mOrientationListener。所以我们核心关注这里。

01

我们看下mOrientationListener

发现了继承自WindowOrientationListener,核心的方法为onProposedRotationChanged,此方法接收旋转改变的变化,扔出一个post出来,看到post的run方法,便是updateRotation,我们转屏就此开始处理。

我们看下WindowOrientationListener,只关注它的构造,我们看个内容:

这里关注AccelSensorJudge ,这个是检测sensor变化的类,我们前面讲过,系统在WMS的初始化时候,初始化了一个PhoneWindowManager,这里在systemready里面进行判断当前系统状态,是否需要开启转屏,如果当前系统开启转屏,会调用WindowOrientationListener里面的enable方法:

通过mSensorManager将这个转屏检测设置下去。我们此处不去深入mSensorManager内部实现,此节不专门跟进此流程。我们只需要关注的就是,系统在开机之后,判断当前如果没有关闭检测转屏,此时就会调用enable将mOrientationJudge注册进入mSensorManager,来实时检测转屏消息,如果发生改变,则会进入自己内部的callback方法,具体为:onSensorChanged

我们这里不截屏了,onSensorChanged会去计算,当前是否达到了转屏所需要的角度,如果到了,触发 onProposedRotationChanged方法,此方法就会来到

PhoneWindowManager.java里面mOrientationListener实现的onProposedRotationChanged方法:

于是,我们知道了,转屏产生时,这里关注点是updateRotation方法了。上面的,我们再给个图,来看下这个的传递过程:

如上,流程清晰了,我们就专注看updateRotation方法了。

03

我们看下updateRotation的代码:

继续追踪:

再看:

这里会去调用updateRotationUncheckedLocked来判断是否转屏了,如果是,则会走sendNewConfiguration,去通知系统,当前需要更新状态了。关于updateRotationUncheckedLocked,我们当前不具体分析,我们讲解主要围绕分屏来扩展,因此跳过这个方法,直接去看sendNewConfiguration,看下这个代码。

04

在看这个代码之前,我们打个断点,看下我们要跟踪的流程:


我们就是要顺这个思路。我们看sendNewConfiguration方法:

这里就走入了AMS了。

computeNewConfiguration 计算出最新的配置值,然后更新。我们看updateConfigurationLocked

继续往下来看,就到了我们需要分析的核心位置了:

嗯,核心地方,代码又是一大堆,郁闷。我们慢慢看,需要关注的又给你高亮了。

mSystemThread.applyConfigurationToResources 更新当前system_server进程的资源信息。

app.thread.scheduleConfigurationChanged 通知所有的application,当前配置有变化。此过程会调用到activity的onConfigurationChanged方法,用来通知activity当前配置的更改。

紧接着两个广播:

ACTION_CONFIGURATION_CHANGED

ACTION_LOCALE_CHANGED

这个只有变更属于位置的时候才发生,主要就是语言变化。

用broadcastIntentLocked 广播出去的。


接下来有到了繁杂的流程中了:

这里使用setNewConfiguration方法,去判断是否需要变更的stack,将所有需要变更的栈,返回,然后调用resizeStackLocked,将栈里面的所有task进行修正。setNewConfiguration的内容为:

这里就是关注下onConfigurationChanged方法,此方法返回需要resize的stack列表。

 defaultDisplayContent.getDockedDividerController().onConfigurationChanged(); 这个方法完成屏幕方向变化,更新当前分割线的数据。

我们再去systemUi那边,看下Divider.java里面,也有onConfigurationChanged,还是复写的方法,我们需要关注这个,因为此方法是在转屏的时候,会触发。

我们来到SystemUIApplication.java这个是systemui进程的application实现,它会在转屏的时候,收到通知过来,我们看它里面的方法:

按照我们之前讲的,mServices里面有Divider,于是这条线就对上了。系统方向改变,会调用SystemUIApplication.java里面的onConfigurationChanged方法,这里它会调用注册进来的所有mServices,去依次通知onConfigurationChanged,这里面便有我们的分割线,嗯,就是这么完美。

05

我们回到WindowManagerService.java这里的onConfigurationChanged,前面讲解了会返回resize的stack列表,于是我们关心这里的返回值是谁给出的。

我们看到mChangedStackList用来返回,所以我们的关注点进入到stack.onConfigurationChanged()方法里面,这里for循环用来完成遍历所有的stack,来进行判断是否需要resize。

这里去掉无关的内容,我们关注updateBoundsAfterConfigChange方法。mFullscreen变量,来判断是否是全屏stack,如果是直接返回。由于我们当前在分屏模式下,这里会将全屏栈的所有TASK变为非全屏,于是我们全屏栈的TASK此处都会走下来(mFullscreen==false)我们这里看到,系统给了DOCKED_STACK_ID特殊的处理。

计算当前是否DockSide改变了,这个改变了就是代表分割线的方向。此处我们知道,当系统进入分屏模式,DOCK栈和FULL栈都会是非全屏状态,于是这里的默认返回都是true,也就意味着,这些TASK都会进行resize。这个是关健,resize决定了改变当前每个stack的大小,对应的就会修改task的大小,一直到acitivty的大小,这里会存储在activity的对应task的config里面,需要时候可以通过接口获取。

06


回到ActivityManagerService.java里面,我们看完了mWindowManager.setNewConfiguration,这里依据当前的改变,来判断是否有stack需要变化,我们因为在分屏模式下,于是这里会有需要更新的stack,于是我们此处返回有值,那么我们会进入到:

关于这里的resizeStackLocked,我们之前几节都在重复讲解,此处不再细化了。完成了这个动作(主要的内容就是这里,需要resize来处理task的updateOverrideConfiguration方法,会完成relauncher等一系列动作),下来的内容为:

拿到主栈,当前focus的栈。拿到最上面的activity(用ActivityRecord记录),然后调用ensureActivityConfigurationLocked更新它的状态。我们再简单阅读下

mStackSupervisor.ensureActivitiesVisibleLocked,为什么简单阅读呢,因为里面内容过多,没法细化去讲解,主要的含义为:判断哪些activity需要显示出来,然后我们将这些状态更新一下。(比如我最前面是个半屏透明窗口,那么系统必然要将此窗口下面的另个窗口内容显示出来,此方法便是完成这个任务)


详细的ensureActivitiesVisibleLocked内容为:(高亮关键部分,不做细致分析)


此方法的注释为:Make sure that all activities that need to be visible (that is, they currently can be seen by the user) actually are. 就是完成activity的显示判断依据。


阅读此文,可以参照

http://blog.csdn.net/jinzhuojun/article/details/50085491 两边对应来看,会更加清晰明了。此文讲的内容偏少,那就回看下之前内容,温故而知新。


如果有收获,赞赏鼓励下作者。

更多内容,关注微信公众号:代码GG之家

加微信 code_gg_boy  进入代码GG交流群





 
代码GG之家 更多文章 google 分屏 横屏模式 按home键界面错乱故障分析(三) google 分屏 横屏模式 按home键界面错乱故障分析(二) google 分屏 横屏模式 按home键界面错乱故障分析(一) Android基础进阶之学习使用AIDL进行跨进程通信 校园江湖(二)表哥出狱
猜您喜欢 CocoaChina六周年感言:坚持,积累,跟对人,做对事 抓包,只为让DBA过的更开心 启明星-数据的生产 这组图让你看清中国企业的真正实力 运维的冬天来了,我给你暖暖