企业🤖AI智能体构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
#### binder的工作机制 下面的代码是在IBookManager.aidl中,系统自动生成的IBookManager.java文件 ~~~ /* * This file is auto-generated. DO NOT MODIFY. */ package com.ryg.chapter_2; /* * IBookManager它继承了IInterface这个接口,同时它自己也还是个接口, * 所有可以在Binder中传输的接口都要继承IInterface接口。 * * 首先,它声明了两个方法getBookList和addBook(在最后面),显然这就是我们在IBookManager.aidl中所声明的方法, * 同时它还声明了两个整型的id(TRANSACTION_getBookList、TRANSACTION_addBook)分别用于标识这两个方法。 * 接着,它声明了一个内部类Stub,这个Stub就是一个Binder类, * 当客户端和服务端都位于同一个进程时,方法调用不会走跨进程的transact过程, * 而当两者位于不同进程时,方法调用需要走transact过程, * 这个逻辑由Stub的内部代理类Proxy来完成。 * *这个接口的核心就是内部类Stub和Stub的内部代理类Proxy * */ public interface IBookManager extends android.os.IInterface { /** * Local-side IPC implementation stub class. */ /* * 首先这个Stub,它是一个内部类,它继承了Binder,所以它是一个Binder, * 同时Stub还实现了IBookManager中的方法。 * */ public static abstract class Stub extends android.os.Binder implements com.ryg.chapter_2.aidl.IBookManager { //Binder的唯一标识符。 一般用于当前Binder的类名表示 private static final java.lang.String DESCRIPTOR = "com.ryg.chapter_2.aidl.IBookManager"; /** * Construct the stub at attach it to the interface. */ public Stub() { this.attachInterface (this, DESCRIPTOR); } /** * Cast an IBinder object into an com.ryg.chapter_2.aidl.IBookManager interface, * generating a proxy if needed. */ /* * 用于将服务端的Binder对象转换成客户端所需的AIDL接口类型的对象, * 这种转换过程是区分进程的, * 如果客户端和服务端位于同一进程,那么此方法返回的就是服务端的Stub对象本身, * 否则(即客户端和服务端不在同一个进程)返回的是系统封装后的Stub.proxy代理对象。 * */ public static com.ryg.chapter_2.aidl.IBookManager asInterface(android.os.IBinder obj) { if ((obj == null)) { return null; } android.os.IInterface iin = obj.queryLocalInterface (DESCRIPTOR); // 同一进程 if (((iin != null) && (iin instanceof com.ryg.chapter_2.aidl.IBookManager))) { return ((com.ryg.chapter_2.aidl.IBookManager) iin); } // 不同进程 return new com.ryg.chapter_2.aidl.IBookManager.Stub.Proxy (obj); } //此方法用于返回当前Binder对象,也就是内部类Stub。 @Override public android.os.IBinder asBinder() { return this; } /* * 这个方法运行在服务端中的Binder线程池中, * 当客户端发起跨进程请求时,远程请求会通过系统底层封装后交由此方法来处理。 * 该方法的原型是 public Boolean onTransact(int code,android.os.Parcel data,android.os.Parcel reply,int flags) * 服务端通过code可以确定客户端所请求的目标方法是什么, * 接着从data中取出目标方法所需的参数, * 然后执行目标方法。 * 当目标方法执行完毕后,就向reply中写入返回值。 * 如果此方法返回false,那么客户端的请求会失败,因此我们可以利用这个特性来做权限验证。 * (毕竟也不希望随便一个进程都可以远程调用我们的服务) * */ @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_getBookList: { data.enforceInterface (DESCRIPTOR); //这句才是调用了真正的执行过程呢 java.util.List<com.ryg.chapter_2.aidl.Book> _result = this.getBookList (); reply.writeNoException (); reply.writeTypedList (_result); return true;//返回true表示调用成功 } case TRANSACTION_addBook: { data.enforceInterface (DESCRIPTOR); com.ryg.chapter_2.aidl.Book _arg0; if ((0 != data.readInt ())) { _arg0 = com.ryg.chapter_2.aidl.Book.CREATOR.createFromParcel (data); } else { _arg0 = null; } //这句才是调用了真正的执行过程呢 this.addBook (_arg0); reply.writeNoException (); return true; } case TRANSACTION_registerListener: { data.enforceInterface (DESCRIPTOR); com.ryg.chapter_2.aidl.IOnNewBookArrivedListener _arg0; _arg0 = com.ryg.chapter_2.aidl.IOnNewBookArrivedListener.Stub.asInterface (data.readStrongBinder ()); this.registerListener (_arg0); reply.writeNoException (); return true; } case TRANSACTION_unregisterListener: { data.enforceInterface (DESCRIPTOR); com.ryg.chapter_2.aidl.IOnNewBookArrivedListener _arg0; _arg0 = com.ryg.chapter_2.aidl.IOnNewBookArrivedListener.Stub.asInterface (data.readStrongBinder ()); this.unregisterListener (_arg0); reply.writeNoException (); return true; } } return super.onTransact (code, data, reply, flags); } //代理类Proxy。 private static class Proxy implements com.ryg.chapter_2.aidl.IBookManager { /* * 这个mRemote代表的就是目标对象角色, * */ 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; } /* * 这个方法运行在客户端, * 因为当客户端和服务端不在同一进程时,服务端返回代理类Proxy,所以客户端会通过Proxy调用到代理类的getBookList方法, * 当客户端远程调用此方法时,它的内部实现是这样的: * 首先创建该方法所需要的输入型Parcel对象_data、输出型Parcel对象_reply和返回值对象List, * 然后把该方法的参数信息写入_data中, * 接着调用transact方法来发起RPC(远程过程调用)请求,同时当前线程挂起, * 然后服务端的onTransact方法会被调用,直到RPC过程返回后,当前线程继续执行, * 并从_reply中取出RPC过程的返回结果。 * 最后返回_reply中的数据。 * */ @Override public java.util.List<com.ryg.chapter_2.aidl.Book> getBookList() throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain (); android.os.Parcel _reply = android.os.Parcel.obtain (); java.util.List<com.ryg.chapter_2.aidl.Book> _result; try { _data.writeInterfaceToken (DESCRIPTOR); mRemote.transact (Stub.TRANSACTION_getBookList, _data, _reply, 0); _reply.readException (); _result = _reply.createTypedArrayList (com.ryg.chapter_2.aidl.Book.CREATOR); } finally { _reply.recycle (); _data.recycle (); } return _result; } /** * 这个方法运行在客户端,执行过程和getBookList一样,只是addBook没有返回值, * 所以不需要从_reply中取出返回值 */ @Override public void addBook(com.ryg.chapter_2.aidl.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 (); } finally { _reply.recycle (); _data.recycle (); } } @Override public void registerListener(com.ryg.chapter_2.aidl.IOnNewBookArrivedListener listener) throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain (); android.os.Parcel _reply = android.os.Parcel.obtain (); try { _data.writeInterfaceToken (DESCRIPTOR); _data.writeStrongBinder ((((listener != null)) ? (listener.asBinder ()) : (null))); mRemote.transact (Stub.TRANSACTION_registerListener, _data, _reply, 0); _reply.readException (); } finally { _reply.recycle (); _data.recycle (); } } @Override public void unregisterListener(com.ryg.chapter_2.aidl.IOnNewBookArrivedListener listener) throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain (); android.os.Parcel _reply = android.os.Parcel.obtain (); try { _data.writeInterfaceToken (DESCRIPTOR); _data.writeStrongBinder ((((listener != null)) ? (listener.asBinder ()) : (null))); mRemote.transact (Stub.TRANSACTION_unregisterListener, _data, _reply, 0); _reply.readException (); } finally { _reply.recycle (); _data.recycle (); } } } /* * 用于标识方法的整型id。 * 它们用于在transact过程总客户端所请求的到底是哪个方法。 * */ 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); } /* * 声明了在IBookManager.aidl中所声明的方法。 * 这里才是真正的方法声明。具体实现我们仍然没有看到呢。 * */ public java.util.List<com.ryg.chapter_2.aidl.Book> getBookList() throws android.os.RemoteException; public void addBook(com.ryg.chapter_2.aidl.Book book) throws android.os.RemoteException; public void registerListener(com.ryg.chapter_2.aidl.IOnNewBookArrivedListener listener) throws android.os.RemoteException; public void unregisterListener(com.ryg.chapter_2.aidl.IOnNewBookArrivedListener listener) throws android.os.RemoteException; } ~~~ ![](https://box.kancloud.cn/2016-05-29_574aa689ca354.png) 对于上图有网友这样理解,原文点击[这里](http://blog.csdn.net/zizidemenghanxiao/article/details/50341773) 对于自动生成的IBookManager.java文件,它是服务器端的代码。 当客户端向服务端发送连接请求时, * 如果客户端和服务端在同一进程中,那么服务端就向客户端返回Stub这个Binder对象, * 如果客户端和服务端在不同进程中,那么服务端就向客户端返回内部类Stub的内部代理类Proxy,然后客户端根据这个Proxy来调用Proxy内部的方法,这个Proxy内部含有服务端真正的Binder对象也就是那个内部类Stub,在客户端调用Proxy内部的方法也就会导致调用Stub的transact方法,而Stub的transact方法又会回调它自己的onTransact方法,onTransact方法是在服务端运行的,而transact方法是在客户端调用的,这样就实现了客户端调用服务端的方法了。当然这所有的传递过程也少不了Parcel这个数据包的协助。 * * * * * > **Binder一个很重要的作用是:将客户端的请求参数通过Parcel包装后传到远程服务端,远程服务端解析数据并执行对应的操作,同时客户端线程挂起,当服务端方法执行完毕后,再将返回结果写入到另外一个Parcel中并将其通过Binder传回到客户端,客户端接收到返回数据的Parcel后,Binder会解析数据包中的内容并将原始结果返回给客户端,至此,整个Binder的工作过程就完成了。由此可见,Binder更像一个数据通道,Parcel对象就在这个通道中跨进程传输,至于双方如何通信,这并不负责,只需要双方按照约定好的规范去打包和解包数据即可。** * * * * *