Binder机制学习总结(四)-Java接口部分

来源:互联网 发布:tomcat java 端口设置 编辑:程序博客网 时间:2024/06/06 23:31

        因为上一节service manager中,对于binder通信的客户端(BpServiceManager)和服务端(service manager进程)已经有比较详细的解释,所以,不再对于Binder通信的client端和server端做分析,有兴趣的同学可以看看MediaPlayerService和MediaPlayer,网上很多资料有讲解。

        当目前为止,所有的代码都是以C/C++语言的,但是,App开发者通常使用Java语言,那么Java是如何使用Binder通信的呢?

AIDL

        很多时候,我们是通过aidl(Android Interface Define Language)间接的使用Binder机制的。例如,我们准备了下面这样一个aidl文件:
package com.ray.example;interface RInterface {    void hello(String message);}
       经过IDE的编译,我们会得到下面这样的Java文件:
/*___Generated_by_IDEA___*//* * This file is auto-generated.  DO NOT MODIFY. * Original file: /home/ray/Learning&Study/BinderProProject/SearchApp/src/main/java/com/ray/example/RInterface.aidl */package com.ray.example;public interface RInterface extends android.os.IInterface{/** Local-side IPC implementation stub class. */public static abstract class Stub extends android.os.Binder implements com.ray.example.RInterface{private static final java.lang.String DESCRIPTOR = "com.ray.example.RInterface";/** Construct the stub at attach it to the interface. */public Stub(){this.attachInterface(this, DESCRIPTOR);}/** * Cast an IBinder object into an com.ray.example.RInterface interface, * generating a proxy if needed. */public static com.ray.example.RInterface asInterface(android.os.IBinder obj){if ((obj==null)) {return null;}android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);if (((iin!=null)&&(iin instanceof com.ray.example.RInterface))) {return ((com.ray.example.RInterface)iin);}return new com.ray.example.RInterface.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_hello:{data.enforceInterface(DESCRIPTOR);java.lang.String _arg0;_arg0 = data.readString();this.hello(_arg0);reply.writeNoException();return true;}}return super.onTransact(code, data, reply, flags);}private static class Proxy implements com.ray.example.RInterface{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 void hello(java.lang.String message) 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.writeString(message);mRemote.transact(Stub.TRANSACTION_hello, _data, _reply, 0);_reply.readException();}finally {_reply.recycle();_data.recycle();}}}static final int TRANSACTION_hello = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);}public void hello(java.lang.String message) throws android.os.RemoteException;}

        编译产生的java文件提供了三个对象:

RInterface接口:继承自IInterface接口,并且有一个hello的成员函数。作为server和client之间的约定,双方都会使用。

RInterface.Stub抽象类:继承自Binder类,并且提供了onTransact函数的实现,以及静态函数asInterface。

RInterface.Stub.Proxy类:实现了RInterface接口,实现了hello函数。

XXXX.Stub

        主要由Server端实现,Server端通过继承本类,来提供具体的处理逻辑。通常,在Server端,我们会有如下代码:
package com.ray.example;import android.app.Service;import android.content.Intent;import android.os.IBinder;import android.os.RemoteException;import android.util.Log;/** * Created by ray on 2/7/14. */public class RServer extends RInterface.Stub {    public final String TAG_RAY = "ray";    @Override    public void hello(String message) throws RemoteException {        Log.i(TAG_RAY,"Hello~ " + message);    }}
        这里通过重载来hello函数来提供具体的处理逻辑。而hello函数是如何被调用的呢?这就需要回顾RInterface.Stub类对于onTransact函数的重载:
@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_hello:{data.enforceInterface(DESCRIPTOR);java.lang.String _arg0;_arg0 = data.readString();this.hello(_arg0);reply.writeNoException();return true;}}return super.onTransact(code, data, reply, flags);}
        当onTransact函数被以特定的参数调用时,hello函数会被调用:
static final int TRANSACTION_hello = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
        Android系统约定,code必须大于等于
    int FIRST_CALL_TRANSACTION  = 0x00000001;
        并且,小于等于
    int LAST_CALL_TRANSACTION   = 0x00ffffff;
        否则,code可能和Binder协议的一些保留code冲突。
        至于onTransact函数是如何被调用,就需要涉及到Binder类的内部实现,我们稍后分析。

XXXX.Stub.Proxy

        主要由Client端使用,顾名思义,担当Server的代理角色。
        通常,在Clent端,会有类似如下的代码:
package com.ray.example;import android.os.IBinder;import android.os.RemoteException;/** * Created by ray on 2/7/14. */public class RClient {    private RInterface mRInterface;    public RClient (IBinder binder){        mRInterface = RInterface.Stub.asInterface(binder);    }    public void sayHello(String message) throws RemoteException {        mRInterface.hello("Ray");    }}
        而,我们知道Rinterface.Stub.asInterface函数会构造一个RInterface.Stub.Proxy类的实例,并返回:
public static com.ray.example.RInterface asInterface(android.os.IBinder obj){if ((obj==null)) {return null;}android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);if (((iin!=null)&&(iin instanceof com.ray.example.RInterface))) {return ((com.ray.example.RInterface)iin);}return new com.ray.example.RInterface.Stub.Proxy(obj);}
        所以,客户端的mRInterface实际上是RInterface.Stub.Proxy。而调用Proxy对于hello的实现:
@Override public void hello(java.lang.String message) 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.writeString(message);mRemote.transact(Stub.TRANSACTION_hello, _data, _reply, 0);//mRemote的类型为IBinder_reply.readException();}finally {_reply.recycle();_data.recycle();}
       很明显的,是通过Binder机制转发请求,但是mRemote是如何实现transaction函数的呢?我们暂时还不知道。

小结

  1. aidl文件编译成java文件时,提供了三个对象:
  2. XXXX接口,这个接口根据aidl文件的内容生成,作为通信双方的约定。
  3. XXXX.Stub抽象类,这个抽象类继承自Binder类。它实现了从Binder中读取到数据以后,呼叫业务逻辑处理代码的功能。Server端通过继承并实现业务逻辑来使用它。
  4. XXXX.Stub.Proxy类,这个类封装了一个IBinder接口,它实现了把Client端请求通过Binder发送到Server端的功能。Client可以通过XXXX.Stub.asInterface函数来获得XXXX.Stub.Proxy实例。

IBinder接口

        IBinder接口的声明,并不难理解:
public interface IBinder {    int FIRST_CALL_TRANSACTION  = 0x00000001;    int LAST_CALL_TRANSACTION   = 0x00ffffff;        //异步binder    int FLAG_ONEWAY             = 0x00000001;        public String getInterfaceDescriptor() throws RemoteException;        public boolean pingBinder();        public boolean isBinderAlive();        public IInterface queryLocalInterface(String descriptor);        public void dump(FileDescriptor fd, String[] args) throws RemoteException;        public void dumpAsync(FileDescriptor fd, String[] args) throws RemoteException;    //进行binder通信    public boolean transact(int code, Parcel data, Parcel reply, int flags)        throws RemoteException;    //死亡通知    public interface DeathRecipient {        public void binderDied();    }    //注册死亡通知    public void linkToDeath(DeathRecipient recipient, int flags)            throws RemoteException;    //注销死亡通知    public boolean unlinkToDeath(DeathRecipient recipient, int flags);}

Binder类        

        Binder类的声明有点长,所以,这边仅仅列出几个重点函数:
public class Binder implements IBinder {    /* mObject is used by native code, do not remove or rename */    private int mObject;    private IInterface mOwner;    private String mDescriptor;    // client端的进程id    public static final native int getCallingPid();    // client端的用户id    public static final native int getCallingUid();        // 清除client端的进程id和用户id    public static final native long clearCallingIdentity();    public Binder() {        init();        }    /**     * Default implementation is a stub that returns false.  You will want     * to override this to do the appropriate unmarshalling of transactions.     *     * If you want to call this, call transact().

*/ protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { if (code == INTERFACE_TRANSACTION) { reply.writeString(getInterfaceDescriptor()); return true; } else if (code == DUMP_TRANSACTION) { ParcelFileDescriptor fd = data.readFileDescriptor(); String[] args = data.readStringArray(); if (fd != null) { try { dump(fd.getFileDescriptor(), args); } finally { try { fd.close(); } catch (IOException e) { // swallowed, not propagated back to the caller } } } // Write the StrictMode header. if (reply != null) { reply.writeNoException(); } else { StrictMode.clearGatheredViolations(); } return true; } return false; } /** * Default implementation rewinds the parcels and calls onTransact. On * the remote side, transact calls into the binder to do the IPC. */ public final boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { if (false) Log.v("Binder", "Transact: " + code + " to " + this); if (data != null) { data.setDataPosition(0); } boolean r = onTransact(code, data, reply, flags); if (reply != null) { reply.setDataPosition(0); } return r; } protected void finalize() throws Throwable { try { destroy(); } finally { super.finalize(); } } private native final void init(); private native final void destroy(); // Entry point from android_util_Binder.cpp's onTransact private boolean execTransact(int code, int dataObj, int replyObj, int flags) { Parcel data = Parcel.obtain(dataObj); Parcel reply = Parcel.obtain(replyObj); // theoretically, we should call transact, which will call onTransact, // but all that does is rewind it, and we just got these from an IPC, // so we'll just call it directly. boolean res; try { res = onTransact(code, data, reply, flags); } catch (RemoteException e) { reply.setDataPosition(0); reply.writeException(e); res = true; } catch (RuntimeException e) { reply.setDataPosition(0); reply.writeException(e); res = true; } catch (OutOfMemoryError e) { RuntimeException re = new RuntimeException("Out of memory", e); reply.setDataPosition(0); reply.writeException(re); res = true; } reply.recycle(); data.recycle(); return res; }

        到目前为止,我们似乎还没发现Java的Binder类和native层的C++Binder接口存在什么联系,不过,我们还没看过Binder类的原生方法。

android_os_Binder_init

static void android_os_Binder_init(JNIEnv* env, jobject obj){    JavaBBinderHolder* jbh = new JavaBBinderHolder();    if (jbh == NULL) {        jniThrowException(env, "java/lang/OutOfMemoryError", NULL);        return;    }    ALOGV("Java Binder %p: acquiring first ref on holder %p", obj, jbh);    jbh->incStrong((void*)android_os_Binder_init);    env->SetIntField(obj, gBinderOffsets.mObject, (int)jbh);}
        init函数构造了一个JavaBBinderHolder实例,看起来奥秘应该就在这个JavaBBinderHolder中了。不过,在此之前,我们先解释下
    env->SetIntField(obj, gBinderOffsets.mObject, (int)jbh);
       首先,需要从gBinderoffsets变量说起:
static struct bindernative_offsets_t{    // Class state.    jclass mClass;    jmethodID mExecTransact;    // Object state.    jfieldID mObject;} gBinderOffsets;
        它有三个成员。而这三个成员的含义,我们可以从下面的代码中了解:
const char* const kBinderPathName = "android/os/Binder"static int int_register_android_os_Binder(JNIEnv* env){    jclass clazz;    clazz = env->FindClass(kBinderPathName);//clazz即Java Binder类    LOG_FATAL_IF(clazz == NULL, "Unable to find class android.os.Binder");    gBinderOffsets.mClass = (jclass) env->NewGlobalRef(clazz);    gBinderOffsets.mExecTransact        = env->GetMethodID(clazz, "execTransact", "(IIII)Z");//mExecTransact指向Binder类的execTrasaction函数    assert(gBinderOffsets.mExecTransact);    gBinderOffsets.mObject        = env->GetFieldID(clazz, "mObject", "I");//mObject指向Binder类的mObject成员    assert(gBinderOffsets.mObject);    return AndroidRuntime::registerNativeMethods(//注册原生函数        env, kBinderPathName,        gBinderMethods, NELEM(gBinderMethods));}
        而register_android_os_Binder函数则会在Dalvik虚拟机启动的时候执行。相似的,还有gBinderInternalOffsets和gBinderProxyOffsets。所以,我们现在可以知道:
    env->SetIntField(obj, gBinderOffsets.mObject, (int)jbh);
        的作用就是把JavaBBinderHolder的实例地址,保存到Binder的mObject成员中。其实,类似这样的处理手法在Android中非常常见,例如MessageQueue和NactiveMessageQueue。

android_os_Binder_destroy

        理解了init,destory就不难理解了:
static void android_os_Binder_destroy(JNIEnv* env, jobject obj){    JavaBBinderHolder* jbh = (JavaBBinderHolder*)        env->GetIntField(obj, gBinderOffsets.mObject);//从Binder.mObject获得jbh    if (jbh != NULL) {        env->SetIntField(obj, gBinderOffsets.mObject, 0);        ALOGV("Java Binder %p: removing ref on holder %p", obj, jbh);//设置Binder.mObject=0        jbh->decStrong((void*)android_os_Binder_init);//通过强引用计数,控制自己的生命周期    } else {        // Encountering an uninitialized binder is harmless.  All it means is that        // the Binder was only partially initialized when its finalizer ran and called        // destroy().  The Binder could be partially initialized for several reasons.        // For example, a Binder subclass constructor might have thrown an exception before        // it could delegate to its superclass's constructor.  Consequently init() would        // not have been called and the holder pointer would remain NULL.        ALOGV("Java Binder %p: ignoring uninitialized binder", obj);    }}

JavaBBinderHolder

        JavaBBinderHolder的实现比较简单:
class JavaBBinderHolder : public RefBase{public:    sp<JavaBBinder> get(JNIEnv* env, jobject obj)    {        AutoMutex _l(mLock);        sp<JavaBBinder> b = mBinder.promote();        if (b == NULL) {            b = new JavaBBinder(env, obj);//构造JavaBBinder实例,这里的obj参数为java的Binder类            mBinder = b;            ALOGV("Creating JavaBinder %p (refs %p) for Object %p, weakCount=%d\n",                 b.get(), b->getWeakRefs(), obj, b->getWeakRefs()->getWeakCount());        }        return b;    }    sp<JavaBBinder> getExisting()    {        AutoMutex _l(mLock);        return mBinder.promote();    }private:    Mutex           mLock;    wp<JavaBBinder> mBinder;};
        不过,它引入了下一个角色:JavaBBinder。

JavaBBinder

class JavaBBinder : public BBinder{public:    JavaBBinder(JNIEnv* env, jobject object)        : mVM(jnienv_to_javavm(env)), mObject(env->NewGlobalRef(object))    {        ALOGV("Creating JavaBBinder %p\n", this);        android_atomic_inc(&gNumLocalRefs);        incRefsCreated(env);    }    bool    checkSubclass(const void* subclassID) const    {        return subclassID == &gBinderOffsets;    }    jobject object() const    {        return mObject;    }protected:    virtual ~JavaBBinder()    {        ALOGV("Destroying JavaBBinder %p\n", this);        android_atomic_dec(&gNumLocalRefs);        JNIEnv* env = javavm_to_jnienv(mVM);        env->DeleteGlobalRef(mObject);    }    virtual status_t onTransact(        uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0)    {        JNIEnv* env = javavm_to_jnienv(mVM);        ALOGV("onTransact() on %p calling object %p in env %p vm %p\n", this, mObject, env, mVM);        IPCThreadState* thread_state = IPCThreadState::self();        const int strict_policy_before = thread_state->getStrictModePolicy();        thread_state->setLastTransactionBinderFlags(flags);        //printf("Transact from %p to Java code sending: ", this);        //data.print();        //printf("\n");        jboolean res = env->CallBooleanMethod(mObject, gBinderOffsets.mExecTransact,            code, (int32_t)&data, (int32_t)reply, flags);        jthrowable excep = env->ExceptionOccurred();        if (excep) {            report_exception(env, excep,                "*** Uncaught remote exception!  "                "(Exceptions are not yet supported across processes.)");            res = JNI_FALSE;            /* clean up JNI local ref -- we don't return to Java code */            env->DeleteLocalRef(excep);        }        // Restore the Java binder thread's state if it changed while        // processing a call (as it would if the Parcel's header had a        // new policy mask and Parcel.enforceInterface() changed        // it...)        const int strict_policy_after = thread_state->getStrictModePolicy();        if (strict_policy_after != strict_policy_before) {            // Our thread-local...            thread_state->setStrictModePolicy(strict_policy_before);            // And the Java-level thread-local...            set_dalvik_blockguard_policy(env, strict_policy_before);        }        jthrowable excep2 = env->ExceptionOccurred();        if (excep2) {            report_exception(env, excep2,                "*** Uncaught exception in onBinderStrictModePolicyChange");            /* clean up JNI local ref -- we don't return to Java code */            env->DeleteLocalRef(excep2);        }        // Need to always call through the native implementation of        // SYSPROPS_TRANSACTION.        if (code == SYSPROPS_TRANSACTION) {            BBinder::onTransact(code, data, reply, flags);        }        //aout << "onTransact to Java code; result=" << res << endl        //    << "Transact from " << this << " to Java code returning "        //    << reply << ": " << *reply << endl;        return res != JNI_FALSE ? NO_ERROR : UNKNOWN_TRANSACTION;    }    virtual status_t dump(int fd, const Vector<String16>& args)    {        return 0;    }private:    JavaVM* const   mVM;    jobject const   mObject;};
        原来JavaBBinder继承自BBinder。现在我们终于看到了Native层的Binder接口。从前面几节的内容,我们知道,BBinder代表着用户空间的Binder实体。所以,JavaBBinder也是代表用户空间的Binder实体。
        抛开其他次要的部分不谈,我们只关注onTransact函数:
   virtual status_t onTransact(        uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0)    {        ......        jboolean res = env->CallBooleanMethod(mObject, gBinderOffsets.mExecTransact,            code, (int32_t)&data, (int32_t)reply, flags);//调用Binder实例的execTransact方法        ......    }
        用最简单的视角去分析onTransact函数,我们会发现,它会调用Binder类的execTransact函数,而前面,我们有看到execTransact函数会调用Binder类的onTransact函数,这样,最终就会执行Service的业务逻辑,处理Client的请求。至于JavaBBinder的onTransact函数何时被调用,看过前面两节内容的读者应该就心中有数了,稍后我们会更加具体的分析。
        这样,我们现在已经知道在Server端,native层的binder接口是何如与Java接口交互的。接下来,让我们看看Client端

BinderProxy

        BinderProxy类同样在frameworks/base/core/android/os/Binder.java中:
final class BinderProxy implements IBinder {    public native boolean pingBinder();    public native boolean isBinderAlive();        public IInterface queryLocalInterface(String descriptor) {        return null;    }        public native String getInterfaceDescriptor() throws RemoteException;    public native boolean transact(int code, Parcel data, Parcel reply,            int flags) throws RemoteException;    public native void linkToDeath(DeathRecipient recipient, int flags)            throws RemoteException;    public native boolean unlinkToDeath(DeathRecipient recipient, int flags);    public void dump(FileDescriptor fd, String[] args) throws RemoteException {        Parcel data = Parcel.obtain();        Parcel reply = Parcel.obtain();        data.writeFileDescriptor(fd);        data.writeStringArray(args);        try {            transact(DUMP_TRANSACTION, data, reply, 0);            reply.readException();        } finally {            data.recycle();            reply.recycle();        }    }        public void dumpAsync(FileDescriptor fd, String[] args) throws RemoteException {        Parcel data = Parcel.obtain();        Parcel reply = Parcel.obtain();        data.writeFileDescriptor(fd);        data.writeStringArray(args);        try {            transact(DUMP_TRANSACTION, data, reply, FLAG_ONEWAY);            reply.readException();        } finally {            data.recycle();            reply.recycle();        }    }    BinderProxy() {        mSelf = new WeakReference(this);    }        @Override    protected void finalize() throws Throwable {        try {            destroy();        } finally {            super.finalize();        }    }        private native final void destroy();        private static final void sendDeathNotice(DeathRecipient recipient) {        if (false) Log.v("JavaBinder", "sendDeathNotice to " + recipient);        try {            recipient.binderDied();        }        catch (RuntimeException exc) {            Log.w("BinderNative", "Uncaught exception from death notification",                    exc);        }    }        final private WeakReference mSelf;    private int mObject;    private int mOrgue;}
        这里,我们只关心transact函数的实现:
static jboolean android_os_BinderProxy_transact(JNIEnv* env, jobject obj,        jint code, jobject dataObj, jobject replyObj, jint flags) // throws RemoteException{    ......    IBinder* target = (IBinder*)        env->GetIntField(obj, gBinderProxyOffsets.mObject);//和前面介绍过的gBinderOffsets相似,gBinderProxyOffsets的mObject成员指向BinderProxy实例的mObject成员    if (target == NULL) {        jniThrowException(env, "java/lang/IllegalStateException", "Binder has been finalized!");        return JNI_FALSE;    }    ......    status_t err = target->transact(code, *data, reply, flags);//关键的调用    ......}
        从上面的代码可以看到,BinderProxy.mObject成员中保存了C++的IBinder对象的指针,然后通过这个IBinder对象调用transact函数,进行binder通信。transact函数的实现,上一个章节中有介绍,所以BinderProxy的分析也到此为止。

总结

  • 通常,我们(应用开发者)通过aidl来进行binder通信,而aidl实现了
    • XXXX接口的声明
    • XXXXStub的实现,是对于Binder类的继承,通过onTransact函数来呼叫业务逻辑代码
    • XXXXStub.Proxy的实现,它拥有一个IBinder,通过这个IBinder来实现请求的转发
  • Binder类的mObject成员指向原生层的JavaBBinderHolder实例,而JavaBinderHolder实例的get函数,可以生成JavaBBinder实例,JavaBBinder继承自BBinder,是Server端的Binder实体
  • BinderProxy类的mObject成员指向原生层的IBinder实例,而IBinder通常是一个BpBinder实例,是Client端的Binder代理
        仅仅从以上的分析,可能大家无法把整个Java层和C++层Binder通信的过程理清楚,不过没关系,后面我们会分析Service和Binder通信的关系。从中,我们应该可以看到一个完整的Java层Binder通信过程。
0 0
原创粉丝点击