SwallowJoe的博客

Be a real go-getter,
NEVER SETTLE!

0%

以下分析基于Android S.

简述

在前面两篇文章中我们打通了应用进程和Input进程,这两者通过一对名为InputChannel实际是通过socket实现的通道来通信。然后我们又梳理了窗口信息是如何更新并传递给Input进程的。现在我们简单梳理一下一次触摸事件分发给窗口的过程。

事件要分发,首先是需要找到被分发的事件和对应的目标窗口。

阅读全文 »

以下分析基于Android S.

简述

上文中,我们知道了应用View和窗口与input系统交互通道InputChannel的打通过程。有了通信通道,就可以通过这个来通信,将input事件传递给应用程序。很自然的,input系统中必须要保存代表该应用窗口的对象,用于识别以及分发事件。

还记得我们初始化WindowState时,有创建过一个InputWindowHandleWrapper类的对象,当时我们认为是将该Window注册进input系统:

阅读全文 »

以下分析基于Android S.

简述

本文集中研究input和窗口的关系, 特别是input系统是如何将事件传给正确的窗口进程的。

在Activity的resume过程中,会通过ViewRootImpl.setView向WMS传递其窗口信息,我们还是从这里入手:

阅读全文 »

以下分析基于Android S.

简述

这篇文章中我们重点关注焦点窗口的更新,所谓焦点窗口就是当前选择的窗口。在Android里可以通过下面的adb命令来查看当前的焦点窗口:

adb shell dumpsys window |grep -iE “mCurr*”

我们知道一个实体显示器对应一个DisplayId, 相应的有一个DisplayContent,如同我们人眼或者相机的对焦,同一时刻只能有一个焦点,那么对应一个Display一般来说也只有一个焦点窗口了。

我们之前一直分析的WMS.addWindow,在应用进程调用setView传入对应窗口属性之后,当然也会有焦点窗口的重新计算了:

阅读全文 »

以下分析基于Android S.

简述

前面几篇文章中,我们弄清楚了WMS中比较核心的几个类的作用以及初始化等流程。现在我们看看Activity启动时的启动窗口动画过程,以此为锲子剖析WMS相关流程。

启动窗口,如其名,最合理的地方应该是在Activity启动的时候播放其动画的,回到startActivityInner,开始看:

5-1

阅读全文 »

以下分析基于Android S.

简述

之前分析,Activity在被start时会创建其对应ActivityRecord并保存在对应DisplayContent的mTokenMap中,之后在该Activity被resume时,会通过其对应ViewRootImpl中的setView调用到WMS的addWindow方法,传入参数就是该Activity的ViewRootImpl中的W作为IWindow、存储该Activity窗口属性信息的LayoutParams以及InputChannel被传入WMS,通过这些信息创建WindowState:

阅读全文 »

以下分析基于Android S.

简述

上文中我们知道Activity的Window被添加至WMS其实就是该Activity的ViewRootImpl中的W作为IWindow、存储该Activity窗口属性信息的LayoutParams以及InputChannel被传入WMS,然后生成WindowToken, 当然之后WindowToken自然是保存在DisplayContent.mTokenMap中,该map的key即对应Activity中的mToken(LocalActivityRecord)。

在Activity的Window被添加至WMS中,我们仅仅分析了一半,然后重点区分析了DisplayContent的构建,了解了其层次结构器的创建过程以及layer的个数和Window类型对应的layer。现在我们接着看WindowToken的创建,上文中留有一个疑问:

阅读全文 »

以下分析基于Android S.

简述

在我们开始分析WMS是怎么管理不同应用的Window的时,有点一头雾水,不知如何下手。那么我们还是从单个Activity的Window被添加至WMS中来入手。

从上文中我们知道PhoneWindow是通过IWindowSession被添加的,在ViewRoontImpl中调用了addToDisplayAsUser:

1
2
3
4
res = mWindowSession.addToDisplayAsUser(mWindow, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(), userId,
mInsetsController.getRequestedVisibility(), inputChannel, mTempInsets,
mTempControls);

这里的mWindow是ViewRootImpl.W类的对象,用于WMS和该Window通信。

阅读全文 »

以下分析基于Android S.

简述

之前我们通过Vsync这个Android绘制的脉搏疏通了绘制的流程,在Activity的显示研究过程中,粗略接触了WindowManagerService,也即Android的窗口管理。

接下来我们深入探讨一下Android中的窗口管理设计,以便我们理解View、Activity、Window、Task等之间的关系。

首先还是从WindowManagerService服务的启动开始,在Android开机流程中,我们知道WMS是在引导服务和核心服务启动之后才会开始的:

阅读全文 »

简介

接上文,我们现在了解了binder驱动的加载过程,回过头继续分析App使用Binder通信的过程。

先回顾下App使用binder通信的大致过程:

  1. 创建AIDL文件,定义接口函数并在服务端app中实现,并注册进SystemServer
  2. 客户端app通过SystemServer获取服务端注册的Service所代表的IBinder(BpBinder)
    1. Client app <–> SystemServer <–> Server app
    2. Server App将Service的IBinder保存在SystemServer中,在Client App通过bindService的时候,传入。
  3. 客户端app通过该IBinder与服务端app直接通信。

之前我们分析到最后一步是:IPCThreadState#talkWithDriver

阅读全文 »

简介

接上文,想要了解binder驱动的工作原理,我们从binder驱动加载过程开始:

在android/kernel/msm-4.19/drivers/android/binder.c中,我们可以看到有这么一行:

1
device_initcall(binder_init);

在Linux内核的启动过程中,一个驱动的注册用module_init调用,即device_initcall,它的initcall 的level为6。

他可以将驱动设备加载进内核中,以供后续使用。

阅读全文 »

简介

接上文,首先回顾一下IBinder相关接口的类图:

2_4_IBinder全类图

我们知道在Client App中获取的IBinder实际上是BinderProxy类型的对象。那么在上一文中Client App调用sayHello方法过程的的#2.3.2中,我们卡住了,现在可以继续了:

1
2
3
4
virtual status_t        transact(   uint32_t code,
const Parcel& data,
Parcel* reply,
uint32_t flags = 0) = 0;
阅读全文 »

简介

接上文,首先回顾一下IBinder相关接口的类图:

DemoInterfac

现在我们Client进程已经拿到Server端IDemoInterface中的IBinder对象,但是这个IBinder对象到底是哪个呢,Stub本身?还是Proxy亦或是Proxy中的mRemote?

还是看sayHello的调用过程先:

1
2
3
4
5
6
7
8
9
10
11
12
override fun onServiceConnected(p0: ComponentName?, p1: IBinder?) {
Log.d("Client", "DemoService connected")
// 远程服务连接成功,打个招呼
// 1.1 这个asInterface是做了什么操作呢?
val mProxyBinder = IDemoInterface.Stub.asInterface(p1)
try {
// 2.1 sayHello!
mProxyBinder.sayHello(5000, "Hello?")
} catch (e:RemoteException) {

}
}
阅读全文 »

简介

在初学Android的时候,一般是从四大组件开始学起的。最开始学,是通过追代码流程的方式快速熟悉Android系统框架。

在这个速学的过程中,很多细节部分就被忽略掉了(这也是必须的,否则学起来极其痛苦且缓慢)。

比如四大组件之一的Service,在跨进程通信的时候,我们只知道是通过Binder通信的。至于内部实现是如何就不甚了了。

接下来我们通过一个简单的Demo深入探究这个跨进程通信的过程。

阅读全文 »

Andorid Q

接着上文,当我们接收到来自App RenderThread线程渲染后的Surface之后,会在SurfaceFlinger收到下一次Vsync时做合成。
前面我们也稍微分析了一下,直接看handleMessageRefresh方法:

图片

从上面trace上也可以看出收到Vsync后,sf首先调用handleMessageInvalidate检查时候需要进行合成。
如果需要就会调用方法handleMessageRefresh去做合成,最后将合成后的图像送入屏幕显示。

这里重点分析handleMessageRefresh.

阅读全文 »

Android Q

前面分析了Vsync信号的始末,其实还有很多可以细究的部分。比如硬件vsync是什么时候开始,什么时候结束?校准算法的原理等等。
接下来我们先看看SurfaceFlinger合成帧的部分。

阅读全文 »

Andorid Q

一. DispSync

DispSyncThread, 软件产生vsync的线程, 也控制硬件VSync信号同步。

接上一篇,SF EventThread在显示屏准备完毕后,会调用enableVSyncLocked,最终是在DispSync的mEventListeners中添加了一个EventListener。
我们先看DispSync线程的创建过程。

阅读全文 »

Andorid Q

一. SFEventThread

  1. EventControlThread: 控制硬件vsync的开关
  2. DispSyncThread: 软件产生vsync的线程
  3. SF EventThread: 该线程用于SurfaceFlinger接收vsync信号用于渲染
  4. App EventThread: 该线程用于接收vsync信号并且上报给App进程,App开始画图

从这4个线程,可以将vsync分为4种不同的类型

  1. HW vsync, 真实由硬件产生的vsync信号
  2. SW vsync, 由DispSync产生的vsync信号
  3. SF vsync, SF接收到的vsync信号
  4. App vsync, App接收到的vsync信号

这里我们着重看看SF EventThread.

阅读全文 »

以下分析基于Android R.

简述

上一章我们分析了SurfaceFlinger是如何根据Framework传入的帧率参数选择合适帧率的。

接来下我们详细看看SurfaceFlinger是如何通知硬件切换帧率的。

阅读全文 »