前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Android高频面试专题 - 进阶篇(三)Binder机制

Android高频面试专题 - 进阶篇(三)Binder机制

作者头像
Android扫地僧
发布2020-03-19 16:15:10
9060
发布2020-03-19 16:15:10
举报
文章被收录于专栏:Android进阶Android进阶

Binder机制一直是Android面试的一个难点,尤其是Binder驱动,那不是一篇文章就能简单说清楚的,本篇还是一样,作为面试复习的一个支撑,阅读如果出现不懂的,需要及时查阅相关资料。

1、Linux内核基础知识

  • 进程隔离/虚拟地址空间 为保证操作系统不同进程间数据互不干扰,进程直接是相互隔离的,这样即使A进程发生崩溃,B进程也不会受到影响。进程隔离其实是基于虚拟地址空间实现的,操作系统对于不同进程来说是共享的,但是进程隔离后,每个进程任务自己所独享的操作系统其实是虚拟的,如果二者之间需要通信,则需要通过某种机制。Android就是基于Binder机制。
  • 系统调用 Linux将用户空间和内核空间也是隔离开来的,那么用户的应用程序如果需要访问内核空间,唯一的方式就是系统调用,通过这个统一入口接口,所有的资源访问都是在内核的控制下执行,以免导致对用户程序对系统资源的越权访问,从而保障了系统的安全和稳定。
  • Binder驱动 通过系统调用,用户空间可以访问内核空间,那么如果一个用户空间想与另外一个用户空间进行通信怎么办呢?传统的 Linux有很多通信机制,但是 Binder 并不是 Linux 内核的一部分,它是怎么做到访问内核空间的呢? Linux 的动态可加载内核模块(Loadable Kernel Module,LKM)机制解决了这个问题;模块是具有独立功能的程序,它可以被单独编译,但不能独立运行。它在运行时被链接到内核作为内核的一部分在内核空间运行。这样,Android系统可以通过添加一个内核模块运行在内核空间,用户进程之间的通过这个模块作为桥梁,就可以完成通信了。 在 Android 系统中,这个运行在内核空间的,负责各个用户进程通过 Binder 通信的内核模块叫做 Binder 驱动;

2、什么是Binder

Android作为移动端操作系统,传统的Linux进程间通信机制不满足于Android,所以开发了一套新的IPC机制,就是Binder机制。

3、为什么Android使用Binder机制

Linux 本身就支持很多通信机制,比如 Socket,管道,共享内存。选择Binder机制主要有以下2个原因

  • 性能 内存资源对Android来说非常宝贵,Socket作为一款通用接口,其传输效率低,开销大,主要用在跨网络的进程间通信和本机上进程间的低速通信。消息队列和管道采用存储-转发方式,即数据先从发送方缓存区拷贝到内核开辟的缓存区中,然后再从内核缓存区拷贝到接收方缓存区,至少有两次拷贝过程。共享内存虽然无需拷贝,但控制复杂,难以使用。
  • 安全性 传统IPC机制对通信双方的身份都没有严格的验证,比如Socket通信ip地址是客户端手动填入,很容易进行伪造,而Binder机制从协议本身就支持对通信双方做身份校检,因而大大提升了安全性。

4、Binder机制通信模型

Binder的通信机制有4个重要角色:Client、Server、Binder驱动、ServiceManager。

Client、Server、ServiceManager都在用户空间,处于不同进程。Binder驱动位于内核空间,ServiceManager相对于通讯录,内部保存了Server相关的信息,这样Client就可以通过ServiceManager拿到Server的信息,Binder驱动就相当于通信基站,这样Client和Server直接就可以通信了。

5、Binder机制通信原理

结合以上通信模型,可以看出Binder通信机制分三步:

第一步:ServiceManager在其内部维护一张表;

第二步:服务端进程向ServiceManager注册信息;

第三步:客户端进程向ServiceManager取得信息,通过Binder驱动与服务端进程通信;

这里我们一直在强调通过Binder驱动进行通信,那么Binder驱动究竟是如何进行通信的

如上图,Client想调用Server的的add方法,该方法返回一个Object对象。

首先,Server会先向ServiceManager注册一张表,这个表中就存储了相关信息,告诉ServiceManager我这里有一个返回值为Object的add方法,client向ServiceManager中查询Server端有没有一个返回值为Object的add方法,由于进程之间的通信都是在内核中进行的,驱动会在数据传输时做一些手脚,不会返回给client真正的server的Object的对象,而是返回一个代理对象,这个代理对象里包含了一个add方法,要注意,代理对象的add方法是一个空方法,它唯一要做的只是需要将参数包装好之后交给Binder驱动来实现。

Binder驱动收到代理对象的add方法之后,会在ServiceManager表中查询存在有这个方法,Binder驱动就会将代理对象替换成server端的对象,调用server端的add方法,最后将结果返回给Client。

6、AIDL是什么?与Binder的关系

AIDL(Android Interface definition language),从名字可以看出,它是一个Language,所以它并不是Android的跨进程通信机制,它只是我们程序员偷懒的一个工具,真正的进程间通信,还是Binder来实现的,AIDL只是帮我们生成Binder和BinderProxy接口类,只要你愿意,完全可以不创建AIDL文件,自己实现这一套代码。

7、AIDL使用步骤

①新建AIDL文件,例如IMyAidlInterface.aidl,内部声明一个add方法

②然后我们只需要点击 Build -> Make Project,等待构建完成,AS就会自动为我们生成复杂的Java文件。在build\generated\aidl_source_output_dir\目录下,会生成一个IMyAidlInterface.java文件继承自IInterface,并且内部生成了一个抽象静态内部类Stub

  • 该类实现了IMyAidlInterface继承自IInterface的方法asBinder。可将将接口转化为Binder。
  • 该类同时提供了一个可以将Binder转化为IMyAidlInterface实现类的方法,asInterface。
  • 该类继承自Binder类,重写了Binder类的onTransact方法。该方法的作用是,接收客户端发来的请求,并将请求分发至各个接口。
  • 该类中又自定义了一个非抽象静态类Proxy,也实现了IMyAidlInterface。该类在asInterface中被调用。
  • 该类为每个接口方法定义了一个整型的唯一标识。

可以看到,Proxy已经实现了add方法,那我们为什么还要怎么实现自己的业务逻辑呢?其实在Proxy的构造方法中,传入了一个IBinder对象,保存为成员变量mRemote,这里的add实现,其实是调用了mRemote的transact方法,将请求发送到了真正的服务端来实现,那么Proxy是在哪里被调用的,经过查看,是在Stub类的asInterface方法中

这里面的逻辑是,如果当前是Server端自己调用,那么直接返回Binder对象本身,否则,返回一个代理对象Proxy, 这里也印证了前面的理论,客户端拿到的其实是代理对象,并不是直接与服务端交互。

③有了这些系统帮我们生成的通信基础的代码,我们只需要关心服务端和客户端就好了,接下来创建服务端代码MyAidlService.java,并在Manifest文件将其声明在另一个进程

④客户端通过bindService()来绑定服务端的时候,我们返回了Binder,也就是之前的stub对象,这里才是实现我们自己的业务逻辑。

⑤客户端通过bindService中的ServiceConnection拿到IBinder对象后,就可以通过IMyAidlInterface.Stub.asInterface(service)转换为我们的服务端AIDL类(代理类),从而实现进程间通信。


好累,差点把自己都绕晕了

就到这吧

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-02-29,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Android扫地僧 微信公众号,前往查看

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档