朔月的专栏

写在前面的

当一个Android App存在某个不需要UI的后台运行需求时,或者是因为内存占用需要采用多进程方案时,我们免不了与多进程打交道。必不可少的,需要考虑Binder在其中如何实现。

最常见的Binder实现当然是AIDL,然而Binder的实现绝不仅仅只有AIDL一种方式,如果止步于写.aidl,那么对于Binder,对于Android整体的跨进程传输过程的理解都只能流于形式。

但是想理解Binder不是一件容易的事情,Binder的概念涉及太多知识点,遍观各大论坛上关于Binder的博客或是文章,作者多半已经默认阅读者具备了必要的学习基础。这对于零基础的同学肿么办,我罗列出了几个自己学习中觉得十分重要的知识点,如果希望能够彻底的理解Binder JAVA层概念,那么务必要明了这些知识点。希望对那些初学者朋友有一定帮助。

接口语言

AIDL是Android为了在不同进程中实现Binder接口的一套专用接口语言。

在维基百科上对于接口语言的定义是这样的

接口描述语言(Interface description language,缩写IDL),是用来描述软件组件接口的一种计算机语言。IDL通过一种中立的方式来描述接口,使得在不同平台上运行的对象和用不同语言编写的程序可以相互通信交流;比如,一个组件用C++写成,另一个组件用Java写成。

接口语言通常用来描述两种不同对象之间共同一套通信协议,放在Android概念里,一般指的是两个不同进程之间需要通信时必须遵守的一套标准。

IPC

Binder的实质仍然是IPC。

通常我们所说的IPC,指的是以某种标准所做的进程间通信过程(inter-process communication)。我们知道,Android的每一个应用可以视作是跑在Davlk虚拟机上的独立进程。而Linux内核出于对进程安全的考虑,要求不同UID/GID的进程不能访问互相访问彼此的资源。因此一般来讲,每个Android应用,或者说每个独立进程的组件都不能像本地方法一样调用其他进程方法。

基于这个原因,Linux内核支持若干种进程间通信机制,为的是在维护进程安全性的同时还能提供针对不同场景的通信手段。而在Android Binder用到的是叫做匿名共享内存(Anonymous Shared Memory)的方式。Binder的实质就是通过这种IPC方式来完成不同进程之间的通信的。

C/S结构

Binder的实现是一个典型的C/S结构。

C/S可以简单的理解为系统为了负载均衡,将一个大任务拆分为多个子任务,并分发给不同的终端结构来处理,以达到减少负荷提高响应速度的目的。在Android的环境中,在分布式系统中,终端结构可以是计算机与服务器,而在Android系统中,则指的是不同的进程实体。理解了C/S结构的一些特征,对Binder的消息握手,传输模式等等行为会有更深刻的理解。

Binder的概念

终于说到了Binder。

对于Binder的解释,最官方的莫过于developerAndroid对于Service使用这一章的说明。如果详细的读过这篇文档,我想大部分人能够对Binder的使用,特别是如何通过AIDL来实现Binder接口的操作,有比较清楚的认识。

但是Binder究竟是什么?它是如何实现的?

这里十分推荐老罗关于Binder学习计划这个系列的文档,对于Binder的整体运行机制有了十分清晰的描述,如果你需要整体全面的理解Binder,那么阅读源代码的同时,这套文档一定可以帮助你很多。

弄清楚以上几个概念后,我们可以开始讨论Binder的实现了。

Binder的实现有很多种,最常见的方式是通过AIDL来实现,相信做过跨进程访问Service的同学也肯定写过.aidl。除此之外,Android还支持通过Message方式和直接继承Binder类的方式来完成Binder实现。

而我要给大家介绍的,就是最后一种方式。

继承Binder类的IBinder接口实现

我以一个最简单的功能为例——控制并打印不同进程的pid,来介绍一个典型的Binder实现过程。

创建项目,并设置多进程运行环境

为了在同一个项目中模拟多进程情形,我将Service组件设置为其他的进程

<activity>=><service=>Activity以及Service表现

在我们的模拟代码中,Activity与Service绑定之后可以在onServiceConnection回调中获取一个Binder实例,通过对这个对象向下转型得到指定Interface的接口对象,从而调用Service中实现的具体的LogService方法。 真实的情况虽然没有所描述的这么简单,但也与之相差不远,流程图如下:

Created with Raphal 2.1.2ActivityActivityProxyProxyASMASMStubStubServiceService客户端进程获取Binder代理服务端进程实现具体请求方法返回值将返回值返回至客户端进程

Activity和Servie的代码实现如下: Activity端

void onServiceConnected(ComponentName name, IBinder service) {mService = StubService.asInterface(service);Log.d(TAG, “pid=” + android.os.Process.myPid());mService.LogService();}(ComponentName name) {mService = null;}};(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);bindService(new Intent(this, BinderService.class), serviceConnection, BIND_AUTO_CREATE);}…}

Service端实现

{String TAG = “BinderService”;//implement the interfaceprivate StubService mBinder = new StubService() {() {Log.d(TAG, “pid=” + android.os.Process.myPid());}};IBinder onBind(Intent intent) {return mBinder;}}

简单的描述就是。 – Actiivty尝试去bind一个Service。 – bind成功之后,Activity可以得到一个Binder对象。 – 通过这个Binder对象,Activity能够调用被bind的那个Service里实现的具体方法,也就是实现了远程调用Service的目的。

而这里有几个问题: 1. Activity获取的Binder对象本质是什么? 2. 为什么可以通过这个Binder对象远程调用Service方法? 3. 我们如何区分不同进程中的实例对象?

这几个问题可以从具体的实现代码中得到答案。

Binder代理端的实现

在我们的demo中,Activity代表的是C/S模型中的Client端进程,Binder结构实现的过程之一,就是会交给这个Client进程一个它的Proxy实现,也就是我们在onServiceConnection回调中所得到的Binder实例。

具体怎么生成Proxy实例的呢?从代码中可以看到:

{();}

最开始,我们必须创建一个继承子IInterface的接口,并在这个接口中声明我们在Client进程中要调用的,Service进程中会实现的方法。

总有看腻的时候,不论何等荣华的身份,

朔月的专栏

相关文章:

你感兴趣的文章:

标签云: