# android Binder分析 站点:答源(https://www.dandroid.cn/) 原文:https://www.dandroid.cn/archives/18869 Canonical:https://www.dandroid.cn/archives/18869 作者:dandroid004 发布日期:2023-09-04 最后更新:2023-09-12 16:40 分类:Android系统开发 / Framework源码 内容类型:post 说明:本页是原文的纯文本镜像,供大模型与检索器完整读取;不含导航、广告、付费框。引用请以上方「原文」链接为准。 ## 正文 讲Android Binder机制的文章非常多,这篇文章主要是理一下我对Binder的理解。本文不是一篇介绍Binder的文章,也不是一篇探讨Binder实现的文章。 本文会以AndroidStudio根据aidl接口自动产生的java文件来看Binder,进而来理解Binder机制。 其实Android的Binder机制类似于:RPC(远程过程调用)。如果你理解它,相信Binder机制就更容易理解了。 首先我们使用AndroidStudio来定义一个aidl接口: interface IUserManager { int getUserAge(in String userName); } 然后我们来直接看一个由AndroidStudio根据自定义的aidl接口IUserManager产生的IUserManager.java文件。 这个文件我们来分3个部分看: IUserManager接口结构 public interface IUserManager extends android.os.IInterface { public static abstract class Stub extends android.os.Binder implements com.susion.demo.aidl.IUserManager {..} public int getUserAge(java.lang.String userName) throws android.os.RemoteException; } 这个接口的结构还是很简单的: 它继承自android.os.IInterface。 定义了一个待实现的方法int getUserAge() 定义了一个Stub类。这个类继承自Binder,并实现了IUserManager接口。 int getUserAge()这个方法就是我们IUserManager接口的方法。而android.os.IInterface是什么呢?先看一下它在源码中的定义: /** * Base class for Binder interfaces. When defining a new interface, * you must derive it from IInterface. */ public interface IInterface { /** * Retrieve the Binder object associated with this interface. * You must use this instead of a plain cast, so that proxy objects * can return the correct result. */ public IBinder asBinder(); //IBinder是Binder的抽象接口 } 即他是所有Binder都要实现的接口, 为什么呢?举一个我们都熟悉的场景 : 比如ApplicationThread,ActivityManagerService(运行在服务端进程)就可以通过它来调用我们客户端的方法。我们会把这些方法抽象为一个接口(IApplicationThread),这个接口可以理解为我们告诉服务端,你可以对客户端执行哪些操作。 我们还知道ApplicationThread其实他就是一个Binder。所以这两者一结合就可以这么说ApplicationThread: 客户端提供给服务端一个Binder,通过这个Binder服务端可以对客户端做一些操作,这些操作具体定义在IApplicationThread接口中。 我们称IApplicationThread为ApplicationThread这个Binder的功能。 所以Binder除了可以理解为系统给我们提供的一个跨进程通信的对象。 我们在用Binder通信时,还可以说Binder是一个具有某些功能的一个对象。 那么怎么表示Binder有功能呢? 即要继承IInterface 。IInterface可以表示Binder有功能, 不然你想一下那么多Binder都只实现自己的接口, 那么系统层就不好操作了,它总不能向下强转为Binder吧,所以Android定义了一个更高层级的接口IInterface。描述Binder功能的接口必须继承自这个接口。 重点: Binder、Binder的功能(IApplicationThread)、IInterface它们都在同一个对象上 -> ApplicationThread Stub 它是IUserManager的内部静态类,看一下它的具体声明: static abstract class Stub extends android.os.Binder implements com.susion.demo.aidl.IUserManager 即它是一个Binder,可以用来跨进程通信。它具有IUserManager定义的功能。 看一下它的具体结构: public static abstract class Stub extends android.os.Binder implements com.susion.demo.aidl.IUserManager { private static final java.lang.String DESCRIPTOR = "com.susion.demo.aidl.IUserManager"; static final int TRANSACTION_userCount = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); public Stub() { this.attachInterface(this, DESCRIPTOR); } public static com.susion.demo.aidl.IUserManager asInterface(android.os.IBinder obj) { if ((obj == null)) { return null; } android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); if (((iin != null) && (iin instanceof com.susion.demo.aidl.IUserManager))) { return ((com.susion.demo.aidl.IUserManager) iin); } return new com.susion.demo.aidl.IUserManager.Stub.Proxy(obj); } @Override public android.os.IBinder asBinder() {retun this;} @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {...} private static class Proxy implements com.susion.demo.aidl.IUserManager {...} } 我们还是一个一个的看一下: DESCRIPTOR 基于我们前面的解释,我们知道在跨进程通信中Binder对象具有某种功能->IInterface。但是Binder通信机制中那么多Binder都有IInterface。那么系统怎么识别哪个Binder是哪个Binder呢?所以IInterface只是一个能力的抽象,DESCRIPTOR就是来表示具体是哪一个功能IInterface。 TRANSACTION_userCount 即功能下的哪个操作。 Stub构造函数 public Stub() { this.attachInterface(this, DESCRIPTOR); } 即一个Stub(Binder)在构造的时候,就标识好了自己的具体功能IInterface(IUserManager)。来看一下attachInterface(this, DESCRIPTOR)做了什么: //Binder.java public void attachInterface(@Nullable IInterface owner, @Nullable String descriptor) { mOwner = owner; mDescriptor = descriptor; } 即,Binder在内部会用IInterface来保存自己的功能。和这个功能更对应的唯一描述descriptor,方便在通信的时候寻找。 asBinder() 自己返回自己,因为自己本身就是个Binder呀。 onTransact() 当其他进程想跨进程调用我这个Binder的功能时,必须通过这个方法来沟通。这个方法我们最后再来看。 asInterface(android.os.IBinder obj) 即接收一个IBinder(这个IBinder是系统传入的), 把这个IBinder转化为它所具有功能接口。其实这里就是Binder跨进程通信的一个核心 。那怎么转化的呢? 调用者和Binder对象位于同一个进程 那么系统就会直接传给你在这个进程创建的Stub(Binder)。所以 obj.queryLocalInterface(DESCRIPTOR): public IInterface queryLocalInterface(String descriptor) { if (mDescriptor.equals(descriptor)) { return mOwner; } return null; } 即如果参数descriptor和这个Binder的功能唯一描述相同。就会返回Binder的功能mOwner。 调用者和Binder对象不在同一个进程 这时系统实际传的是一个BinderProxy, 你可以理解为它是另一个进程中的Binder的替身。我们就可以把它当成另一个进程的Binder。我们看一下BinderProxy的queryLocalInterface()方法: /** * Retrieve a local interface - always null in case of a proxy */ public IInterface queryLocalInterface(String descriptor) { return null; } 所以此时asInterface()返回的是: IUserManager.Stub.Proxy(obj), 即代理对象,它代理了BinderProxy。 IUserManager.Stub.Proxy 它是Stub的静态内部类,如果调用者和Binder不在同一个进程的话,调用者拿到的实际是它: private static class Proxy implements com.didi.virtualapk.demo.aidl.IUserManager { 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 int getUserAge(java.lang.String userName) throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); int _result; try { _data.writeInterfaceToken(DESCRIPTOR); _data.writeString(userName); mRemote.transact(Stub.TRANSACTION_getUserAge, _data, _reply, 0); _reply.readException(); _result = _reply.readInt(); } finally { _reply.recycle(); _data.recycle(); } return _result; } } 我们前面说了它其实是BinderProxy的代理。为什么要对BinderProxy加这个代理呢?看一下getUserAge(): public int getUserAge(java.lang.String userName) throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); int _result; try { _data.writeInterfaceToken(DESCRIPTOR); _data.writeString(userName); mRemote.transact(Stub.TRANSACTION_getUserAge, _data, _reply, 0); _reply.readException(); _result = _reply.readInt(); } finally { _reply.recycle(); _data.recycle(); } return _result; } 即是调用mRemote.transact()(BinderProxy的)方法。Stub.TRANSACTION_getUserAge是要调用的远程Binder方法的getUserAge()对应的描述符。 _data是序列化后的入参、_reply是序列化后的返回值。可以看到_data所携带的参数是需要序列化的,_reply所带的内容是被序列化的,所以读取要反序列化。 所以IUserManager.Stub.Proxy类的作用就是在跨进程调用时对传给mRemote(BinderProxy)的参数做序列化,对mRemote(BinderProxy)返回值做反序列化。参数的接受者和返回者是BinderProxy 具体调用Binder的能力是使用BinderProxy的transact()方法,它是跨进程通信的核心 , 我们来看一下这个方法: public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { ... return transactNative(code, data, reply, flags); // native 方法 } 省略了不重要的代码。即BinderProxy是通过transactNative来与远程Binder跨进程通信的。具体怎么实现,这里就不追究了。 Stub.onTransact() 我们前面没有看这个方法,这里我们来看一下: 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_getUserAge: { data.enforceInterface(DESCRIPTOR); java.lang.String _arg0; _arg0 = data.readString(); int _result = this.getUserAge(_arg0); reply.writeNoException(); reply.writeInt(_result); return true; } } return super.onTransact(code, data, reply, flags); } 根据IUserManager.Stub.Proxy我们知道,如果不在同一个进程,那么参数是被序列化后传过来的,所以这个方法是用来对入参做反序列化,并对返回值做序列化的。 最后我们用一张图来总结Binder进程通信机制 : --- 由 答源 DAN 底座 1.4.1 生成 · 2026-11-11T03:21:16+00:00