IPC之AIDL(3)系统为我们做了什么
2017-05-16 16:01
363 查看
内容大纲:
前面几篇我们介绍了如何使用AIDL实现IPC 那么你会有疑问了 我们用的asInterface是什么, Stub又是什么,现在让我们一点一点来看。在我们编译的时候,系统会吧aidl生成对应的java类(这就是为什么支持aidl这种文件格式了),我们先来看一下系统生成的类(本文涉及到的系统源码都是基于android-23):
[/code]
我们可以看到IInterface中只有一个方法 就是asBinder 返回一个IBinder,IBinder也是一个接口。
[/code]
这个返回接口的名称,我们在Binder中可以看到它的具体实现:
[/code]
我们可以看到系统通过attachInterface来给接口名称赋值,主要是为了作为跨进程通信时候接口的标识,我们可以在Binder的子类Stub也就是系统为我们生成的类中看到具体的接口名称:
[/code]
我们可以看到其实就是接口的全路径。
[/code]
就是字面意思ping一下 来确认Binder是否可以链接到Binder,只有当宿主进程不存在的时候才返回false。
[/code]
返回Binder是否存活。如果进程不是存活状态,那么返回false。
[/code]
根据接口的描述返回一个本地接口,如果返回的是null的话(就是跨进程),需要你去实现代理(在使用aidl的时候系统为我们已经实现好了)
[/code]
这个基本上是IBinder中最重要的一个函数了,它用来相应对象的操作,例如我们本例中的一个addBook操作,它的参数主要有如下几个:
1.code 一次操作的唯一标识,要介于常量FIRST_CALL_TRANSACTION( 0x00000001)和 LAST_CALL_TRANSACTION(0x00ffffff)之间
2.data 需要传递的数据不能为空
3.reply 返回的数据
4.flats 附加的操作标识,通常返回0. 如果设置成FLAG_ONEWAY表示呼叫方不会等待被呼叫方放回结果(只在跨进程的时候生效)。
我们再来看下Stub中的具体实现:
[/code]
将IBinder转换成我们需要的接口,我们可以看到基本的逻辑是:如果从本地找到了接口就返回本地接口(没有跨进程),否则返回Stub的代理类,关于代理类我们稍后再说,这个逻辑规则基本贯穿了Stub中的所有方法:即先找本地,如果没有(跨进程)则返回代理。
[/code]
首先在Stub类中 系统为我们的每一个方法值都赋予了一个id
可以看到是基于TRANSACTIOn_{$method name}来命名的参数是基于FIRST_CALL_TRANSACTION递增的。然后再onTransaction方法中系统会switch code判断当前调用的是哪个方法然后做相应的操作 我们来看下addBook的具体实现:
[/code]
我们不难看出,基本思路就是将对象和Parceable之间转换处理。
我们再来看下代理类Proxy:
Proxy是实现了接口IBookManager的代理类,其构造方法如下:
[/code]
构造函数是一个IBinder,之后代理中的相关调用都会转到这个Binder中去处理,我们还是来看一下addBookManager接口:
[/code]
可以看到和onTransact中最大的区别在于 它将具体的处理时间交给了跨进程的Binder处理。
以上就是在我们编写AIDL文件后 系统为我们生成文件的解析。
1.了解基本的aidl原理(不涉及底层)
前面几篇我们介绍了如何使用AIDL实现IPC 那么你会有疑问了 我们用的asInterface是什么, Stub又是什么,现在让我们一点一点来看。在我们编译的时候,系统会吧aidl生成对应的java类(这就是为什么支持aidl这种文件格式了),我们先来看一下系统生成的类(本文涉及到的系统源码都是基于android-23):
package com.wlh.animation.ipctest; // Declare any non-default types here with import statements public interface IBookManager extends android.os.IInterface { /** * Local-side IPC implementation stub class. */ public static abstract class Stub extends android.os.Binder implements com.wlh.animation.ipctest.IBookManager { private static final java.lang.String DESCRIPTOR = "com.wlh.animation.ipctest.IBookManager"; /** * Construct the stub at attach it to the interface. */ public Stub() { this.attachInterface(this, DESCRIPTOR); } /** * Cast an IBinder object into an com.wlh.animation.ipctest.IBookManager interface, * generating a proxy if needed. */ public static com.wlh.animation.ipctest.IBookManager asInterface(android.os.IBinder obj) { ... } @Override public android.os.IBinder asBinder() { return this; } @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException { switch (code) { case INTERFACE_TRANSACTION: { ... } case TRANSACTION_getBookList: { ... } case TRANSACTION_addBook: { ... } case TRANSACTION_registerListener: { ... } case TRANSACTION_unRegisterListener: { ... } } return super.onTransact(code, data, reply, flags); } private static class Proxy implements com.wlh.animation.ipctest.IBookManager { private android.os.IBinder mRemote; Proxy(android.os.IBinder remote) { mRemote = remote; } @Override public android.os.IBinder asBinder() { return mRemote; } public java.lang.String getInterfaceDescriptor() { return DESCRIPTOR; } @Override public java.util.List
IBookManager IInterface
首先是IBookManager,它是一个继承自IInterface的接口,我们先来看下IInterface接口中有哪些东西:public interface IInterface { public IBinder asBinder(); }
[/code]
我们可以看到IInterface中只有一个方法 就是asBinder 返回一个IBinder,IBinder也是一个接口。
Stub Binder
Stub是一个抽象类继承了Binder 实现了IBookManager接口Binder
Binder实现了IBinder,我们来看下IBinder中的内容.我们这里只介绍一些重要的变量和方法,其它的说明读者可自行查阅源码中的注释。getInterfaceDescriptor
源码定义如下:/** * Get the canonical name of the interface supported by this binder. */ public String getInterfaceDescriptor() throws RemoteException;
[/code]
这个返回接口的名称,我们在Binder中可以看到它的具体实现:
public void attachInterface(IInterface owner, String descriptor) { mOwner = owner; mDescriptor = descriptor; } public String getInterfaceDescriptor() { return mDescriptor; }
[/code]
我们可以看到系统通过attachInterface来给接口名称赋值,主要是为了作为跨进程通信时候接口的标识,我们可以在Binder的子类Stub也就是系统为我们生成的类中看到具体的接口名称:
private static final java.lang.String DESCRIPTOR = "com.wlh.animation.ipctest.IBookManager"; /** * Construct the stub at attach it to the interface. */ public Stub() { this.attachInterface(this, DESCRIPTOR); }
[/code]
我们可以看到其实就是接口的全路径。
pingBinder, isBinderAlive,
/** * Check to see if the object still exists. * * @return Returns false if the * hosting process is gone, otherwise the result (always by default * true) returned by the pingBinder() implementation on the other * side. */ public boolean pingBinder();
[/code]
就是字面意思ping一下 来确认Binder是否可以链接到Binder,只有当宿主进程不存在的时候才返回false。
/** * Check to see if the process that the binder is in is still alive. * * @return false if the process is not alive. Note that if it returns * true, the process may have died while the call is returning. */ public boolean isBinderAlive();
[/code]
返回Binder是否存活。如果进程不是存活状态,那么返回false。
queryLocalInterface
/** * Attempt to retrieve a local implementation of an interface * for this Binder object. If null is returned, you will need * to instantiate a proxy class to marshall calls through * the transact() method. */ public IInterface queryLocalInterface(String descriptor);
[/code]
根据接口的描述返回一个本地接口,如果返回的是null的话(就是跨进程),需要你去实现代理(在使用aidl的时候系统为我们已经实现好了)
transact
/** * Perform a generic operation with the object. * * @param code The action to perform. This should * be a number between {@link #FIRST_CALL_TRANSACTION} and * {@link #LAST_CALL_TRANSACTION}. * @param data Marshalled data to send to the target. Must not be null. * If you are not sending any data, you must create an empty Parcel * that is given here. * @param reply Marshalled data to be received from the target. May be * null if you are not interested in the return value. * @param flags Additional operation flags. Either 0 for a normal * RPC, or {@link #FLAG_ONEWAY} for a one-way RPC. */ public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException;
[/code]
这个基本上是IBinder中最重要的一个函数了,它用来相应对象的操作,例如我们本例中的一个addBook操作,它的参数主要有如下几个:
1.code 一次操作的唯一标识,要介于常量FIRST_CALL_TRANSACTION( 0x00000001)和 LAST_CALL_TRANSACTION(0x00ffffff)之间
2.data 需要传递的数据不能为空
3.reply 返回的数据
4.flats 附加的操作标识,通常返回0. 如果设置成FLAG_ONEWAY表示呼叫方不会等待被呼叫方放回结果(只在跨进程的时候生效)。
我们再来看下Stub中的具体实现:
asInterface
public static com.wlh.animation.ipctest.IBookManager asInterface(android.os.IBinder obj) { if ((obj == null)) { return null; } android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); if (((iin != null) && (iin instanceof com.wlh.animation.ipctest.IBookManager))) { return ((com.wlh.animation.ipctest.IBookManager) iin); } return new com.wlh.animation.ipctest.IBookManager.Stub.Proxy(obj); }
[/code]
将IBinder转换成我们需要的接口,我们可以看到基本的逻辑是:如果从本地找到了接口就返回本地接口(没有跨进程),否则返回Stub的代理类,关于代理类我们稍后再说,这个逻辑规则基本贯穿了Stub中的所有方法:即先找本地,如果没有(跨进程)则返回代理。
onTransact
@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException { switch (code) { case INTERFACE_TRANSACTION: { reply.writeString(DESCRIPTOR); return true; } case TRANSACTION_addBook: { 。。。 } } }
[/code]
首先在Stub类中 系统为我们的每一个方法值都赋予了一个id
static final int TRANSACTION_getBookList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); static final int TRANSACTION_addBook = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1); static final int TRANSACTION_registerListener = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2); static final int TRANSACTION_unRegisterListener = (android.os.IBinder.FIRST_CALL_TRANSACTION + 3);
可以看到是基于TRANSACTIOn_{$method name}来命名的参数是基于FIRST_CALL_TRANSACTION递增的。然后再onTransaction方法中系统会switch code判断当前调用的是哪个方法然后做相应的操作 我们来看下addBook的具体实现:
case TRANSACTION_addBook: { data.enforceInterface(DESCRIPTOR); com.wlh.animation.ipctest.Book _arg0; if ((0 != data.readInt())) { _arg0 = com.wlh.animation.ipctest.Book.CREATOR.createFromParcel(data); } else { _arg0 = null; } this.addBook(_arg0); reply.writeNoException(); if ((_arg0 != null)) { reply.writeInt(1); _arg0.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE); } else { reply.writeInt(0); } return true; }
[/code]
我们不难看出,基本思路就是将对象和Parceable之间转换处理。
我们再来看下代理类Proxy:
Proxy是实现了接口IBookManager的代理类,其构造方法如下:
Proxy(android.os.IBinder remote) { mRemote = remote; }
[/code]
构造函数是一个IBinder,之后代理中的相关调用都会转到这个Binder中去处理,我们还是来看一下addBookManager接口:
@Override public void addBook(com.wlh.animation.ipctest.Book book) throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); try { _data.writeInterfaceToken(DESCRIPTOR); if ((book != null)) { _data.writeInt(1); book.writeToParcel(_data, 0); } else { _data.writeInt(0); } mRemote.transact(Stub.TRANSACTION_addBook, _data, _reply, 0); _reply.readException(); if ((0 != _reply.readInt())) { book.readFromParcel(_reply); } } finally { _reply.recycle(); _data.recycle(); } }
[/code]
可以看到和onTransact中最大的区别在于 它将具体的处理时间交给了跨进程的Binder处理。
以上就是在我们编写AIDL文件后 系统为我们生成文件的解析。
相关文章推荐
- 平时我们常常说先做出一个原型系统,那么究竟什么是原型呢?
- 探索 Android 系统启动流程 - 当我们按下电源键,Android 究竟做了些什么?
- 什么是“判定问题”?(3)- NP-hard与NP 已有 1586 次阅读 2015-12-1 12:19 |个人分类:不确定性问题和算法讨论|系统分类:科研笔记|关键词:NP-hard NP 我们
- 我们要的究竟是什么:对于CMS系统的思考
- 我们要的究竟是什么:对于CMS系统的思考(四) 推荐
- 我们要的究竟是什么:对于CMS系统的思考(五) 推荐
- 当讨论分布式系统时,我们都会讨论些什么?
- HDFS是什么?HDFS适合做什么?我们应该怎样操作HDFS系统?
- 我们能从Linux系统上学到什么?谈谈linux的四个维度
- 我们要监控的对象是什么-IT监控系统系列
- 我们要的究竟是什么:对于CMS系统的思考(六) 推荐
- 讨论系统高可用时,我们在讨论什么?
- 我们要的究竟是什么:对于CMS系统的思考(三) 推荐
- (第3篇)HDFS是什么?HDFS适合做什么?我们应该怎样操作HDFS系统?
- (第3篇)HDFS是什么?HDFS适合做什么?我们应该怎样操作HDFS系统?
- 我们要的究竟是什么:对于CMS系统的思考(一) 推荐
- 我们要的究竟是什么:对于CMS系统的思考(二) 推荐
- 我们来上海做什么?
- 一个网上流传的段子解释什么是大数据,及它给我们生活带来的影响
- 我们最缺少的是什么