By  高煥堂 2009.7.31

 

台灣Android技術服務中心 主持人

Android軟硬整合高階技術課程 主講人

 

*** 其他相關文章

 

 

     Java層的Activity透過BinderProxy來與遠距的(Remote)服務進行溝通。例如myBinder繼承Binder

 

 

 

    Java層而觀之,myActivity可以經由bindService()而建立它與myBinder之間的連結。然而,這個連結是透過C++層的機制而達成的。如果你只想要開發Java層級的應用程式的話,並不需要閱讀本文。如果你想學習Android框架的原理,或修改Android框架,或撰寫Android的核心服務,進行軟硬整合,就必須熟悉幕後的重要機制。如下圖所示:

 

 

 

上圖之目的:myActivity想呼叫BinderProxyIBinder::transact()函數,進而呼叫到myBinderIBinder::onTransact()函數。就像一條橋,兩端分別是myActivitymyBinder

   為了要達成上述的目的,需要建立一些物件(如同橋墩),例如BpBinder物件,以及JavaBBinder物件;如此才能達成目的。茲詳細說明如下:

 

** myService::onCreate()函數誕生myBinder物件時,就呼叫到Binder()函數,它將myBinder物件的mObject欄位ID存入Native公用變數gBinderOffsets.mObject裡。接著,init()JavaBBinderHolder物件的參考存入myBinder物件的mObject欄位裡。** 此時,若已知myBinder物件,藉由ibinderForJavaObject()可取得該物件相對應的JavaBBinderHolder物件。

 

** 例如,當myActivitty呼叫bindService()函數,就藉由ibinderForJavaObject()可取得該物件相對應的JavaBBinderHolder物件,然後從JavaBBinderHolder物件取得關於myBinder的資訊,進而誕生JavaBBinder物件來與myBinder物件相互輝映。當已知JavaBBinder物件,可藉由javaObjectForIBinder 可取得該物件相對應的myBinder物件。

 

** 建立了右邊的橋墩(JavaBBinder物件)之後,也必須建立左邊的橋墩。AndroidBinder System可以幫忙建立左邊的橋墩:BpBinder物件。

 

** 已知BpBinder物件,藉由javaObjectForIBinder ()可取得該物件相對應的BinderProxy物件,   或誕生新的BinderProxy物件。並且,將BindProxy物件的mObject欄位ID存入Native公用變數gBinderProxyOffsets.mObject裡。還將BpBinder物件的參考存入BinderProxy物件的mObject欄位裡。

 

** 有了BinderProxy物件,myActivity裡就能呼叫BinderProxyIBinder::transact()函數,進而呼叫到myBinderIBinder::onTransact()函數。也可藉由ibinderForJavaObject()可取得該物件相對應的BpBinder物件。

 

 

**** 以下是參考資料 ****

**** 是從Android框架原始程式碼裡面摘錄出來的,

     提供給您參考。

 

---- BinderProxy類別是定義於Android 框架的/java/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);

 

    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 (Config.LOGV) 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;

}

 

其中,最重要的Native函數是:

    public native boolean transact(int code, Parcel data, Parcel reply, int flags)

          throws RemoteException;

 

Native函數實作於:

 

---- Native函數定義於Android 框架的/jni/android_util_binder.cpp檔案裡

 

static struct binderproxy_offsets_t

{

    // Class state.

    jclass mClass;

    jmethodID mConstructor;

    jmethodID mSendDeathNotice;

 

    // Object state.

    jfieldID mObject;

    jfieldID mSelf;

 

} gBinderProxyOffsets;

 

在這gBinderProxyOffsets.mObject裡,放的是BpBinder

 

static jboolean android_os_BinderProxy_transact(JNIEnv* env, jobject obj,

                                                jint code, jobject dataObj,

                                                jobject replyObj, jint flags)

{

    if (dataObj == NULL) {

        jniThrowException(env, "java/lang/NullPointerException", NULL);

        return JNI_FALSE;

    }

 

    Parcel* data = parcelForJavaObject(env, dataObj);

    if (data == NULL) {

        return JNI_FALSE;

    }

    Parcel* reply = parcelForJavaObject(env, replyObj);

    if (reply == NULL && replyObj != NULL) {

        return JNI_FALSE;

    }

 

    IBinder* target = (IBinder*)

        env->GetIntField(obj, gBinderProxyOffsets.mObject);

    if (target == NULL) {

        jniThrowException(env, "java/lang/IllegalStateException", "Binder has been finalized!");

        return JNI_FALSE;

    }

 

    LOGV("Java code calling transact on %p in Java object %p with code %d/n",

            target, obj, code);

    //printf("Transact from Java code to %p sending: ", target); data->print();

    status_t err = target->transact(code, *data, reply, flags);

    //if (reply) printf("Transact from Java code to %p received: ", target); reply->print();

    if (err == NO_ERROR) {

        return JNI_TRUE;

    } else if (err == UNKNOWN_TRANSACTION) {

        return JNI_FALSE;

    }

 

    signalExceptionForError(env, obj, err);

    return JNI_FALSE;

}

 

 

還含有:

sp ibinderForJavaObject(JNIEnv* env, jobject obj)

{

    if (obj == NULL) return NULL;

 

    if (env->IsInstanceOf(obj, gBinderOffsets.mClass)) {

        JavaBBinderHolder* jbh = (JavaBBinderHolder*)

            env->GetIntField(obj, gBinderOffsets.mObject);

        return jbh != NULL ? jbh->get(env) : NULL;

    }

 

    if (env->IsInstanceOf(obj, gBinderProxyOffsets.mClass)) {

        return (IBinder*)

            env->GetIntField(obj, gBinderProxyOffsets.mObject);

    }

 

    LOGW("ibinderForJavaObject: %p is not a Binder object", obj);

    return NULL;

}

 

 

還含有:

 

static void android_os_Binder_init(JNIEnv* env, jobject clazz)

{

    JavaBBinderHolder* jbh = new JavaBBinderHolder(env, clazz);

    if (jbh == NULL) {

        jniThrowException(env, "java/lang/OutOfMemoryError", NULL);

        return;

    }

    LOGV("Java Binder %p: acquiring first ref on holder %p", clazz, jbh);

    jbh->incStrong(clazz);

    env->SetIntField(clazz, gBinderOffsets.mObject, (int)jbh);

}

 

static int int_register_android_os_Binder(JNIEnv* env)

{

    jclass clazz;

 

    clazz = env->FindClass(kBinderPathName);

    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");

    assert(gBinderOffsets.mExecTransact);

 

    gBinderOffsets.mObject

        = env->GetFieldID(clazz, "mObject", "I");

    assert(gBinderOffsets.mObject);

 

    return AndroidRuntime::registerNativeMethods(

        env, kBinderPathName,

        gBinderMethods, NELEM(gBinderMethods));

}

 

還含有:

 

jobject javaObjectForIBinder(JNIEnv* env, const sp& val)

{

    if (val == NULL) return NULL;

 

    if (val->checkSubclass(&gBinderOffsets)) {

        // One of our own!

        jobject object = static_cast(val.get())->object();

        //printf("objectForBinder %p: it's our own %p!/n", val.get(), object);

        return object;

    }

 

    // For the rest of the function we will hold this lock, to serialize

    // looking/creation of Java proxies for native Binder proxies.

    AutoMutex _l(mProxyLock);

 

    // Someone else's...  do we know about it?

    jobject object = (jobject)val->findObject(&gBinderProxyOffsets);

    if (object != NULL) {

        jobject res = env->CallObjectMethod(object, gWeakReferenceOffsets.mGet);

        if (res != NULL) {

            LOGV("objectForBinder %p: found existing %p!/n", val.get(), res);

            return res;

        }

        LOGV("Proxy object %p of IBinder %p no longer in working set!!!", object, val.get());

        android_atomic_dec(&gNumProxyRefs);

        val->detachObject(&gBinderProxyOffsets);

        env->DeleteGlobalRef(object);

    }

 

    object = env->NewObject(gBinderProxyOffsets.mClass, gBinderProxyOffsets.mConstructor);

    if (object != NULL) {

        LOGV("objectForBinder %p: created new %p!/n", val.get(), object);

        // The proxy holds a reference to the native object.

        env->SetIntField(object, gBinderProxyOffsets.mObject, (int)val.get());

        val->incStrong(object);

 

        // The native object needs to hold a weak reference back to the

        // proxy, so we can retrieve the same proxy if it is still active.

        jobject refObject = env->NewGlobalRef(

                env->GetObjectField(object, gBinderProxyOffsets.mSelf));

        val->attachObject(&gBinderProxyOffsets, refObject,

                jnienv_to_javavm(env), proxy_cleanup);

 

        // Note that a new object reference has been created.

        android_atomic_inc(&gNumProxyRefs);

        incRefsCreated(env);

    }

 

    return object;

}

更多相关文章

  1. android框架设计
  2. Android:电话拨号器、呼叫记录、结束通话、Android显示单位
  3. Android(安卓)TabHost与FragmentActivity
  4. 活用Android的Message Queue
  5. Android(安卓)SQLiter cursor的使用
  6. Android(安卓)animation - 文字旋转示例
  7. Android获取通话记录
  8. Android呼叫管理服务之会话发起协议(SIP)API
  9. 使用Android拨打电话功能

随机推荐

  1. 从零开始学android:Android中的基本控件(
  2. Linux 4.4内核移植以及Android系统编译
  3. Android 客户端与服务器交互
  4. Android Service,startService binderServ
  5. 图文详解Android Studio搭建Android集成
  6. 使用Android Studio搭建Android集成开发
  7. Android多线程下载远程图片
  8. Android手机访问Django测试服务器方法
  9. Android工程中R.java文件的重新生成——(
  10. [置顶] Android(安卓)中轴时光轴