zoukankan      html  css  js  c++  java
  • 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进程启动时完成。

           

  • 相关阅读:
    JDK5后的特性整理
    正向代理与反向代理的区别与异同
    我所用过的nginx的功能
    网页端消息推送之推与拉
    在一个py脚本中调用另外一个py脚本中的类或函数
    import与from ... import ...的区别
    python 读取文件
    shell中的特殊变量IFS
    shell 重定向以及文件描述符
    shell下读取文件数据
  • 原文地址:https://www.cnblogs.com/bokeofzp/p/6726739.html
Copyright © 2011-2022 走看看