Android进阶笔记

Android进阶笔记-5. IPC机制 & Binder 原理

2022-01-12  本文已影响0人  今阳说

IPC机制

一次进程间通信至少包含两个进程,由于进程隔离机制的存在,通信双方必然需要借助 IPC(进程间通信,inter-Process Communication)来实现;

Linux中的IPC机制种类

管道(pipe)
信号(sinal)
信号量(semophore)
消息队列(Message)
共享内存(Share Memory)
套接字(Socket)

Android中的IPC机制

序列化
Serializable与Parcelable区别
AIDL
服务端:
客户端:
Bundle
共享文件和SharedPreferences
Messenger(信使,轻量级的IPC方案)
public Messenger(IBinder target) {
    mTarget = IMessenger.Stub.asInterface(target);
}
Socket
ContentProvider
Binder

Binder 跨进程通信原理

为什么要使用Binder

1. 性能
  1. 管道、消息队列、Socket的拷贝次书都是两次,性能不是很好;
  2. 共享内存不需要拷贝,性能最好;
  3. Binder拷贝1次,性能仅次于共享内存;
Linux 下传统的进程间通信原理与不足
  1. 一次数据传递需要经历:用户空间 –> 内核缓存区 –> 用户空间,需要2次数据拷贝,效率不高。
  2. 接收数据的缓存区由数据接收进程提供,但是接收进程并不知道需要多大的空间来存放将要传递过来的数据,因此只能开辟尽可能大的内存空间或者先调用API接收消息头来获取消息体的大小,浪费了空间或者时间。
2. 稳定性
  1. Binder是基于C/S架构的,技术上已经很成熟,稳定;
  2. 共享内存没有分层,难以控制,并发同步访问临界资源时,可能还会产生死锁;
3. 安全
4. 语言

Android中Binder的来源

Linux的动态内核可加载模块

Binder 驱动

内核空间(KernelSpace)和用户空间(UserSpace)
进程隔离
系统调用
内存映射(Memory Map)
Binder驱动通过内存映射进行跨进程通信的步骤
  1. Binder驱动在内核空间创建一个数据接收缓存区。
  2. 在内核空间开辟一块内核缓存区,建立内核缓存区和数据接收缓存区之间的映射关系,以及数据接收缓存区和接收进程用户空间地址的映射关系。
  3. 发送方进程通过copy_from_user()函数将数据拷贝 到内核中的内核缓存区,由于内核缓存区和接收进程的用户空间存在内存映射,
    因此也就相当于把数据发送到了接收进程的用户空间,这样便完成了一次进程间的通信,整个过程只使用了1次拷贝,效率更高。

基于Binder通信的C/S架构

[图片上传失败...(image-18e90-1641984042595)]

Binder机制 在Android中的具体实现

Binder 通信过程

1. 启动ServiceManager
int main(int argc, char** argv)
{
    //binder_state结构体用来存储binder的三个信息:
    //int fd; //binder设备的文件描述符
    //void *mapped; //binder设备文件映射到进程的地址空间
    //size_t mapsize; //内存映射后,系统分配的地址空间的大小,默认为128KB
    struct binder_state *bs;
    union selinux_callback cb;
    char *driver;

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

    //binder_open:打开binder设备文件,调用mmap函数进行内存映射,申请128k字节大小的内存空间
    bs = binder_open(driver, 128*1024);
    ...
    //binder_become_context_manager:将servicemanager注册成为Binder机制的上下文管理者,这个管理者在整个系统只有一个
    if (binder_become_context_manager(bs)) {
        ALOGE("cannot become context manager (%s)\n", strerror(errno));
        return -1;
    }
    ...
    if (getcon(&service_manager_context) != 0) {
        ALOGE("SELinux: Failed to acquire service_manager context. Aborting.\n");
        abort();
    }
    //servicemanager成功注册成为Binder机制的上下文管理者后,servicemanager就是Binder机制的“总管”了,
    //它需要在系统运行期间处理client端的请求,由于client端的请求不确定何时发送,因此需要通过无限循环来实现
    binder_loop(bs, svcmgr_handler);

    return 0;
}
  1. 打开binder设备文件,调用mmap函数进行内存映射,申请128k字节大小的内存空间
  2. 将servicemanager注册成为Binder机制的上下文管理者,这个管理者在整个系统只有一个
  3. servicemanager成功注册成为Binder机制的上下文管理者后,servicemanager就是Binder机制的“总管”了,它需要在系统运行期间通过无限循环处理client端的请求
用户态和内核态
2. 注册服务
int main(int argc __unused, char **argv __unused)
{
    signal(SIGPIPE, SIG_IGN);
    //获取ProcessState实例,打开/dev/binder设备,设定Binder最大的支持线程数
    //并使用mmap为Binder驱动分配一个虚拟地址空间用来接收数据。
    sp<ProcessState> proc(ProcessState::self());
    //获取ServiceManager,其他进程就可以和当前的ServiceManager进行交互
    //ServiceManager中使用了Binder通信(BpBinder),它自身也是属于Binder体系的
    //这里得到的实例是BpServiceManager,它实现了IServiceManager,并且通过BpBinder来实现通信
    sp<IServiceManager> sm(defaultServiceManager());
    ALOGI("ServiceManager: %p", sm.get());
    InitializeIcuOrDie();
    //注册MediaPlayerService,
    //其中调用了defaultServiceManager()->addService将数据打包发送给BpBinder来进行处理
    //BpBinder新建一个IPCThreadState对象,并将通信的任务交给IPCThreadState
    //IPCThreadState的writeTransactionData函数用于将命令协议和数据写入到mOut中
    //IPCThreadState的waitForResponse函数主要做了两件事,
    //一件事是通过ioctl函数操作mOut和mIn来与Binder驱动进行数据交互,另一件事是处理各种命令协议。
    MediaPlayerService::instantiate();
    ResourceManagerService::instantiate();
    registerExtensions();
    //启动Binder线程池
    ProcessState::self()->startThreadPool();
    //当前线程加入到线程池
    IPCThreadState::self()->joinThreadPool();
}

- BpBinder,BBinder是Binder通信的“双子星”,都继承了IBinder;
- BpBinder是Client端与Server交互的代理类,而BBinder则代表了Server端。
- BpBinder和BBinder是一一对应的,BpBinder会通过handle来找到对应的BBinder
- BpBinder和BBinder负责Binder的通信,而IServiceManager用于处理ServiceManager的业务
  1. MediaServer通过Binder驱动,使用mmap接收数据;
  2. 获取一个IServiceManager的实例BpServiceManager,其并且通过BpBinder来实现通信;
  3. 通过defaultServiceManager注册MediaPlayerService,这里MediaPlayerService是Client端,用于请求添加系统服务。而Server端则是指的是ServiceManager,用于完成系统服务的添加,两端通过向Binder驱动发送命令协议来完成系统服务的添加;
3. 获取服务
IMediaDeathNotifier::getMediaPlayerService()
{
    ALOGV("getMediaPlayerService");
    Mutex::Autolock _l(sServiceLock);
    if (sMediaPlayerService == 0) {
        sp<IServiceManager> sm = defaultServiceManager();//实例为BpServiceManager
        sp<IBinder> binder;
        do {
            //获取名为”media.player”的系统服务(MediaPlayerService),返回的值为BpBinder
            binder = sm->getService(String16("media.player"));
            if (binder != 0) {
                break;
            }
            //这个时候MediaPlayerService可能还没有向ServiceManager注册
            //所以休眠0.5s后继续调用getService,直到获取服务对应的为止
            usleep(500000); //4
        } while (true);

        if (sDeathNotifier == NULL) {
            sDeathNotifier = new DeathNotifier();
        }
        binder->linkToDeath(sDeathNotifier);
        //interface_cast通过BpBinder的handle来找到对应的服务,即BpMediaPlayerService。
        sMediaPlayerService = interface_cast<IMediaPlayerService>(binder);
    }
    ALOGE_IF(sMediaPlayerService == 0, "no media player service!?");
    return sMediaPlayerService;
}
4. 使用服务
private ComponentName startServiceCommon(Intent service, boolean requireForeground, UserHandle user) {
    try {
        ...
        //
        ComponentName cn = ActivityManager.getService().startService(
                mMainThread.getApplicationThread(), service,
                service.resolveTypeIfNeeded(getContentResolver()), requireForeground,
                getOpPackageName(), getAttributionTag(), user.getIdentifier());
        ...
        return cn;
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }
}
@UnsupportedAppUsage
public static IActivityManager getService() {
    return IActivityManagerSingleton.get();
}

@UnsupportedAppUsage
private static final Singleton<IActivityManager> IActivityManagerSingleton =
    new Singleton<IActivityManager>() {
        @Override
        protected IActivityManager create() {
            final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
            final IActivityManager am = IActivityManager.Stub.asInterface(b);
            return am;
        }
    };
从不同角度看Binder定义
  1. 从IPC角度:Binder是Android中的一种跨进程通信方式,该通信方式在linux中没有,是Android独有;
  2. 从Android Driver层:Binder还可以理解为一种虚拟的物理设备,它的设备驱动是/dev/binder;
  3. 从Android Framework层:Binder是各种Manager(ActivityManager、WindowManager等)和相应xxxManagerService的桥梁;
  4. 从Android APP层:Binder是客户端和服务端进行通信的媒介,当bindService的时候,服务端会返回一个包含了服务端业务调用的 Binder对象,通过这个Binder对象,客户端就可以获取服务端提供的服务或者数据,这里的服务包括普通服务和基于AIDL的服务
  5. 从 Server 进程的角度,Binder 指的是 Server 中的 Binder 实体对象;
  6. 从 Client 进程的角度,Binder 指的是对 Binder 代理对象,是 Binder 实体对象的一个远程代理
  7. 从传输过程的角度,Binder 是一个可以跨进程传输的对象;Binder 驱动会对这个跨越进程边界的对象对一点点特殊处理,自动完成代理对象和本地对象之间的转换。

参考

我是今阳,如果想要进阶和了解更多的干货,欢迎关注微信公众号 “今阳说” 接收我的最新文章

上一篇下一篇

猜你喜欢

热点阅读