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进程启动时完成。

       

 

posted @ 2017-04-18 11:05  Lammy  阅读(857)  评论(0编辑  收藏  举报