读书笔记:深入理解Android卷I

闲来无事,重新系统地学习一下 Android 系统的整个框架,《深入理解Android卷I》这本书之前貌似有看过,但是那时对 Android 的理解尚浅,有很多地方都没有理解,现在重读,相信一定能对 Android 系统原理有更加深入的理解,“学而时习之,不亦说乎”。

书籍的具体章节,这里就不重新码字了,有兴趣的可以自己看看。这里只是记录自己读书的一些新的发现以及心得。

虽然这本书的内容是居于 Android 2.2 的,但是 Android 的很多编程理念,原理还是相通的。

第一章:阅读前的准备工作

这一章主要介绍了 Android 的整体框架,从上到下,依次是 apps 层,framework 层,这两层是 java 环境的;然后是 native 层的各种 library,以及 Android runtime,runtime 里面包括一些核心库,以及虚拟机;(书中并没有提到 hal 层,因为 Android 2.2 还没有 hal 这个概念)然后是 linux 层。
这一章还讲述了如何搭建开发环境,make module 这样的编译方式可以自行查找模块的依赖关系,具体效果需要实践进行验证。因为自己曾经试过 make module 方式,因为某些 test 模块没有编译而被中断。但是这种编译方式,对于 aboot,boot,system image 等镜像的编译时是有效的。如果 make sepolicy 编译 sepolicy 模块有效的话,对于调试 selinux 策略倒是帮助挺大的。
另外 make -B module 会强制编译所有的目标文件,这个对于某些情况下目标文件没有更新的情况,应该会挺有用的。

第二章:深入理解JNI

这一章介绍 JNI 相关的知识,对我自己比较新的知识点就是 java 中声明的 native 函数与 so 库中的 jni 函数的关联有两种注册方式:第一种是静态方式,直接通过特定规则的程序名称来查找,例如 JNI EXPORT void JNICALL Java_android_media_MediaScanner_processFile 这种命名方式,相信大家有了解过,以前写 app 的 jni 代码,经常用这种方式;第二种方式是动态注册方式,就是系统源码中常用的 JNI_OnLoad 函数中进行动态注册,这也是作者推荐的方式,因为有一些初始化工作可以在这个函数里面实现(如果是系统源码,的确是推荐这种方式)。

第三章:深入理解 init

这一章温习了 earlyinit、init、earlyboot、boot 的 几个section 的启动顺序;还有就是 Android 2.2 的 uevent 事件是放在 init 进程中进行处理的,而新版本的 Android 是通过独立的 ueventd 进程来处理 uevent 事件的,当然,ueventd 也是由 init 进程启动的。
还有就是 init 里面通过链表管理所有的 service。
同时还学习了进程的退出,重新启动的流程,以及 property_get 是通过共享内存进行读取,而 property_set 是客户端进程通过 socket 进行进程间通信,然后由 init 进程通过权限判断后,最终对 property 进行写入。比较特殊的 ro.xxx 属性是不能修改的。最后就是调用 property_change 函数对变化后的 property 的事件处理,例如 onproperty:persist.service.adb.enable=1 ,就启动 adbd。

第四章:深入理解zygote

创建 Java 世界的三部曲:
1. 创建虚拟机–startVm
2. 注册 jni 函数
3. 通过 jni,调用 Java 中的 zygoteInit 类的 main 函数,这样就进入了 Java 世界

jni check 的作用是对 jni 调用做检查工作,但是检查会影响系统运行速度,所以一般都是 eng 版本才启用。

preloadClass 是由 framework/base/tools/preload 工具生成,它需要判断每个类的加载的时间是否大于 1250 微秒,超过这个时间类会被写入到 preload-classes 文件中,然后由 zygote 加载(之前自己对 preload-classes 的理解有误,误以为是重要的类才有需要 preload )。

UI 编程中经常使用的 com.android.R.xxx 资源是由 zygote 在 preload-resources 中加载的,它主要是加载 framework-res.apk 中的资源。

system_server 由 zygote 创建。system_server 通过 socket 向 zygote 发送创建应用进程的请求;zygote 通过创建好的 zygote 服务端,接受其他进程的请求。

通过抛出异常的方式,对 exec 的一种近似的模拟,以此来避免堆栈的浪费,很精妙的设计。

system_server 通过 init1 创建各种 native 服务,通过 init2 创建各种 java 服务。

第五章:深入理解常见类

这一章讲述的是 sp 和 wp,strong pointer 和 weak point 的概念,又是一个很晦涩的东西。有点像 java 的强引用和弱引用。
还学习了 Thead 的同步方法,以及 Looper 和 handler 的原理和用法。

第六章:深入理解Binder

Binder 是比较难理解的一个概念,通过对这一章的N次重复研读,终于搞懂了 Bp 与 Bn 的概念,binder 驱动在通信中扮演的角色,以及通信层和业务层的概念,作者分析代码很清晰明了,对 binder 的理解更加深入了。可惜的是对 binder 驱动的讲解没有,例如 Bp 与 Bn 通信是如何做到的,还有就是 binder 驱动对于共享内存的处理,这也是 binder 由于其他进程间通信的重要区分之一,毕竟内存一次拷贝比两次拷贝效率还是有优化的。这方面之前有了解了一下,但是具体原理还是需要以后深入去研究。

第七章:深入理解 Audio 系统

Audio 系统的一个很复杂的系统,因为工作中对音频的改造比较小,所以这一章粗略过了一下,主要是学习音频输出的 AudioTrack,音频输入的 AudioRecord,已经控制音频输出设备策略的 AudioPolicyService,已经音频控制的逻辑核心 AudioFlinger,还有一点就是,设备是有多个输出设备的,例如扬声器,听筒,蓝牙耳机等。

第八章:深入理解 Surface 系统

不得不说,这一章难度真的是超大,看的云里雾里的,只能粗略的阅读概要了,希望以后对 Android Surface 系统更加了解了,再深入看看这一章。虽然难,但是在作者的解读下,还是有一些体会的:Activity UI 的绘制,本身基于一个 PhoneWindow,然后 PhoneWindow 有一个 ViewRoot, ViewRoot 中有一个 decorView,还有一个 surface, decorView 中有 titleView,以及我们应用中的 Activity 的生命周期中的 onCreate 调用 setContentView 设置的 View,而 surface 是用于 PhoneWindow 的 UI 绘制的,它提供了 Canvas, 最终提供了一块 bitmap 内存,值得注意的是,多个 view 的绘制,是绘制在同一个 bitmap 内存中的。还有就是 surfaceview 是独立于应用的 surfaceview 的,它有自己的 surface,直接与底层打交道,多用于 camera 和 video,这里有一个设想,手写控件如果用 surfaceview 来实现,绘图效率是否会有大幅的提升,实际使用会遇到哪些问题,这个是值得以后去验证的。

第九章:深入理解 Vold 和 Rild

这一章主要讲解了两个 deamon 进程,Vold 和 Rild。
Vold 主要负责外部存储设备系统的管理和控制。初步学习了 uevent 事件出发,发送,接受,处理。java 层的 MountService 和 native 层的 vold 的交互。
而 Rild 即 Radio interface layer daemon,学习了 Rild 与 Baseband Process 以及 Phone 的交互,大致了解了一个拨打电话的流程。
Vold 和 Rild 都是自己之前接触比较少,这一次也算是系统的初步了解了这两个模块的原理,对 Android 系统的了解也更深一步。

第十章:深入理解 MediaScanner

本章学习了 MediaScanner,主要是通过 android.process.media 中监控到 boot_complete 的广播,然后发送 intent 启动 MediaScanService,由 MediaScanService 的工作线程启动 MediaScanner 来扫描媒体文件,并更新到 android.process.media 的 MediaProvider 中。

全书完:历时两个月,利用空闲时间,终于完成了这本书的学习,有深入研读,也有走马观花,总体来说对于 Android 的了解更加深入了。后面会继续卷II 的学习,不过,在这之前,可能要抽空完善一下手写方面的应用的开发。

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据