AIDL 和binder 原理
来源:互联网 发布:网络公关公司危机公关 编辑:程序博客网 时间:2024/05/29 06:53
文章中提到的 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(){接口方法实现}
先建立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线程池中的。
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。
根据原理,我们得出AIDL的使用流程,其实很简单,大致就是在服务端创建一个Service,然后创建一个Binder对象,最后在客户端得到这个Binder对象。
先建立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线程池中的。
阅读全文
0 0
- AIDL 和binder 原理
- Binder-基础知识和AIDL
- AIDL和Binder图解
- Binder机制和AIDL
- android service binder 和AIDL
- Android IPC、Binder和AIDL
- Android Studio 创建AIDL以及Binder 原理
- Binder底层原理,aidl.java文件分析
- Binder AIDL
- Binder&AIDL
- AIDL使用和Binder机制详解
- Android AIDL和Binder 简单分析
- Binder和AIDL之间的关系
- Android Binder 全解析(3) -- AIDL原理剖析
- Android Binder 全解析(3) -- AIDL原理剖析
- binder的机制和原理
- binder的机制和原理
- android进程间通讯流程分析:使用 Binder和AIDL
- influxdb简介
- oss php sdk+laravel搭建图片处理静态网站
- 欢迎使用CSDN-markdown编辑器
- ECMAScript 6 入门(第三版)
- CocosCreator基础:新建项目
- AIDL 和binder 原理
- Linux服务器和Windows本地间scp命令上传下载文件的使用
- 面试知一二
- Matlab 2016a安装激活,启动显示License Manager Error-8,解决方法?
- 中国新的AI警察局将不会有人类
- 笔试题解读
- 欢迎使用CSDN-markdown编辑器
- 归并排序算法个人理解
- 机器学习初学者——模型评估与选择