前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Android 中的Binder跨进程通信机制与AIDL

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

作者头像
先知先觉
发布2019-01-21 11:44:31
7440
发布2019-01-21 11:44:31
举报

如果对进程、线程概念还很懵懂的同学可以看一下之前发表的一篇博客,里面是基础概念: 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

这里写图片描述
这里写图片描述
代码语言:javascript
复制
// 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 这里贴出一部分

代码语言:javascript
复制
/**
        * 开户
        * @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;
}
代码语言:javascript
复制
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+"销户";
    }
}
*/
代码语言:javascript
复制
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
 * 现在接口有了,服务端也有了,接下来就是客户端了
 *
 */
代码语言:javascript
复制
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)

代码语言:javascript
复制
Intent intent = new Intent(this,BankService.class);
        intent.setAction("cn.augest.test.aidl.bank");
        bindService(intent, serviceConnection, BIND_AUTO_CREATE);

必须显性,不然在安卓5.0会报错!!!!!

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2016年11月15日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 为什么需要跨进程通信?
  • 为什么在Android中使用Binder进行跨进程通信?
  • Binder是什么?
  • 如何使用Binder进行跨进程通信呢?
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档