Android Framework 架构介绍,Binder理解

Android Framework 架构介绍,Binder理解,第1张

概述一,AndroidFramework架构介绍1.Android系统架构Android本质就是在标准的Linux系统上增加了Java虚拟机Dalvik/ART,并在Dalvik/ART虚拟机上搭建了一个JAVA的applicationframework,所有的应用程序都是基于JAVA的applicationframework之上。Android分为四个层,从高层到低层分别是 一,AndroID Framework架构介绍1.AndroID系统架构

AndroID本质就是在标准的linux系统上增加了Java虚拟机Dalvik/ART,并在Dalvik/ART虚拟机上搭建了一个JAVA的application framework,所有的应用程序都是基于JAVA的application framework之上。

AndroID分为四个层,从高层到低层分别是应用程序层、应用程序框架层、系统运行库层和linux内核层。

AndroID架构

 

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服务十个部分。

Java FrameWork


3)系统运行库层(C/C++程序库和AndroID运行时库)

① C/C++程序库

AndroID 包含一些C/C++库,这些库能被AndroID系统中不同的组件使用。它们通过 AndroID 应用程序框架为开发者提供服务。以下是一些核心库:

C/C++程序库

② 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系统的启动完成。

BootLoader --> linux kernel --> init --> SystemServer --> Launcher
三,Binder理解

以下内容基于《Android Framework精编内核解析》

1)Binder概述

AndroID系统中,每个应用程序是由AndroID的ActivityServicebroadcastContentProvIDer这四剑客的中一个或多个组合而成,这四剑客所涉及的多进程间的通信底层都是依赖于Binder IPC机制。例如当进程A中的Activity要向进程B中的Service通信,这便需要依赖于Binder IPC。不仅于此,整个AndroID系统架构中,大量采用了Binder机制作为IPC(Inter-Process Communication 进程间通信)方案,当然也存在部分其他的IPC方式,比如Zygote通信便是采用socket。

Binder作为AndroID系统提供的一种IPC机制,无论从事系统开发还是应用开发,都应该有所了解,这是AndroID系统中最重要的组成,也是最难理解的一块知识点,错综复杂。

① IPC原理

从进程角度来看IPC机制

AndroID进程间IPC

 

每个AndroID的进程,只能运行在自己进程所拥有的虚拟地址空间。对应一个4GB的虚拟地址空间,其中3GB是用户空间,1GB是内核空间,当然内核空间的大小是可以通过参数配置调整的。对于用户空间,不同进程之间彼此是不能共享的,而内核空间却是可共享的。ClIEnt进程向Server进程通信,恰恰是利用进程间可共享的内核内存空间来完成底层通信工作的,ClIEnt端与Server端进程往往采用ioctl(ioctl 是设备驱动程序中设备控制接口函数,打开关闭,读写)等方法跟内核空间的驱动进行交互。

② Binder通信原理

Binder通信采用C/S架构,从组件视角来说,包含ClIEnt、Server、ServiceManager以及Binder驱动,其中ServiceManager用于管理系统中的各种服务。架构图如下所示:

Binder通信C/S架构

可以看出无论是注册服务和获取服务的过程都需要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架构图

 

图中红色代表整个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、booleanString,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客户端,接收到服务端发送出来的书名;接着,服务端收到客户端重新定义的书的序列号;

 

 

参考文章

《Android Framework入门介绍》

《Framework学习(一)Android 系统架构》

《android系统启动流程》

《Android AIDL 使用》

《想进阶,AIDL你得学习一下》

 

总结

以上是内存溢出为你收集整理的Android Framework 架构介绍,Binder理解全部内容,希望文章能够帮你解决Android Framework 架构介绍,Binder理解所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/web/1028334.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-23
下一篇 2022-05-23

发表评论

登录后才能评论

评论列表(0条)

保存