博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android进程间通信机制Binder应用层分析
阅读量:5895 次
发布时间:2019-06-19

本文共 4195 字,大约阅读时间需要 13 分钟。

hot3.png

1. 概述

学姐今天复习了下Android进程间通信方式,打算从基本概念、使用原因、基本使用、原理分析几个方面来讲讲。

想要对进程间通信方式有个相对全面的了解,就先从几个比较重要的概念IPC、AIDL、Binder说起吧。

(1)IPC:Inter-Process Communication,即进程间通信

(2)AIDL:Android Interface Definition Language,即Android接口定义语言。Client和Service要实现 

跨进程通信,必须遵循的接口规范。需要创建.aidl文件,外在表现上和Java中的interface有点类似。

(3)Binder:Android进程间通信是通过Binder来实现的。远程Service在Client绑定服务时,会在onBind()的回调中返回一个Binder,当Client调用bindService()与远程Service建立连接成功时,会拿到远程Binder实例,从而使用远程Service提供的服务。

 

2. 为什么使用Binder?

下面内容学姐参考别人的博文,进行了总结。

Linux系统进程间通信方式:

(1)传统机制。如管道(Pipe)、信号(Signal)和跟踪(Trace),适用于父子进程或兄弟进程,其中命名管道(Named Pipe),支持多种类型进程

(2)System V IPC机制。如报文队列(Message)、共享内存(Share Memory)和信号量(Semaphore)

(3)Socket通信

然而,以上方式在性能和安全性方面存在不足:

(1)性能方面。管道和队列采用存储转发方式,数据从发送方缓存区->内核缓存区->接收方缓存区,会经历两次拷贝过程;共享内存无拷贝但控制复杂;Socket传输效率低下,且连接的建立与中断有一定开销。

(2)安全性方面。传统IPC方式无法获得对方进程可靠的UID和PID,无法鉴别对方身份,若采用在数据包里填入UID/PID的方式,容易被恶意程序利用;传统IPC方式的接入点是开放性的,无法建立私有通道,容易被恶意程序猜测出接收方地址,获得连接。

而Binder是基于C/S通信模式,传输过程只需要一次拷贝,且为Client添加UID/PID身份,性能和安全性更好,因此Android进程间通信使用了Binder。

 

3. 基本使用

假设本地Client需要使用远程Service的计算器功能。

(1)新建Client和远程Service两个Android工程。

(2)在远程Service工程中,创建ICalculator.aidl文件,并创建CalculatorService类。

05121423_28nl.jpg

(3)在Client工程中,拷贝以上.aidl文件及目录,使用Service提供的服务。

05121423_Q1qx.jpg

(4)启动Client和Service工程,即可实现进程间通信。

 

4. 原理分析

由于Binder机制涉及的东西很多。学姐本文并不打算深入到内核源码,关于Client是怎样获取到远程Binder的会在后续文章再讲述。下面主要是从应用层角度分析。

我们先看看ICalculator.aidl编译生成的ICalculator.java文件。

05121424_goVa.jpg

05121424_2g4c.jpg

在基本使用部分,我们可以看到,Client在与Service建立连接成功后,会拿到远程Binder实例(此处不能直接使用远程Binder原因还不是很清楚),并调用Stub的asInterface方法将其转换成ICalculator接口。

mCalculator = ICalculator.Stub.asInterface(service);

这一步执行的操作是:根据接口描述符,从Binder中本地查找对应的接口,若有则直接返回;否则,将Binder对象传给本地代理Stub.Proxy对象,并返回本地代理,由本地代理来接管相应的服务,Proxy也实现了ICalculator接口。

这一步之后,Client就可以使用远程Service提供的服务了。

再看看onClick()事件中的加法操作。

result = mCalculator.add(2, 1);

mCalculator即为上面得到的本地代理对象,其add()的实现是

 

@Override public int add(int a, int b) throws android.os.RemoteException{    android.os.Parcel _data = android.os.Parcel.obtain();    android.os.Parcel _reply = android.os.Parcel.obtain();    int _result;    try {        _data.writeInterfaceToken(DESCRIPTOR);        _data.writeInt(a);        _data.writeInt(b);        mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);        _reply.readException();        _result = _reply.readInt();    }    finally {        _reply.recycle();        _data.recycle();    }    return _result;}

可以看到实际上是调用连接建立成功后的远程Binder的transact(add)方法。再看看Binder.transact实现

public final boolean transact(int code, Parcel data, Parcel reply,        int flags) throws RemoteException {    if (false) Log.v("Binder", "Transact: " + code + " to " + this);    if (data != null) {        data.setDataPosition(0);    }    boolean r = onTransact(code, data, reply, flags);    if (reply != null) {        reply.setDataPosition(0);    }    return r;}

可以看到最后调用了远程Binder的onTransact()方法,也就是走到了远程Binder的Stub.onTransact()方法。这个方法实现是

@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException{    switch (code)    {        case TRANSACTION_add:        {            data.enforceInterface(DESCRIPTOR);            int _arg0;            _arg0 = data.readInt();            int _arg1;            _arg1 = data.readInt();            int _result = this.add(_arg0, _arg1);            reply.writeNoException();            reply.writeInt(_result);            return true;        }        ...    }}

这里最终调用到了远程Service工程创建的ICalculator.Stub实例mBinder的add()方法即a+b,因此得到了最后的结果。

 

好了,我们再来梳理下,Client获得并使用Service服务的过程:

(1)Client与Service建立连接,得到远程Binder(这个Binder就是Service的onBind返回的Binder,但是客户端不能直接使用,具体原因还不是很明确)。

(2)将远程Binder传给本地代理,得到本地代理Stub.Proxy实例。

(3)通过本地代理Stub.Proxy实例间接调用远程Binder对象的add()方法。 具体实现是:由于远程Binder已经传给了本地代理Stub.Proxy。那么通过本地代理Stub.Proxy实例间接调用远程Binder的transact(TRANSACTION_add)操作;调用远程Binder的onTransact()方法;调用远程Binder的实现类ICalculator.Stub的add()方法

(4)得到结果

 

下面再总结下ICalculator、Stub、Proxy这3个类的关系:

ICalculator:就是一个接口类。内部包括之前的接口方法和静态Stub类。

Stub:远程Binder实现类。继承类Binder和ICalculator接口。

Proxy:远程Binder代理类。实现ICalculator接口。

 

5. 总结

(1)Binder相当于不同进程间数据通信的通道

(2)核心是代理模式,使用本地代理Proxy操作远端Binder,使用相应服务

(3)如理解有误,欢迎指正

 

6. 参考链接

http://blog.csdn.net/singwhatiwanna/article/details/19756201

http://blog.csdn.net/luoshengyang/article/details/6618363

转载于:https://my.oschina.net/android520/blog/699875

你可能感兴趣的文章
vue2.0 仿手机新闻站(六)详情页制作
查看>>
FreeRTOS的内存管理
查看>>
JSP----九大内置对象
查看>>
Java中HashMap详解
查看>>
delphi基本语法
查看>>
沙盒目录介绍
查看>>
260. Single Number III
查看>>
Hadoop生态圈-Kafka的完全分布式部署
查看>>
css的border的solid
查看>>
Haskell 差点儿无痛苦上手指南
查看>>
[MODx] Build a CMP (Custom manager page) using MIGX in MODX 2.3 -- 1
查看>>
NTP 服务器配置
查看>>
jQuery自动完成点击html元素
查看>>
[算法]基于分区最近点算法的二维平面
查看>>
webpack多页应用架构系列(七):开发环境、生产环境傻傻分不清楚?
查看>>
笨办法学C 练习1:启用编译器
查看>>
树的总结--树的性质(树的深度) leetcode
查看>>
nagios短信报警(飞信fetion20080522004-linrh4)
查看>>
【Android游戏开发之六】在SurfaceView中添加组件!!!!并且相互交互数据!!!!...
查看>>
linux 将大文件分成小文件
查看>>