文章中提到的 IBookManager 和 getBookList 是下面代码中的 IMyAidlInterface 和 sum(**)函数

GIT: https://github.com/whtchl/AidlTemplate
Binder的原理

要想了解AIDL就需要先了解Binder的原理,所以这里先说一下Binder原理,Binder的原理大概是这样:

服务器端:当我们在服务端创建好了一个Binder对象后,内部就会开启一个线程用于接收binder驱动发送的消息,收到消息后会执行相关的服务器代码。

Binder驱动:当服务端成功创建一个Binder对象后,Binder驱动也会创建一个mRemote对象,该对象的类型也是Binder类,客户就可以借助这个mRemote对象来访问远程服务,注意这里是借助,真正调用的时候需要将这个转换成对应的对象,比如使用AIDL的时候就要转换成AIDL对象。

客户端:客户端要想访问Binder的远程服务,就必须获取远程服务的Binder对象在binder驱动层对应的mRemote引用。当获取到mRemote对象的引用后,就可以调用相应Binder对象的暴露给客户端的方法(如果有方法的话)。

AIDL

AIDL的本质其实就是系统为我们提供了一种快速实现Binder的工具,我们完全可以不用AIDL,自己去写代码实现Binder,但是当你写出来的时候会发现其实和AIDL自动生成的代码一模一样。我们接下来来分析一下原理,因为AIDL的实现其实就是快速实现Binder,所以原理自然离不开Binder。但是在分析原理之前,我们先将系统根据我们定义的AIDL文件自动生成的java文件分析一下。比较重要的就是Stub和它的内部代理类Proxy。我们说一下重要的方法:

asInterface(android.os.IBinder obj)
用于将服务器的Binder对象转换成客户端所需的AIDL接口类型的对象,这种转换过程是区分进程的,如果客户端和服务端位于统一进程,那么返回服务器的Stub对象本身,否则返回的是系统封装后的Stub.proxy对象。

onTransact(int code,android.os.Parcel data,android.os.Parcel reply,int flags)
这个方法运行在服务端的Binder线程池中,当客户端发起跨进程请求时,远程请求会通过系统底层封装后交由服务端 的onTransact方法来处理。这个方法有四个参数,分别是code ,data,reply,flags.code是确定客户端请求的方法是哪个,data是目标方法所需的参数,reply是服务器端执行完后的返回值。如果这个方法返回false,那么客户端的请求会失败。

Proxy#getBookList
这里的getBookList方法就是在自定义的AIDL文件中定义的方法,这个方法运行在客户端,当客户端远程调用此方法的时候,内部实现是这样的:首先在代理类中创建该方法所需要的输入型Parcel对象_data,输出型Parcel对象_reply和返回值对象List;然后把该方法的参数信息写入_data中,接着mRemote调用transact方法来发起RPC(远程过程调用)请求, 同时当前线程挂起,然后服务端的onTransact方法会被调用,直到RPC返回后,当前线程继续执行,并从_reply中取出RPC过程的返回结果并返回(如果有返回值的话),之前创建的参数其实就是onTransact()方法需要的参数。

说完了重要方法,接下来分析AIDL原理:

服务端:因为要实现Binder,必须在服务器端创建一个Binder对象,如何创建呢?就是newAIDL接口中的Stub内部类,代码示例如:
Binder mBinder=new IBookManager.Stub(){接口方法实现}

其中IBookManager是系统根据我们自己定义的IBookManager.AIDL所生成的类。

Binder驱动:在AIDL中,Binder驱动其实就是Service。

客户端: 要实现客户端跨进程和服务端通信,必须获得服务端的Binder对象在binder驱动层对应的mRemote引用,如何获得呢?首先绑定远程服务,绑定成功后的ServiceConnection中的IBinder service其实就是mRemote引用,但是因为是使用AIDL方式,所以需要在客户端中调用IBookManager.Stub.asInterface(android.os.IBinder obj)方法将服务器返回的Binder对象转换成AIDL接口,然后就可以通过这个接口去调用服务器的远程方法了。

根据原理,我们得出AIDL的使用流程,其实很简单,大致就是在服务端创建一个Service,然后创建一个Binder对象,最后在客户端得到这个Binder对象。

AIDL使用流程:
先建立AIDL,如果在你建立的AIDL接口中,有自定义的类,那么,也需要建立这个类的AIDL,并且名字要完全相同。同时在使用的时候,一定要显示的导入这个类。接下来的流程就是跟Binder的一样了。
服务器端:创建Binder对象,并且实现接口中的方法。
客户端:绑定service,得到Binder对象在驱动层对应的mRemote引用。  
重点

1.当你在客户端调用服务器的方法的时候,其实是通过代理去访问,详情可以看上面的重点方法介绍里的Proxy#getBookList,所以你在客户端连续调用两次服务器的同一个方法的时候,比如,这里的getBookList,你会发现,里面的对象都不一样。因为每次在调用方法的时候,在代理类中都会创建该方法所需要的参数对象,所以里面的对象会变化。
2.AIDL中无法使用普通的接口,只能使用AIDL接口,并且实现AIDL接口的时候不能用implements,因为需要实现的接口其实是自定义接口.Stub,而不是自己定义的那个接口。使用implements无法实现。  
3.解注册的时候需要使用到RemoteCallbackList,需要注意的是这个类的beginBroadcast()和finishBroadcast()一定要配对使用,否则会出现异常java.lang.IllegalStateException: beginBroadcast() called while already in a broadcast,特别是在使用for循环的时候。
4.对于AIDL中的in,out,inout这里就直接附上一篇别人写的博客,这篇博客讲的很详细,而且我也赞同他的观点,纸上得来终觉浅,绝知此事要躬行。  
5 .当使用客户端调用服务器的方法的时候,被调用的方法运行在服务器的Binder线程池中,同时客户端会被挂起,如果此时服务端方法执行耗时的话,就会导致客户端线程长时间阻塞,如果客户端线程是UI线程的话,就会导致客户端ANR,注意的是onServiceConnected(ComponentName name, IBinder service)和onServiceDisconnected(ComponentName name)都运行在UI线程,所以不能在这里调用服务端耗时的方法。同理,对于服务端调用客户端的方法的情况,比如服务端调用客户端的listener中的方法的时候也是一样。即服务端挂起,方法运行在客户端的Binder线程池中。  
6.当服务端因为某种异常原因停止,我们需要重新启动服务端,这里有两种方式,因为AIDL的底层是Binder,所以可以使用Binder的linkToDeath和unlinkToDeath方法。还有一种方式是在onServiceDisconnected(ComponentName name)重新绑定。这两个区别就是第二种方式可以访问UI,第一种不行,因为像之前说的,onServiceDisconnected(ComponentName name)是运行在UI线程里的。而第一种方式使用的时候需要设置一个IBinder.DeathRecipient接口用于接收服务端binder因为特殊原因消失的通知,当收到通知的时候就会回调binderDied()方法,我们在这里unlinkToDeath并且重新绑定service。而这个binderDied()方法是运行在客户端的Binder线程池中的。

AIDL 和binder 原理相关推荐

  1. 写给App开发的Binder原理系列

    前言 Binder原理是掌握系统底层原理的基石,也是进阶高级工程师的必备知识点,这篇文章不会过多介绍Binder原理,而是讲解学习Binder前需要的掌握的知识点. 我认为学好Binder原理的秘诀主 ...

  2. Linux 角度看binder原理(四

    Linux 角度看binder原理(四) Service注册 这里使用media服务作为例子. #frameworks/av/media/mediaserver/main_mediaserver.cp ...

  3. 写给 Android 应用工程师的 Binder 原理剖析

    2019独角兽企业重金招聘Python工程师标准>>> 一. 前言 这篇文章我酝酿了很久,参考了很多资料,读了很多源码,却依旧不敢下笔.生怕自己理解上还有偏差,对大家造成误解,贻笑大 ...

  4. 2019 Android 高级面试题总结 从java语言到AIDL使用与原理

    说下你所知道的设计模式与使用场景 a.建造者模式: 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示. 使用场景比如最常见的AlertDialog,拿我们开发过程中举例,比如C ...

  5. AIDL使用以及原理分析

    AIDL使用以及IPC原理分析(进程间通信) 概要 为了大家能够更好的理解android的进程间通信原理,以下将会从以下几个方面讲解跨进程通讯信: 1. 必要了解的概念 2. 为什么要使用aidl进程 ...

  6. 2019-Android-高级面试题总结-从java语言到AIDL使用与原理

    匿名内部类同样会持有外部类的引用,如果在线程中执行耗时操作就有可能发生内存泄漏,导致外部类无法被回收,直到耗时任务结束,解决办法是在页面退出时结束线程中的任务 3.Handler内存泄漏 Handle ...

  7. aidl demo调用原理

    通过网络的例子,生成的BookManager如下所示:service和client都是相同的java文件生成的. 这个类的例子添加book和查询book两个例子 客户端创建bookmananger方法 ...

  8. Android Binder 原理,android实战项目pdf

    信号: 不适用于信息交换,更适用于进程中断控制,比如非法内存访问,杀死某个进程等: 2.1 性能: Binder数据拷贝只需要一次,而管道.消息队列.Socket都需要2次,共享不需要内存拷贝:从性能 ...

  9. Binder原理学习记录

    前言 在平时的开发中,我们不免会遇到跨进程的通信,平时使用系统提供的诸如ActivityServiceManager这些系统服务,其实就是使用了跨进程的调用,那么跨进程的调用,需要解决的就是进程间的通 ...

最新文章

  1. Docker快速验证tomcat单机多实例方案
  2. 服务器到底长什么样子啊(#゚Д゚)?
  3. 重拾-Spring Transaction
  4. 给history命令加上执行用户和时间
  5. 实时动态测量技术的不足与改进方法
  6. java private 接口_java接口中 定义 private 私有方法
  7. 730版本去掉恼人的提示信息
  8. 对象导论---JAVA编程思想
  9. android编程读取sd卡txt文件,如何读取SD卡中的txt文件?
  10. python的pass在函数中的作用_Pass Share:Python / Julia 中函数变量的传递机制
  11. 线性代数【15】复合线性变换-矩阵乘法 和 三维变换
  12. html 网站右侧导航,页面右侧固定导航.html
  13. lua编译器和ide
  14. CRM 客户管理系统C#源码
  15. org.apache.hadoop.hbase.ipc.ServerNotRunningYetException: Server is not runn Hbase shell 无法执行命令
  16. 使用积分图像进行自适应二值化[Derek Bradley, Gerhard Roth, 2007]
  17. 008 触发器实现三分频
  18. 网络编程+go+java,Go语言中的TCP/IP网络编程
  19. django mongo engine
  20. 【数据科学家】什么是数据科学?

热门文章

  1. 哲学家就餐 java_java模拟哲学家就餐问题
  2. 3dvary灯光材质为什么不亮_夜间跑高速开近光灯与为什么近光灯和刹车泡容易坏。...
  3. 四、HTTP响应报文格式
  4. 2.QML组件、图像几何变换和元素定位器
  5. 2.innodb后台线程
  6. 记录一下HALCON检测螺钉是否存在
  7. OpenNI框架介绍
  8. sqlplus可以连接plsql连接不上_为什么有的iPhone/iPad连接不上电脑?
  9. 如何在 Kubernetes 中对无状态应用进行分批发布
  10. linux集群-keepalived介绍-用keepalived配置高可用集群