Binder
Binder是什么?
机制:
Binder
是一种进程间通信的机制
驱动:
Binder
是一个虚拟物理设备驱动
应用层:
Binder
是一个能发起进程间通信的
JAVA
类
Binder
就是
Android
中的血管,在
Android
中我们使用
Activity,Service
等组件都需要和
AMS
(
system_server
)进行通信,这种跨进程的通信都是通过
Binder
完成。
Activity,Service
等组件和
AMS
不是同一个进程,其实也是多进程通信。
Android系统中,涉及到多进程间的通信底层都是依赖于Binder IPC机制。
例如当进程
A
中的
Activity
要向进程
B
中的
Service
通信,这便需要依赖于
Binder IPC
。不仅于此,整
个
Android
系统架构中,大量采用了
Binder
机制作为
IPC
(进程间通信,
Interprocess
Communication
)方案。
也存在部分其他的
IPC
方式,如管道、
SystemV
、
Socket
等
为什么使用Binder
性能方面:
Binder
相对于传统的
Socket
方式,更加高效
Binder
数据拷贝只需要一次,而管道、消息队列、
Socket
都需要
2
次,共享内存方式一次内存拷贝
都不需要,但实现方式又比较复杂。
安全方面:
传统的进程通信方式对于通信双方的身份并没有做出严格的验证,比如
Socket
通信的
IP
地址是客户
端手动填入,很容易进行伪造
Binder
机制从协议本身就支持对通信双方做身份校检,从而大大提升了安全性
IPC
原理

Binder IPC
实现原理
跨进程通信是需要内核空间做支持的。传统的
IPC
机制如管道、
Socket
都是内核的一部分。
Binder IPC
正是基于内存映射(
mmap
)来实现的,但是
mmap()
通常是用在有物理介质的文件系统
上,进程中的用户区域是不能直接和物理设备打交道的。
如果想要把磁盘上的数据读取到进程的用户区域,需要两次拷贝(磁盘
–>
内核空间
–>
用户空间)
,
通常在
这种场景下
mmap()
就能发挥作用,通过在物理介质和用户空间之间建立映射,减少数据的拷贝次数,
用内存读写取代
I/O
读写,提高文件读取效。
AIDL
AIDL简介
AIDL(
Android
接口定义语言),可以使用它定义客户端与服务端进程间通信(
IPC
)的编程接口。在 Android系统中,每个进程都运行在一块独立的内存中,在其中完成自己的各项活动,与其他进程都分 隔开来。可是有时候我们又有应用间进行互动的需求,比较传递数据或者任务委托等,AIDL
就是为了满 足这种需求而诞生的。通过AIDL
,可以在一个进程中获取另一个进程的数据和调用其暴露出来的方法, 从而满足进程间通信的需求。 AIDL是用于定义服务端和客户端通信接口的一种描述语言,可以拿来生产
IPC
代码,从某种意义上说 AIDL其实就是一个模板,因为在使用过程中,实际起作用的并不是
AIDL
文件,而是据此生产的一个 Interface的实例代码,
AIDL
其实是为了避免我们重复写代码而出现的一个模板。
注意:
只有在需要不同应用的客户端通过
IPC
方式访问服务,并且希望在服务中进行多线程处理
时,您才有必要使用
AIDL
。如果您无需跨不同应用执行并发
IPC
,则应通过实现
Binder
来创建接
口;或者,如果您想执行
IPC
,但
不
需要处理多线程,请使用
Messenger
来实现接口。无论如
何,在实现
AIDL
之前,请您务必理解绑定服务。
使用流程
1. 在
.aidl
文件中定义
AIDL
接口,并将其添加到应用工程的
src
目录下,创建完成之后
rebuild
2. Android SDK 工具会自动生成基于该
.aidl
文件的 IBinder 接口,具体的业务对象实现这个接口, 这个具体的业务对象也是 IBinder 对象,当绑定服务的时候会根据实际情况返回具体的通信对象 (本地还是代理)
3. 将客户端绑定到该服务上,之后就可以调用
IBinder
中的方法来进行进程间通信(
IPC
)
下面从几个方面介绍
AIDL
的使用
1. 创建
.aildl
文件
2. 具体的业务对象实现基于
.aidl
文件生成的接口
3. 向客户端公开接口
4. 客户端远程调用
5.
验证
AIDL
创建
.aildl
文件
在 AIDL
中可以通过可带参数以及返回值的一个或多个方法来声明接口,参数和返回值可以是任意类 型,AIDL
中支持的数据类型如下: java 的
8
种数据类型:
byte
、
short
、
int
、
long
、
float
、
double
、
boolean
、
char
除此之外支持 String
、
charSequence
、
List
、
Map
自定义数据类型
如果参数或返回值类型为 List
或
Map
时:
List
中的所有元素都必须是
AIDL
支持的数据类型、其他
AIDL
生成的接口或自己声明的可打包类
型。可选择将
List
用作
“
通用
”
类(例如,
List
)。另一端实际接收的具体类始终是
ArrayList
,但生
成的方法使用的是
List
接口。
Map
中的所有元素都必须是
AIDL
支持的数据类型、其他
AIDL
生成的接口或您声明的可打包类
型。 不支持通用
Map
(如
Map<String,Integer>
形式的
Map
)。 另一端实际接收的具体类始终
是
HashMap
,但生成的方法使用的是
Map
接口。
具体的业务对象实现基于
.aidl
文件生成的接口
打开IPersonAidlInterface.aidl
,在
.aidl
文件中添加具体的业务方法,文件内容如下
:
interface IkeyAidlInterface {
void setName(String name);
void setAge(int money);
String getInfo();
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
double aDouble, String aString);
}
.
然后,重新
rebuild project , Android SDK
工具会在相应的目录生成对应的与
.aidl
文件同名的
.java
接口文件,具体目录如下:

那么这个业务要体现在什么地方呢,从上面可知
Stub
是一个抽象类,那么它所提供的具体业务必
然需要一个具体的实现类来完成,下面实现这个具体的业务类,具体如下
public class IKeyimpl extends IkeyAidlInterface.Stub{
String name;
int money;
@Override
public void setName(String name) throws RemoteException {
this.name=name;
}
@Override
public void setAge(int money) throws RemoteException {
Intent intent = new Intent();
intent.setClass(KeyService.this,MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
this.money=money;
}
@Override
public String getInfo() throws RemoteException {
return "交易账户:"+name+"金额是:"+money;
}
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
}
}
向客户端公开接口
创建一个
Service
以便对外提供具体的业务,具体如下:
public class KeyService extends Service {
public KeyService() {
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
return new IKeyimpl();
}
}
也可以将Stub 抽象类与service复合写如下:
public class KeyService extends Service {
public KeyService() {
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
return new IKeyimpl();
}
public class IKeyimpl extends IkeyAidlInterface.Stub{
String name;
int money;
@Override
public void setName(String name) throws RemoteException {
this.name=name;
}
@Override
public void setAge(int money) throws RemoteException {
Intent intent = new Intent();
intent.setClass(KeyService.this,MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
this.money=money;
}
@Override
public String getInfo() throws RemoteException {
return "交易账户:"+name+"金额是:"+money;
}
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
}
}
}
客户端远程调用
通过上面几步完成了服务的搭建,并将服务运行在独立进程中,下面主要就是客户端的具体调用了,具 体实现参考如下:
public class MainActivity extends AppCompatActivity {
private Button button,button2,button3,button4;
TextInputEditText textField,edt_one;
private IkeyAidlInterface ikeyAidlInterface;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button=findViewById(R.id.button);
button2=findViewById(R.id.button2);
button3=findViewById(R.id.button3);
button4=findViewById(R.id.button4);
textField=findViewById(R.id.textField);
edt_one=findViewById(R.id.edt_one);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent();
intent.setComponent(new ComponentName("com.example.day36start2","com.example.day36start2.KeyService"));
bindService(intent,conn,BIND_AUTO_CREATE);
}
});
button2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
try {
ikeyAidlInterface.setName("a123456");
ikeyAidlInterface.setAge(100);
String zys=ikeyAidlInterface.getInfo();
Log.i("take", zys);
} catch (RemoteException e) {
e.printStackTrace();
}
}
});
button3.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
}
});
}
private ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
ikeyAidlInterface = IkeyAidlInterface.Stub.asInterface(service);
Log.i("TAG" , ""+ikeyAidlInterface);
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
}
在新版本要在AndroidManifest.xml中写上如下代码:
<queries>
<package android:name="com.example.day36start2" />
</queries>