android binder机制详解
Binder是一种架构,该架构提供了服务端接口,Binder驱动、客户端接口三个模块,如下图:
为了我们更好的分析这三个模块,我先给出我写的demo音乐播放器服务写aidl,抛出start和stop方法 自动生成的java文件
/* * This file is auto-generated. DO NOT MODIFY. * Original file: E:\\android-studio-workspace\\MyBinder\\app\\src\\main\\aidl\\com\\example\\user\\mybinder\\IMyAidlInterface.aidl */ package com.example.user.mybinder; // Declare any non-default types here with import statements public interface IMyAidlInterface extends android.os.IInterface { /** * Local-side IPC implementation stub class. */ public static abstract class Stub extends android.os.Binder implements com.example.user.mybinder.IMyAidlInterface { private static final java.lang.String DESCRIPTOR = "com.example.user.mybinder.IMyAidlInterface"; /** * Construct the stub at attach it to the interface. */ public Stub() { this.attachInterface(this, DESCRIPTOR); } /** * Cast an IBinder object into an com.example.user.mybinder.IMyAidlInterface interface, * generating a proxy if needed. */ public static com.example.user.mybinder.IMyAidlInterface asInterface(android.os.IBinder obj) { if ((obj == null)) { return null; } android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); if (((iin != null) && (iin instanceof com.example.user.mybinder.IMyAidlInterface))) { return ((com.example.user.mybinder.IMyAidlInterface) iin); } return new com.example.user.mybinder.IMyAidlInterface.Stub.Proxy(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: { reply.writeString(DESCRIPTOR); return true; } case TRANSACTION_basicTypes: { data.enforceInterface(DESCRIPTOR); int _arg0; _arg0 = data.readInt(); long _arg1; _arg1 = data.readLong(); boolean _arg2; _arg2 = (0 != data.readInt()); float _arg3; _arg3 = data.readFloat(); double _arg4; _arg4 = data.readDouble(); java.lang.String _arg5; _arg5 = data.readString(); this.basicTypes(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5); reply.writeNoException(); return true; } case TRANSACTION_start: { data.enforceInterface(DESCRIPTOR); this.start(); reply.writeNoException(); return true; } case TRANSACTION_stop: { data.enforceInterface(DESCRIPTOR); this.stop(); reply.writeNoException(); return true; } } return super.onTransact(code, data, reply, flags); } private static class Proxy implements com.example.user.mybinder.IMyAidlInterface { 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; } /** * Demonstrates some basic types that you can use as parameters * and return values in AIDL. */ @Override public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) 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.writeInt(anInt); _data.writeLong(aLong); _data.writeInt(((aBoolean) ? (1) : (0))); _data.writeFloat(aFloat); _data.writeDouble(aDouble); _data.writeString(aString); mRemote.transact(Stub.TRANSACTION_basicTypes, _data, _reply, 0); _reply.readException(); } finally { _reply.recycle(); _data.recycle(); } } @Override public void start() throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); try { _data.writeInterfaceToken(DESCRIPTOR); mRemote.transact(Stub.TRANSACTION_start, _data, _reply, 0); _reply.readException(); } finally { _reply.recycle(); _data.recycle(); } } @Override public void stop() throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); try { _data.writeInterfaceToken(DESCRIPTOR); mRemote.transact(Stub.TRANSACTION_stop, _data, _reply, 0); _reply.readException(); } finally { _reply.recycle(); _data.recycle(); } } } static final int TRANSACTION_basicTypes = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); static final int TRANSACTION_start = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1); static final int TRANSACTION_stop = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2); } /** * Demonstrates some basic types that you can use as parameters * and return values in AIDL. */ public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException; public void start() throws android.os.RemoteException; public void stop() throws android.os.RemoteException; }
服务端:它其实就是一个binder对象(有能力的程序员可以自己写利用binder对象来完成服务端的功能,具体如何做不清楚书上写的),当我们创建aidl文件(aidl创建后rebind后就会自动生成相应的java文件 ,其实可以直接自己写java文件,自动生成的java文件只是一种普遍的习惯),在Service里自己写binder对象该对象继承aidl生成的java文件中 Stub(它继承了binder实现),在onBinder中返回自己的binder对象的时候服务端内部就会启动一个隐藏程序,该隐藏程序用来接收bidner驱动的消息,接受消息后会执行binder对象中的onTransact()函数,因此要实现binder服务就必须重载onTransact()方法。
1 、根据函数第一个参数code 执行不动的方法,code 是Stub中定义的全局不变变量,会根据code不同执行相应的操作。(也有一些是在Ibinder中已经定义好的,主要是自己添加的方法的code)。
2、onTrabsact()作用是将它的参数转化为服务端方法所用到的参数,onTransact()的参数来源则是代理proxy中获得的binder驱动对象IBinder mRemote调用的transact()方法中的参数。因此,每个方法都是利用binder驱动的transact()方法发送消息给服务端,服务端通过继承自aidl生成java文件中stub的binder对象的onTransact方法将参数转化为服务的对应方法参数。如客户端调用start()方法调用过程:
客户端 binder获取代理proxy->start()------>binder驱动调用transact()--------->服务端自定义binder继承自aidl 中Stub,利用Stub的静态方法onTrancsact()将transact的参数转化为服务的参数 ------> 执行服务中的start()方法 -- > 数据返回binder驱动 -- >客户端
binder驱动端:当服务端创建时候,aidl生成的java文件中proxy类中会创建IBinder mRemote 对象,它重载了transact(0方法,代理就是通过它调用transact方法来向服务端发送和接受消息的,trancsact主要3个功能,见流程图。
客户端:客户端是利用binderService 的回调函数获得代理对象,代理对象引用了binder驱动 mRemote对象,在代理的start()、stop()方法中利用mRemote的transact()向服务端发送消息,从而执行服务中方法,然后通过mRemote再返回结果。
因此我们了解了一下知识点:
1 、binder框架中有2个binder 一个是服务端的binder 另一个是驱动binder,服务端会有多个服务则存在多个binder对象,因此会多一个线程,而binder驱动端则不会多产生一个线程。
2、binder 中利用aidl工具生成的java文件中transact和ontransact()参数来确定参数的顺序,保证了传递和接受数据的顺序。
3、aidl生成的java文件包含三部分:
(1)、java Interface,IService,其内部包含aidl声明的一些方法,并且该接口继承与 android.os.IInterface 接口,因此得提供asBinder()方法。
(2)、一个静态的公有虚类Stub 继承android.os.Binder 且implements Iservice , 因为Iservice接口的方法由它的成员类proxy来实现,因此定义为虚类。
(3)、proxy类,即所谓的代理,stub的asInterface()方法就可以返回代理对象,它是Stub的成员类
之所以把三个类写在一个文件内主要是方便维护和代码的简洁。
4 transact()的最后一个参数是IPC调用的2中模式,0 则是双向的,即服务端执行执行玩指定服务后会返回一定数据,1则表示不返回任何数据。调用该方法后客户端线程进入Binder驱动。
5,Binder 内部有 asInterface(android.os.IBinder obj),服务端内部当然也可以使用该服务,而Binder内部有queryLocalInterface(String description)方法,通过字符串判断该binder对象是否为本地的Binder引用。当创建的Binder对象时,服务端进程内部创建Binder对象,binder驱动中也会创建一个Binder对象。如果从远程获取服务端的Binder,则只会返回Binder驱动中的Binder对象,而如果从服务端进程内部获取Binder对象,则会获得服务端本身的Binder对象。因而mRemote是对binder驱动的一个引用,onserviceConnected()参数IBinder service是Binder驱动的binder引用,然后返回的是proxy,代理持有Binder驱动的binder引用mRemote,从而可以向服务端发送消息。
系统服务binder对象(ServiceManager 介绍)
写程序时,经常用到getSystemService(String serviceName)方法来获取一个系统服务,那么这些服务的binder引用是如何传递给客户端的呢?须知系统服务并不是通过startService()启动的。
getSystemService()方法的实现是在ContextImpl类中,该方法所返回的Service很多,而这些service一般都是由ServiceManager管理。
serviceManager管理服务
serviceManager是一个独立的进程,其本身也是个service,Framwork提供了个系统方法 BinderInternal.getContextObject(),用来获取serciceManager对应的Binder应用。该方法返回ServiceManager后,可通过ServiceManager提供的方法,获取其他系统的sercice的Binder引用。这样设计的好处就是系统只需要暴漏一个全局Binder,就可以通过这个全局binder获取其他的系统服务的binder引用,隐藏其他系统服务,从而有助于系统的扩展,以及调用系统服务的安全检查。其他服务启动时候将自己的binder对象传递给ServiceManager,即所谓的注册(addSercice)。
下面的代码可以看出ContextImpl.getSystemService()中各种Service的具体获取方式,如INPUT_METHOD_SERVCICE,的代码如下:
}else if(INPUT_METHOD_SERVICE.equals(name)) return InputMethodManager.getInstance(this);
InputMethodManager.getInstance()的方法如下
synchronized (mInstanceSync){ if(mInstance != null){ return mInstance; } IBinder b = SystemManager.getService(Context.INPUT_METHOD_SERVICE); IInputMethodManager service = IInputMethodManager.Stub.asInterface(b); mInstace = new InputMethodManager(srvice , mainLooper); } rerurn mInstance
从上面的函数可以看出ServiceManager 获取InputMethod service 对应的Binder 对象b,然后将该binder对象作为IIputmethodManager.Stub.asInterface()的参数,返回一个IInputMethodManger的统一接口。
而SystemManager.getService()方法的代码如下:
public static IBinder gerService(String name){ try{ IBinder service =sCashe.get(name); if(service != null){ return service; }else { return getIServiceManager().getService(name); } }catch(remoteException e){ Log.e(TAG , "error in getService" , e); } return null }
即首先从sCashe缓存中查看是否有对应的Binder对象,有则返回,没有则调用getIServiceManager().getservice(name),第一个函数getIserviceMnager()即用于返回系统中唯一的ServiceManager对应的Binder,其代码如下:
prviate static IserviceManager gerIServiceManger(){ if(sServiceMnager != null){ return sServiceManager; } //find the Service manager sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject()); return sServiceManager; }
以上代码中,BinderInternal.getContextobject静态方法即用于迂回ServiceManager 对用的全局Binder对象,该方法不需要任何参数,因为它的作用是固定的。从这个角度来看,这个方法的命名似乎应该更明确一些,如:getServiceManager()。
关于使用addService()向ServiceManager中添加一个服务一般是在SystemService进程启动时完成。