Binder in Java

AngelDevil發表於2013-09-23

Android在Native層實現了程式間的Binder通訊,但是上層應用程式的開發及Framework的實現都是Java,用Java層再實現一次肯定是不合理的,Java可以透過JNI呼叫Native Code,所以透過JNI複用Binder在Native層的實現就是一個順理成章的事情。

註冊Service

在Init程式的init2階段,系統啟動了ServerThread,在ServerThread中會啟動很多用Java實現的系統服務,比如說PowerService:

power = new PowerManagerService();
ServiceManager.addService(Context.POWER_SERVICE, power);

新建Server端實體,然後向ServiceManager註冊,從程式碼表面看是和Native層Binder一樣的。PowerManagerService繼承自Java層的Binder類:

public final class PowerManagerService extends IPowerManager.Stub
public interface IPowerManager extends android.os.IInterface {
    public static abstract class Stub extends android.os.Binder implements android.os.IPowerManager {

所以在new PowerManagerService時會呼叫Binder的建構函式,Binder的建構函式中呼叫了init(),init是native方法,執行JNI的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);
}

在android_os_Binder_init,新建了一個JavaBBinderHolder對角,並將其指標儲存在了obj即Binder的gBinderOffsets.mObject域中,而gBinderOffsets.mObject又是個什麼東西?看一下它的定義:

static struct bindernative_offsets_t
{
    jclass mClass;
    jmethodID mExecTransact;
    jfieldID mObject;
} gBinderOffsets;

在AndroidRuntine::startReg中會呼叫register_android_os_Binder,register_android_os_Binder會呼叫int_register_android_os_Binder等函式建立Java層Binder、BinderProxy、BinderInternal、Log等與Native層的對映關係。比如在int_register_android_os_Binder中會透過JNI標準的方法GetMethodID等初始化gBinderOffsets:

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

在android_os_Binder_init中new了一個JavaBBinderHolder,JavaBBinderHolder new了一個JavaBBinder儲存到了自己的成員wp<JavaBBinder> mBinder中。

JavaBBinder繼承自Native層的BBinder,並且將Java層的Binder物件(此處即PowerManagerService)儲存到了成員mObject中,並透過object()方法返回。

現在我們發現,JavaBinder,BinderBBinderHolder,JavaBBinder存在相互引用關係:

  • PowerManagerService.mObject->JavaBBinderHolder
  • JavaBBinderHolder.mBinder->JavaBBinder
  • JavaBBinder.mObject->PowerManagerService

Binder是一種Client-Server型別的IPC,PowerManagerService屬於Server端,從Native Binder中我們知道,Client透過BpBinder經由Binder Driver、BBinder與Serverr通訊,PowerManagerService透過JavaBBinderHolder引用JavaBBinder,而JavaBBinder繼承自BBinder,符合了Server的條件,Server實體有了,接下來就要向ServiceManager註冊,透過以下方法:

ServiceManager.addService(Context.POWER_SERVICE,power);
// In ServiceManager public static void addService(String name, IBinder service) { try { getIServiceManager().addService(name, service, false); } catch (RemoteException e) { Log.e(TAG, "error in addService", e); } } private static IServiceManager getIServiceManager() { if (sServiceManager != null) { return sServiceManager; } sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject()); return sServiceManager; }

 BinderInternal.getContextObject是一個Native方法,呼叫JNIandroid_os_BinderInternal_getContextObject:

static jobject android_os_BinderInternal_getContextObject(JNIEnv* env, jobject clazz)
{
    sp<IBinder> b = ProcessState::self()->getContextObject(NULL);
    return javaObjectForIBinder(env, b);
}

ProcessState::self()->getContextObject就很熟悉了,在Binder in Native中可以知道,這個呼叫返回new BpBinder(0)。

javaObjectForIBinder的作用就是,新建一個Java層的BinderProxy物件,將Native層的BpBinder儲存到BinderProxy.mObject,並將BinderProxy的弱引用透過attachObject儲存到Native層的BpBinder(成員mObjects中),這樣Java層的BinderProxy與Native層的BpBinder就可以相互引用了。Java層的BinderProxy及其在Native層的表示間的對映關係同Binder類一樣也是在register_android_os_Binder中建立的。

上面紅色的部分就等效於:

gServiceManager = ServiceManagerNative.asInterface(new BinderProxy());

 ServiceManagerNative繼承自IServiceManager與Java層的Binder類,BinderProxy可以引用BpBinder。asInterface就像Native Binder中的interface_cast的,asInterface實現可以簡化為:

return new ServiceManagerProxy(obj);

obj是BinderProxy物件。ServiceManagerProxy直接將這個BinderProxy物件儲存在了成員mRemote中,並透過asBinder返回。

ServiceManagerProxy同時實現了IServiceManager,而且由其名字可知,ServiceManagerProxy是作為ServiceManager在Client端的代理的,看下它的addService的實現:

public void addService(String name, IBinder service, boolean allowIsolated)
            throws RemoteException {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        data.writeInterfaceToken(IServiceManager.descriptor);
        data.writeString(name);
        data.writeStrongBinder(service);
        data.writeInt(allowIsolated ? 1 : 0);
        mRemote.transact(ADD_SERVICE_TRANSACTION, data, reply, 0);
        reply.recycle();
        data.recycle();
    }

writeStrongBinder是Native方法,呼叫android_os_Parcel_writeStrongBinder,在android_os_Parcel_writeStrongBinder將Java Parcel轉換成Native Parcel(Native Parcel的指標儲存在Java Parcel的成員變數中),然後呼叫以下語句:

const status_t err = parcel->writeStrongBinder(ibinderForJavaObject(env, object));

sp<IBinder> ibinderForJavaObject(JNIEnv* env, jobject obj)根據obj返回JavaBBinder或Native BpBinder,在這裡傳入的obj 是PowerManagerService,返回JavaBBinder。接下來呼叫了mRemote.transact,mRemote是BinderProxy的物件。

BinderProxy的transact是Native方法,呼叫JNIandroid_os_BinderProxy_transact,在android_os_BinderProxy_transact中透過:

IBinder* target = (IBinder*) env->GetIntField(obj, gBinderProxyOffsets.mObject);
...
status_t err = target->transact(code, *data, reply, flags);

獲取到BinderProxy中儲存的BpBinder,然後呼叫BpBinder的transact,到這裡就和Native Binder的呼叫流程一樣了,Native ServiceManager會註冊我們的Service,在這裡是PowerManagerService。

 獲得註冊的Service

Service已經向ServiceManager註冊了,那麼我們怎麼獲得所註冊的Service,或者更準確地說,怎麼獲得所註冊的Service的代理呢?

回想下我們在APK中是怎麼獲取系統服務的:

PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);

看一下getSystemService的實現,位於ContextImpl中:

    @Override
    public Object getSystemService(String name) {
        ServiceFetcher fetcher = SYSTEM_SERVICE_MAP.get(name);
        return fetcher == null ? null : fetcher.getService(this);
    }

        registerService(POWER_SERVICE, new ServiceFetcher() {
                public Object createService(ContextImpl ctx) {
                    IBinder b = ServiceManager.getService(POWER_SERVICE);
                    IPowerManager service = IPowerManager.Stub.asInterface(b);
                    return new PowerManager(ctx.getOuterContext(),
                            service, ctx.mMainThread.getHandler());
                }});

1. ServiceManager.getService獲得IBinder物件

同ServiceManager.addService一樣,ServiceManager.getService首先獲得一個ServiceManagerProxy的物件,然後呼叫它的getService方法:

    public IBinder getService(String name) throws RemoteException {
        ...
        mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0);
        IBinder binder = reply.readStrongBinder();
        ...
        return binder;
    }

mRemote是BinderProxy物件,內部引用了BpBinder,呼叫BinderProxy的Native方法transact與Binder通訊,然後透過readStrongBinder()讀取返回的資料,一個IBinder物件。

readStrongBinder中透過javaObjectForIBinder返回了BinderProxy物件,前面已經說過。

2. 透過asInterface將獲得的IBinder物件轉換成IPowerManager物件

IPowerManager.Stub.asInterface可以簡化為:

return new android.os.IPowerManager.Stub.Proxy(obj);

Proxy只是將傳入的引數(BinderProxy)儲存到了成員mRemote中並透過asBinder返回。

Proxy與Stub都是IPowerManager.aidl編譯後生成的類,都位於IPowerManager.java中。關於aidl網上有很多資料。

3. IPowerManager物件是不向外暴露的,構造一個PowerManager封裝IPowerManager返回。

PowerManager只是將IPowerManager儲存在了成員變數中,PowerManager中儲存了BinderProxy,BinderProxy中引用了Native BpBinder,就可以與Server進行通訊了。

Server端響應Client請求

Server端接收到Client的請求後會呼叫BBinder的transact處理請求,transact會呼叫虛擬函式onTransact,JavaBBinder繼承自BBinder,所以會呼叫JavaBBinder::onTransact,在JavaBBinder::onTransact中有以下一句:

jboolean res = env->CallBooleanMethod(mObject, gBinderOffsets.mExecTransact, code, (int32_t)&data, (int32_t)reply, flags);

透過JNI反向呼叫了Java類的方法。前面我們知道了,Java實現的Service中,Service物件,JavaBBinderHolder,JavaBBinder存在相互引用關係,JavaBBinder的成員mObject引用了Java中的Service物件,比如此處的PowerManagerService,而且在int_register_android_os_Binder中透過

gBinderOffsets.mExecTransact  = env->GetMethodID(clazz, "execTransact", "(IIII)Z");

將Service的execTransact方法(其實是Binder的方法)儲存在了gBinderOffsets.mExecTransact中,所在以JavaBBinder::onTransact中會呼叫Binder.execTransact。在Binder.execTransact中呼叫了onTransact,執行子類即Stub類的onTransact方法,在onTransact中根據code值執行相應的方法,最終是呼叫Service類(繼承自Stub)中相應的方法。

總結

Java層透過JNI利用了Native層的Binder,在JNI函式註冊時會建立Java層Binder,BinderProxy,BinderInternal等類與Native層的對映關係。Java層Service實體繼承自Java層的Binder類,在Binder類初始化時會建立一個JavaBBinderHolder作為JavaBBinder的容器,JavaBBinder繼承自BBinder,Java層Binder類引用JavaBBinderHolder,JavaBBinderHolder引用JavaBBinder,JavaBBinder繼承自BBinder並引用Java層的Binder類,這三者互相引用,這樣Java層的Service實體就可以透過BBinder與驅動進行通訊了。

程式向Java層的ServiceManager代理傳送GET_SERVICE請求,然後透過JNI向Native層的ServiceManager請求服務,Native層的ServiceManager返回請求的服務的代理物件BpBinder,透過javaObjectForIBinder函式將Native的BpBinder轉化為Java層對應的BinderProxy,然後透過aidl生成的Stub類asInterface方法將BinderProxy封閉到請求的服務的代理物件中,這個代理物件引用了BinderProxy,BinderProxy內部儲存了Native層的BpBinder,這樣就可以與驅動進行通訊了。

當Server端接收到Client的請求時會透過BBinder的transact呼叫Server的服務,BBinder的transact呼叫虛擬函式onTransact,這樣就會調到BBinder的子類JavaBBinder的onTransact,而JavaBinder::onTransact會透過JNI反向呼叫到Java層Binder類的execTransact,Binder.execTransact呼叫onTransact即子類Stub的onTransact,然後根據code值呼叫Service實體類(繼承自Stub)相應的方法。

相關文章