先来看几个问题是否能回答:
1)Android系统开发语言有两种:Java、c/c++,它们各用于开发那些层次
2)JNI实质是什么,位于什么位置,NDK又是什么
3)Android虚拟机是用于干什么的,什么时候介于工作
4)既然Android内核主要是c/c++实现的,那么是否可以用C++来写app
5)aidl又是什么,位于那一层
6)各层次的如何配合工作
1.首先来看一幅图吧:
对于这个图,基本每一个Android Developer都不会陌生。没错,这个就是刚刚接触Android的时候,所要了解Android系统框架,每一个Android入门级的书籍都不会绕开这个图。先来回顾下上面图的含义:
a. Android系统分为四层:应用层、framework层、系统库、Linux内核
b. 应用层为系统对用户所提供的应用程序,比如:Contacts--联系人或者叫通讯录
c. framework层向应用开发层开发者提供统一的api,著名的AMS、WMS、四大组件等,均位于该层
d. 系统库层提供framework层所需要的系统级实现,比如提供图形缓制相关的OpenGL、数据库存储
e. Linux内核:提供操作系统的本质功能:文件管理、内存管理、进程管理、网络协议栈等
以上基本是大家都明白的,也很容易由图上看出的,再来看一下下述结论:
f. 图中的蓝色部分是用Java代码实现的,向上层所提供的接口也是Java接口
g. 核心库与虚拟机共同构成了Android的运行时框架,提供对上层Java代码的编译解析能力
h. 绿色部分为使用c/c++语言实现的,与Java层通过JNI实现相互调用
2. 因为性能问题,Android系统的大部分内在逻辑都是用c/c++实现的,而对外开放的接口却是Java的,为什么要这么设计的,这个是和语言特点有关系的。
c/c++在算法运行效率上要比Java高几倍,当然,现在伴随着JVM优化的越来越好,差异越来越小,硬件环境也越来越好,更拉近了差距,但在系统的设计层面,运行效率高的一定比低的要好,优化的空间也要更大,积少成多,整个系统就会快很多,因此内核的实现是c/c++的。对于开发者来讲,c/c++实现诸如界面、事件之类的上层逻辑,开发成本要大不小,且c/c++对于开发者能力的积累也要求较高,api的丰富程序也不如Java,因此,使用Java提供给开发者开发复杂多变的业务是更合适的。使用了两种语言,有优点就有弊端,我的理解是,增加了Android系统实现的复杂性,看过Binder的源码同学都会有这个体会,时而Java层,时而c++层,不停的调入调出,流程烦琐而复杂。(在我之前的文章中有三篇是专门写Binder的,感兴趣可以看下)。对于理解系统源码的人,也增加了学习的成本。
再来说下JNI与NDK,首先,JNI是属于Java虚拟机的一部分,既不属于c/c++,也不属于Android,提供了Java可以调用c/c++的一种机制。这边有一个理解误区,c/c++代码是否也是通过Java虚拟机(或者是Android虚拟机)进行编译解析连接的呢?答案是否定的。c/c++是通过so接入apk的,so在Linux系统是一种ELF文件格式,可以理解为是一种可执行的文件格式。那么Java程序怎么通过虚拟机调用.so呢?通过虚拟机所提供的System.loadLibrary接口,虚拟机会去载入c/c++库,调用c/c++库中的JNI_OnLoad函数,后续过程感兴趣的同学可以参考下google官方文档中关于JNI的说明,需要注意的一点是调到c/c++层后,会将当前VM对象传入,即是c/c++代码中的JNIEnv对象。NDK是什么,NDK只是开发JNI,生成c/c++库的一个环境。也就是说如果不想太方便,完全可以直接在Android系统中通过命令编出so。NDK是属于Android的,和Java没有任何关系。
理解了JNI的实质,再来看看JNI属于上面的系统结构的那个部分:一般来讲,是framework与系统库通信的接口。有一般就会有特殊,比如自己定义so,然后使用System.loadLibrary装载,这个更应归属于应用层(毕竟是实现应用层的业务)。再额外提一点,通过System.loadLibary方式导入实现叫显式的库导入方式,还有一种隐式的导入方式:如果是系统应用,则在应用编入系统中时会装载c/c++库,如果是第三方应用,在安装的时候,使用dex2oat装载,两种装载都是在装载与应用相关的c/c++库(系统库)。
3. 以一个例子讲解下各层的合作关系吧:通过launcher的icon打开应用,以下所提到的AMS为ActivityManagerService
a. 首先,launcher也是一个app,属于应用层,其打开app为调用startActivity
b. startActivity会调到framework层的相关函数,然后逐层调用后,向AMS发送startActivity请求
c. 在b中的过程,向AMS发送startActivity,首先要获得AMS,通信方式为Binder,Binder对外的接口(Java层部分)属于Framework层,通过JNI方式调用的c++层实现,位于系统库层,binder驱动位于Linux内核层(Binder的实现原理可以看我之前发过的文章)
d. AMS处理该事件,调用launcher进程执行pauseActivity,位于应用层,执行完毕后,再次回调AMS
e. AMS查看是否需要新起一个进程(此处不再展示,详见Android的AMS模块),处理好进程后,通过Binder,通知该进程startActivity,也位于应用层
4.回过头来,再看看上面提到的几个问题
几个问题:
1) Android系统开发语言有两种:Java、c/c++,它们各用于开发那些层次
上面已有结论,请看第2条
2)JNI实质是什么,位于什么位置,NDK又是什么
上面已有结论,请看第2条
3)Android虚拟机是用于干什么的,什么时候介于工作
Android虚拟机用于编译解析Java层的代码,分系统应用和第三方应用,处理及介于方式不太一样,上面第2条中有少许提及。
4)既然Android内核主要是c/c++实现的,那么是否可以用C++来写app
可以的,目前已有NativeActivity的实现,但c/c++用于实现界面并非最好的工具,详见第2条
5)aidl又是什么,位于那一层
上面已有结论,请看第3条中的c,aidl只有binder在Java层的接口规范,因此位于framework层。
6)各层次的如何配合工作
请看第3条中示例