您的位置:首页 > 移动开发 > Android开发

Android 中的Binder跨进程通信机制与AIDL

2016-11-15 18:48 567 查看
如果对进程、线程概念还很懵懂的同学可以看一下之前发表的一篇博客,里面是基础概念:

IPC进程间通信/跨进程通信

http://blog.csdn.net/github_33304260/article/details/52895331

为什么需要跨进程通信?

答:两个对象能直接互相访问的前提是两个对象在相同的内存地址空间中,如果两个对象那个在两个不同的进程中,比如ActivityManager和ActivityManagerService,不能直接互调需要跨进程技术,所以需要跨进程通信。那么问题来了,已有那么多跨进程手段,如上一篇讲的管道,Socket等,为什么还要大费周折弄一个Binder?

为什么在Android中使用Binder进行跨进程通信?

答:之说以这么大费周折,那肯定有Binder的过人之处。

Socket开销大且效率不高;管道和队列拷贝次数过多,而且传统跨进程通信手段安全性不高,接收方无法识别UID、PID,对于移动设备的安全性和效率考虑设计出来Binder。那么Binder这么好究竟是什么东西呢?

Binder是什么?

答:BInder是由四个模块组成,Binder Driver 、Binder Client、Binder Server、 Server Manager。

Binder Client相当于客户端,Binder Server相当于服务器, ServerManager相当于DNS服务器,Binder Driver 相当于一个路由器。

Binder Driver位于内核空间,主要负责Binder通信的建立,以及其在进程见得传递和Binder引用计数管理/数据包的传输等。Binder Server与 Binder Client之间的跨进程通信则通过Binder Driver转发。对于 Binder Client只需要知道自己要使用Binder的名字以及该binder实体在 Server Manager中的0号引用即可。ServerManager就是一个标准的BinderServer,并且在Android中约定其在Binder通信过程中唯一标识符永远是0。那说了这么多到底怎么进行跨进程呢?

如何使用Binder进行跨进程通信呢?

答: Binder Driver 和ServerManager是底层的没必要实现,只需实现Binder Client和Binder Server。但是Binder Server代码在C中实现,并且逻辑复杂,所以Android提供了一个简单的方式–AIDL–来生成一个Binder Server。

下面看一下具体demo

github地址:

https://github.com/libin7278/DesignModle

新建一个AIDl



// IBackAidl.aidl
package com.mvp.libin.aidl_example;

// Declare any non-default types here with import statements

interface IBackAidl {
/**
* 开户
* @param name
* @param password
* @return
*/
String OpenAccount(String name,String password);

/**
* 存钱
* @param money
* @param account
* @return
*/
String saveMoney(int money,String account);

/**
* 取钱
* @param money
* @param account
* @param password
* @return
*/
String tackMoney(int money,String account,String password);

/**
* 销户
* @param account
* @param password
* @return
*/
String closeAccount(String account,String password);
}


然后在build/generated可以看到生成的IBackAidl.java

这里贴出一部分

/**
* 开户
* @param name
* @param password
* @return
*/
@Override public java.lang.String OpenAccount(java.lang.String name, java.lang.String password) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.lang.String _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeString(name);
_data.writeString(password);
mRemote.transact(Stub.TRANSACTION_OpenAccount, _data, _reply, 0);
_reply.readException();
_result = _reply.readString();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
/**
* 存钱
* @param money
* @param account
* @return
*/
@Override public java.lang.String saveMoney(int money, java.lang.String account) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.lang.String _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(money);
_data.writeString(account);
mRemote.transact(Stub.TRANSACTION_saveMoney, _data, _reply, 0);
_reply.readException();
_result = _reply.readString();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
/**
* 取钱
* @param money
* @param account
* @param password
* @return
*/
@Override public java.lang.String tackMoney(int money, java.lang.String account, java.lang.String password) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.lang.String _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(money);
_data.writeString(account);
_data.writeString(password);
mRemote.transact(Stub.TRANSACTION_tackMoney, _data, _reply, 0);
_reply.readException();
_result = _reply.readString();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
/**
* 销户
* @param account
* @param password
* @return
*/
@Override public java.lang.String closeAccount(java.lang.String account, java.lang.String password) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.lang.String _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeString(account);
_data.writeString(password);
mRemote.transact(Stub.TRANSACTION_closeAccount, _data, _reply, 0);
_reply.readException();
_result = _reply.readString();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}
static final int TRANSACTION_OpenAccount = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_saveMoney = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
static final int TRANSACTION_tackMoney = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);
static final int TRANSACTION_closeAccount = (android.os.IBinder.FIRST_CALL_TRANSACTION + 3);
}
/**
* 开户
* @param name
* @param password
* @return
*/
public java.lang.String OpenAccount(java.lang.String name, java.lang.String password) throws android.os.RemoteException;
/**
* 存钱
* @param money
* @param account
* @return
*/
public java.lang.String saveMoney(int money, java.lang.String account) throws android.os.RemoteException;
/**
* 取钱
* @param money
* @param account
* @param password
* @return
*/
public java.lang.String tackMoney(int money, java.lang.String account, java.lang.String password) throws android.os.RemoteException;
/**
* 销户
* @param account
* @param password
* @return
*/
public java.lang.String closeAccount(java.lang.String account, java.lang.String password) throws android.os.RemoteException;
}


package com.mvp.libin.aidl_example;

import android.os.Binder;

import java.util.UUID;

/**
* Created by libin on 16/11/16.
*/

public class BanklBinder extends IBackAidl.Stub{
@Override
public String OpenAccount(String name, String password) {
return name+"开户成功"+ UUID.randomUUID().toString();
}

@Override
public String saveMoney(int money, String account) {
return "账户:"+account+"存入"+money+"人民币";
}

@Override
public String tackMoney(int money, String account, String password) {
return "账户:"+account+"取出"+money+"人民币";
}

@Override
public String closeAccount(String account, String password) {
return "账户:"+account+"销户";
}
}

//===================================>下面是本地服务
/*
public class BanklBinder extends Binder implements IBank {
@Override
public String OpenAccount(String name, String password) {
return name+"开户成功"+ UUID.randomUUID().toString();
}

@Override
public String saveMoney(int money, String account) {
return "账户:"+account+"存入"+money+"人民币";
}

@Override
public String tackMoney(int money, String account, String password) {
return "账户:"+account+"取出"+money+"人民币";
}

@Override
public String closeAccount(String account, String password) {
return "账户:"+account+"销户";
}
}
*/


package com.mvp.libin.aidl_example;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.support.annotation.Nullable;

/**
* Created by libin on 16/11/16.
*/

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

//====================================>
/**
* 这里是模拟 所以可以把BankService看做 Binder Server
* 现在接口有了,服务端也有了,接下来就是客户端了
*
*/


package com.mvp.libin.aidl_example;

import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {
private IBackAidl mBanklBinder; //服务端的Server对象

private TextView tv;

//用于绑定Server的ServerConnection对象
private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mBanklBinder =IBackAidl.Stub.asInterface(service);
}

@Override
public void onServiceDisconnected(ComponentName name) {

}
};

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

tv = (TextView) findViewById(R.id.tv);

Intent intent = new Intent(this,BankService.class);
intent.setAction("cn.augest.test.aidl.bank");
bindService(intent, serviceConnection, BIND_AUTO_CREATE);

init(R.id.b1);
init(R.id.b2);
init(R.id.b3);
init(R.id.b4);
}

@Override
protected void onDestroy() {
super.onDestroy();
unbindService(serviceConnection);
}

private void init(int id) {
Button button = (Button) findViewById(id);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.b1:
try {
tv.setText(mBanklBinder.OpenAccount("libin", "123456"));
} catch (RemoteException e) {
e.printStackTrace();
}
break;
case R.id.b2:
try {
tv.setText(mBanklBinder.saveMoney(12345, "libin"));
} catch (RemoteException e) {
e.printStackTrace();
}
break;
case R.id.b3:
try {
tv.setText(mBanklBinder.tackMoney(123,"libin", "123456"));
} catch (RemoteException e) {
e.printStackTrace();
}
break;
case R.id.b4:
try {
tv.setText(mBanklBinder.closeAccount("libin", "123456"));
} catch (RemoteException e) {
e.printStackTrace();
}
break;
}
}
});
}
}




这下就能看到两个进程了!

不过要注意:

1)

android:process="cn.aigestudio.BinderServer"
必须加入这个 才能新开启线程 上一篇已经讲过

2)

Intent intent = new Intent(this,BankService.class);
intent.setAction("cn.augest.test.aidl.bank");
bindService(intent, serviceConnection, BIND_AUTO_CREATE);


必须显性,不然在安卓5.0会报错!!!!!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息