1.input事件处理

input事件的重点在于 InputReaderInputDispatcher,这两个都是SystemServer进程中的两个 native 循环线程。

native 循环线程是指在 Android 系统中使用本地代码编写的循环线程,通常用于执行高性能或与硬件相关的任务

大概流程如下:

  1. InputReader:从 EventHub 读取输入事件,并交给 InputDispatcher 处理。

  2. InputDispatcher:接收事件后进行包装,寻找目标窗口并分发事件。

  3. InboundQueue (IQ):存放从 InputReader 获取的输入事件。

  4. OutboundQueue (OQ):存放即将分发给各个应用窗口的事件。

  5. WaitQueue (WQ):记录已分发给应用但尚未处理完成的事件。

  6. PendingInputEventQueue (AQ):存放应用需要处理的输入事件,表示事件已传递到应用进程。

  7. deliverInputEvent (DIE):表示应用的 UI 线程被输入事件唤醒。

  8. InputResponse (IR):表示输入事件的处理区域,包括一个 Input_Down 事件、多个 Input_Move 事件和一个 Input_Up 事件。

  9. App 响应:应用内部在其界面视图树中处理输入事件。

疑问:

上图为input事件走向。

在放入aq队列之后,唤醒应用主线程,在deliverInputEvent流程中进行时间的分发和处理,先交给window创建时的多个不同类型的InputStage中一次进行处理。

InputStage可以理解为按照策略在View和窗口之间传递,比如输入法处理逻辑的封装(ImeInputStage)

InputStage是责任链设计模式

之后进行具体处理时,会从View布局树根节点遍历,进行分发拦截处理逻辑。

事件处理结束之后,调用finishInputEvent结束处理逻辑,并通知inputDishpatcher,从wq队列中移除事件,以免ANR。

判断为点击事件之后,通过ActivityManager Binder调用AMS的startActivity服务拉起应用启动逻辑(这里从systemserver能看到)

2.应用进程创建启动

2.1 Pause桌面

上面讲到SystemServer开始执行StartActivity,开始执行StartActivityInner操作

在StartActivityInner中,会检查当前的activity是否是resume状态,是否是需要打开的应用

如果不是,那就通知当前activity执行pause状态

接着当前activity执行完onPause生命周期后,binder通知系统完成操作

AMS收到后继续进行启动应用操作,判断要启动的应用进程是否存在

如果不存在,开始创建应用进程(Start proc: com.jio.myjio)

2.2 创建应用进程

安卓系统中的进程都是由Zygote进程fork出的,需要创建新进程时,AMS会通过socket链接并通知zygote开机时创建的socket服务端,之后fork。流程如下图:

这方面涉及到开机流程详细可以去搜索了解,或者之后的文章提及

  1. 上图先链接到zygote服务端,发送socket请求,请求中包含了创建进程时的一些参数等信息,返回值包含了进程的pid号。

  2. 应用进程初始化,主要做了一下一些事情:

    1. 设置默认的java异常处理机制。

    2. JNI调用,启动了Binder线程池(自己创建的)。

    3. 通过反射调用main方法,下面看看main函数做了什么:

      1. 创建并启动主线程的Loop循环。

      2. attach进程到AMS中(通过binder注册进程)。

        主线程初始化完成之后,可以开始接收Messege由handler进行处理。

  3. 在注册进程到AMS阶段,attachapplication过程中会调用bindapplication初始化函数。

    bindapplication会做如下事情:

    1. 根据将要打开的应用创建对应apk的LoadApk对象。

    2. 创建应用的Context(上下文)。

    3. 创建类加载器触发art虚拟机加载应用的Dex文件。

    4. 通过LoadApk加载应用的Resource资源。

    5. 创建应用Application对象。

    6. 调用oncreate开始执行生命周期。

2.3 Activity创建与初始化

2.3.1 ActivityStart

  1. 创建Activity的Context对象。

  2. 通过反射创建Activity对象。

  3. 执行Activity的attach,会创建应用窗口的phoneWindow对象并设置WindowsManager。

    这一步可以理解为讲Activity与Application以及Context联系起来。

    phoneWindow是Activity窗口容器,负责管理窗口视图层次结构以及各种界面元素。

    WindowsManager是在phoneWindow中使用,用来管理和渲染应用的接口

  4. 执行Activity的oncreate生命周期函数,并在setContextView中创建窗口的DecorView。

    DecorView(装饰视图) 是整个窗口的根视图

    DecorView内部的层次结构大致如下:

    • 最外层是FrameLayout,包含了ContentView和其他装饰元素。

    • ContentView是实际显示应用UI的部分,由setContentView传入的布局文件生成。

2.3.2 ActivityResume

  1. 执行应用Activiity的onResume生命周期函数。

  2. 执行刚才的windowManager.addView开启视图绘制逻辑。

  3. 创建Activity的ViewRootImpl对象。

    它是 View 系统和 Window 系统之间的桥梁

    每个 Activity 都有一个与之关联的 ViewRootImpl 对象,用于处理窗口的绘制、输入事件的分发、以及窗口动画等。

  4. 执行VewRootImpl的setView开启UI界面绘图动作。

2.3.3 应用UI布局与绘制

我们现提一下如ActivityPhoneWindowDecorViewViewRootImplWindowManager它们之间的关系与职责。

Window

  • 抽象类,通过控制 DecorView 提供标准的 UI 方案,比如背景、标题、虚拟按键等。

  • PhoneWindowWindow 的唯一实现类,Activity 创建时生成。应用的内容会装载到其内部的 mDecor(即 DecorView)中。

DecorView

  • 是整个界面布局 View 树的根节点,负责承载和管理所有界面元素。

WindowManager

  • 是一个接口,继承自 ViewManager,提供了对 View 的基本操作方法。

  • WindowManagerImpl 是它的实现类,内部通过 WindowManagerGlobal 来操作 View

WindowManagerGlobal

  • 全局单例,负责将 View 添加到窗口中,通过 ViewRootImpl 管理 View 的显示和更新。

ViewRootImpl

  • 是所有 View 的父级,负责管理 View 的绘制以及与系统窗口管理服务(WMS)的交互。

  • 内部包含 mView(即 DecorView)、mSurface(画布),和 Choreographer(用于管理帧渲染的时序)。

    Choreographer 的引入,主要是配合系统Vsync垂直同步机制(Android“黄油计划”中引入的机制之一,协调APP生成UI数据和SurfaceFlinger合成图像,避免Tearing画面撕裂的现象),给上层 App 的渲染提供一个稳定的 Message 处理的时机,也就是 Vsync 到来的时候 ,系统通过对 Vsync 信号周期的调整,来控制每一帧绘制操作的时机。Choreographer 扮演 Android 渲染链路中承上启下的角色:

    1. 承上:负责接收和处理 App 的各种更新消息和回调,等到 Vsync 到来的时候统一处理。比如集中处理 Input(主要是 Input 事件的处理) 、Animation(动画相关)、Traversal(包括 measure、layout、draw 等操作) ,判断卡顿掉帧情况,记录 CallBack 耗时等;

    2. 启下:负责请求和接收 Vsync 信号。

  • 它是应用 UI 渲染的核心,负责将界面绘制到 mSurface 上,并协调 vsync 信号以确保流畅的渲染。

2.3.4 我们继续讲解setView

requestLayout()

  • 触发 measurelayoutdraw,即界面的重新绘制流程。

与 WMS 的交互

  • 通过 Binder 调用系统窗口管理服务(WMS)的 addWindow 接口,添加并注册应用窗口。

  • 传入 inputChannel 用于接收触控事件。此步骤完成后,View 就可以显示到屏幕上了。

事件接收

  • 创建 WindowInputEventReceiver 对象,处理应用窗口的触控事件。

View 的层次结构

  • 调用 view.assignParent(this),将 DecorView 的父类设置为 ViewRootImpl。虽然 ViewRootImpl 不是 View,但它是所有 View 的顶层父级。

而这里开始,就和我之前讲过的出帧链接在一起,大家可以看我那一片文章的详情。

安卓出帧流程 | Arden の 勇者聚集地 (ardenlee.love)