一,Android Framework架构介绍
1.Android系统架构
Android本质就是在标准的Linux系统上增加了Java虚拟机Dalvik/ART,并在Dalvik/ART虚拟机上搭建了一个JAVA的application framework,所有的应用程序都是基于JAVA的application framework之上。
Android分为四个层,从高层到低层分别是应用程序层、应用程序框架层、系统运行库层和Linux内核层。
Linux 内核
原生 C/C++ 库 + Android Runtime
Java API 框架(Android Framework 框架层)
系统应用
1)APPLICATION (System Apps)
该层提供一些核心应用程序包,主要为系统中的应用,如桌面,闹铃,设置,日历,电话,短信等系统应用。同时,应用开发工程师设计和编写属于的应用程序也在这一层。
2)APPLICATION FRAMEWORK(Java API 框架)
应用框架层为开发人员提供了可以开发应用程序所需要的API,我们平常开发应用程序都是调用的这一层所提供的API,当然也包括系统的应用。这一层的是由Java代码编写的,所以可以称为Java Framework。应用框架层是系统的核心部分,一方面向上提供接口给应用层调用,另一方面向下与C/C++程序库以及硬件抽象层等进行衔接。
应用程序框架层包括活动管理器、位置管理器、包管理器、通知管理器、资源管理器、 电话管理器、窗口管理器、内容提供者、视图系统和XMPP服务十个部分。
3)系统运行库层(C/C++程序库和Android运行时库)
① C/C++程序库
Android 包含一些C/C++库,这些库能被Android系统中不同的组件使用。它们通过 Android 应用程序框架为开发者提供服务。以下是一些核心库:
② Android Runtime运行时库
运行时库又分为核心库和ART(5.0系统之后,Dalvik虚拟机被ART取代)。核心库提供了Java语言核心库的大多数功能,这样开发者可以使用Java语言来编写Android应用。相较于JVM,Dalvik虚拟机是专门为移动设备定制的,允许在有限的内存中同时运行多个虚拟机的实例,并且每一个Dalvik 应用作为一个独立的Linux 进程执行。独立的进程可以防止在虚拟机崩溃的时候所有程序都被关闭。而替代Dalvik虚拟机的ART的机制与Dalvik不同。在Dalvik下,应用每次运行的时候,字节码都需要通过即时编译器转换为机器码,这会拖慢应用的运行效率,而在ART 环境中,应用在第一次安装的时候,字节码就会预先编译成机器码,使其成为真正的本地应用。
4)Linux Kernel
Android 的核心系统服务基于Linux 内核,在此基础上添加了部分Android专用的驱动。系统的安全性、内存管理、进程管理、网络协议栈和驱动模型等都依赖于该内核。Linux内核也是作为硬件与软件栈的抽象层。
5)各层之间的联系
从下至上排序,Linux层为第1层,系统运行库层为第2层,JavaFrameWork层为第3层,System Apps层为第4层;
Android的第一层是用C语言实现,第二层由C和C++实现,第3、4层主要是用Java实现的;
第1、2层之间,从linux的操作系统的角度来看,是由内核空间和用户空间的分界线;
第2、3层之间是本地代码层和java代码层的接口;
第3、4层之间,是android的系统API的接口;
第一层运行于内核空间,第2、3、4层运行于用户空间。
2.Android系统启动过程
Android启动过程包含从Linux内核加载到Home应用程序启动的整个过程。
1)Android是基于linux内核的系统平台,启动时,首先通过Bootloader(系统加载器),加载Linux内核。在Linux加载启动时,与普通的Linux启动过程相同,先初始化内核,然后调用init进程(Linux用户空间中第一个进程,是所有进程的父进程)。
2) Init进程启动Zygote。init进程启动. init进程主要来创建和挂载启动所需的文件目录,启动属性服务(类似于windows的注册表),启动Zygote进程。
3) Zygote(孵化器)进程的建立是真正的Android运行空间,Zygote孵化第一个进程SystemServer,SystemServer启动各种系统服务线程。
SystemServer进程在Android的运行环境中扮演了"神经中枢"的作用,APK应用中能够直接交互的大部分系统服务都在该进程中运行,常见的比如WindowManagerServer(WMS)、ActivityManagerSystemService(AMS)、PackageManagerServer(PMS)等,这些系统服务都是以一个线程的方式存在于SystemServer进程中。
SystemService会启动Binder线程池 创建SystemServiceManage对系统服务的创建启动和生命周期进程管理,并启动各种java层系统服务,接着会调用WMS,AMS等服务的systemReady()完成启动.
4) 当以上服务线程都启动后,AMS以systemReady调用完成最后启动,在ActivityManagerService的systemReady方法中调用startHomeActivityLocked来启动Action为Intent.ACTION_MAIN Category为Intent.CATEGORY_HOME的应用,也就是Launcher所配置的标签,启动第一个Activity。至此,Android系统的启动完成。
三,Binder理解
以下内容基于《Android Framework精编内核解析》
1)Binder概述
Android系统中,每个应用程序是由Android的Activity
,Service
,Broadcast
,ContentProvider
这四剑客的中一个或多个组合而成,这四剑客所涉及的多进程间的通信底层都是依赖于Binder IPC机制。例如当进程A中的Activity要向进程B中的Service通信,这便需要依赖于Binder IPC。不仅于此,整个Android系统架构中,大量采用了Binder机制作为IPC(Inter-Process Communication 进程间通信)方案,当然也存在部分其他的IPC方式,比如Zygote通信便是采用socket。
Binder作为Android系统提供的一种IPC机制,无论从事系统开发还是应用开发,都应该有所了解,这是Android系统中最重要的组成,也是最难理解的一块知识点,错综复杂。
① IPC原理
从进程角度来看IPC机制
每个Android的进程,只能运行在自己进程所拥有的虚拟地址空间。对应一个4GB的虚拟地址空间,其中3GB是用户空间,1GB是内核空间,当然内核空间的大小是可以通过参数配置调整的。对于用户空间,不同进程之间彼此是不能共享的,而内核空间却是可共享的。Client进程向Server进程通信,恰恰是利用进程间可共享的内核内存空间来完成底层通信工作的,Client端与Server端进程往往采用ioctl(ioctl 是设备驱动程序中设备控制接口函数,打开关闭,读写)等方法跟内核空间的驱动进行交互。
② Binder通信原理
Binder通信采用C/S架构,从组件视角来说,包含Client、Server、ServiceManager以及Binder驱动,其中ServiceManager用于管理系统中的各种服务。架构图如下所示:
可以看出无论是注册服务和获取服务的过程都需要ServiceManager,需要注意的是此处的Service Manager是指Native层的ServiceManager(C++),并非指framework层的ServiceManager(Java)。ServiceManager是整个Binder通信机制的大管家,是Android进程间通信机制Binder的守护进程,要掌握Binder机制,首先需要了解系统是如何首次启动Service Manager。当Service Manager启动之后,Client端和Server端通信时都需要先获取Service Manager接口,才能开始通信服务。
图中Client/Server/ServiceManage之间的相互通信都是基于Binder机制。既然基于Binder机制通信,那么同样也是C/S架构,则图中的3大步骤都有相应的Client端与Server端。
注册服务:Server进程要先注册Service到ServiceManager。该过程:Server是客户端,ServiceManager是服务端。
获取服务:Client进程使用某个Service前,须先向ServiceManager中获取相应的Service。该过程:Client是客户端,ServiceManager是服务端。
使用服务:Client根据得到的Service信息建立与Service所在的Server进程通信的通路,然后就可以直接与Service交互。该过程:client是客户端,server是服务端。
图中的Client,Server,Service Manager之间交互都是虚线表示,是由于它们彼此之间不是直接交互的,而是都通过与Binder驱动进行交互的,从而实现IPC通信方式。其中Binder驱动位于内核空间,Client,Server,Service Manager位于用户空间。Binder驱动和Service Manager可以看做是Android平台的基础架构,而Client和Server是Android的应用层,开发人员只需自定义实现client、Server端,借助Android的基本平台架构便可以直接进行IPC通信。
③ C/S模式
BpBinder(客户端)和BBinder(服务端)都是Android中Binder通信相关的代表。
- client端:BpBinder.transact()来发送事务请求;
- server端:BBinder.onTransact()会接收到相应事务。
2)Binder 驱动概述
Binder 驱动是 Android 专用的,但底层的驱动架构与 Linux 驱动一样。binder驱动在以 misc 设备进行注册,作为虚拟字符设备,没有直接操作硬件,只是对设备内存的处理。主要是驱动设备的初始化(binder_init),打开 (binder_open),映射(binder_mmap),数据操作(binder_ioctl)。
Binder 驱动的 init 、 open 、 mmap 、 ioctl这 4 个核心方法:
初始化(binder_init),为了注册 misc 设备,初始化字符设备;
打开 (binder_open),打开 binder 驱动设备;
映射(binder_mmap),申请内存空间,实现用户空间的 Buffer 和内核空间的Buffer 同步操作的功能;
数据操作(binder_ioctl),该函数负责在两个进程间收发 IPC 数据和 IPC reply 数据,执行相应的 ioctl 操作;
3)ServiceManager
① 启动 ServiceManager
ServiceManager 是 Binder IPC 通信过程中的守护进程,本身也是一个 Binder服务,ServiceManager 本身工作相对简单,其核心功能:查询和注册服务。对于 Binder IPC
通信过程中,其实更多的情形是 BpBinder 和 BBinder 之间的通信,比如ActivityManagerProxy 和 ActivityManagerService 之间的通信等。
注册服务:记录服务名和 handle 信息,保存到 svclist 列表;
查询服务:根据服务名查询相应的的 handle 信息。
ServiceManger 集中管理系统内的所有服务,通过权限控制进程是否有权注册服务,通过字符串名称来查找对应的Service; 由于ServiceManger进程建立跟所有向其注册服务的死亡通知, 那么当服务所在进程死亡后, 会只需告知ServiceManager。每个 Client 通过查询 ServiceManager 可获取 Server 进程的情况,降低所有 Client 进程直接检测会导致负载过重。
② 获取 ServiceManager
获取 Service Manager 是通过 defaultServiceManager() 方法来完成,当进程注册服务(addService)或 获取服务(getService)的过程之前,都需要先调用
defaultServiceManager()方法来获取 gDefaultServiceManager 对象。对于gDefaultServiceManager 对象,如果存在则直接返回;如果不存在则创建该对象,创建过程包括调用 open()打开 binder 驱动设备,利用 mmap()映射内核的地址空间。
4)framework层分析
主要分析Binder在java framework层的框架
Binder架构
binder在framework层,采用JNI技术来调用native(C/C++)层的binder架构,从而为上层应用程序提供服务。 native层中,binder是C/S架构,分为Bn端(Server)和Bp端(Client)。对于java层在命名与架构上非常相近,同样实现了一套IPC通信架构。
图中红色代表整个framework层 binder架构相关组件;
Binder类代表Server端,BinderProxy类代码Client端;
图中蓝色代表Native层Binder架构相关组件;
上层framework层的Binder逻辑是建立在Native层架构基础之上的,核心逻辑都是交予Native层方法来处理。
framework层的ServiceManager类与Native层的功能并不完全对应,framework层的ServiceManager类的实现最终是通过BinderProxy传递给Native层来完成的。
如何使用AIDL(重点)
AIDL是Android中IPC(Inter-Process Communication)方式中的一种,AIDL是Android Interface definition language的缩写。其主要作用是用于进程间的通讯。
既然在Android系统中,进程间相互独立,但是有时候我们又有应用间进行互动的需求,比较传递数据或者任务委托等,AIDL就是为了满足这种需求而诞生的。通过AIDL,可以在一个进程中获取另一个进程的数据和调用其暴露出来的方法,从而满足进程间通信的需求。进程间相互传递的数据类型如下:
- 八种基本数据类型:byte、char、short、int、long、float、double、boolean
- String,CharSequence
- 实现了Parcelable接口的数据类型
- List 类型。List承载的数据必须是AIDL支持的类型,或者是其它声明的AIDL对象
- Map类型。Map承载的数据必须是AIDL支持的类型,或者是其它声明的AIDL对象
编写代码:
创建两个工程,一个作为服务端,一个作为客户端,客户端绑定服务端service,然后调用方法向服务端获取书籍名称,向服务端添加书籍序号。
1)创建服务端
① 在Android Studio中 src目录上右键创建一个AIDL文件 并命名,完成后会再main下自动生成一个aidl目录,该目录的包名和java下的包名是一致的。
创建完成后样式如下图所示:
每次生成的.aidl文件后我们需要build一下才能让系统生成自后我们能使用文件。因为在进程间通信中真正起作用的并不是 AIDL 文件,而是系统据此而生成的文件,在Android Studio下,我们可以在build/generated/aidl目录下找到这些Java文件。之后需要使用到当中的内部静态抽象类 Stub。
当然我们可以在所有aidl文件写完再build,也可以每次写完一个build一下。
② 我们在java对应bean目录下 生成一个实体类,这里我们写一个书籍类;
我们要在AIDL中用到这个实体类,所以需要用Parcelable序列化该实体类:
③ 接着我们要把用到的bean类在上面创建的aidl包下相同目录下创建对应实体类的aidl文件,并把它改为声明parcelable数据类型的AIDL文件;
注意这里的parcelable是小写。
④ 然后可以再开始写的IMyAidlInterface.aidl里定义能被客户端调用的接口:
至此,我们的aidl文件写完了, 写完后我们make project或者make对应的module让漏掉的文件自动生成。
⑤ 接下来 在java下创建一个类IBinder继承IMyAidlInterface.aidl对应的IMyAidlInterface.Stub,实现对应的方法:
⑥ 然后使用服务暴露接口给外部,创建一个服务RemoteService 继承Service,实现对应方法,绑定MyBinder:
⑦ 在清单文件里注册服务:
到这里服务端的完成了.接下来是创建客户端。
2)创建Client客户端
① 新建一个工程作为客户端,我们把服务端的 的aidl整个包下所有东西都拷贝到新项目中,然后make project或者make对应的module:
② 如果aidl有用到bean实体类,我们也要把这些实体类照搬过来:
③ 接下来,我们就可以在客户端的activity里连接远程服务 实现aidl通信:
具体代码如下:
public class ClientActivity extends AppCompatActivity {
private IMyAidlInterface iMyAidlInterface;
private TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = findViewById(R.id.txt);
bind();
}
private boolean connected = false;
private ServiceConnection serviceConnection;
private void bind() {
Intent intent = new Intent();
intent.setComponent(new ComponentName("com.example.aidl", "com.example.aidl.RemoteService"));
bindService(intent, serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.d("chin", "onServiceConnected");
connected = true;
iMyAidlInterface = IMyAidlInterface.Stub.asInterface(service);
try {
textView.setText(iMyAidlInterface.getName());
iMyAidlInterface.setNumber(56);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.d("chin", "onServiceDisconnected");
iMyAidlInterface = null;
connected = false;
}
}, BIND_AUTO_CREATE);
}
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(serviceConnection);
}
}
在onServiceConnected()回调中,我们使用IMyAidlInterface.Stub.asInterface(service)方法返回我们的接口的引用。接着客户端就可以通过它来与服务端通信了。
先运行服务端,在运行客户端,得到结果如下:
- 首先,我们Client客户端,接收到服务端发送出来的书名;
- 接着,服务端收到客户端重新定义的书的序列号;
参考文章