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<IBinder> 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<IBinder>& val)

{

if (val == NULL) return NULL;

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

// One of our own!

jobject object = static_cast<JavaBBinder*>(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. Dagger2 在 Android 项目的正确使用方式【完整篇】
  3. Weex 04 Weex中Android项目的生成和交互
  4. Android教父高焕堂:开源只是手段,开放才是目的
  5. 【Android】在开发项目的时候,利用AndroidStudio开发工具,突然一直
  6. Android中网络编程以及与服务器上Web项目的基础交互
  7. android 如何把新建项目的那个 android app project
  8. Android近百个项目的源代码

随机推荐

  1. Android 中自定义View的应用
  2. Android spannableStringBuilder用法整理
  3. Android Menu功能菜单
  4. android 侧滑菜单DrawerLayout
  5. android command
  6. 在android中使用HttpURLConnection进行文
  7. 如何隐藏Android4.0及以上版本的ActionBa
  8. android获取设备存储信息
  9. To use MuPDF source code in Android
  10. 基于Retrofit+RxJava的Android分层网络请