五分钟读懂Android中的Binder跨进程机制和AIDL工具

前言

做Android开发,迈入高级必须会的技术很多,而且肯定包括Binder技术,关于Binder的了解,笔者最开始只是使用AIDL工具开发接口,生成Service的服务方法,对于其内部的实现细节不太了解。从书本上或者搜索看了好几遍,每次都是似懂非懂,然后日子久了,连那点印象也不见了。所以最近的这次综合了解了这个技术后,决定将自己的理解记录下来,一方面巩固理解,一方面分享给需要的朋友。

两个对象能直接互相访问的前提是这两个对象都存在于相同的内存地址空间中,如果两个对象位于两个不同进程,则不能直接互相调用。Binder 是Android中的一种跨进程通信方式,即IPC(Inter-process Communication)一种。首先,我们学习开发最开始知道的知识点,线程是CPU的最小调度单位;进程是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,进程可以包含多个线程。理论是这么说,从客观认识上,一个普通的app就是一个进程,很明显两个app之间不能够直接通信,如果需要,那就要用到IPC的各种方式,这里只讲binder,或者说Android中的Service,即Android四大组件之一,Binder主要用在service中。

Binder主要模块

Binder框架图1, Binder框架
Binder主要分为Binder服务端、Binder客户端和Binder驱动。
首先Binder服务端,可以看做是一个Binder类的对象,该对象创建后,会接收Binder驱动发送的消息,即在收到消息的回调中处理,执行服务代码。这个回调即是onTransact()方法。
从翻译来看,transact是办理、处理的意思,这里就可以认为,binder驱动这个中介把客户端的需求发到了服务端,服务端即可以根据回调信息进行处理。那既然有收,肯定客户端要发数据,服务端才能收到。
在这里插入图片描述
最后看Binder客户端,客户端要访问远程服务,调用服务接口,那么就必须获取远程服务在Binder对象中对应的mRemote引用,或者可以直接认为获取Binder。然后调用其transact()方法,将客户端要调用的函数和参数传递到服务端,当然是经由Binder驱动中介传到服务端。
由于Binder驱动位于内核空间,且较底层,所以我们不用太深入了解其原理,只需把它看做一个黑盒,我们只看接口输入输出,作为和服务端传递信息的信使就可以,等学有余力我们继续深挖。这里可以有个大概的认识,其为字符型设备,用户可以从/dev/binder设备文件节点上通过open和ioctl文件操作函数与Binder driver通信,其主要负责Binder通信机制的建立以及在进程间传递和Binder引用计数管理、数据包传输等。

Demo示例

这里以一个aidl的demo为示例,其链接为binderdemo,其中此project中的app module为binder的server端,有MediaService作为服务器,添加的AIDL接口。然后binderclient module为binder客户端。

// IMediaService.aidl
package com.example.binderserver;
import com.example.binderserver.MediaInfo;

// Declare any non-default types here with import statements
interface IMediaService{
   
void startplay(in MediaInfo info);
void stop();
void search(String name);
}

其中的MediaInfo的aidl源码为:

// MediaInfo.aidl
package com.example.binderserver;

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

parcelable MediaInfo;

AIDL中支持的数据类型有:
1.基本数据类型:int、long、char、boolean、double等;
2.String和CharSequence;
3.ArrayList,且其每个元素都必须是支持的数据类型;
4.HashMap,且其每个元素都是支持的数据类型;
5.Parcelable,即所有实现了parcelable接口的对象;
6.AIDL,即所有AIDL接口本身。
所以根据第5条,MediaInfo非其他AIDL支持的类型,自定义类必须继承parcelable。
而parcelable是Android序列化中最重要的方式,在跨进程通信中很重要,总之,就是重要。 想对其有深入了解的读者可以参考我的另一篇文章:一文看懂Android中的序列化
接下来我们继续说服务端和客户端,为了读者更快了解框架全貌,这里先把代码附录上。
服务端的代码如下,

   public class MediaService extends Service {
   
    private static final String TAG = "MediaService";

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
   
        return (IBinder) mBinder;
    }

    private IMediaService mBinder = new IMediaService.Stub() {
   
        @Override
        public void startplay(MediaInfo info) throws RemoteException {
   
            Log.d(TAG, "startplay mediaInfo =" + info.toString());
        }

        @Override
        public void stop() throws RemoteException {
   
            Log.d(TAG, "service stop  ");
        }

        @Override
        public void search(String name) throws RemoteException {
   
            Log.d(TAG, "service search name=" + name);
        }
    };
}

客户端的代码如下:

public class MainActivity extends Activity {
   
    private static final String TAG = "binderclient";
    ServiceConnection conn;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
   
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        conn = new ServiceConnection() {
   
            @Override
            public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
   
                Log.d(TAG, "onServiceConnected");
                IMediaService binder = IMediaService.Stub.asInterface(iBinder);
                try {
   
                    Log.d(TAG, "onServiceConnected search invoke");
                    binder.search("忘情水");
                    Log.d(TAG, "onServiceConnected startplay invoke");
                    binder.startplay(new MediaInfo("夜空中最闪亮的星", "xxx", "逃跑计划"));
                    Log.d(TAG, "onServiceConnected stop invoke");
                    binder.stop();
                } catch (RemoteException e) 
  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值