上篇文章深入理解Binder(一),从AIDL谈起我们介绍了AIDL的基本使用,用AIDL两个App的通信是实现了,可是又有小伙伴疑惑了,为什么使用AIDL就能够实现两个App之间的通信?本文我们就来详细说说这个问题。

Binder单从字面上理解,它有活页夹,粘合剂的意思,活页夹可以用来把两个东西夹在一起。在我们的Android系统中,Binder主要用来实现进程之间的通信(IPC),它的主要作用就是把多个App夹在一起。那么这个Binder到底是个什么东西呢?其实它是一个工作在Linux层面的驱动,这一段驱动运行在内核态。我们在客户端调用Binder都是通过系统调用最终完成的。Binder本身又是一种架构,这种架构提供了服务端、Binder驱动和客户端三个模块。我们用AIDL在服务端和客户端生成的文件都是为了完成服务端和客户端的相关功能,OK,那么接下来我们就从服务端、Binder驱动、客户端三个方面来分别分析Binder的工作原理。

1.服务端

Binder服务端实际上就是一个Binder类的对象,当我们创建一个Binder对象的时候,Binder内部就会启动一个隐藏线程,该线程的主要作用就是接收Binder驱动发送来的消息,那么Binder驱动为什么会给Binder服务端的线程发送消息呢?原因很简单,我们在客户端调用服务端的时候并不能直接调用服务端相应的类和方法,只能通过Binder驱动来调用。当服务端的隐藏线程收到Binder驱动发来的消息之后,就会回调服务端的onTransact方法,我们来看看这个方法的方法头:

protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException

刚方法接收四个参数,这四个参数都是客户端的Binder传来的,第一个参数用来指定客户端要调用服务端的哪一个方法,第二个参数是客户端传来的参数,第三个参数表示服务端返回的参数,最后一个flags表示客户端的调用是否有返回值,0表示服务端执行完成之后有返回值,1表示服务端执行完后没有返回值。OK,基于对服务端这样的理解,我来自定义一个类,继承自Binder ,实现和上一篇博文类似的功能:

public class MyAddBinder extends Binder {
private final static int ADD = 1;
@Override
protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
switch (code) {
case ADD:
data.enforceInterface("MyAddBinder");
int a = data.readInt();
int b = data.readInt();
int add = add(a, b);
reply.writeInt(add);
return true;
}
return super.onTransact(code, data, reply, flags);
} public int add(int a, int b) {
return a + b;
}
}

小伙伴们请看,假设我的服务端依然是提供一个加法服务,当Binder驱动调用onTransact方法的时候,我先根据code来判断客户端是想调用哪个方法,然后从data中读出客户端传递来的所有数据,注意读取顺序要和客户端的写入顺序一致(如果小伙伴们对Parcel的使用还不熟悉的话,可以参考这篇文章android开发之Parcelable使用详解 ),读出来之后调用相应的方法获取两个数的和,然后再将结果写入到reply中即可。写好之后,在服务端的Service中再将该BInder返回即可,如下:

public class MyService extends Service {
@Nullable
@Override
public IBinder onBind(Intent intent) {
return new MyAddBinder();
}
}

OK,这就是一个简单的Binder服务端。

2.Binder驱动

Binder驱动是Binder服务端和Binder客户端之间连接的一个桥梁,当一个服务端Binder被创建出来的时候,系统同时会在Binder驱动中创建另外一个Binder对象,当客户端想要访问远程的Binder服务端的时候, 都是通过这个Binder对象来完成的。那么Binder驱动中的这个对象要怎么样获取呢?其实很简单,这个BInder对象就是我们用绑定的方式启动一个Service服务时,在绑定成功时所获取的那个IBinder对象。如下:

boolean b = bindService(intent, new ServiceConnection() {

            @Override
public void onServiceConnected(ComponentName name, IBinder service) {
//这个service就是Binder驱动中创建的Binder对象
mRemote = service;
} @Override
public void onServiceDisconnected(ComponentName name) { }
}, Service.BIND_AUTO_CREATE);

客户端和服务端之间的交互就是通过这个Binder对象来进行的。

3.客户端

客户端就简单了,我们首先需要在客户端获取Binder驱动中的Binder对象,然后调用该对象中的transact方法进行数据传递。客户端在向服务端发送消息的时候是以线程间通信的模式来进行的,而且调用服务端代码是同步进行的,也就是说线程会阻塞。OK,基于此,我们就来看看客户端代码该怎么写:

int code = 1;
//向服务端发送的数据
Parcel data = Parcel.obtain();
//接收服务端返回的数据
Parcel reply = Parcel.obtain();
data.writeInterfaceToken("MyAddBinder");
data.writeInt(10);
data.writeInt(9);
try {
mRemote.transact(code, data, reply, 0);
int i = reply.readInt();
Log.d("google.sang", "add: " + i);
reply.recycle();
data.recycle();
} catch (RemoteException e) {
e.printStackTrace();
}

第10行,在客户端调用Binder驱动中的transact方法进行消息发送,传递的四个参数就是我们在第一小节中所说的四个参数,这里不再赘述。第6行代码实际上是一个验证字符串,对应了第一小节中的data.enforceInterface("MyAddBinder");行代码。OK,就这样写了之后,在不使用AIDL工具的情况下,我们依然实现了跨进程通信。

OK,经过上文的讲解相信小伙伴们对Binder的工作机制已经有了一个大致的了解。

以上。

代码下载http://download.csdn.net/detail/u012702547/9646948

深入理解Binder(二),Binder是什么?的更多相关文章

  1. Andorid Binder进程间通信---Binder本地对象,实体对象,引用对象,代理对象的引用计数

    本文參考<Android系统源码情景分析>,作者罗升阳. 一.Binder库(libbinder)代码: ~/Android/frameworks/base/libs/binder --- ...

  2. 深入理解OOP(二):多态和继承(继承)

    本文是深入浅出OOP第二篇,主要说说继承的话题. 深入理解OOP(一):多态和继承(初期绑定和编译时多态) 深入理解OOP(二):多态和继承(继承) 深入理解OOP(三):多态和继承(动态绑定和运行时 ...

  3. C++ 中类的构造函数理解(二)

    C++ 中类的构造函数理解(二) 写在前面 上次的笔记中简要的探索了一下C++中类的构造函数的一些特性,这篇笔记将做进一步的探索.主要是复制构造函数的使用. 复制构造函数 复制构造函数也称拷贝构造函数 ...

  4. ppp 完全理解(二)【转】

    转自:https://blog.csdn.net/tianruxishui/article/details/44057717 ppp 完全理解(二) pppd 协议及代码分析 作者:李圳均 日期:20 ...

  5. Java 反射理解(二)-- 动态加载类

    Java 反射理解(二)-- 动态加载类 概念 在获得类类型中,有一种方法是 Class.forName("类的全称"),有以下要点: 不仅表示了类的类类型,还代表了动态加载类 编 ...

  6. [Binder深入学习二]Binder驱动——基础数据结构二

    Userspace和KernelSpace进行交互时,大部分命令是通过 ioctl 实现的,在这个过程中,最重要的一个便是 BINDER_WRITE_READ 命令了. #define BINDER_ ...

  7. [C# 基础知识系列]专题八: 深入理解泛型(二)

    引言: 本专题主要是承接上一个专题要继续介绍泛型的其他内容,这里就不多说了,就直接进入本专题的内容的. 一.类型推断 在我们写泛型代码的时候经常有大量的"<"和"& ...

  8. 关于SVM数学细节逻辑的个人理解(二):从基本形式转化为对偶问题

    第二部分:转化为对偶问题进一步简化 这一部分涉及的数学原理特别多.如果有逻辑错误希望可以指出来. 上一部分得到了最大间隔分类器的基本形式:   其中i=1,2,3...m 直接求的话一看就很复杂,我们 ...

  9. 对CAS机制的理解(二)

    一.Java当中CAS的底层实现首先看看AtomicInteger的源码,AtomicInteger中常用的自增方法 incrementAndGet: public final int increme ...

随机推荐

  1. C# 中的数组(array)

    原文 C# 中的数组(array) 特性 数组是一个无序的元素序列.数组元素存储在一个连续性的内存块中,并可使用一个整数索引来访问. C# 声明数组变量时,数组的大小不是声明的一部分.这点与C/C++ ...

  2. HDU 5534 Partial Tree 完全背包

    一棵树一共有2*(n-1)度,现在的任务就是将这些度分配到n个节点,使这n个节点的权值和最大. 思路:因为这是一棵树,所以每个节点的度数都是大于1的,所以事先给每个节点分配一度,答案 ans=f[1] ...

  3. 【暑假】[数学]UVa 10375 Choose and divide

    UVa 10375 Choose and divide 题目: http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=19601 思路 ...

  4. 深度学习-使用cuda加速卷积神经网络-手写数字识别准确率99.7%

    源码和运行结果 cuda:https://github.com/zhxfl/CUDA-CNN C语言版本参考自:http://eric-yuan.me/ 针对著名手写数字识别的库mnist,准确率是9 ...

  5. Petshop学习第二天

    数据访问层的数据访问设计 1.数据层的内容: 数据库访问.Messaging.membership.Profile四部分 2.数据库对象的分类: 一类:数据实体,对应数据库中相应的数据表,它们作为数据 ...

  6. 【Hadoop代码笔记】Hadoop作业提交之客户端作业提交

    1.      概要描述仅仅描述向Hadoop提交作业的第一步,即调用Jobclient的submitJob方法,向Hadoop提交作业. 2.      详细描述Jobclient使用内置的JobS ...

  7. MAX16054

    MAX16054是带有单个开关去抖以及内部闭锁电路的按键通/断控制器,可接受机械开关产生的嘈杂输入,并经过一个有工厂设置的延迟时间后产生干净的数字锁存输出. 开关通.断期间,MAX16054无接触抖动 ...

  8. hdu 5585 Numbers【大数+同余定理】

    Numbers Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Sub ...

  9. rxjs5.X系列 —— Combination/Multicasting系列 api 笔记

    欢迎指导与讨论 :) 前言 本文是笔者翻译 RxJS 5.X 官网各类operation操作系列的的第三篇 -- Combination组合与Multicasting广播.如有错漏,希望大家指出提醒O ...

  10. 【Away3D代码解读】其它一些的记录(持续更新)

    查看当前正在使用的AGAL代码可以在程序开始时添加下面的代码,AGAL代码会被trace出来: Debug.active = true; 具体的输出是在MaterialPassBase类的update ...