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

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

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏编码前线

Android中的序列化:Parcelable和Serializable

13310
来自专栏Android知识点总结

Android材料设计之Behavior攻坚战

接触目标view时才会回调:onStartNestedScroll 加了layout_behavior的View是child

24320
来自专栏有困难要上,没有困难创造困难也要上!

Android项目编译报错Failed to resolve: firebase-iid-interop

修改 build.gradle 文件,将其中 jcenter() 和 google() 两个仓库换一下顺序,比如

12520
来自专栏AndroidTv

前端入门7-JavaScript语法之相关术语声明正文-相关术语

作为一个前端小白,入门跟着这几个来源学习,感谢作者的分享,在其基础上,通过自己的理解,梳理出的知识点,或许有遗漏,或许有些理解是错误的,如有发现,欢迎指点下。

11130
来自专栏Android先生

Flutter组件学习(二)—— Image

上一节中,我们讲了 Flutter 中 Text 组件的一些用法以及 API,本节我们继续学习 Flutter 中的 Image 组件,同样先上图:

27430
来自专栏Android 开发者

[译] 为用户提供安全可靠的体验

我们不遗余力地关注 Google Play Store 的安全性和隐私,以确保 Android 用户拥有发现和安装他们喜欢的应用程序和游戏的积极体验。我们定期更...

11240
来自专栏Android 开发者

用新技术 “派生” 动听旋律 | Android 开发者故事

QQ 音乐 Android 团队平台组的负责人阿宝,在和 QQ 音乐一同寻求突破的过程中,他发现创意、研发和平台的助力是让应用进步的三个重要因素。所以,他和团队...

14120
来自专栏Android知识点总结

Android资源res之矢量图完全指南(加SVG-path命令分析)

16240
来自专栏非著名程序员

我今天浏览 Twitter 的时候,发现了一个好东西

今天很累,很累,本来不想写文章来,所以晚上回家之后,打开 Twitter 想浏览一下外国的新闻,顺便看看 NBA 的集锦来。可是,像我这么爱学习的一个人, Tw...

17520
来自专栏androidBlog

聊一聊Android 中巧妙的位操作

如果不采用或运算符来写,采用布尔值来记录每一种状态,那每一次绘制 TextView 的时候,你得判断多少次,才能得出 TextView 的对其方向。

10530

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励