binder 订阅
BINDER致力于为都市男性打造一系列商务休闲皮具,无论大学生、白领,还是主管都必须的上品皮具。融汇商务皮具与休闲包理念,打破了以正装皮具为主的局面;并以互联网直销依托“大牌品质、低廉价格和完美售后”拉近受众群的距离。当下都市男性在严谨的工作和快节奏的生活氛围中,更加注重休闲、舒适、随意的生活品味。 展开全文
BINDER致力于为都市男性打造一系列商务休闲皮具,无论大学生、白领,还是主管都必须的上品皮具。融汇商务皮具与休闲包理念,打破了以正装皮具为主的局面;并以互联网直销依托“大牌品质、低廉价格和完美售后”拉近受众群的距离。当下都市男性在严谨的工作和快节奏的生活氛围中,更加注重休闲、舒适、随意的生活品味。
信息
品牌文化
品牌树形象,品质得人心
主要产品
服装、皮具、皮鞋等
品牌创立
男性把皮具当成一种品味风格
外文名
BINDER
BINDER品牌创立
当今,男性已经把皮具当成是生活中的点缀品,它代表的是一种品味,一种风格。BINDER为此而来。在国外男士皮具已经超脱了消费品的简单意义,如同女人的香水,携带的是一种文化,传达的是一种生活方式。
收起全文
精华内容
参与话题
问答
  • Binder通信

    2016-04-23 21:27:35
    AIDL 文件: package com.test.demo; interface ITestService { int Add(); } Build Java工程生成ITestService.java文件: /* * This file is auto-generated. DO

    学习和使用Android Service也有一段时间了,今天有点总结和记录下个人感悟的想法。


    首先,我们要明白,Binder只是Android中众多IPC方式中的一种。只不过相对于其它IPC方式,在Android中,Binder更为灵活和方便而已。

    其次,Binder通信和业务之间的关系:

    1>  Binder 是通信机制

    2> 业务只是基于Binder进行通信,当然也可以使用别的IPC方式通信

    说白了,Binder只是一种传递数据的方式,是为业务服务的。而Android帮我们把Binder的这种通信机制和我们的业务巧妙地封装融合在一起,使我们在实际应用过程中不用花费大量的精力和时间在IPC通信上,而是更加专注在业务逻辑的实现上。


    AIDL 文件:


        package com.test.demo;   
          
        interface ITestService {       
            int Add();  
        }  

    Build Java工程会根据ITestService.aidl文件生成ITestService.java文件:


    /*
     * This file is auto-generated.  DO NOT MODIFY.
     * Original file: C:\\src\\com\\test\\demo\\ITestService.aidl
     */
    package com.test.demo;
    public interface ITestService extends android.os.IInterface
    {
    /** Local-side IPC implementation stub class. */
    public static abstract class Stub extends android.os.Binder implements com.test.demo.ITestService
    {
    private static final java.lang.String DESCRIPTOR = "com.test.demo.ITestService";
    /** Construct the stub at attach it to the interface. */
    public Stub()
    {
    this.attachInterface(this, DESCRIPTOR);
    }
    /**
     * Cast an IBinder object into an com.test.demo.ITestService interface,
     * generating a proxy if needed.
     */
    public static com.test.demo.ITestService asInterface(android.os.IBinder obj)
    {
    if ((obj==null)) {
    return null;
    }
    android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
    if (((iin!=null)&&(iin instanceof com.test.demo.ITestService))) {
    return ((com.test.demo.ITestService)iin);
    }
    return new com.test.demo.ITestService.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_Add:
    {
    data.enforceInterface(DESCRIPTOR);
    int _result = this.Add();
    reply.writeNoException();
    reply.writeInt(_result);
    return true;
    }
    }
    return super.onTransact(code, data, reply, flags);
    }
    private static class Proxy implements com.test.demo.ITestService
    {
    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 Add() 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);
    mRemote.transact(Stub.TRANSACTION_Add, _data, _reply, 0);
    _reply.readException();
    _result = _reply.readInt();
    }
    finally {
    _reply.recycle();
    _data.recycle();
    }
    return _result;
    }
    }
    static final int TRANSACTION_Add = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
    }
    public int Add() throws android.os.RemoteException;
    }
    

    ITestService.java 中定义了ITestService接口和子类Stub以及Stub的子类Proxy

    Stub类是一个抽象类,从Binder和ITestService接口派生而来,它是给Server端即Service使用的。我们要在Service中定义一个Stub类实例,并且实现这样一个Stub类实例中对应的ITestService的接口函数。

    Proxy类也是从ITestService派生而来,它是给Client端用的。它其实就是Client访问Service的一个代理,它内部有一个BpBinder,通过它可以和Service里的BBinder进行通信。

    Client访问Proxy感觉就像Client直接访问Service一样。


    很好奇为什么Stub中的asInterface为什么不是直接返回Proxy对象?竟然有可能返回一个Stub对象?

    /**
     * Cast an IBinder object into an com.test.demo.ITestService interface,
     * generating a proxy if needed.
     */
    public static com.test.demo.ITestService asInterface(android.os.IBinder obj)
    {
    if ((obj==null)) {
    return null;
    }
    android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
    if (((iin!=null)&&(iin instanceof com.test.demo.ITestService))) {
    return ((com.test.demo.ITestService)iin);
    }
    return new com.test.demo.ITestService.Stub.Proxy(obj);
    }

    Binder类中的queryLocalInterface和attachInterface方法:

        public IInterface queryLocalInterface(String descriptor) {  
            if (mDescriptor.equals(descriptor)) {  
                return mOwner;  
            }  
            return null;  
        }
    
    
       public void attachInterface(IInterface owner, String descriptor) {  
         mOwner = owner;  
         mDescriptor = descriptor;  
       }  
    

    而我们从Stub的构造函数中可以看到,owner就是Stub对象的this指针,即当前的Stub对象自己
        /** Construct the stub at attach it to the interface. */  
        public Stub() {  
            this.attachInterface(this, DESCRIPTOR);  
        }  

    所以,asInterface从一个IBinder对象可以转换成一个Proxy或是一个Stub对象。Proxy对象,很好理解,即Proxy里是封装了BpBinder, 通过BpBinder和server端的BBinder进行通信。 那Stub对象呢,什么时候会返回一个Stub对象呢? 我个人的理解是当service是一个本地service的时候,只有这种情况的时候拿到IBinder对象后是不需要Proxy进行跨进程通信,而直接可以使用Server端实现的Stub对象来访问service的方法(个人猜测,未经证实。后面有时间可以去测试下)。

    展开全文
  • binder通信

    2016-03-15 01:42:11
    1.binder通信概述  binder通信是一种client-server的通信结构,  1.从表面上来看,是client通过获得一个server的代理接口,对server进行直接调用;  2.实际上,代理接口中定义的方法与server中定义的方法是...

    1.binder通信概述

        binder通信是一种client-server的通信结构,
        1.从表面上来看,是client通过获得一个server的代理接口,对server进行直接调用;
        2.实际上,代理接口中定义的方法与server中定义的方法是一一对应的;
        3.client调用某个代理接口中的方法时,代理接口的方法会将client传递的参数打包成为Parcel对象;
        4.代理接口将该Parcel发送给内核中的binder driver.
        5.server会读取binder driver中的请求数据,如果是发送给自己的,解包Parcel对象,处理并将结果返回;
        6.整个的调用过程是一个同步过程,在server处理的时候,client会block住。

     

     

     

    2.service manager

    Service Manager是一个linux级的进程,顾名思义,就是service的管理器。这里的service是什么概念呢?这里的service的概念和init过程中init.rc中的service是不同,init.rc中的service是都是linux进程,但是这里的service它并不一定是一个进程,也就是说可能一个或多个service属于同一个linux进程。在这篇文章中不加特殊说明均指android native端的service。

    任何service在被使用之前,均要向SM(Service Manager)注册,同时客户端需要访问某个service时,应该首先向SM查询是否存在该服务。如果SM存在这个service,那么会将该service的handle返回给client,handle是每个service的唯一标识符。
        
        SM的入口函数在service_manager.c中,下面是SM的代码部分
    int main(int argc, char **argv)
    {
        struct binder_state *bs;
        void *svcmgr = BINDER_SERVICE_MANAGER;

        bs = binder_open(128*1024);

        if (binder_become_context_manager(bs)) {
            LOGE("cannot become context manager (%s)/n", strerror(errno));
            return -1;
        }

        svcmgr_handle = svcmgr;
        binder_loop(bs, svcmgr_handler);
        return 0;
    }

    这个进程的主要工作如下:
        1.初始化binder,打开/dev/binder设备;在内存中为binder映射128K字节空间;
        2.指定SM对应的代理binder的handle为0,当client尝试与SM通信时,需要创建一个handle为0的代理binder,这里的代理binder其实就是第一节中描述的那个代理接口;

    3.通知binder driver(BD)使SM成为BD的context manager;
    4.维护一个死循环,在这个死循环中,不停地去读内核中binder driver,查看是否有可读的内容;即是否有对service的操作要求, 如果有,则调用svcmgr_handler回调来处理请求的操作。

    5.SM维护了一个svclist列表来存储service的信息。

     



    这里需要声明一下,当service在向SM注册时,该service就是一个client,而SM则作为了server。而某个进程需要与service通信时,此时这个进程为client,service才作为server。因此service不一定为server,有时它也是作为client存在的。

     

    由于下面几节会介绍一些与binder通信相关的几个概念,所以将SM的功能介绍放在了后面的部分来讲。

    应用和service之间的通信会涉及到2次binder通信。

    1.应用向SM查询service是否存在,如果存在获得该service的代理binder,此为一次binder通信;
    2.应用通过代理binder调用service的方法,此为第二次binder通信。

    3.ProcessState

    ProcessState是以单例模式设计的。每个进程在使用binder机制通信时,均需要维护一个ProcessState实例来描述当前进程在binder通信时的binder状态。
        ProcessState有如下2个主要功能:
        1.创建一个thread,该线程负责与内核中的binder模块进行通信,称该线程为Pool thread;
        2.为指定的handle创建一个BpBinder对象,并管理该进程中所有的BpBinder对象。

     

    3.1 Pool thread

                在Binder IPC中,所有进程均会启动一个thread来负责与BD来直接通信,也就是不停的读写BD,这个线程的实现主体是一个IPCThreadState对象,下面会介绍这个类型。

                下面是 Pool thread的启动方式:

    ProcessState::self()->startThreadPool();

    3.2 BpBinder获取

    BpBinder主要功能是负责client向BD发送调用请求的数据。它是client端binder通信的核心对象,通过调用transact函数向BD发送调用请求的数据,它的构造函数如下:

    BpBinder(int32_t handle);
        通过BpBinder的构造函数发现,BpBinder会将当前通信中server的handle记录下来,当有数据发送时,会通知BD数据的发送目标。

    ProcessState通过如下方式来获取BpBinder对象:

    ProcessState::self()->getContextObject(handle);

    在这个过程中,ProcessState会维护一个BpBinder的vector mHandleToObject,每当ProcessState创建一个BpBinder的实例时,回去查询mHandleToObject,如果对应的handle已经有binder指针,那么不再创建,否则创建binder并插入到mHandleToObject中。
        ProcessState创建的BpBinder实例,一般情况下会作为参数构建一个client端的代理接口,这个代理接口的形式为BpINTERFACE,例如在与SM通信时,client会创建一个代理接口BpServiceManager.
        
       

    4.IPCThreadState

    IPCThreadState也是以单例模式设计的。由于每个进程只维护了一个ProcessState实例,同时ProcessState只启动一个Pool thread,也就是说每一个进程只会启动一个Pool thread,因此每个进程则只需要一个IPCThreadState即可。
        Pool thread的实际内容则为:
        IPCThreadState::self()->joinThreadPool();

     

    ProcessState中有2个Parcel成员,mIn和mOut,Pool thread会不停的查询BD中是否有数据可读,如果有将其读出并保存到mIn,同时不停的检查mOut是否有数据需要向BD发送,如果有,则将其内容写入到BD中,总而言之,从BD中读出的数据保存到mIn,待写入到BD中的数据保存在了mOut中。

    ProcessState中生成的BpBinder实例通过调用IPCThreadState的transact函数来向mOut中写入数据,这样的话这个binder IPC过程的client端的调用请求的发送过程就明了了。

     

    IPCThreadState有两个重要的函数,talkWithDriver函数负责从BD读写数据,executeCommand函数负责解析并执行mIn中的数据。

    5.主要基类

    5.1基类IInterface

    为server端提供接口,它的子类声明了service能够实现的所有的方法;


    5.2基类IBinder
        BBinder与BpBinder均为IBinder的子类,因此可以看出IBinder定义了binder IPC的通信协议,BBinder与BpBinder在这个协议框架内进行的收和发操作,构建了基本的binder IPC机制。
    5.3基类BpRefBase
        client端在查询SM获得所需的的BpBinder后,BpRefBase负责管理当前获得的BpBinder实例。

     

     

    6.两个接口类

    6.1 BpINTERFACE

    如果client想要使用binder IPC来通信,那么首先会从SM出查询并获得server端service的BpBinder,在client端,这个对象被认为是server端的远程代理。为了能够使client能够想本地调用一样调用一个远程server,server端需要向client提供一个接口,client在在这个接口的基础上创建一个BpINTERFACE,使用这个对象,client的应用能够想本地调用一样直接调用server端的方法。而不用去关心具体的binder IPC实现。
    下面看一下BpINTERFACE的原型:
        class BpINTERFACE : public BpInterface<IINTERFACE>

        顺着继承关系再往上看
        template<typename INTERFACE>
        class BpInterface : public INTERFACE, public BpRefBase

        BpINTERFACE分别继承自INTERFACE,和BpRefBase;
    ● BpINTERFACE既实现了service中各方法的本地操作,将每个方法的参数以Parcel的形式发送给BD。
    例如BpServiceManager的
        virtual status_t addService(const String16& name, const sp<IBinder>& service)
        {
            Parcel data, reply;
            data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
            data.writeString16(name);
            data.writeStrongBinder(service);
            status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);
            return err == NO_ERROR ? reply.readExceptionCode() : err;
        }
    ● 同时又将BpBinder作为了自己的成员来管理,将BpBinder存储在mRemote中,BpServiceManager通过调用BpRefBase的remote()来获得BpBinder指针。

     

    6.2 BnINTERFACE

    在定义android native端的service时,每个service均继承自BnINTERFACE(INTERFACE为service name)。BnINTERFACE类型定义了一个onTransact函数,这个函数负责解包收到的Parcel并执行client端的请求的方法。

        顺着BnINTERFACE的继承关系再往上看,
            class BnINTERFACE: public BnInterface<IINTERFACE>

        IINTERFACE为client端的代理接口BpINTERFACE和server端的BnINTERFACE的共同接口类,这个共同接口类的目的就是保证service方法在C-S两端的一致性。

        再往上看
            class BnInterface : public INTERFACE, public BBinder

        同时我们发现了BBinder类型,这个类型又是干什么用的呢?既然每个service均可视为一个binder,那么真正的server端的binder的操作及状态的维护就是通过继承自BBinder来实现的。可见BBinder是service作为binder的本质所在。

        那么BBinder与BpBinder的区别又是什么呢?

        其实它们的区别很简单,BpBinder是client端创建的用于消息发送的代理,而BBinder是server端用于接收消息的通道。查看各自的代码就会发现,虽然两个类型均有transact的方法,但是两者的作用不同,BpBinder的transact方法是向IPCThreadState实例发送消息,通知其有消息要发送给BD;而BBinder则是当IPCThreadState实例收到BD消息时,通过BBinder的transact的方法将其传递给它的子类BnSERVICE的onTransact函数执行server端的操作。

     

    7. Parcel

    Parcel是binder IPC中的最基本的通信单元,它存储C-S间函数调用的参数.但是Parcel只能存储基本的数据类型,如果是复杂的数据类型的话,在存储时,需要将其拆分为基本的数据类型来存储。

        简单的Parcel读写不再介绍,下面着重介绍一下2个函数

     

    7.1 writeStrongBinder

    当client需要将一个binder向server发送时,可以调用此函数。例如
            virtual status_t addService(const String16& name, const sp<IBinder>& service)
            {
                Parcel data, reply;
                data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
                data.writeString16(name);
                data.writeStrongBinder(service);
                status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);
                return err == NO_ERROR ? reply.readExceptionCode() : err;
            }


    看一下writeStrongBinder的实体
    status_t Parcel::writeStrongBinder(const sp<IBinder>& val)
    {
        return flatten_binder(ProcessState::self(), val, this);
    }

    接着往里看flatten_binder
    status_t flatten_binder(const sp<ProcessState>& proc,
        const sp<IBinder>& binder, Parcel* out)
    {
        flat_binder_object obj;
        
        obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
        if (binder != NULL) {
            IBinder *local = binder->localBinder();
            if (!local) {
                BpBinder *proxy = binder->remoteBinder();
                if (proxy == NULL) {
                    LOGE("null proxy");
                }
                const int32_t handle = proxy ? proxy->handle() : 0;
                obj.type = BINDER_TYPE_HANDLE;
                obj.handle = handle;
                obj.cookie = NULL;
            } else {
                obj.type = BINDER_TYPE_BINDER;
                obj.binder = local->getWeakRefs();
                obj.cookie = local;
            }
        } else {
            obj.type = BINDER_TYPE_BINDER;
            obj.binder = NULL;
            obj.cookie = NULL;
        }
        
        return finish_flatten_binder(binder, obj, out);
    }

        还是拿addService为例,它的参数为一个BnINTERFACE类型指针,BnINTERFACE又继承自BBinder,
        BBinder* BBinder::localBinder()
        {
            return this;
        }
        所以写入到Parcel的binder类型为BINDER_TYPE_BINDER,同时你在阅读SM的代码时会发现如果SM收到的service的binder类型不为BINDER_TYPE_HANDLE时,SM将不会将此service添加到svclist,但是很显然每个service的添加都是成功的,addService在开始传递的binder类型为BINDER_TYPE_BINDER,SM收到的binder类型为BINDER_TYPE_HANDLE,那么这个过程当中究竟发生了什么?
        为了搞明白这个问题,花费我很多的事件,最终发现了问题的所在,原来在BD中做了如下操作(drivers/staging/android/Binder.c):


    static void binder_transaction(struct binder_proc *proc,
                       struct binder_thread *thread,
                       struct binder_transaction_data *tr, int reply)
    {
    ..........................................

        if (fp->type == BINDER_TYPE_BINDER)
            fp->type = BINDER_TYPE_HANDLE;
        else
            fp->type = BINDER_TYPE_WEAK_HANDLE;
        fp->handle = ref->desc;
    ..........................................
    }

     


    阅读完addService的代码,你会发现SM只是保存了service binder的handle和service的name,那么当client需要和某个service通信了,如何获得service的binder呢?看下一个函数

    7.2 readStrongBinder

    当server端收到client的调用请求之后,如果需要返回一个binder时,可以向BD发送这个binder,当IPCThreadState实例收到这个返回的Parcel时,client可以通过这个函数将这个被server返回的binder读出。


    sp<IBinder> Parcel::readStrongBinder() const
    {
        sp<IBinder> val;
        unflatten_binder(ProcessState::self(), *this, &val);
        return val;
    }


    往里查看unflatten_binder


    status_t unflatten_binder(const sp<ProcessState>& proc,
        const Parcel& in, sp<IBinder>* out)
    {
        const flat_binder_object* flat = in.readObject(false);
        
        if (flat) {
            switch (flat->type) {
                case BINDER_TYPE_BINDER:
                    *out = static_cast<IBinder*>(flat->cookie);
                    return finish_unflatten_binder(NULL, *flat, in);
                case BINDER_TYPE_HANDLE:
                    *out = proc->getStrongProxyForHandle(flat->handle);
                    return finish_unflatten_binder(
                        static_cast<BpBinder*>(out->get()), *flat, in);
            }        
        }
        return BAD_TYPE;
    }


    发现如果server返回的binder类型为BINDER_TYPE_BINDER的话,也就是返回一个binder引用的话,直接获取这个binder;如果server返回的binder类型为BINDER_TYPE_HANDLE时,也就是server返回的仅仅是binder的handle,那么需要重新创建一个BpBinder返回给client。


        有上面的代码可以看出,SM保存的service的binder仅仅是一个handle,而client则是通过向SM获得这个handle,从而重新构建代理binder与server通信。


        这里顺带提一下一种特殊的情况,binder通信的双方即可作为client,也可以作为server.也就是说此时的binder通信是一个半双工的通信。那么在这种情况下,操作的过程会比单工的情况复杂,但是基本的原理是一样的,有兴趣可以分析一下MediaPlayer和MediaPlayerService的例子。

     

    8. 经典桥段分析

    main_ mediaserver.cpp
    int main(int argc, char** argv)
    {

    //创建进程mediaserver的ProcessState实例
        sp<ProcessState> proc(ProcessState::self());

    //获得SM的BpServiceManager
        sp<IServiceManager> sm = defaultServiceManager();
        LOGI("ServiceManager: %p", sm.get());

    //添加mediaserver中支持的service。
        AudioFlinger::instantiate();
        MediaPlayerService::instantiate();
        CameraService::instantiate();
        AudioPolicyService::instantiate();

    //启动ProcessState的pool thread
        ProcessState::self()->startThreadPool();

    //这一步有重复之嫌,加不加无关紧要。
        IPCThreadState::self()->joinThreadPool();
    }

     

    9. Java 层的binder机制

    了解了native通信机制后,再去分析JAVA层的binder机制,就会很好理解了。它只是对native的binder做了一个封装。这一部分基本上没有太复杂的过程,这里不再赘述了。

    展开全文
  • 1 前言Binder通信机制是Android中很重要的一个概念,贯穿整个Android系统。因此无论是作为一个Android系统开发者还是App开发者,都应该重点掌握。关于Binder机制的博客文章,网上都很多了,很多写的也比较好。因此本...

    1 前言

    Binder通信机制是Android中很重要的一个概念,贯穿整个Android系统。因此无论是作为一个Android系统开发者还是App开发者,都应该重点掌握。关于Binder机制的博客文章,网上都很多了,很多写的也比较好。因此本系列仅仅作为深入掌握Binder的一个学习笔记。废话不多少,开始吧。

    2 Binder通信整体框架

    Binder通信的整体框架如下图:
    这里写图片描述
    上面只是Binder通信的一个简图,大体的讲解了Binder通信涉及到的角色。

    可以看到,Binder通信是一个典型的C/S架构,一共有四个角色Client、Server、ServiceManager以及binder驱动。各个角色的作用如下:

    Client:客户端,获取和使用服务的的对象,例如,在Android系统中,我们常常用Context#getSystemService(@ServiceName @NonNull String name)获取的就是一个Client,例如ActivityManager,WindowManager等都是一个Client。

    Server:服务提供商,主要为客户端提供各种服务,例如常见的ActivityManagerService,WindowManagerService等。这些服务往往是管理整个Android系统的各种功能,是Android Framework层的核心。

    ServiceManager: ServiceManager用于管理系统中的各种服务,因为Android系统功能很强大,往往有几十个服务,因此需要一个统一的服务管理者来管理。

    Binder驱动: Binder通信的底层载体和支撑。Binder驱动支撑着整个Binder IPC过程,它是Binder实现IPC的基础,对于一般APP开发者来说,了解的少。但是它却有很大的作用,因此仍然需要了解。

    3 Binder通信机制要点

    个人觉得,要掌握Binder通信,可以从以下几个方面来掌握

    1 Android 中使用Binder的原因
    2 Binder驱动与协议
    3 ServiceManager如何管理服务
    4 Server如何注册服务
    5 Client如何获取服务和使用服务
    6 Binder 线程池工作过程

    这每一个小点,都打算写一篇博客来分析,后续的博客打算逐步更新。

    暂时写这么多吧,后续根据实际情况增加

    展开全文
  • binder通信实例

    2016-09-01 16:35:26
    这是一个底层的binder通信列子希望对大家有用
  • Binder通信机制

    万次阅读 2017-04-03 03:48:58
    Binder简介 Binder是android系统中实现的一种高效的IPC机制,平常接触到的各种...framework层的Binder通信用到的相关java类型都是对应C++类型的一个封装。 这里framework层就是android提供的java api层,类似j


    Binder简介

    Binder是android系统中实现的一种高效的IPC机制,平常接触到的各种XxxManager,以及绑定Service时都在使用它进行跨进程操作。
    它的实现基于OpenBinder项目,属于核心库。framework层的Binder通信用到的相关java类型都是对应C++类型的一个封装。

    这里framework层就是android提供的java api层,类似jre中的java标准类库,也就是我们sdk中用到的各种java类型。

    IPC和远程对象(Remotable Object)

    在Java编程中,大多数情况下都是进程内的各个对象相互交互,另一些情况,java程序和其它进程进行的通信,就是IPC(inter-process communication)。

    广义上看,像最常见的HTTP网络通信就是一种跨进程通信——客户端java程序和远程服务器上的服务进程通信。所以,其它进程可以是非java程序,如C++程序。抽象的看,不论哪两种语言的程序进程之间的沟通,都是一些方法调用——可以调用的方法就是所谓的协议,或接口API。

    在Java中,一切皆对象,那么在和一个外部进程通信时,首先需要针对它的一组接口描述——也就是方法描述,此描述的类型定义显然就是通过接口实现了。这样,此接口所定义的通信协议就是本地java端对外部进程可执行操作的一个描述,实际上其它进程是否是java程序,是否有对象之说倒不重要,这里站在java程序的角度,虚拟地认为其它进程内部包含一个拥有这些操作的对象——远程对象——算是本地接口的实现类对象。远程对象的概念是从某个进程看其它进程的对象而言的。

    java程序使用java接口对远程进程通信协议进行描述,其它像Swift这样的语言又有它们自己的通信协议的描述方式。

    Binder系统

    下面用Binder-SYS表示安卓系统中运行的Binder系统,Binder-IPC表示Binder实现IPC的机制。

    Server和Client

    Binder-SYS将通信的双方分为Server和Client,即C/S架构。
    两端进程均使用一个接口IBinder的实例进行通信,它定义了方法IBinder.transact(),方法原型:

    /**
     * Perform a generic operation with the object.
     *
     * @param code The action to perform.  This should
     * be a number between {@link #FIRST_CALL_TRANSACTION} and
     * {@link #LAST_CALL_TRANSACTION}.
     * @param data Marshalled data to send to the target.  Must not be null.
     * If you are not sending any data, you must create an empty Parcel
     * that is given here.
     * @param reply Marshalled data to be received from the target.  May be
     * null if you are not interested in the return value.
     * @param flags Additional operation flags.  Either 0 for a normal
     * RPC, or {@link #FLAG_ONEWAY} for a one-way RPC.
     */
    public boolean transact(int code, Parcel data, Parcel reply, int flags)
        throws RemoteException;
    • code
      表示要执行的动作,类似Handler发送的Message的what。
      code指示了当前远程操作的命令,IBinder定义了像INTERFACE_TRANSACTION、PING_TRANSACTION这样的几个通用命令。自己使用的命令的标识值需要在FIRST_CALL_TRANSACTION和LAST_CALL_TRANSACTION之间,仅仅是整数范围的一个约定,很好理解。

    • data和reply
      data和reply参数相当于普通java方法里的调用参数和返回值。Parcel类型是可以跨进程的数据。

    • flags
      参数flags只有0和FLAG_ONEWAY两种,默认的跨进程操作是同步的,所以transact()方法的执行会阻塞,调用以同步的形式传递到远程的transact(),等待远端的transact()返回后继续执行——最好理解的方式就是把两端的transact()看作一个方法,Binder机制的目标也就是这样。指定FLAG_ONEWAY时,表示Client的transact()是单向调用,执行后立即返回,无需等待Server端transact()返回。

    Server和Client利用IBinder跨进程通信的原理是:

    Client调用其IBinder实例的transact()发起操作,Binder-SYS使得方法调用传递到Server端,以相同的参数执行Server端IBinder实例的transact()方法——这就是Binder-SYS实现的跨进程操作。

    Binder和BinderProxy

    Binder-SYS提供了BinderBinderProxy作为IBinder的子类。
    每一个Binder对象都会唯一关联一个BinderProxy对象。
    在跨进程通信时,提供服务的Server进程持有一个Binder对象,记为Server_Binder_obj。而其它Client进程持有关联的BinderProxy对象,记为Client_BinderProxy_obj。不同Client进程里的BinderProxy是不同java对象,而底层是同一个由Binder-SYS维护的C++对象。所以BinderProxy对象实际上是跨进程唯一的。
    这里Proxy的含义就是Client进程得到的Server端Binder对象的一个本地引用。

    最终Client对Server发起远程调用的过程就是:
    Client调用其BinderProxy实例的transact()发起操作,Binder-SYS使得方法调用传递到Server端,以相同的参数执行Server端Binder实例的transact()方法

    这里注意下transact()在BinderProxy和Binder中的不同之处:
    BinderProxy.transact()方法是Client用来主动发出远程操作命令的,它接收code、data参数。BinderProxy是个final类,它的transact()方法只能被调用。
    Binder.transact()是用来被动响应Client发出的远程调用的。
    BinderProxy.transact()调用后,Server端Binder.transact()方法以同样的code、data参数被调用。
    Binder类定义了onTransact()方法来供子类去响应命令,而它的transact()方法调用onTransact()的逻辑。onTransact()更好的表达了Binder的行为。

    通信过程

    有了以上核心概念,Binder-IPC的原理还是很简单明了的,一次跨进程远程通信的过程是:

    1. Client的代码调用BinderProxy.transact(),发起远程调用。参数flags为0时方法阻塞,等待Server端对应方法返回后继续执行。参数flags为FLAG_ONEWAY时立即返回。

    2. Client中的transact()调用传递式触发Server端Binder.transact()的调用,它又调用Binder.onTransact()。

    3. Server端,Binder.onTransact()中,子类的重写方法根据收到的code,执行对应业务逻辑,设置必要的返回数据到参数reply,然后Binder.transact()方法返回。

    4. Client端,BinderProxy.transact()从阻塞状态返回,调用者解析得到必要的返回参数,继续执行。

    可以看到,Binder机制维持了Client进程的transact()的调用传递给Server端transact()以及相应的调用返回的传递过程。注意参数flags为FLAG_ONEWAY时指定通信为“单向”的,这样整个远程调用就成为了异步的——Client的transact()会很快返回,不需要等待Server端的方法调用完成(甚至是开始)。

    以上就是Binder-IPC的主要原理。

    示例项目:StudentManager

    下面提供一个示例项目来说明如何使用Binder-IPC完成跨进程通信。
    案例提供这样的功能:
    Server端程序实现了学生管理功能,提供了按学号查询学生年龄的操作。
    然后Client通过Binder-IPC对Server端执行远程调用获得结果。

    协议部分

    从编程角度看,使用Binder-IPC实现Client和Server通信,有一些类型它们都会用到,这些类型仅仅和通信相关,而不涉及实际业务。这里称它们为通信协议相关类型。
    一般都是提供服务的Server端定义这些类型,下面就依次实现它们。

    通信接口

    它定义了Server端可接收的方法调用,也就是Client可以发起的远程调用。
    这里根据假设的需求,定义下面的接口:

    package com.idlestars.binderdemo.serviceapi;
    ...
    
    interface IStudentManager extends IInterface {
      String DESCRIPTOR = "com.tiro.binder.StudentManagerStub";
      int TRANSACTION_GET_AGE = (IBinder.FIRST_CALL_TRANSACTION + 0);
    
      int getAge(int studentId) throws RemoteException;;
    }

    通信接口是偏业务上的,它定义了方法getAge()用来根据学生id来获取其年龄。下面对它进行一些说明。

    • RemoteException
      所有接口方法需要声明RemoteException异常,跨进程操作时目标服务进程总可能意外终止,或者服务类调用Parcel.writeException()来通知异常发生,这样Client端接口方法的调用就抛出RemoteException。

    • DESCRIPTOR
      对当前接口的一个字符串标识,Binder类的attachInterface()和queryLocalInterface()方法会用到它。

    • TRANSACTION_GET_AGE
      对应接口方法getAge()的命令code。

    • IInterface
      Binder-IPC要求的标准实现方式是,通信接口需要继承接口IInterface。它定义了asBinder()方法用来返回接口实例关联的IBinder对象。
      这是因为一般正是Server端的Binder子类会实现通信接口,然后,Client是无法拿到Server端的IStudentManager对象的,所以,为Client定义一个本地的IStudentManager的代理实现类,该实现类使用BinderProxy调用Server端方法获取结果。
      也就是通常两端实现接口IStudentManager的地方都密切关联了一个可以用来远程通信的IBinder对象,而asBinder()就是用来返回这个IBinder的。
      经试验,这不是必须的。

    Client端代理类

    有了通信接口后,紧接着需要实现Server和Client使用IBinder进行数据交互的部分。也就是transact()的逻辑。
    IStudentManager的实现是位于Server端的,Client端无法得到其对象。所以,Client端定义一个接口的代理实现类:

    package com.idlestars.binderdemo.serviceapi;
    ...
    public class StudentManager implements IStudentManager {
        IBinder mRemote;
    
        public StudentManager(IBinder remote) {
            mRemote = remote;
        }
    
        @Override
        public int getAge(int studentId) throws RemoteException {
            Parcel data = Parcel.obtain();
            Parcel reply = Parcel.obtain();
    
            try {
                data.writeInterfaceToken(DESCRIPTOR);
                data.writeInt(studentId);
                mRemote.transact(TRANSACTION_GET_AGE, data, reply, 0);
                reply.readException();
                int age = reply.readInt();
    
                return age;
            } finally {
                data.recycle();
                reply.recycle();
            }
        }
    
        @Override
        public IBinder asBinder() {
            return mRemote;
        }
    }

    代理类StudentManager对getAge()的实现是通过mRemote来发送远程调用。
    此处的mRemote是连接到Server时,Server端Binder关联的BinderProxy对象。
    上面getAge()中写入和读取数据的顺序必须和Server端的Binder.onTransact()对应——主要就是code的取值和data、reply中数据的写入读取顺序。

    StudentManager实现的IInterface.asBinder()返回它组合的mRemote。

    Server端通信类

    应用层提供可供其它进程访问的服务的方式就是通过Service组件,Service组件所在进程就是Server进程。
    Client进程使用bindService()来和Server进程进行通信。

    所以这里需要准备onBind()返回的Binder对象。同进程内的bindService()调用会返回给调用者Binder对象本身,而其它进程的调用最终得到的是Binder关联的BinderProxy对象。总之这个Binder子类就是服务绑定者后续和服务进行通信的渠道。

    Server端使用Binder进行通信,也就是是响应transact()调用。
    一般为了让返回的Binder对象可以被同进程内的绑定者当做IStudentManager去使用,这里定义的Binder子类就同时实现IStudentManager。

    在Binder.onTransact()中将会实现和Client使用的代理类StudentManager.transact()对应的通信数据交换逻辑。
    这部分逻辑是和IStudentManager定义的业务方法无关的。
    为了方便将Binder.onTransact()的逻辑暴漏给Client——因为Client程序会最终引用这些类型,不论是源码方式还是库引用,处于安全或方便的目的,这里先定义一个抽象的Binder子类StudentManagerStub,它完成了和StudentManager交换数据,响应远程调用的逻辑。作为一个抽象类,它实现接口IStudentManager,但不去做任何实际处理,onBind()返回的类型会继承它,并实现IStudentManager的方法。

    public abstract class StudentManagerStub extends Binder implements IStudentManager {
    
        public StudentManagerStub() {
            this.attachInterface(this, DESCRIPTOR);
        }
    
        @Override
        public IBinder asBinder() {
            return this;
        }
    
        @Override
        protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
            switch (code)
            {
                case INTERFACE_TRANSACTION:
                {
                    reply.writeString(DESCRIPTOR);
                    return true;
                }
                case TRANSACTION_GET_AGE:
                {
                    data.enforceInterface(DESCRIPTOR);
                    int stuId = data.readInt();
                    reply.writeNoException();
                    reply.writeInt(getAge(stuId));
                    return true;
                }
            }
            return super.onTransact(code, data, reply, flags);
        }
    
        public static IStudentManager asInterface(IBinder obj) {
            if (obj == null) {
                return null;
            }
            IStudentManager in =
                    (IStudentManager)obj.queryLocalInterface(DESCRIPTOR);
            if (in != null) {
                return in;
            }
    
            return new StudentManager(obj);
        }
    }

    可以看到StudentManagerStub.onTransact()和StudentManager.transact()是对应的,后者的每一个code和前者都有一个case语句去处理。重要的是,有关data、reply参数的数据的写入和读取顺序也严格对应。

    在onTransact()中调用了getAge()方法,它由最终的StudentManagerStub的子类去完成。getAge()是业务方法,和通信细节没有关系。

    StudentManagerStub作为Binder子类,它实现的IInterface.asBinder()直接返回其对象本身——它既是IInterface的子类,又是Binder子类。

    小结

    以上的IStudentManager、StudentManager、StudentManagerStub是协议部分涉及到的类型。它们由Server端程序提供,Client端去引用。

    StudentManagerStub的定义,使得Server端通信协议实现和通信接口的业务方法的实现得以分离。

    有关协议类型要注意下面几点

    • 数据支持
      IBinder.transact()可传递的数据只能是Parcel类型的,关于它可携带的数据类型参见其API。
      Parcel对象可以携带的类型决定了通信所能支持的数据类型。

    • 通信规则
      Client传递的调用参数data和Server端返回的reply数据,它们在写入和读取的顺序上必须是一致的。
      写入和读取的顺序也是通信规则的一部分,所以两端的transact()、onTransact()逻辑严格对应。

    业务部分

    除了Binder-IPC需要的通信协议相关的类型,Server端需要提供Service来供其它进程绑定。并且它自己实现IStudentManager的业务方法。

    Client中会使用代理类StudentManager来访问服务。

    定义Service

    Server提供一个Service组件来供自身程序、其它程序等访问:

    public class RemoteService extends Service {
        StudentManagerService mBinder = new StudentManagerService();
    
        @Nullable
        @Override
        public IBinder onBind(Intent intent) {
            return mBinder;
        }
    }

    为了突出重点,RemoteService的代码非常简单。就是返回一个StudentManagerService对象。
    额外的工作就是在AndroidManifest.xml中注册它。

    注意onBind()的机制是仅在第一个bindService()的请求时返回关联的IBinder对象,之后不再调用。
    所以,一个Service在运行期间也只能通过一个IBinder对象和各个Client通信。

    实现IStudentManager

    onBind()返回的StudentManagerService继承自StudentManagerStub,它只需要完成实际的getAge()方法。
    StudentManagerStub已经实现了通信协议的逻辑。

    class StudentManagerService extends StudentManagerStub {
        @Override
        public int getAge(int studentId) throws RemoteException {
            return Math.abs(studentId % 30);
        }
    }

    Client访问Service

    Client端访问目标Service的步骤如下:

    1. 调用bindService()。
    2. 将返回的IBinder使用StudentManagerStub.asInterface()转换为IStudentManager的实例。
    3. 像普通接口那样使用IStudentManager。

    可以看到,其实对Client端而言,它只需要知道IStudentManager即可,而
    StudentManagerStub和StudentManager直接由提供服务类的Server端定义即可。
    在不同程序间进行Service的访问时,由谁来提供这些通信协议的类型是一个说一不二的事情。

    使用bindService()来绑定服务是很基础的事情了。
    如果是同进程,那么onServiceConnected()返回的是上面onBind()返回的StudentManagerService对象。
    如果是不同进程,返回的是onBind()返回的StudentManagerService对象关联的BinderProxy对象。

    所以bindService()得到的IBinder是和Service是否在同一个进程密切相关的。
    上面StudentManagerStub.asInterface()方法正是用来将bindService()得到的IBinder转换为最终要用到的IStudentManager的实例:

    public static IStudentManager asInterface(IBinder obj) {
        if (obj == null) {
            return null;
        }
        IStudentManager in =
                (IStudentManager)obj.queryLocalInterface(DESCRIPTOR);
        if (in != null) {
            return in;
        }
    
        return new StudentManager(obj);
    }
    • 和Service同进程
      参数obj就是StudentManagerService,因为使用的是IStudentManager.DESCRIPTOR,它的queryLocalInterface()返回StudentManagerService对象本身,成功强转为IStudentManager。

    • 和Service不同进程
      参数obj是BinderProxy对象,上面if语句不会执行,这时,Client进程得到一个组合了此obj的StudentManager代理类对象,StudentManager负责远程调用Server端的方法。

    这里使用queryLocalInterface()而不是instanceof这类方式执行类型检查,因为不能依赖到
    StudentManagerService,包括对类型名称的假设。
    而接口标识这样的方式可以满足上面的IStudentManager类型在Server进程内,或Client端两种转换要求。

    实际上方法asInterface()放在协议类型StudentManagerStub、StudentManager中都可以。

    Client访问Service的代码:

    IStudentManager mStudentManager;
    
    ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            mStudentManager = StudentManagerStub.asInterface(service);
        }
    
        @Override
        public void onServiceDisconnected(ComponentName name) {
            mStudentManager = null;
        }
    };
    
    private void bindToService() {
        Intent intent = new Intent(this, RemoteService.class);
        bindService(intent, connection, BIND_AUTO_CREATE);
    }

    bindService()的使用不过多介绍,intent可以指定为Action字符串。

    执行远程调用

    bindService()获得一个IStudentManager对象后,就可以用它来调用Server端的方法了。
    实际上,Client端的代码调用getAge()方法和其它java方法没什么两样,唯一的区别就是需要捕获可能的RemoteException异常。

    下面的方法onGetAgeClick()是按钮点击处理,它读取输入的stuId作为参数,执行getAge(),将返回结果显示。

    public void onGetAgeClick(View view) {
        if (mStudentManager != null) {
            try {
                int stuId = Integer.valueOf(et_stu_id.getText().toString());
                int age = mStudentManager.getAge(stuId);
    
                tv_age.setText("Age: " + age);
            } catch (Exception e) {
                Log.d("Binder", "getAge Exception: " + e.getMessage());
            }
        }
    }

    Binder机制的不同使用方式

    需要注意的一点是,以上关于Binder架构讨论的种种都是针对典型的IPC的情形的。
    不过IBinder的使用在app层一般都是结合作为四大组件之一的Service进行的,也就是bindService()。Service可以是其它app的Service类,或者是当前程序本身的Service类,可以运行在相同进程或其它进程。

    非Service方式的使用

    framework层的ActivityManager、PackageManager等都是利用了Binder机制。但它们的服务类不是通过Service组件去提供。

    以IActivityManager为例:

    • 接口IActivityManager定义了有关管理系统中所有Activity的API。
    • ActivityManagerService继承自Binder,并实现了IActivityManager,相当于一个Server端的服务类。
    • SystemServer进程启动后,它实例化ActivityManagerService对象,然后注册到ServiceManager中。
    • ActivityManager通过ServiceManager获得ActivityManagerService的BinderProxy,它也实现了IActivityManager,
      相当于一个代理类。

    可见,像系统服务它们位于特殊的进程内,不是以Service组件的方式运行。
    其注册和获取的方式也不是bindService()这样的,而是依赖ServiceManager。

    这里简单的举例Binder的非Service使用形式,说明一点,Binder机制提供“更底层”的API,bindService()方式访问Service组件时用到Binder架构,在app开发中这是主要形式。但可以脱离Service来使用Binder进行IPC通信。

    SystemServer作为系统进程它的生命周期必然会更稳定,而Service对进程的“重要性”的影响显然还不如Activity。
    在使用Binder来进行IPC时,总要关心目标进程的存活状态,后面会再涉及到这点。

    Service方式

    此时分两种情况:目标Service在同一进程和不同进程。绑定其它程序的Service肯定是不同进程的情况了。而当前项目里的Service也可以通过在AndroidManifest.xml中声明不同的android:process来使其运行在另外进程中。

    同进程内

    这种是最简单的bindService()的使用场景。
    此时,Service.onBind()返回的就是Binder的子类。它是同进程的对象,而且类型已知。
    Service返回的Binder类是可以完全访问Service的功能的,为了使用此Binder和Service通信,有以下方式:

    • Binder子类提供一些public方法供调用,这些方法操作Service。
    • Binder子类返回对应的Service对象供使用。
    • Binder子类返回寄宿在Service中的一些公开成员对象供访问,一般就是此Service提供的不同接口的实现类对象。

    此时不需要标准的Client端,bindService()的调用者得到Binder后就可以访问Service提供的各项功能了。

    绑定同程序不同进程中的Service

    此时从另一个进程获取到的是BinderProxy对象,属于标准的IPC方式。
    bindService()的代码最终获得的是代理类,而不是Binder对象本身。
    此时的使用方式和上面StudentManager示例完全一样。
    因为是同一个程序,涉及的相关类型无需显示引用。

    绑定其它程序的Service

    其它程序必然运行在其它进程。这时,通信协议相关的IStudentManager、StudentManagerStub和
    StudentManager这些类型都是目标程序提供的。
    自己的项目中需要引用这些类型,之后的使用方式和上面StudentManager示例一样。

    向Server端注册回调

    除了可以调用Server端的业务接口方法外,还可以向Server注册回调接口,这样就相当于实现了跨进程的观察者模式。或者是类似广播监听器那样的效果。

    文章底部“案例代码”中的RemoteService示例演示了如何注册回调接口道其它进程。
    示例中的通信接口如下:

    interface IRemoteServiceCallback {
        void valueChanged(int value);
    }
    
    interface IRemoteService {
      void registerCallback(IRemoteServiceCallback cb);
      void unregisterCallback(IRemoteServiceCallback cb);
    }

    代码演示了Client使用IRemoteService将自己实现的IRemoteServiceCallback对象注册到Server。
    之后Server端就可以调用valueChanged()方法通知Client。

    实际上IRemoteServiceCallback对象肯定是无法跨进程传递的,valueChanged()的调用又是一次IPC过程,
    此时Client作为IRemoteServiceCallback的实现方,而Server作为IRemoteServiceCallback方法的调用方,valueChanged()的远程调用的过程中,原Server是Client,原Client是Server。

    可见Binder-IPC进行的通信中,Server和Client是相对概念。对应一个通信接口,谁发起远程调用,谁就是Client。

    registerCallback()传递给Server的是当前Client实现IRemoteServiceCallback所定义的Binder子类对象的BinderProxy。考虑许多Client向Server注册回调接口的情形,最终的,Server端维护了这些Client提供的
    IRemoteServiceCallback实例关联的IBinder对象,Server通过这些IBinder对象通知Client,达到调用其valueChanged()方法。

    android.os.RemoteCallbackList正是用来管理远程回调接口的,它就是以这些接口实例关联的IBinder作为标识。所以可以用来跨进程唯一标识不同Clients注册的IRemoteServiceCallback对象。

    监听Server端IBinder的死亡

    当Client端持有的IBinder代表着的其它进程中的服务类时,就需要特别关注其是否仍然有效——一般就是其所在进程是否还在运行决定。有下面三个方法用来完成对远程对象的检查:

    • The transact() method will throw a RemoteException exception if you try to call it on an IBinder whose process no longer exists.
    • The pingBinder() method can be called, and will return false if the remote process no longer exists.
    • The linkToDeath() method can be used to register a IBinder.DeathRecipient with the IBinder, which will be called when its containing process goes away.

    使用bindService()时都知道,目标Service所在进程终止时,ServiceConnection.onServiceConnected()方法就会执行(总会在main线程中执行)。

    因为使用IBinder的方式不限于Service中,所以在IBinder类的级别上也可以去主动监听服务类对象的死亡。
    前面在IBinder的说明中提到它提供了几个方法用来检查目标Binder是否存活,而主动获取其死亡通知的方式
    就是注册IBinder.DeathRecipient到代理类持有的IBinder。

    Client在获取到IBinder后:

    binder.linkToDeath(new IBinder.DeathRecipient() {
        @Override
        public void binderDied() {
            // 做一些清理,或者是尝试重新激活目标服务进程
        }
    }, 0);

    linkToDeath()会在binder线程池中的线程中执行,第二个参数flags文档中竟然没有说明?

    线程问题

    当Server和Client处在同一个进程或不同进程中时,transact()的执行所在的线程会是不同的表现。

    不同进程

    • Client端
      Client端是发起transact()的地方,其方法调用者所在线程就是transact()的执行线程。
      前面的知识已经明确知道了transact()可以是同步或异步的,如果是同步的形式,而Server端的transact()很可能会耗时,那么Client端的transact()就不应该在UI线程中执行。

    • Server端
      服务类对象所在的Server进程会维护一个binder专用的线程池来处理来自Client的请求。
      所以Server端的transact()的执行总是异步的,因此还需要注意线程同步的问题。

    不论Client的transact()的参数flags指定为0或0和FLAG_ONEWAY,Server端transact()总是在某个线程池的线程中执行。flags仅仅影响Client端transact()是否立即返回。

    同一个进程

    一般若自己的app内部bindService()来访问进程内的Service时,就属于同进程的C/S通信。
    此时Client获取到的IBinder就是服务类对象本身,所以,最终Client和Server端的transact()的执行是同一个方法的调用!!

    Binder的其它形式

    手动去实现Binder-IPC用到的各种类型非常繁琐,而且如果对Binder的使用不需要非常多的控制时,可以利用下面的AIDL和Messenger方式完成IPC,它们都是对Binder使用的一个简化。

    AIDL

    AIDL是方便定义通信协议的一个工具,注意它的工作过程是属于项目的构建的一部分。
    使用aidl时,需要用它来定义通信的接口,声明用到的自定义的数据格式。
    之后工具会自动生成java文件,作为最终编译的代码的一部分。

    其生成的类型包括:

    • 通信接口
      类似上面的IStudentManager,一个继承IInterface的接口。

    • Server端通信基类
      如上面的StudentManagerStub,它实现onTransact()的逻辑,用来响应不同命令,会调用业务接口IStudentManager的对应方法得到执行结果。
      作为协议的一部分,它不去实现接口的业务方法。
      onTransact()实现了Server端通信的细节。

    最终的服务类继承“Server端通信基类”,并实现通信接口里业务方法的逻辑。

    • 代理类
      如上面的StudentManager,它封装一个BinderProxy与远程服务类对象进行通信。

    作为一个工具,它的功能就是简化开发过程。和上面实现Server端、Client端相关类型的最终效果是一样的。
    更多细节参见api文档aidl的介绍,文章底部资料部分给出了具体地址。

    Messenger

    在创建一个可绑定的Service时,有三种方式可以提供onBind()返回的IBinder对象:

    • 返回Binder子类
      这种方式只有同进程时才可行,否则会返回给其它进程Binder的代理BinderProxy对象。

    • AIDL
      特点是跨进程,且Server端transact()的执行是由Binder线程池里的线程调用的,需要进行并发控制。

    • Messenger
      这种方式下,通信的命令被封装为Message对象,而且Server端使用一个Handler来依次处理收到的命令,不存在并发。

    使用Messenger的步骤如下:

    • The service implements a Handler that receives a callback for each call from a client.
    • The Handler is used to create a Messenger object (which is a reference to the Handler).
    • The Messenger creates an IBinder that the service returns to clients from onBind().
    • Clients use the IBinder to instantiate the Messenger (that references the service's Handler), which the client uses to send Message objects to the service.
    • The service receives each Message in its Handler—specifically, in the handleMessage() method.

    这种方式下,Client和Server之间没有接口方法,而是由Client发送Message表示的命令被Server端处理。
    可见Messenger简化了transact()的过程为handler发送消息的方式,Messenger的底层依然是标准的binder IPC方式实现的,Messenger的作用就类似上面的代理类,不过它实现的是通用的IMessenger接口。

    如果需要Server端向Client发送Message,在Client中定义好Handler和Messenger,然后把Messenger设置给发送到Server的Message对象的replyTo字段。

    IPC权限

    如果Server端需要对访问它的Client做权限检查,那么可以在AndroidManifest.xml中首先定义好权限。
    方法android.content.ContextWrapper#checkCallingOrSelfPermission()可以用来检查调用者是否拥有指定的权限。

    如果使用的是Service,那么onBind()处可以控制是否返回IBinder给某个Client,但是onBind()只会被执行一次,若返回null的话,后续的onServiceConnected()也不会执行。这里没有试验这种默认行为是否影响其它进程对服务的绑定,但终究不灵活。

    在onTransact()方法中,Binder提供了getCallingPid()和getCallingUid()来获得当前transact()执行时调用者的进程和用户等信息。在这里,进行权限检查,然后选择性返回false的话会更好些,也就是说,针对一次具体的transact()操作可以拒绝响应,但不影响其它的transact()调用。

    补充

    跨进程递归调用

    The Binder system also supports recursion across processes. For example if process A performs a transaction to process B, and process B while handling that transaction calls transact() on an IBinder that is implemented in A, then the thread in A that is currently waiting for the original transaction to finish will take care of calling Binder.onTransact() on the object being called by B. This ensures that the recursion semantics when calling remote binder object are the same as when calling local objects.

    Binder对象的生命周期

    Binder class is just a basic IPC primitive; it has no impact on an application's lifecycle, and is valid only as long as the process that created it continues to run. To use this correctly, you must be doing so within the context of a top-level application component (a Service, Activity, or ContentProvider) that lets the system know your process should remain running.

    You must keep in mind the situations in which your process could go away, and thus require that you later re-create a new Binder and re-attach it when the process starts again. For example, if you are using this within an Activity, your activity's process may be killed any time the activity is not started; if the activity is later re-created you will need to create a new Binder and hand it back to the correct place again; you need to be aware that your process may be started for another reason (for example to receive a broadcast) that will not involve re-creating the activity and thus run its code to create a new Binder.

    Binder简介

    Binder是android系统中实现的一种高效的IPC机制,平常接触到的各种XxxManager,以及绑定Service时都在使用它进行跨进程操作。
    它的实现基于OpenBinder项目,属于核心库。framework层的Binder通信用到的相关java类型都是对应C++类型的一个封装。

    这里framework层就是android提供的java api层,类似jre中的java标准类库,也就是我们sdk中用到的各种java类型。

    IPC和远程对象(Remotable Object)

    在Java编程中,大多数情况下都是进程内的各个对象相互交互,另一些情况,java程序和其它进程进行的通信,就是IPC(inter-process communication)。

    广义上看,像最常见的HTTP网络通信就是一种跨进程通信——客户端java程序和远程服务器上的服务进程通信。所以,其它进程可以是非java程序,如C++程序。抽象的看,不论哪两种语言的程序进程之间的沟通,都是一些方法调用——可以调用的方法就是所谓的协议,或接口API。

    在Java中,一切皆对象,那么在和一个外部进程通信时,首先需要针对它的一组接口描述——也就是方法描述,此描述的类型定义显然就是通过接口实现了。这样,此接口所定义的通信协议就是本地java端对外部进程可执行操作的一个描述,实际上其它进程是否是java程序,是否有对象之说倒不重要,这里站在java程序的角度,虚拟地认为其它进程内部包含一个拥有这些操作的对象——远程对象——算是本地接口的实现类对象。远程对象的概念是从某个进程看其它进程的对象而言的。

    java程序使用java接口对远程进程通信协议进行描述,其它像Swift这样的语言又有它们自己的通信协议的描述方式。

    Binder系统

    下面用Binder-SYS表示安卓系统中运行的Binder系统,Binder-IPC表示Binder实现IPC的机制。

    Server和Client

    Binder-SYS将通信的双方分为Server和Client,即C/S架构。
    两端进程均使用一个接口IBinder的实例进行通信,它定义了方法IBinder.transact(),方法原型:

    /**
     * Perform a generic operation with the object.
     *
     * @param code The action to perform.  This should
     * be a number between {@link #FIRST_CALL_TRANSACTION} and
     * {@link #LAST_CALL_TRANSACTION}.
     * @param data Marshalled data to send to the target.  Must not be null.
     * If you are not sending any data, you must create an empty Parcel
     * that is given here.
     * @param reply Marshalled data to be received from the target.  May be
     * null if you are not interested in the return value.
     * @param flags Additional operation flags.  Either 0 for a normal
     * RPC, or {@link #FLAG_ONEWAY} for a one-way RPC.
     */
    public boolean transact(int code, Parcel data, Parcel reply, int flags)
        throws RemoteException;
    • code
      表示要执行的动作,类似Handler发送的Message的what。
      code指示了当前远程操作的命令,IBinder定义了像INTERFACE_TRANSACTION、PING_TRANSACTION这样的几个通用命令。自己使用的命令的标识值需要在FIRST_CALL_TRANSACTION和LAST_CALL_TRANSACTION之间,仅仅是整数范围的一个约定,很好理解。

    • data和reply
      data和reply参数相当于普通java方法里的调用参数和返回值。Parcel类型是可以跨进程的数据。

    • flags
      参数flags只有0和FLAG_ONEWAY两种,默认的跨进程操作是同步的,所以transact()方法的执行会阻塞,调用以同步的形式传递到远程的transact(),等待远端的transact()返回后继续执行——最好理解的方式就是把两端的transact()看作一个方法,Binder机制的目标也就是这样。指定FLAG_ONEWAY时,表示Client的transact()是单向调用,执行后立即返回,无需等待Server端transact()返回。

    Server和Client利用IBinder跨进程通信的原理是:

    Client调用其IBinder实例的transact()发起操作,Binder-SYS使得方法调用传递到Server端,以相同的参数执行Server端IBinder实例的transact()方法——这就是Binder-SYS实现的跨进程操作。

    Binder和BinderProxy

    Binder-SYS提供了BinderBinderProxy作为IBinder的子类。
    每一个Binder对象都会唯一关联一个BinderProxy对象。
    在跨进程通信时,提供服务的Server进程持有一个Binder对象,记为Server_Binder_obj。而其它Client进程持有关联的BinderProxy对象,记为Client_BinderProxy_obj。不同Client进程里的BinderProxy是不同java对象,而底层是同一个由Binder-SYS维护的C++对象。所以BinderProxy对象实际上是跨进程唯一的。
    这里Proxy的含义就是Client进程得到的Server端Binder对象的一个本地引用。

    最终Client对Server发起远程调用的过程就是:
    Client调用其BinderProxy实例的transact()发起操作,Binder-SYS使得方法调用传递到Server端,以相同的参数执行Server端Binder实例的transact()方法

    这里注意下transact()在BinderProxy和Binder中的不同之处:
    BinderProxy.transact()方法是Client用来主动发出远程操作命令的,它接收code、data参数。BinderProxy是个final类,它的transact()方法只能被调用。
    Binder.transact()是用来被动响应Client发出的远程调用的。
    BinderProxy.transact()调用后,Server端Binder.transact()方法以同样的code、data参数被调用。
    Binder类定义了onTransact()方法来供子类去响应命令,而它的transact()方法调用onTransact()的逻辑。onTransact()更好的表达了Binder的行为。

    通信过程

    有了以上核心概念,Binder-IPC的原理还是很简单明了的,一次跨进程远程通信的过程是:

    1. Client的代码调用BinderProxy.transact(),发起远程调用。参数flags为0时方法阻塞,等待Server端对应方法返回后继续执行。参数flags为FLAG_ONEWAY时立即返回。

    2. Client中的transact()调用传递式触发Server端Binder.transact()的调用,它又调用Binder.onTransact()。

    3. Server端,Binder.onTransact()中,子类的重写方法根据收到的code,执行对应业务逻辑,设置必要的返回数据到参数reply,然后Binder.transact()方法返回。

    4. Client端,BinderProxy.transact()从阻塞状态返回,调用者解析得到必要的返回参数,继续执行。

    可以看到,Binder机制维持了Client进程的transact()的调用传递给Server端transact()以及相应的调用返回的传递过程。注意参数flags为FLAG_ONEWAY时指定通信为“单向”的,这样整个远程调用就成为了异步的——Client的transact()会很快返回,不需要等待Server端的方法调用完成(甚至是开始)。

    以上就是Binder-IPC的主要原理。

    示例项目:StudentManager

    下面提供一个示例项目来说明如何使用Binder-IPC完成跨进程通信。
    案例提供这样的功能:
    Server端程序实现了学生管理功能,提供了按学号查询学生年龄的操作。
    然后Client通过Binder-IPC对Server端执行远程调用获得结果。

    协议部分

    从编程角度看,使用Binder-IPC实现Client和Server通信,有一些类型它们都会用到,这些类型仅仅和通信相关,而不涉及实际业务。这里称它们为通信协议相关类型。
    一般都是提供服务的Server端定义这些类型,下面就依次实现它们。

    通信接口

    它定义了Server端可接收的方法调用,也就是Client可以发起的远程调用。
    这里根据假设的需求,定义下面的接口:

    package com.idlestars.binderdemo.serviceapi;
    ...
    
    interface IStudentManager extends IInterface {
      String DESCRIPTOR = "com.tiro.binder.StudentManagerStub";
      int TRANSACTION_GET_AGE = (IBinder.FIRST_CALL_TRANSACTION + 0);
    
      int getAge(int studentId) throws RemoteException;;
    }

    通信接口是偏业务上的,它定义了方法getAge()用来根据学生id来获取其年龄。下面对它进行一些说明。

    • RemoteException
      所有接口方法需要声明RemoteException异常,跨进程操作时目标服务进程总可能意外终止,或者服务类调用Parcel.writeException()来通知异常发生,这样Client端接口方法的调用就抛出RemoteException。

    • DESCRIPTOR
      对当前接口的一个字符串标识,Binder类的attachInterface()和queryLocalInterface()方法会用到它。

    • TRANSACTION_GET_AGE
      对应接口方法getAge()的命令code。

    • IInterface
      Binder-IPC要求的标准实现方式是,通信接口需要继承接口IInterface。它定义了asBinder()方法用来返回接口实例关联的IBinder对象。
      这是因为一般正是Server端的Binder子类会实现通信接口,然后,Client是无法拿到Server端的IStudentManager对象的,所以,为Client定义一个本地的IStudentManager的代理实现类,该实现类使用BinderProxy调用Server端方法获取结果。
      也就是通常两端实现接口IStudentManager的地方都密切关联了一个可以用来远程通信的IBinder对象,而asBinder()就是用来返回这个IBinder的。
      经试验,这不是必须的。

    Client端代理类

    有了通信接口后,紧接着需要实现Server和Client使用IBinder进行数据交互的部分。也就是transact()的逻辑。
    IStudentManager的实现是位于Server端的,Client端无法得到其对象。所以,Client端定义一个接口的代理实现类:

    package com.idlestars.binderdemo.serviceapi;
    ...
    public class StudentManager implements IStudentManager {
        IBinder mRemote;
    
        public StudentManager(IBinder remote) {
            mRemote = remote;
        }
    
        @Override
        public int getAge(int studentId) throws RemoteException {
            Parcel data = Parcel.obtain();
            Parcel reply = Parcel.obtain();
    
            try {
                data.writeInterfaceToken(DESCRIPTOR);
                data.writeInt(studentId);
                mRemote.transact(TRANSACTION_GET_AGE, data, reply, 0);
                reply.readException();
                int age = reply.readInt();
    
                return age;
            } finally {
                data.recycle();
                reply.recycle();
            }
        }
    
        @Override
        public IBinder asBinder() {
            return mRemote;
        }
    }

    代理类StudentManager对getAge()的实现是通过mRemote来发送远程调用。
    此处的mRemote是连接到Server时,Server端Binder关联的BinderProxy对象。
    上面getAge()中写入和读取数据的顺序必须和Server端的Binder.onTransact()对应——主要就是code的取值和data、reply中数据的写入读取顺序。

    StudentManager实现的IInterface.asBinder()返回它组合的mRemote。

    Server端通信类

    应用层提供可供其它进程访问的服务的方式就是通过Service组件,Service组件所在进程就是Server进程。
    Client进程使用bindService()来和Server进程进行通信。

    所以这里需要准备onBind()返回的Binder对象。同进程内的bindService()调用会返回给调用者Binder对象本身,而其它进程的调用最终得到的是Binder关联的BinderProxy对象。总之这个Binder子类就是服务绑定者后续和服务进行通信的渠道。

    Server端使用Binder进行通信,也就是是响应transact()调用。
    一般为了让返回的Binder对象可以被同进程内的绑定者当做IStudentManager去使用,这里定义的Binder子类就同时实现IStudentManager。

    在Binder.onTransact()中将会实现和Client使用的代理类StudentManager.transact()对应的通信数据交换逻辑。
    这部分逻辑是和IStudentManager定义的业务方法无关的。
    为了方便将Binder.onTransact()的逻辑暴漏给Client——因为Client程序会最终引用这些类型,不论是源码方式还是库引用,处于安全或方便的目的,这里先定义一个抽象的Binder子类StudentManagerStub,它完成了和StudentManager交换数据,响应远程调用的逻辑。作为一个抽象类,它实现接口IStudentManager,但不去做任何实际处理,onBind()返回的类型会继承它,并实现IStudentManager的方法。

    public abstract class StudentManagerStub extends Binder implements IStudentManager {
    
        public StudentManagerStub() {
            this.attachInterface(this, DESCRIPTOR);
        }
    
        @Override
        public IBinder asBinder() {
            return this;
        }
    
        @Override
        protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
            switch (code)
            {
                case INTERFACE_TRANSACTION:
                {
                    reply.writeString(DESCRIPTOR);
                    return true;
                }
                case TRANSACTION_GET_AGE:
                {
                    data.enforceInterface(DESCRIPTOR);
                    int stuId = data.readInt();
                    reply.writeNoException();
                    reply.writeInt(getAge(stuId));
                    return true;
                }
            }
            return super.onTransact(code, data, reply, flags);
        }
    
        public static IStudentManager asInterface(IBinder obj) {
            if (obj == null) {
                return null;
            }
            IStudentManager in =
                    (IStudentManager)obj.queryLocalInterface(DESCRIPTOR);
            if (in != null) {
                return in;
            }
    
            return new StudentManager(obj);
        }
    }

    可以看到StudentManagerStub.onTransact()和StudentManager.transact()是对应的,后者的每一个code和前者都有一个case语句去处理。重要的是,有关data、reply参数的数据的写入和读取顺序也严格对应。

    在onTransact()中调用了getAge()方法,它由最终的StudentManagerStub的子类去完成。getAge()是业务方法,和通信细节没有关系。

    StudentManagerStub作为Binder子类,它实现的IInterface.asBinder()直接返回其对象本身——它既是IInterface的子类,又是Binder子类。

    小结

    以上的IStudentManager、StudentManager、StudentManagerStub是协议部分涉及到的类型。它们由Server端程序提供,Client端去引用。

    StudentManagerStub的定义,使得Server端通信协议实现和通信接口的业务方法的实现得以分离。

    有关协议类型要注意下面几点

    • 数据支持
      IBinder.transact()可传递的数据只能是Parcel类型的,关于它可携带的数据类型参见其API。
      Parcel对象可以携带的类型决定了通信所能支持的数据类型。

    • 通信规则
      Client传递的调用参数data和Server端返回的reply数据,它们在写入和读取的顺序上必须是一致的。
      写入和读取的顺序也是通信规则的一部分,所以两端的transact()、onTransact()逻辑严格对应。

    业务部分

    除了Binder-IPC需要的通信协议相关的类型,Server端需要提供Service来供其它进程绑定。并且它自己实现IStudentManager的业务方法。

    Client中会使用代理类StudentManager来访问服务。

    定义Service

    Server提供一个Service组件来供自身程序、其它程序等访问:

    public class RemoteService extends Service {
        StudentManagerService mBinder = new StudentManagerService();
    
        @Nullable
        @Override
        public IBinder onBind(Intent intent) {
            return mBinder;
        }
    }

    为了突出重点,RemoteService的代码非常简单。就是返回一个StudentManagerService对象。
    额外的工作就是在AndroidManifest.xml中注册它。

    注意onBind()的机制是仅在第一个bindService()的请求时返回关联的IBinder对象,之后不再调用。
    所以,一个Service在运行期间也只能通过一个IBinder对象和各个Client通信。

    实现IStudentManager

    onBind()返回的StudentManagerService继承自StudentManagerStub,它只需要完成实际的getAge()方法。
    StudentManagerStub已经实现了通信协议的逻辑。

    class StudentManagerService extends StudentManagerStub {
        @Override
        public int getAge(int studentId) throws RemoteException {
            return Math.abs(studentId % 30);
        }
    }

    Client访问Service

    Client端访问目标Service的步骤如下:

    1. 调用bindService()。
    2. 将返回的IBinder使用StudentManagerStub.asInterface()转换为IStudentManager的实例。
    3. 像普通接口那样使用IStudentManager。

    可以看到,其实对Client端而言,它只需要知道IStudentManager即可,而
    StudentManagerStub和StudentManager直接由提供服务类的Server端定义即可。
    在不同程序间进行Service的访问时,由谁来提供这些通信协议的类型是一个说一不二的事情。

    使用bindService()来绑定服务是很基础的事情了。
    如果是同进程,那么onServiceConnected()返回的是上面onBind()返回的StudentManagerService对象。
    如果是不同进程,返回的是onBind()返回的StudentManagerService对象关联的BinderProxy对象。

    所以bindService()得到的IBinder是和Service是否在同一个进程密切相关的。
    上面StudentManagerStub.asInterface()方法正是用来将bindService()得到的IBinder转换为最终要用到的IStudentManager的实例:

    public static IStudentManager asInterface(IBinder obj) {
        if (obj == null) {
            return null;
        }
        IStudentManager in =
                (IStudentManager)obj.queryLocalInterface(DESCRIPTOR);
        if (in != null) {
            return in;
        }
    
        return new StudentManager(obj);
    }
    • 和Service同进程
      参数obj就是StudentManagerService,因为使用的是IStudentManager.DESCRIPTOR,它的queryLocalInterface()返回StudentManagerService对象本身,成功强转为IStudentManager。

    • 和Service不同进程
      参数obj是BinderProxy对象,上面if语句不会执行,这时,Client进程得到一个组合了此obj的StudentManager代理类对象,StudentManager负责远程调用Server端的方法。

    这里使用queryLocalInterface()而不是instanceof这类方式执行类型检查,因为不能依赖到
    StudentManagerService,包括对类型名称的假设。
    而接口标识这样的方式可以满足上面的IStudentManager类型在Server进程内,或Client端两种转换要求。

    实际上方法asInterface()放在协议类型StudentManagerStub、StudentManager中都可以。

    Client访问Service的代码:

    IStudentManager mStudentManager;
    
    ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            mStudentManager = StudentManagerStub.asInterface(service);
        }
    
        @Override
        public void onServiceDisconnected(ComponentName name) {
            mStudentManager = null;
        }
    };
    
    private void bindToService() {
        Intent intent = new Intent(this, RemoteService.class);
        bindService(intent, connection, BIND_AUTO_CREATE);
    }

    bindService()的使用不过多介绍,intent可以指定为Action字符串。

    执行远程调用

    bindService()获得一个IStudentManager对象后,就可以用它来调用Server端的方法了。
    实际上,Client端的代码调用getAge()方法和其它java方法没什么两样,唯一的区别就是需要捕获可能的RemoteException异常。

    下面的方法onGetAgeClick()是按钮点击处理,它读取输入的stuId作为参数,执行getAge(),将返回结果显示。

    public void onGetAgeClick(View view) {
        if (mStudentManager != null) {
            try {
                int stuId = Integer.valueOf(et_stu_id.getText().toString());
                int age = mStudentManager.getAge(stuId);
    
                tv_age.setText("Age: " + age);
            } catch (Exception e) {
                Log.d("Binder", "getAge Exception: " + e.getMessage());
            }
        }
    }

    Binder机制的不同使用方式

    需要注意的一点是,以上关于Binder架构讨论的种种都是针对典型的IPC的情形的。
    不过IBinder的使用在app层一般都是结合作为四大组件之一的Service进行的,也就是bindService()。Service可以是其它app的Service类,或者是当前程序本身的Service类,可以运行在相同进程或其它进程。

    非Service方式的使用

    framework层的ActivityManager、PackageManager等都是利用了Binder机制。但它们的服务类不是通过Service组件去提供。

    以IActivityManager为例:

    • 接口IActivityManager定义了有关管理系统中所有Activity的API。
    • ActivityManagerService继承自Binder,并实现了IActivityManager,相当于一个Server端的服务类。
    • SystemServer进程启动后,它实例化ActivityManagerService对象,然后注册到ServiceManager中。
    • ActivityManager通过ServiceManager获得ActivityManagerService的BinderProxy,它也实现了IActivityManager,
      相当于一个代理类。

    可见,像系统服务它们位于特殊的进程内,不是以Service组件的方式运行。
    其注册和获取的方式也不是bindService()这样的,而是依赖ServiceManager。

    这里简单的举例Binder的非Service使用形式,说明一点,Binder机制提供“更底层”的API,bindService()方式访问Service组件时用到Binder架构,在app开发中这是主要形式。但可以脱离Service来使用Binder进行IPC通信。

    SystemServer作为系统进程它的生命周期必然会更稳定,而Service对进程的“重要性”的影响显然还不如Activity。
    在使用Binder来进行IPC时,总要关心目标进程的存活状态,后面会再涉及到这点。

    Service方式

    此时分两种情况:目标Service在同一进程和不同进程。绑定其它程序的Service肯定是不同进程的情况了。而当前项目里的Service也可以通过在AndroidManifest.xml中声明不同的android:process来使其运行在另外进程中。

    同进程内

    这种是最简单的bindService()的使用场景。
    此时,Service.onBind()返回的就是Binder的子类。它是同进程的对象,而且类型已知。
    Service返回的Binder类是可以完全访问Service的功能的,为了使用此Binder和Service通信,有以下方式:

    • Binder子类提供一些public方法供调用,这些方法操作Service。
    • Binder子类返回对应的Service对象供使用。
    • Binder子类返回寄宿在Service中的一些公开成员对象供访问,一般就是此Service提供的不同接口的实现类对象。

    此时不需要标准的Client端,bindService()的调用者得到Binder后就可以访问Service提供的各项功能了。

    绑定同程序不同进程中的Service

    此时从另一个进程获取到的是BinderProxy对象,属于标准的IPC方式。
    bindService()的代码最终获得的是代理类,而不是Binder对象本身。
    此时的使用方式和上面StudentManager示例完全一样。
    因为是同一个程序,涉及的相关类型无需显示引用。

    绑定其它程序的Service

    其它程序必然运行在其它进程。这时,通信协议相关的IStudentManager、StudentManagerStub和
    StudentManager这些类型都是目标程序提供的。
    自己的项目中需要引用这些类型,之后的使用方式和上面StudentManager示例一样。

    向Server端注册回调

    除了可以调用Server端的业务接口方法外,还可以向Server注册回调接口,这样就相当于实现了跨进程的观察者模式。或者是类似广播监听器那样的效果。

    文章底部“案例代码”中的RemoteService示例演示了如何注册回调接口道其它进程。
    示例中的通信接口如下:

    interface IRemoteServiceCallback {
        void valueChanged(int value);
    }
    
    interface IRemoteService {
      void registerCallback(IRemoteServiceCallback cb);
      void unregisterCallback(IRemoteServiceCallback cb);
    }

    代码演示了Client使用IRemoteService将自己实现的IRemoteServiceCallback对象注册到Server。
    之后Server端就可以调用valueChanged()方法通知Client。

    实际上IRemoteServiceCallback对象肯定是无法跨进程传递的,valueChanged()的调用又是一次IPC过程,
    此时Client作为IRemoteServiceCallback的实现方,而Server作为IRemoteServiceCallback方法的调用方,valueChanged()的远程调用的过程中,原Server是Client,原Client是Server。

    可见Binder-IPC进行的通信中,Server和Client是相对概念。对应一个通信接口,谁发起远程调用,谁就是Client。

    registerCallback()传递给Server的是当前Client实现IRemoteServiceCallback所定义的Binder子类对象的BinderProxy。考虑许多Client向Server注册回调接口的情形,最终的,Server端维护了这些Client提供的
    IRemoteServiceCallback实例关联的IBinder对象,Server通过这些IBinder对象通知Client,达到调用其valueChanged()方法。

    android.os.RemoteCallbackList正是用来管理远程回调接口的,它就是以这些接口实例关联的IBinder作为标识。所以可以用来跨进程唯一标识不同Clients注册的IRemoteServiceCallback对象。

    监听Server端IBinder的死亡

    当Client端持有的IBinder代表着的其它进程中的服务类时,就需要特别关注其是否仍然有效——一般就是其所在进程是否还在运行决定。有下面三个方法用来完成对远程对象的检查:

    • The transact() method will throw a RemoteException exception if you try to call it on an IBinder whose process no longer exists.
    • The pingBinder() method can be called, and will return false if the remote process no longer exists.
    • The linkToDeath() method can be used to register a IBinder.DeathRecipient with the IBinder, which will be called when its containing process goes away.

    使用bindService()时都知道,目标Service所在进程终止时,ServiceConnection.onServiceConnected()方法就会执行(总会在main线程中执行)。

    因为使用IBinder的方式不限于Service中,所以在IBinder类的级别上也可以去主动监听服务类对象的死亡。
    前面在IBinder的说明中提到它提供了几个方法用来检查目标Binder是否存活,而主动获取其死亡通知的方式
    就是注册IBinder.DeathRecipient到代理类持有的IBinder。

    Client在获取到IBinder后:

    binder.linkToDeath(new IBinder.DeathRecipient() {
        @Override
        public void binderDied() {
            // 做一些清理,或者是尝试重新激活目标服务进程
        }
    }, 0);

    linkToDeath()会在binder线程池中的线程中执行,第二个参数flags文档中竟然没有说明?

    线程问题

    当Server和Client处在同一个进程或不同进程中时,transact()的执行所在的线程会是不同的表现。

    不同进程

    • Client端
      Client端是发起transact()的地方,其方法调用者所在线程就是transact()的执行线程。
      前面的知识已经明确知道了transact()可以是同步或异步的,如果是同步的形式,而Server端的transact()很可能会耗时,那么Client端的transact()就不应该在UI线程中执行。

    • Server端
      服务类对象所在的Server进程会维护一个binder专用的线程池来处理来自Client的请求。
      所以Server端的transact()的执行总是异步的,因此还需要注意线程同步的问题。

    不论Client的transact()的参数flags指定为0或0和FLAG_ONEWAY,Server端transact()总是在某个线程池的线程中执行。flags仅仅影响Client端transact()是否立即返回。

    同一个进程

    一般若自己的app内部bindService()来访问进程内的Service时,就属于同进程的C/S通信。
    此时Client获取到的IBinder就是服务类对象本身,所以,最终Client和Server端的transact()的执行是同一个方法的调用!!

    Binder的其它形式

    手动去实现Binder-IPC用到的各种类型非常繁琐,而且如果对Binder的使用不需要非常多的控制时,可以利用下面的AIDL和Messenger方式完成IPC,它们都是对Binder使用的一个简化。

    AIDL

    AIDL是方便定义通信协议的一个工具,注意它的工作过程是属于项目的构建的一部分。
    使用aidl时,需要用它来定义通信的接口,声明用到的自定义的数据格式。
    之后工具会自动生成java文件,作为最终编译的代码的一部分。

    其生成的类型包括:

    • 通信接口
      类似上面的IStudentManager,一个继承IInterface的接口。

    • Server端通信基类
      如上面的StudentManagerStub,它实现onTransact()的逻辑,用来响应不同命令,会调用业务接口IStudentManager的对应方法得到执行结果。
      作为协议的一部分,它不去实现接口的业务方法。
      onTransact()实现了Server端通信的细节。

    最终的服务类继承“Server端通信基类”,并实现通信接口里业务方法的逻辑。

    • 代理类
      如上面的StudentManager,它封装一个BinderProxy与远程服务类对象进行通信。

    作为一个工具,它的功能就是简化开发过程。和上面实现Server端、Client端相关类型的最终效果是一样的。
    更多细节参见api文档aidl的介绍,文章底部资料部分给出了具体地址。

    Messenger

    在创建一个可绑定的Service时,有三种方式可以提供onBind()返回的IBinder对象:

    • 返回Binder子类
      这种方式只有同进程时才可行,否则会返回给其它进程Binder的代理BinderProxy对象。

    • AIDL
      特点是跨进程,且Server端transact()的执行是由Binder线程池里的线程调用的,需要进行并发控制。

    • Messenger
      这种方式下,通信的命令被封装为Message对象,而且Server端使用一个Handler来依次处理收到的命令,不存在并发。

    使用Messenger的步骤如下:

    • The service implements a Handler that receives a callback for each call from a client.
    • The Handler is used to create a Messenger object (which is a reference to the Handler).
    • The Messenger creates an IBinder that the service returns to clients from onBind().
    • Clients use the IBinder to instantiate the Messenger (that references the service's Handler), which the client uses to send Message objects to the service.
    • The service receives each Message in its Handler—specifically, in the handleMessage() method.

    这种方式下,Client和Server之间没有接口方法,而是由Client发送Message表示的命令被Server端处理。
    可见Messenger简化了transact()的过程为handler发送消息的方式,Messenger的底层依然是标准的binder IPC方式实现的,Messenger的作用就类似上面的代理类,不过它实现的是通用的IMessenger接口。

    如果需要Server端向Client发送Message,在Client中定义好Handler和Messenger,然后把Messenger设置给发送到Server的Message对象的replyTo字段。

    IPC权限

    如果Server端需要对访问它的Client做权限检查,那么可以在AndroidManifest.xml中首先定义好权限。
    方法android.content.ContextWrapper#checkCallingOrSelfPermission()可以用来检查调用者是否拥有指定的权限。

    如果使用的是Service,那么onBind()处可以控制是否返回IBinder给某个Client,但是onBind()只会被执行一次,若返回null的话,后续的onServiceConnected()也不会执行。这里没有试验这种默认行为是否影响其它进程对服务的绑定,但终究不灵活。

    在onTransact()方法中,Binder提供了getCallingPid()和getCallingUid()来获得当前transact()执行时调用者的进程和用户等信息。在这里,进行权限检查,然后选择性返回false的话会更好些,也就是说,针对一次具体的transact()操作可以拒绝响应,但不影响其它的transact()调用。

    补充

    跨进程递归调用

    The Binder system also supports recursion across processes. For example if process A performs a transaction to process B, and process B while handling that transaction calls transact() on an IBinder that is implemented in A, then the thread in A that is currently waiting for the original transaction to finish will take care of calling Binder.onTransact() on the object being called by B. This ensures that the recursion semantics when calling remote binder object are the same as when calling local objects.

    Binder对象的生命周期

    Binder class is just a basic IPC primitive; it has no impact on an application's lifecycle, and is valid only as long as the process that created it continues to run. To use this correctly, you must be doing so within the context of a top-level application component (a Service, Activity, or ContentProvider) that lets the system know your process should remain running.

    You must keep in mind the situations in which your process could go away, and thus require that you later re-create a new Binder and re-attach it when the process starts again. For example, if you are using this within an Activity, your activity's process may be killed any time the activity is not started; if the activity is later re-created you will need to create a new Binder and hand it back to the correct place again; you need to be aware that your process may be started for another reason (for example to receive a broadcast) that will not involve re-creating the activity and thus run its code to create a new Binder.

    展开全文
  • 说说Binder通信

    2020-03-23 11:12:14
    因为这个概念太重要了,对于我们理解一系列android先关其它知识都是特别重要的,比如我们要分析Activity以及Service组件启动、ActivityManagerService以及WindowManagerService等系统服务,Binder通信都是绕不过去的...
  • Android7.0 Binder通信(4) Java层中的Binder

    千次阅读 2016-09-20 19:50:25
    之前博客分析Binder机制时,集中分析的是Native层Binder的架构,现在来分析一下Java层Binder的架构。
  • Android Binder通信机制简单了解 参考 Android图文解析 Binder跨进程通信 Android Binder之应用层总结与分析 Binder通信的一次内存拷贝 Android Bander设计与实现 Binder通信基础是Kernel的内存共享 一个...
  • 初识Android时,对于Android的整个系统框架梳理了一遍,让之了然于胸,鉴于对kernel的了解,先从Android新增的Binder驱动来入手,尽管Binder理解起来十分生涩,但是如果你认真去分析源码后,会发现其中的奥秘,会...
  • Android7.0 Binder通信(1) ServiceManger

    千次阅读 2016-09-05 19:40:10
    Android是基于Linux的操作系统,在其中运行的应用或者系统服务,实际上就是一个个Linux进程。这意味着它们彼此之间是隔离的,必须通过进程间通信(IPC)来相互传输数据。Binder就是Android实现的一种IPC通信方式。
  • Android Binder通信机制

    千次阅读 2013-06-14 19:14:32
    Binder是Android系统进程间通信(IPC)方式之一。Linux已经拥有管道,system V IPC,socket等IPC手段,却还要倚赖Binder来实现...本文将对Binder的设计细节做一个全面的阐述,首先通过介绍Binder通信模型和 Binde
  • android binder通信架构

    2019-12-12 17:25:10
    android binder通信架构
  • Binder通信机制简介

    2019-08-01 10:20:53
    Binder通信机制简介 Binder是Android系统中大量使用的IPC(Inter-process communication,进程间通讯)机制。无论是应用程序对系统服务的请求,还是应用程序自身提供对外服务,都需要使用到Binder。 使用Binder机制...
  • Android binder通信实例

    2017-03-29 15:58:36
    server端代码:#include #include #include #include #include #include #include <sys/mman.h>#include #include <binder/IIn
  • Binder通信流程图

    2018-12-20 22:12:56
    Java层Binder框架   BpBinder和JavaBBinder是一对的 ,是通信架构的一...例如在客户端发送请求时,是BpBinder把要通信的BBinder的handle告诉binder线程的IPCThreadState,然后IPCThreadState就把handle告诉...
  • Binder通信学习总结

    2017-02-19 16:20:20
    本文是笔者学习Binder通信机制的要点总结,并没有对Binder通信机制进行详细的介绍。描述了Binder机制的四大模块,以及Binder通信的主要特点:数据传递单向性和数据拷贝一次。
  • android binder通信实例

    2019-01-18 11:27:53
    首先定义一个模块的android.mk和.rc文件,这里我的问题是。我只能手动去启动他,不能实现开机自启动 android.mk LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS)... interface_test_binder.cpp \ test_binde...
  • Android Binder通信Sample

    2018-02-27 14:11:14
    关于binder的介绍网上已经有许多了,这里就不多做描述,给两个讲的比较好的链接 ...http://blog.csdn.net/freekiteyu/article/details/70082302(强烈推荐)这边只是贴一份native 中binder通信的sample,希望能够对理解
  • android之binder通信

    2015-12-02 19:12:50
    下面所涉及到的内容基本上都来自—老罗的Android之旅在Android系统的Binder机制中,由一系统组件组成,分别是Client、Server、Service Manager和Binder驱动程序,其中Client、Server和Service Manager运行在用户空间...
  • Binder通信机制介绍

    2017-12-20 11:33:00
    1.Binder通信机制介绍 这篇文章会先对比Binder机制与Linux的通信机制的差别,了解为什么Android会另起炉灶,采用Binder。接着,会根据 Binder的机制,去理解什么是Service Manager,在C/S模型中扮演什么角色。最后,...
  • Binder通信机制总结

    2015-07-04 13:23:09
    IBinder是android中IPC(inner-process communication)通信的基础,也是一个很难理解的概念,由于能力有限,本文只是在大牛的基础上从宏观上大体理清一下思路。 Android底层是基于Linux,Linux中传统IPC方式包括...
  • Binder通信流程分析

    2013-02-19 16:47:36
    一、Binder通信示例图 client和服务server通信必须要三个过程: 1、server之所以成为服务,必须向服务管理器SMgr注册 2、client想同server通信,必须先向服务管理器SMgr获取服务的引用号。 3、client发送...
  • android的Binder通信机制java层浅谈

    千次阅读 2015-11-20 09:28:14
    1.Service Manager的Java代理对象在Java层中,Service Manager的代理对象类型为ServiceManagerProxy。它继承并且实现了IServiceManager接口,其中四个成员函数和一个变量如下: getService、checkService:获取Java...
  • Android Binder通信二 Binder驱动与协议

    千次阅读 2018-01-07 18:33:58
    Binder通信整体框架这篇文章中已经说过Binder驱动是Binder通信的底层载体和支撑。Binder驱动支撑着整个Binder IPC过程。因此还是有必要稍微了解Binder驱动的一些基本概念 2 Binder驱动简介 Binder驱动在Linux...

空空如也

1 2 3 4 5 ... 20
收藏数 518,378
精华内容 207,351
关键字:

binder