美文网首页
2020-02-17-Android的Binder通信原理

2020-02-17-Android的Binder通信原理

作者: 耿望 | 来源:发表于2020-04-04 17:42 被阅读0次

Binder通信是一个比较大的架构,从内核跟native源码角度分析的文章很多,今天准备写一下大概原理,适合跟我一样的新手看。

C/S架构

Binder通信整体架构是我们很熟悉的客户端+服务端模式,客户端进程得到一个BpBinder,也就是binder的代理对象,通过代理对象向内核缓冲区读写数据。服务端得到一个BBinder,也就是binder的本地对象,通过本地对象向内核缓冲区读写数据,这样就实现了跨进程通信。
下面画了一张图:


Binder原理.jpg

内存映射

我们理解一般的跨进程通信需要两次数据拷贝,而Binder只需要一次,这是为什么呢?
在Linux系统中,每个进程之间是独立的,各自拥有自己的内存空间,分为用户空间和内核空间。
如果需要实现通信,就需要把进程A的数据拷贝到内核空间,然后再从内核空间拷贝到进程B。
而binder建立了一个映射关系,把内核缓冲区的数据映射到进程A和进程B,它们的物理地址是一样的,从而省去了一次数据拷贝的过程。
下面画了一张图


IPC数据拷贝.jpg

Binder服务的注册与获取

Binder通信还有一个比较特殊的地方,就是所有的服务都需要通过ServiceManager向Binder驱动注册。
ServiceManager本身也是一个Binder服务,它的本地实现代码都在service_manager.c文件中,同时向外提供了ISeriviceManager接口,开发者可以通过IServiceManager接口获取到一个BpServiceManager对象,通过它来addService或者getService。
下面画了一张图,写了ServiceManager启动,注册跟获取服务的过程:


ServiceManager.jpg

ServiceManager启动过程

我们看下ServiceManager的main方法,初始化的过程做了以下几件事:
1.打开binder驱动,并调用mmap()方法分配内存映射空间:binder_open();
2.通知binder驱动使其成为守护进程:binder_become_context_manager();
3.验证selinux权限,判断进程是否有权注册或查看指定服务;
4.进入循环状态,等待Client端的请求:binder_loop()。
/frameworks/native/cmds/servicemanager/service_manager.c

int main(int argc, char** argv)
{
    struct binder_state *bs;
    union selinux_callback cb;
    char *driver;

    if (argc > 1) {
        driver = argv[1];
    } else {
        driver = "/dev/binder";
    }

    bs = binder_open(driver, 128*1024);//1
    if (!bs) {
#ifdef VENDORSERVICEMANAGER
        ALOGW("failed to open binder driver %s\n", driver);
        while (true) {
            sleep(UINT_MAX);
        }
#else
        ALOGE("failed to open binder driver %s\n", driver);
#endif
        return -1;
    }

    if (binder_become_context_manager(bs)) {//2
        ALOGE("cannot become context manager (%s)\n", strerror(errno));
        return -1;
    }

    cb.func_audit = audit_callback;
    selinux_set_callback(SELINUX_CB_AUDIT, cb);
#ifdef VENDORSERVICEMANAGER
    cb.func_log = selinux_vendor_log_callback;
#else
    cb.func_log = selinux_log_callback;
#endif
    selinux_set_callback(SELINUX_CB_LOG, cb);
//3
#ifdef VENDORSERVICEMANAGER
    sehandle = selinux_android_vendor_service_context_handle();
#else
    sehandle = selinux_android_service_context_handle();
#endif
    selinux_status_open(true);

    if (sehandle == NULL) {
        ALOGE("SELinux: Failed to acquire sehandle. Aborting.\n");
        abort();
    }

    if (getcon(&service_manager_context) != 0) {
        ALOGE("SELinux: Failed to acquire service_manager context. Aborting.\n");
        abort();
    }

    binder_loop(bs, svcmgr_handler);//4

    return 0;
}

获取ServiceManager的代理对象BpServiceManager

接着开发者可以通过IServiceManager接口,获取到ServiceManager的代理对象。
/frameworks/native/libs/binder/IServiceManager.cpp

sp<IServiceManager> defaultServiceManager()
{
    if (gDefaultServiceManager != nullptr) return gDefaultServiceManager;

    {
        AutoMutex _l(gDefaultServiceManagerLock);
        while (gDefaultServiceManager == nullptr) {//1
            gDefaultServiceManager = interface_cast<IServiceManager>(
                ProcessState::self()->getContextObject(nullptr));//2
            if (gDefaultServiceManager == nullptr)
                sleep(1);//3
        }
    }

    return gDefaultServiceManager;
}

这里是一个单例模式,如果gDefaultServiceManager存在就直接返回,否则创建新的gDefaultServiceManager,它就是BpServiceManager。
注释1 处用了一个while循环,保证gDefaultServiceManager创建成功;
注释2 处获取了三个重要的对象:
(1)通过self函数获取一个ProcessState对象;
(2)通过getContextObject获取了一个BpBinder对象;
(3)通过interface_cast获取了一个BpServiceManager对象;
注释3 处如果创建不成功,sleep1秒后再次尝试创建。

向Binder驱动注册服务

通过上面拿到的BpServiceManager,我们可以向Binder驱动注册自己的服务了。这里通过Parcel将数据序列化之后写入内存。
/frameworks/native/libs/binder/IServiceManager.cpp

    virtual status_t addService(const String16& name, const sp<IBinder>& service,
                                bool allowIsolated, int dumpsysPriority) {
        Parcel data, reply;
        data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
        data.writeString16(name);
        data.writeStrongBinder(service);
        data.writeInt32(allowIsolated ? 1 : 0);
        data.writeInt32(dumpsysPriority);
        status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);
        return err == NO_ERROR ? reply.readExceptionCode() : err;
    }

客户端操作是通过BpBinder代理对象,而实际通信操作都是在IPCThreadState类中完成的。
/frameworks/native/libs/binder/BpBinder.cpp

// NOLINTNEXTLINE(google-default-arguments)
status_t BpBinder::transact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
    // Once a binder has died, it will never come back to life.
    if (mAlive) {
        status_t status = IPCThreadState::self()->transact(
            mHandle, code, data, reply, flags);
        if (status == DEAD_OBJECT) mAlive = 0;
        return status;
    }

    return DEAD_OBJECT;
}

通过ServiceManager获取服务

获取服务的过程类似上面,也是通过代理对象获取的,这里就不介绍源码了,画了一下上层java接口的流程。


Binder java.jpg

服务端异常死亡处理

可以通过实现IBinder.DeathRecipient接口,来监听服务端死亡通知。

private class BinderDeathRecipient implements DeathRecipient {
    @Override
    public void onBinderDied() {
        //
    }
}

然后将获取到的IBinder对象,通过IBinder.linkToDeath()方法链接到DeathRecipient。

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.d(TAG, "onServiceConnected ComponentName=" + name);
            mReporterBinder = service;
            try {
                sercie.linkToDeath(new BinderDeathRecipient(), 0);
            } catch (RemoteException e) {
                 //
             }
        }

参考:

Android系统进程间通信Binder机制在应用程序框架层的Java接口源代码分析
彻底理解Android Binder通信架构
Binder系列—开篇
Android深入浅出之Binder机制
Binder死亡通知机制之linkToDeath
Android多进程之Binder的意外死亡及权限校验

相关文章

  • 2020-02-17-Android的Binder通信原理

    Binder通信是一个比较大的架构,从内核跟native源码角度分析的文章很多,今天准备写一下大概原理,适合跟我一...

  • Binder机制

    进程间通信方式 Android Binder框架图 Android系统框架 IPC 进程通信原理 Binder原理...

  • Binder通信机制

    目录 Linux内核背景 Binder通信模型 Binder通信原理 AIDL 总结 1. Linux内核背景 进...

  • 2018-09-04 binder

    【转】图文详解 Android Binder跨进程通信的原理 [【转】](Android Binder机制(超级详...

  • Binder进程间通信-JAVA层

    进程间通信基本原理 进程间通信原理 Binder是什么? IPC(Inter-Process Communicat...

  • Binder Framework层实现

    前言 Binder基本原理 Binder通信采用C/S架构,以内核空间binder驱动为基础,用户空间Servic...

  • Binder通信原理

    在前面的Binder注册与查找一文中,已经介绍过Binder机制在Java层的通信架构。我们知道,在通信过程中,请...

  • Binder进程通信的基本原理

    Binder进程通信的基本原理 基础 Binder是基于linux驱动设备的,所以我们可以把Binder驱动当做文...

  • framework 学习笔记7. 了解Binder驱动

    进程间通信的原理:binder驱动1.png Binder驱动的初始化: 2.1 驱动注册 misc_regist...

  • Android

    ContentProvider 作用 进程间数据共享 即跨进程通信 原理 Binder进程间通信结合匿名共享内存(...

网友评论

      本文标题:2020-02-17-Android的Binder通信原理

      本文链接:https://www.haomeiwen.com/subject/ffxifhtx.html