Binder機制中Jni

在Service綁定成功後,會調用ServiceConnection的onServiceConnected方法,其中會傳入一個IBinder參數。Java層擁有了Proxy便可以與其他進程通訊。這是很奇怪的地方。因爲我們知道,Binder是一個misc的驅動,驅動的操作方法都是系統調用。這裏很自然的想到,一定會用到Jni。
Client調用Proxy中所有的方法,均通過BinderProxy的transact發起:

public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
    Binder.checkParcel(this, code, data, "Unreasonably large binder buffer");

    if (mWarnOnBlocking && ((flags & FLAG_ONEWAY) == 0)) {
        // For now, avoid spamming the log by disabling after we've logged
        // about this interface at least once
        mWarnOnBlocking = false;
        Log.w(Binder.TAG, "Outgoing transactions from this process must be FLAG_ONEWAY",
                new Throwable());
    }

    final boolean tracingEnabled = Binder.isTracingEnabled();
    if (tracingEnabled) {
        final Throwable tr = new Throwable();
        Binder.getTransactionTracker().addTrace(tr);
        StackTraceElement stackTraceElement = tr.getStackTrace()[1];
        Trace.traceBegin(Trace.TRACE_TAG_ALWAYS,
                stackTraceElement.getClassName() + "." + stackTraceElement.getMethodName());
    }
    try {
    //注意這個方法
        return transactNative(code, data, reply, flags);
    } finally {
        if (tracingEnabled) {
            Trace.traceEnd(Trace.TRACE_TAG_ALWAYS);
        }
    }
}

真正的trancsat是在android_util_Binder.cpp實現的,java層只是定義了一個接口。

public native boolean transactNative(int code, Parcel data, Parcel reply,
        int flags) throws RemoteException;

我們來看看其實現:

static jboolean android_os_BinderProxy_transact(JNIEnv* env, jobject obj,
        jint code, jobject dataObj, jobject replyObj, jint flags) // throws RemoteException
{
    if (dataObj == NULL) {
        jniThrowNullPointerException(env, 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->GetLongField(obj, gBinderProxyOffsets.mObject);
    if (target == NULL) {
        jniThrowException(env, "java/lang/IllegalStateException", "Binder has been finalized!");
        return JNI_FALSE;
    }

    ALOGV("Java code calling transact on %p in Java object %p with code %" PRId32 "\n",
            target, obj, code);


    bool time_binder_calls;
    int64_t start_millis;
    if (kEnableBinderSample) {
        // Only log the binder call duration for things on the Java-level main thread.
        // But if we don't
        time_binder_calls = should_time_binder_calls();

        if (time_binder_calls) {
            start_millis = uptimeMillis();
        }
    }

    //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 (kEnableBinderSample) {
        if (time_binder_calls) {
            conditionally_log_binder_call(start_millis, target, code);
        }
    }

    if (err == NO_ERROR) {
        return JNI_TRUE;
    } else if (err == UNKNOWN_TRANSACTION) {
        return JNI_FALSE;
    }

    signalExceptionForError(env, obj, err, true /*canThrowRemoteException*/, data->dataSize());
    return JNI_FALSE;
}

在transact調用完後,系統會在某個時機調用server的onTransact。JavaBBinder繼承自本地框架的BBinder,代表Binder Service服務端的實體,而JavaBBinderHolder保存了JavaBBinder指針,Java層的Binder的mObject保存的JavaBBinderHolder指針的值。調用的順序爲,Binder->JavaBBinderHolder->JavaBBinder(例子中的RemoteService)

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 int32_t strict_policy_before = thread_state->getStrictModePolicy();

    //printf("Transact from %p to Java code sending: ", this);
    //data.print();
    //printf("\n");
    jboolean res = env->CallBooleanMethod(mObject, gBinderOffsets.mExecTransact,
        code, reinterpret_cast<jlong>(&data), reinterpret_cast<jlong>(reply), flags);

    if (env->ExceptionCheck()) {
        jthrowable excep = env->ExceptionOccurred();
        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);
    }

    // Check if the strict mode state changed while processing the
    // call.  The Binder state will be restored by the underlying
    // Binder system in IPCThreadState, however we need to take care
    // of the parallel Java state as well.
    if (thread_state->getStrictModePolicy() != strict_policy_before) {
        set_dalvik_blockguard_policy(env, strict_policy_before);
    }

    if (env->ExceptionCheck()) {
        jthrowable excep = env->ExceptionOccurred();
        report_exception(env, excep,
            "*** Uncaught exception in onBinderStrictModePolicyChange");
        /* clean up JNI local ref -- we don't return to Java code */
        env->DeleteLocalRef(excep);
    }

    // Need to always call through the native implementation of
    // SYSPROPS_TRANSACTION.
    if (code == SYSPROPS_TRANSACTION) {
    //調用server中的onTransact方法
        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;
}

以RemotService爲例,完成加法之後,要將數據傳到client去

@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
{
java.lang.String descriptor = DESCRIPTOR;
switch (code)
{
case INTERFACE_TRANSACTION:
{
reply.writeString(descriptor);
return true;
}
case TRANSACTION_add:
{
data.enforceInterface(descriptor);
int _arg0;
_arg0 = data.readInt();
int _arg1;
_arg1 = data.readInt();
int _result = this.add(_arg0, _arg1);
reply.writeNoException();
//此處回寫數據
reply.writeInt(_result);
return true;
}

從上面分析可知其大致流程,client調用c層傳輸數據後,server處理數據,然後回寫數據(當然這其中數據傳輸依賴於parcel),除去parcel的jni調用,client與server其只有client發生了jni調用,這也就是爲什麼transact方法是native而onTransact不是natvie的原因。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章