6-系统源码
SurfaceView
SurfaceView 的绘制原理
Android应用程序窗口是通过SurfaceFlinger服务来绘制自己的UI。一般来说,每一个窗口在SurfaceFlinger服务中都对应有一个 Surface,用来描述它的绘图表面。对于那些具有SurfaceView的窗口来说,每一个SurfaceView在SurfaceFlinger服务中还对应有一个独立的 Surface,用来单独描述它的绘图表面,以区别于它的宿主窗口的绘图表面。
在 WMS 中会为这个 Window 分配 Surface,并确定显示层级,可见负责显示界面的是画布 Surface,而不是窗口本身,WMS 将他管理的 Surface 交由 SurfaceFlinger 处理,SurfaceFlinger 将这些 Surface 合并后放入到 buffer 中,屏幕会定时从 buffer 中获取显示数据,显示到屏幕上。
刷新率
取的的时间
[[垂直同步vsync]]
SurfaceFlinger
- 在 App 进程中创建 PhoneWindow 后会创建 ViewRoot。ViewRoot 的创建会创建一个 Surface。
- 图像流的最常见消耗方是 SurfaceFlinger,该系统服务会消耗当前可见的 Surface,并使用窗口管理器中提供的信息将它们合成到显示部分。SurfaceFlinger 是可以修改所显示部分内容的唯一服务。SurfaceFlinger 使用 OpenGL 和 Hardware Composer 来合成一组 Surface
- HWComposer 是基于硬件来产生 VSync 信号的,来通知 SurfaceFlinger 重绘控制显示的帧率。
- 图像流生产方可以是生成图形缓冲区以供消耗的任何内容。例如 OpenGL ES、Canvas 2D 和 mediaserver 视频解码器。
Dialog不能用Application的Context
我说不能,解释的是以前在崩溃日志中看到Activity不存在,但Dialog 还存在,然后造成崩溃,后来使用DialogFragment ,这样可以管理弹窗的生命周期,不再存在Dialog 的崩溃。但不知道为什么 Dialog不能使用Application的Context。查了资料总结一下。
用Application的上下文来创建Dialog,在调用它的show方法时程序会Crash,LogCat的异常信息如下:
Caused by: android.view.WindowManager$BadTokenException: Unable to add window – token null is not for an application
Token:这里提到的Token主是指窗口令牌(Window Token),是一种特殊的Binder令牌,Wms用它唯一标识系统中的一个窗口。 必须在一个窗口上
PMS
总结
- 应用安装的时候,通过 PackageManagerService 解析 apk 的 AndroidManifest.xml 文件,提取出这个 apk 的信息写入到 system/packages.xml 文件中,这些信息包括:权限、应用包名、icon、apk 的安装位置、版本、userID 等等。packages.xml 文件位于系统目录下/data/system/packages.xml。
- 同时桌面 Launcher 会为安装过的应用生成不同的应用入口,对应桌面上的应用图标
PackageManagerService
APK安装过程 完全解析
PackageManagerService 通过名字 你可能会想起 和四大组件紧密相关的 ActivityManagerService(AMS),它俩都是运行在SystemServer进程,App端和AMS、PMS进行交互都是通过Binder跨进程完成。AMS负责Activity等四大组件的管理,而PMS则负责 包package 的管理,APK的全称是Android Package,即PMS的作用就是管理APK。
1 |
|
PMS的初始化
因为 所有App运行都需要 这些系统服务,所以是 系统开机的时候 完成 PMS、AMS这些的初始化
1 |
|
在开机系统启动时,zygote 进程会fork一个 SystemServer 进程然后执行上面main方法,这里进行大量的初始化,其中就包括 启动各种服务。 这里我们看 startBootstrapServices():
1 |
|
发现这里开启了 AMS、PMS,并且都使用了Installer。Installer 看名字像是安装器,后面再做介绍。 PMS的main方法内用构造方法创建了PMS实例,而它的构造方法内容特别多,我们关注其中一句调用scanDirTracedLI():
1 |
|
packages.xml:记录系统中 所有安装的应用信息,包括基本信息、签名和权限。
mSettings:用来保存和PMS相关的一些设置,它保存的内容在解析应用时会用到。
先读取packages.xml文件,解析后将数据存放到mSettings中,代表上次启动时的应用包信息。然后扫描所有APK目录并解析APK,最后更新packages.xml文件。 而 packages.xml文件 是在 Settings 构造方法中创建。
data/app 是用户已安装App所在的目录,另外还有system/app存放 系统App。PMS构造方法中会对 这两个目录在内的多个目录进行扫描,我们这里可以猜想到这是开机时对所有已安装App的初始化。
总结
系统启动后创建并启动了PMS,并且PMS完成了对所有存在APK的目录进行了扫描,解析所有APK的AndroidManifest.xml,然后进一步扫描APK 最后提交包扫描结果到 PMS 的属性中。
APK的安装过程
- APK用写入Session且包信息和APK安装操作 都提交到了PMS;
- PMS中先把APK拷贝到 /data/app,然后使用PackageParser2解析APK 获取 四大组件、搜集签名、PackageSetting等信息,并进行校验确保安装成功;
- 接着提交信息包更新系统状态及PMS的内存数据;
- 然后使用 Installer 准备用户目录/data/user、进行 dexOpt;
- 最后发送安装结果通知UI层。
crash流程
IntentSerVice
1 |
|
Context
- Context指:一个应用程序环境的信息,即上下文。Context 是一个接口,ContextImpl 是子类,ContextWapper 是具体实现。
Activity 因为有了 一层 Theme ,所以中间有个 ContextThemeWrapper ,相当于它是Service和Application 的侄子
Context Wrapper 是一个包装类 ,没 任何具体的实现,真正的逻辑都在 Contextlmpl里面
- 可以看出每次创建 Application 和 Acitvity 以及 Service 时就会有一个 ContextImpl 实例,ContentProvider 和B roadcastReceiver 的 Context 是其他地方传入的。
- 所以 Context 数量 = Application 数量 + Activity 数量 + Service 数量,单进程情况下 Application 数量就是 1。
- Application 的 Context 生命周期与应用程序完全相同。Activity 或者 Service 的 Context 与他们各自类生命周期相同。
- Application 通常作为工具类来使用的,Application 中在 onCreate ()方法里去初始化各种全局的变量数据是一种比较推荐的做法,但是如果你想把初始化的时间点提前到极致,也可以去重写 attachBaseContext ()方法。不能写在构造函数里。
注意
虽然 Context 神通广大,但是并不是随便拿到一个 Context 实例就可以为所欲为,还是有一些限制的。在绝大多数场景下,Activity、Service 和 Application 这三种类型的 Context 都是通用的,不过也有几种场景比较特殊,比如启动 Activity、弹出 Dialog。Android 是不允许 Activity 或 Dialog 凭空出现的,一个 Activity 的启动必须建立在另外一个 Activity 的基础之上,也就以此形成任务栈。而 Dialog 则必须在一个 Activity 的上面弹出(除非是 System Alert 类型的 Dialog),因此在这种场景下,我们只能使用 Activity 类的 Context。
- 使用 ApplicationContext 去启动一个 LaunchMode 为 standard 的 Activity。
会报错,因为非 Activity 类型的 Context 没有所谓的任务栈。
- getApplication、getApplicationContext 区别
在绝大多数场景下,getApplication 和 getApplicationContext 这两个方法完全一致,返回值也相同。区别在于 getApplication 只存在于 Activity 和 Service 对象,对于 BroadcastReceiver 和 ContentProvider 只能使用 getApplicationContext。
功能
- 四大组件的交互,包括启动 Activity、Broadcast、Service,获取 ContentResolver 等
- 确定生命周期的、获取各种资源
- 文件、SharedPreference、数据库相关
- 获取系统 / 应用资源,包括 AssetManager、PackageManager、Resources、SystemService 以及 color、string、drawable 等
Service 工作原理
众所周知, Service 有两套流程,一套是启动流程,另一套是绑定流程
假设要启动的 Service 是在一个新的进程中,启动过程可分为5个阶段
- AMS 检查启动 Service 的进程是否存在,如果不存在,先把 Service 信息存下来,然后新建一个新的进程
AMS 检查 Service 是否在 AndroidManifest 声明了 ,若没声明 则会直接报错 AMS检查启动 Service 的进程是否存在,如果不存在,先把 Seic 信息存下来,然后创建一个新的进程,在AMs 中,每个 rice ,都使用 SeviceRecord 对象来保存
你会发现,这段代码和前面介绍的 handleLaunchActivity 差不多,都是 PMS 中取出包的信息 packagelnfo ,这是一个LoadedApk 对象 ,然后获取它的 classload 反射出来一个类的对象,在这里反射的是 Service.
四大组件的逻辑都是如此,所以我们要做插件化,可以在这里做文章,换成插件的classLoader ,加载插件中的四大组件
广播原理
BroadcastManager静态注册是通过 PMS (即:PackageManagerService完成整个注册过程的,除此之外四大组件也是通过PMS完成注册)。
acitivityManagerService通知packmanagerService去查询静态广播,查到后将广播放到BroadcastQueue里,然后用handler机制去动态注册广播
内容提供者原理
原理:packmanagerservice里注册,在使用ContentResolver来进行查询操作时,query 方法层层调用到 ActivityThread 的 acquireExistingProvider 方法,根据URI字符串当中的授权host(即 authority )和当前所在用户的 userId 来获取对应的Provider实例。