1. 程式人生 > >Android 資料Parcel序列化過程原始碼分析

Android 資料Parcel序列化過程原始碼分析

在Android系統中,所有的服務都必須註冊到ServiceManger中,當客戶程序需要請求某一服務時,首先從服務管家ServiceManger中查找出該服務,然後通過RPC遠端呼叫的方式使用該服務。服務在註冊到ServiceManager時,需要將該服務物件傳送到ServiceManager程序。Android是如何將一個binder物件進行序列化呢?本文將對Android的資料序列化進行詳細分析。

在客戶程序向服務程序傳送IPC資料時,通常都是先將資料打包在Parcel物件中,然後通過核心空間傳送到服務程序中。在Android請求註冊服務過程原始碼分析中分別從Java和C++層分析了服務註冊過程的資料流程,

Android IPC資料在核心空間中的傳送過程分析介紹了IPC資料在核心空間的互動過程。客戶程序在將IPC資料打包到Parcel物件前,會首先獲取一個Parcel物件,類似我們去郵局寄信件,首先需要從郵局獲取信封,然後將信件裝入到信封中,填寫上收件人地址等就可以將信件傳送出去。在Android的IPC通訊中,Parcel物件就相當於信封,需要註冊的服務相當於要郵寄的信件,handle就相當於收件人地址...

public void addService(String name, IBinder service, boolean allowIsolated)
		throws RemoteException {
	//獲取Parcel物件
	Parcel data = Parcel.obtain();
	Parcel reply = Parcel.obtain();
	//資料打包到Parcel物件中
	data.writeInterfaceToken(IServiceManager.descriptor);
	data.writeString(name);
	data.writeStrongBinder(service);
	data.writeInt(allowIsolated ? 1 : 0);
	//資料傳送
	mRemote.transact(ADD_SERVICE_TRANSACTION, data, reply, 0);
	//回收Parcel物件
	reply.recycle();
	data.recycle();
}

JNI函式註冊

Zygote程序啟動過程的原始碼分析中介紹了在Zygote程序啟動時會註冊系統JNI函式,對於Parcel物件也不例外:

REG_JNI(register_android_os_Parcel)

Parcel類的JNI註冊函式實現:

int register_android_os_Parcel(JNIEnv* env)
{
    jclass clazz;
    //kParcelPathName = "android/os/Parcel";
    clazz = env->FindClass(kParcelPathName);
    LOG_FATAL_IF(clazz == NULL, "Unable to find class android.os.Parcel");
    //儲存Java層的android.os.Parcel類的資訊到JNI層的gParcelOffsets變數中
    gParcelOffsets.clazz = (jclass) env->NewGlobalRef(clazz);
    gParcelOffsets.mNativePtr = env->GetFieldID(clazz, "mNativePtr", "I");
    gParcelOffsets.obtain = env->GetStaticMethodID(clazz, "obtain",
                                                   "()Landroid/os/Parcel;");
    gParcelOffsets.recycle = env->GetMethodID(clazz, "recycle", "()V");
    //陣列gParcelMethods中存放了Parcel類的JNI函式與Java本地函式之間的對映關係,通過registerNativeMethods()函式即可註冊Parcel類的JNI函式
    return AndroidRuntime::registerNativeMethods(
        env, kParcelPathName,
        gParcelMethods, NELEM(gParcelMethods));
}

gParcelOffsets是C++中的靜態類變數,在Zygote啟動時通過JNI方法來讀取android.os.Parcel類資訊,並保持到gParcelOffsets結構體變數中,當C++層需要建立Java層的Parcel物件時,通過JNI方法及android.os.Parcel類資訊就可以在C++層建立一個Java物件。

獲取Parcel物件

通過Parcel類的靜態成員函式obtain來獲取一個Parcel物件例項

frameworks\base\core\java\android\os\Parcel.java

public static Parcel obtain() {
	final Parcel[] pool = sOwnedPool;
	synchronized (pool) {
		Parcel p;
		for (int i=0; i<POOL_SIZE; i++) {
			p = pool[i];
			if (p != null) {
				pool[i] = null;
				if (DEBUG_RECYCLE) {
					p.mStack = new RuntimeException();
				}
				return p;
			}
		}
	}
	return new Parcel(0);
}

在Parcel類中,定義了一個靜態Parcel物件池:

private static final int POOL_SIZE = 6;
private static final Parcel[] sOwnedPool = new Parcel[POOL_SIZE];
private static final Parcel[] sHolderPool = new Parcel[POOL_SIZE];

函式obtain首先從該Parcel物件池中查詢不為空的Parcel物件,如果沒有找到,就建立一個新的Parcel物件,並且傳遞引數0.

private Parcel(int nativePtr) {
	if (DEBUG_RECYCLE) {
		mStack = new RuntimeException();
	}
	init(nativePtr);
}

構造了Parcel物件後,呼叫init()函式來初始化該物件

private void init(int nativePtr) {
	if (nativePtr != 0) {
		mNativePtr = nativePtr;
		mOwnsNativeParcelObject = false;
	} else {
		mNativePtr = nativeCreate();
		mOwnsNativeParcelObject = true;
	}
}

如果傳進來的引數不為0,就將引數儲存到mNativePtr變數中,該變數儲存的是Java層Parcel對應的C++層Parcel物件的地址,同時設定mOwnsNativeParcelObject為false,表示該Java層Parcel物件現在還沒有關聯上C++層的Parcel物件。因為此時傳進來的引數為0,因此函式將呼叫nativeCreate()函式來建立一個C++層的Parcel物件,並將該物件的地址儲存在mNativePtr變數中,設定mOwnsNativeParcelObject為true,表示該Parcel物件已經關聯了C++的Parcel物件。nativeCreate()函式是一個本地函式,其實現如下:

static jint android_os_Parcel_create(JNIEnv* env, jclass clazz)
{
    Parcel* parcel = new Parcel();
    return reinterpret_cast<jint>(parcel);
}

這個函式很簡單,就是構造一個Parcel物件,並將給物件的地址返回到Java層。

Parcel::Parcel()
{
    initState();
}

void Parcel::initState()
{
    mError = NO_ERROR;
    mData = 0;
    mDataSize = 0;
    mDataCapacity = 0;
    mDataPos = 0;
    ALOGV("initState Setting data size of %p to %d\n", this, mDataSize);
    ALOGV("initState Setting data pos of %p to %d\n", this, mDataPos);
    mObjects = NULL;
    mObjectsSize = 0;
    mObjectsCapacity = 0;
    mNextObjectHint = 0;
    mHasFds = false;
    mFdsKnown = true;
    mAllowFds = true;
    mOwner = NULL;
}

這樣就構造了一對Parcel物件,分別是Java層的Parcel和C++層的Parcel物件,Java層的Parcel物件儲存了C++層的Parcel物件的地址,而C++層在JNI函式註冊時就儲存了Java層的Parcel類的資訊。通過這種方式就Java層的Parcel就可以很方便地找到與其對應的C++層Parcel物件,同時在C++層也可以創建出一個Java層的Parcel物件。

設定Parcel資料容量

Android IPC資料在核心空間中的傳送過程分析中介紹了ProcessState,IPCThreadState物件與程序,執行緒之間的關係,同時介紹了每一個IPCThreadState物件都有mIn,mOut兩個Parcel物件,用於儲存程序間通訊的IPC資料。在IPCThreadState物件的建構函式中,首先會初始化這兩個資料容器的容量

IPCThreadState::IPCThreadState()
    : mProcess(ProcessState::self()),
      mMyThreadId(androidGetTid()),
      mStrictModePolicy(0),
      mLastTransactionBinderFlags(0)
{
    pthread_setspecific(gTLS, this);
    clearCaller();
    mOrigCallingUid = mCallingUid;
	//初始化資料容量
    mIn.setDataCapacity(256);
    mOut.setDataCapacity(256);
}

接下來具體分析Parcel資料容量設定的完整過程

status_t Parcel::setDataCapacity(size_t size)
{
    if (size > mDataCapacity) return continueWrite(size);
    return NO_ERROR;
}

傳進來的引數size為256byte,前面介紹Parcel物件初始化時,mDataCapacity = 0,因此將呼叫continueWrite(256)作進一步處理

status_t Parcel::continueWrite(size_t desired)
{
	//取得已儲存了的Binder物件個數
    size_t objectsSize = mObjectsSize;
	//如果當前設定的資料容量小於已儲存的資料大小
    if (desired < mDataSize) {
        if (desired == 0) {
            objectsSize = 0;
        } else { //去除偏移量大於即將設定的資料容量大小的Binder物件
            while (objectsSize > 0) {
                if (mObjects[objectsSize-1] < desired)
                    break;
                objectsSize--;
            }
        }
    }
    //初始化Parcel物件時被設定為null,只有在執行ipcSetDataReference函式後設置資料容量才執行這個分支
    if (mOwner) {
        // If the size is going to zero, just release the owner's data.
        if (desired == 0) {
            freeData();
            return NO_ERROR;
        }
        // 分配資料空間
        uint8_t* data = (uint8_t*)malloc(desired);
        if (!data) {
            mError = NO_MEMORY;
            return NO_MEMORY;
        }
		//分配Binder物件儲存空間
        size_t* objects = NULL;
        if (objectsSize) {
            objects = (size_t*)malloc(objectsSize*sizeof(size_t));
            if (!objects) {
                mError = NO_MEMORY;
                return NO_MEMORY;
            }
			//調整各指標位置
            size_t oldObjectsSize = mObjectsSize;
            mObjectsSize = objectsSize;
            acquireObjects();
            mObjectsSize = oldObjectsSize;
        }
        //資料拷貝
        if (mData) {
            memcpy(data, mData, mDataSize < desired ? mDataSize : desired);
        }
        if (objects && mObjects) {
            memcpy(objects, mObjects, objectsSize*sizeof(size_t));
        }
        //呼叫回撥函式來回收原有記憶體空間
        mOwner(this, mData, mDataSize, mObjects, mObjectsSize, mOwnerCookie);
        mOwner = NULL;

        mData = data;
        mObjects = objects;
        mDataSize = (mDataSize < desired) ? mDataSize : desired;
        ALOGV("continueWrite Setting data size of %p to %d\n", this, mDataSize);
        mDataCapacity = desired;
        mObjectsSize = mObjectsCapacity = objectsSize;
        mNextObjectHint = 0;

    }
	//當已經儲存了資料時才執行此分支
	else if (mData) {
		//objectsSize為根據空間調整後已儲存的Binder物件個數,mObjectsSize則是空間調整前已儲存的Binder物件個數
        if (objectsSize < mObjectsSize) {
            const sp<ProcessState> proc(ProcessState::self());
			//迴圈釋放無法儲存的那些Binder物件所佔用的記憶體空間
            for (size_t i=objectsSize; i<mObjectsSize; i++) {
                const flat_binder_object* flat = reinterpret_cast<flat_binder_object*>(mData+mObjects[i]);
                if (flat->type == BINDER_TYPE_FD) {
                    // will need to rescan because we may have lopped off the only FDs
                    mFdsKnown = false;
                }
                release_object(proc, *flat, this);
            }
			//重新分配記憶體空間
            size_t* objects =(size_t*)realloc(mObjects, objectsSize*sizeof(size_t));
            if (objects) {
                mObjects = objects;
            }
            mObjectsSize = objectsSize;
            mNextObjectHint = 0;
        }
        // 如果設定的資料容量大於當前的資料容量大小
        if (desired > mDataCapacity) {
			//動態分配記憶體大小
            uint8_t* data = (uint8_t*)realloc(mData, desired);
			//調整各指標的位置
            if (data) {
                mData = data;
                mDataCapacity = desired;
            } else if (desired > mDataCapacity) {
                mError = NO_MEMORY;
                return NO_MEMORY;
            }
        } else {
            if (mDataSize > desired) {
                mDataSize = desired;
                ALOGV("continueWrite Setting data size of %p to %d\n", this, mDataSize);
            }
            if (mDataPos > desired) {
                mDataPos = desired;
                ALOGV("continueWrite Setting data pos of %p to %d\n", this, mDataPos);
            }
        }
        
    } 
	//Parcel物件初始化後,設定資料容量
	else {
        //根據要設定的容量大小分配記憶體空間
        uint8_t* data = (uint8_t*)malloc(desired);
        if (!data) {
            mError = NO_MEMORY;
            return NO_MEMORY;
        }
        
        if(!(mDataCapacity == 0 && mObjects == NULL && mObjectsCapacity == 0)) {
            ALOGE("continueWrite: %d/%p/%d/%d", mDataCapacity, mObjects, mObjectsCapacity, desired);
        }
        //儲存分配記憶體空間的起始地址
        mData = data;
        mDataSize = mDataPos = 0;
        ALOGV("continueWrite Setting data size of %p to %d\n", this, mDataSize);
        ALOGV("continueWrite Setting data pos of %p to %d\n", this, mDataPos);
		//儲存分配的記憶體大小
        mDataCapacity = desired;
    }
    return NO_ERROR;
}

mObjects = NULL;
mObjectsSize = 0;
mObjectsCapacity = 0;
mData = malloc(256);
mDataSize = 0 ;
mDataPos = 0;
mDataCapacity = 256;

writeInterfaceToken函式

public final void writeInterfaceToken(String interfaceName) {
    //mNativePtr儲存了C++層的Parcel物件,interfaceName為需要寫入的資料內容
	nativeWriteInterfaceToken(mNativePtr, interfaceName);
}

static void android_os_Parcel_writeInterfaceToken(JNIEnv* env, jclass clazz, jint nativePtr,jstring name)
{
    //獲取C++ Parcel物件
	Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
	if (parcel != NULL) {
		// 將字串轉換為C++的字串
		const jchar* str = env->GetStringCritical(name, 0);
		if (str != NULL) {
			parcel->writeInterfaceToken(String16(str, env->GetStringLength(name)));
			env->ReleaseStringCritical(name, str);
		}
	}
}

status_t Parcel::writeInterfaceToken(const String16& interface)
{
    //先寫入校驗頭,getStrictModePolicy()函式將返回IPCThreadState成員變數mStrictModePolicy的值,在構造IPCThreadState例項物件時,mStrictModePolicy被賦值為0了
	//#define STRICT_MODE_PENALTY_GATHER 0x100
    writeInt32(IPCThreadState::self()->getStrictModePolicy() | STRICT_MODE_PENALTY_GATHER);
    // 寫入字串內容
    return writeString16(interface);
}

status_t Parcel::writeString16(const String16& str)
{
    return writeString16(str.string(), str.size());
}

函式呼叫了另外的writeString16函式,將要寫入的字串和字串長度作為引數傳遞進去

status_t Parcel::writeString16(const char16_t* str, size_t len)
{
    if (str == NULL) return writeInt32(-1);
    //首先寫入字串長度
    status_t err = writeInt32(len);
    if (err == NO_ERROR) {
	    //計算字串佔用的記憶體空間大小
        len *= sizeof(char16_t);
		//計算字串存放的位置
        uint8_t* data = (uint8_t*)writeInplace(len+sizeof(char16_t));
        if (data) {
		    //將字串拷貝到指定位置
            memcpy(data, str, len);
            *reinterpret_cast<char16_t*>(data+len) = 0;
            return NO_ERROR;
        }
        err = mError;
    }
    return err;
}

接下來看看字串長度是如何寫入的

status_t Parcel::writeInt32(int32_t val)
{
    return writeAligned(val);
}

template<class T>
status_t Parcel::writeAligned(T val) {
    COMPILE_TIME_ASSERT_FUNCTION_SCOPE(PAD_SIZE(sizeof(T)) == sizeof(T));
    //判斷Parcel容器是否已經寫滿
    if ((mDataPos+sizeof(val)) <= mDataCapacity) {
restart_write:
        //將資料長度寫入到mData+mDataPos的位置
        *reinterpret_cast<T*>(mData+mDataPos) = val;
		//調整mDataPos的位置
        return finishWrite(sizeof(val));
    }
    //如果資料已經寫滿,則增大容器容量
    status_t err = growData(sizeof(val));
	//重新寫入資料
    if (err == NO_ERROR) goto restart_write;
    return err;
}


writeStrongBinder函式

writeStrongBinder函式可以將一個Binder物件寫入到Parcel中。在Android系統中,服務端的各個Service繼承於Binder類,以下是Binder家族類關係圖:

下面分別介紹服務物件的構造過程。

對於ActivityManagerService服務來說,其繼承於ActivityManagerNative,而ActivityManagerNative又繼承與Binder類,對於其他的Service來說,根據aidl的模板規範,各個Service都繼承與Stub類,該Stub類於繼承於Binder類,它們之間的類繼承關係如下圖:

因此在構造Service物件時,會首先呼叫Binder類的建構函式,在呼叫Stub類的建構函式,最後才呼叫Service自身的建構函式,構造順序如下:

Binder物件的構造過程

public Binder() {
	init();

	if (FIND_POTENTIAL_LEAKS) {
		final Class<? extends Binder> klass = getClass();
		if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
				(klass.getModifiers() & Modifier.STATIC) == 0) {
			Log.w(TAG, "The following Binder class should be static or leaks might occur: " +
				klass.getCanonicalName());
		}
	}
}

建構函式呼叫了init()函式來完成一些初始化工作。init()函式是一個本地函式,其對應的JNI函式為:

static void android_os_Binder_init(JNIEnv* env, jobject obj)
{
	//建立一個JavaBBinderHolder物件
    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);
	//將JavaBBinderHolder物件的地址儲存到JNI層的gBinderOffsets.mObject中
    env->SetIntField(obj, gBinderOffsets.mObject, (int)jbh);
}

Binder初始過程僅僅建立了一個JavaBBinderHolder物件,並且儲存到了gBinderOffsets.mObject變數中了。

public final void writeStrongBinder(IBinder val) {
	nativeWriteStrongBinder(mNativePtr, val);
}

nativeWriteStrongBinder是一個本地函式,其對應的JNI函式:

static void android_os_Parcel_writeStrongBinder(JNIEnv* env, jclass clazz, jint nativePtr, jobject object)
{
    //將Java層Parcel類成員變數mNativePtr的值轉換為C++層的Parcel指標
    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
    if (parcel != NULL) {
		//首先呼叫ibinderForJavaObject函式將Java層的Binder或BinderProxy物件轉換為C++層的JavaBBinderHolder或BpBinder,然後寫入到C++層的Parcel物件中
        const status_t err = parcel->writeStrongBinder(ibinderForJavaObject(env, object));
        if (err != NO_ERROR) {
            signalExceptionForError(env, clazz, err);
        }
    }
}

ibinderForJavaObject函式將Java層物件轉換為C++層的物件。

sp<IBinder> ibinderForJavaObject(JNIEnv* env, jobject obj)
{
    if (obj == NULL) return NULL;
    //如果obj是Java層的Binder物件,則從gBinderOffsets.mObject中取出前面構造該服務物件時建立的JavaBBinderHolder物件
    if (env->IsInstanceOf(obj, gBinderOffsets.mClass)) {
        JavaBBinderHolder* jbh = (JavaBBinderHolder*)env->GetIntField(obj, gBinderOffsets.mObject);
        return jbh != NULL ? jbh->get(env, obj) : NULL;
    }
    //如果obj是Java層的BinderProxy物件,則從gBinderProxyOffsets.mObject中取出BpBinder物件
    if (env->IsInstanceOf(obj, gBinderProxyOffsets.mClass)) {
        return (IBinder*)env->GetIntField(obj, gBinderProxyOffsets.mObject);
    }
    ALOGW("ibinderForJavaObject: %p is not a Binder object", obj);
    return NULL;
}

函式首先判斷需要轉換的是Java層的Binder物件還是BinderProxy物件,如果是Binder物件,則取出在構造服務物件時建立的JavaBBinderHolder物件,如果該物件不為空,則呼叫JavaBBinderHolder物件的get函式來獲取JavaBBinder物件,相反則返回空;如果是BinderProxy物件,則取出該BinderProxy對應的C++層的BpBinder物件。這裡傳進來的是一個服務物件,屬於Binder物件,在構造該服務時已經建立了JavaBBinderHolder物件,因此此時取出來的物件不為空,通過get函式獲取JavaBBinder物件:

sp<JavaBBinder> get(JNIEnv* env, jobject obj)
{
	AutoMutex _l(mLock);
	sp<JavaBBinder> b = mBinder.promote();
	if (b == NULL) {
		b = new JavaBBinder(env, obj);
		mBinder = b;
		ALOGV("Creating JavaBinder %p (refs %p) for Object %p, weakCount=%d\n",
			 b.get(), b->getWeakRefs(), obj, b->getWeakRefs()->getWeakCount());
	}

	return b;
}

因為在構造JavaBBinderHolder物件時並沒有初始化其成員變數mBinder,因此b=NULL,建立並返回一個新的JavaBBinder物件。JavaBBinder物件的構造過程如下:

JavaBBinder(JNIEnv* env, jobject object)
	: mVM(jnienv_to_javavm(env)), mObject(env->NewGlobalRef(object))
{
	//建立了服務Binder物件的全域性引用,並儲存到mObject變數
	ALOGV("Creating JavaBBinder %p\n", this);
	android_atomic_inc(&gNumLocalRefs);
	incRefsCreated(env);
}

回到ibinderForJavaObject函式,該函式首先建立一個JavaBBinder物件,並建立Java層服務Binder物件的全域性引用,儲存到JavaBBinder物件的mObject變數中,返回建立的JavaBBinder物件例項。

1)由於每個服務都是一個Binder物件,在構造服務時,會首先在C++層構造一個JavaBBinderHolder物件,並將該物件的指標儲存到Java層的服務的mObject變數中;

2)C++層的JavaBBinderHolder物件通過成員變數mBinder指向一個C++層的JavaBBinder物件,JavaBBinder類繼承於BBinder類,是服務在C++層的表現形式;

3)C++層的JavaBBinder物件又通過成員變數mObject指向Java層的Binder服務物件;

當呼叫函式writeStrongBinder()來序列化一個Java層的Binder服務時,其實是序列化C++層的JavaBBinder物件。

parcel->writeStrongBinder(new JavaBBinder(env, service))

接著呼叫writeStrongBinder函式將建立的JavaBBinder物件寫入到Parcel容器中。

status_t Parcel::writeStrongBinder(const sp<IBinder>& val)
{
    return flatten_binder(ProcessState::self(), val, this);
}

函式直接呼叫flatten_binder來寫入Binder物件。該函式使用flat_binder_object結構體來描述Binder實體物件或Binder引用物件

status_t flatten_binder(const sp<ProcessState>& proc,
    const sp<IBinder>& binder, Parcel* out)
{
	//使用flat_binder_object來表示傳輸中的binder物件
    flat_binder_object obj;
    //設定標誌位
    obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
    if (binder != NULL) {
		//判斷是否為本地Binder物件
        IBinder *local = binder->localBinder();
		//如果是Binder引用物件BpBinder
        if (!local) {
            BpBinder *proxy = binder->remoteBinder();
            if (proxy == NULL) {
                ALOGE("null proxy");
            }
			//取得BpBinder物件的成員變數mHandle的值
            const int32_t handle = proxy ? proxy->handle() : 0;
            obj.type = BINDER_TYPE_HANDLE;
            obj.handle = handle;
            obj.cookie = NULL;
		//如果是Binder實體物件BBinder
        } else {
            obj.type = BINDER_TYPE_BINDER;
            obj.binder = local->getWeakRefs();
            obj.cookie = local;
        }
    } else {
        obj.type = BINDER_TYPE_BINDER;
        obj.binder = NULL;
        obj.cookie = NULL;
    }
    
    return finish_flatten_binder(binder, obj, out);
}

0x7f表示處理該Binder請求的執行緒最低優先順序,FLAT_BINDER_FLAG_ACCEPTS_FDS表示該Binder可以接收檔案描述符。傳進來的引數binder為JavaBBinder物件,JavaBBinder繼承於BBinder類,是一個Binder實體物件,因此引數binder不為空。

IBinder的localBinder()和remoteBinder()函式都是虛擬函式,由子類來實現,BBinder類實現了localBinder()函式,而BpBinder類實現了remoteBinder()函式。

BBinder* BBinder::localBinder()
{
    return this;
}

BpBinder* BpBinder::remoteBinder()
{
    return this;
}

因此local不為空,obj結構體成員的值為:

obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
obj.type = BINDER_TYPE_BINDER;
obj.binder = local->getWeakRefs();
obj.cookie = local;

最後呼叫函式finish_flatten_binder將flat_binder_object寫入到Parcel中

inline static status_t finish_flatten_binder(
    const sp<IBinder>& binder, const flat_binder_object& flat, Parcel* out)
{
    return out->writeObject(flat, false);
}

out傳進來的是Parcel物件指標,

status_t Parcel::writeObject(const flat_binder_object& val, bool nullMetaData)
{
    const bool enoughData = (mDataPos+sizeof(val)) <= mDataCapacity;
    const bool enoughObjects = mObjectsSize < mObjectsCapacity;
    if (enoughData && enoughObjects) {
restart_write:
        *reinterpret_cast<flat_binder_object*>(mData+mDataPos) = val;
        
        // Need to write meta-data?
        if (nullMetaData || val.binder != NULL) {
            mObjects[mObjectsSize] = mDataPos;
            acquire_object(ProcessState::self(), val, this);
            mObjectsSize++;
        }
        
        // remember if it's a file descriptor
        if (val.type == BINDER_TYPE_FD) {
            if (!mAllowFds) {
                return FDS_NOT_ALLOWED;
            }
            mHasFds = mFdsKnown = true;
        }

        return finishWrite(sizeof(flat_binder_object));
    }

    if (!enoughData) {
        const status_t err = growData(sizeof(val));
        if (err != NO_ERROR) return err;
    }
    if (!enoughObjects) {
        size_t newSize = ((mObjectsSize+2)*3)/2;
        size_t* objects = (size_t*)realloc(mObjects, newSize*sizeof(size_t));
        if (objects == NULL) return NO_MEMORY;
        mObjects = objects;
        mObjectsCapacity = newSize;
    }
    
    goto restart_write;
}

每一個Binder物件都使用flat_binder_object結構體來描述,並寫入到Parcel物件中,寫入過程如下:

因此在註冊一個Java服務時,向ServiceManager程序傳送的是flat_binder_object資料,flat_binder_object,JavaBBinder,Service之間的關係如下圖:

readStrongBinder()函式的物件轉換過程:


readStrongBinder函式

在ServiceManagerProxy類的getService()函式中,通過mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0)向ServiceManager程序傳送服務查詢資訊,然後呼叫IBinder binder = reply.readStrongBinder()讀取ServiceManager程序查詢的服務代理物件。接下來詳細分析服務Binder物件的讀取過程。

public final IBinder readStrongBinder() {
	return nativeReadStrongBinder(mNativePtr);
}

函式直接呼叫的是nativeReadStrongBinder()函式,該函式是一個本地函式,引數mNativePtr是Parcel物件reply在C++中對應的Parcel物件地址。

private static native IBinder nativeReadStrongBinder(int nativePtr);

其對應的JNI函式為

frameworks\base\core\jni\android_os_Parcel.cpp

static jobject android_os_Parcel_readStrongBinder(JNIEnv* env, jclass clazz, jint nativePtr)
{
    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
    if (parcel != NULL) {
        return javaObjectForIBinder(env, parcel->readStrongBinder());
    }
    return NULL;
}

函式首先通過Java層傳過來的nativePtr找到C++層的Parcel物件,然後呼叫該Parcel物件的readStrongBinder()函式來讀取服務的Binder代理物件

sp<IBinder> Parcel::readStrongBinder() const
{
    sp<IBinder> val;
    unflatten_binder(ProcessState::self(), *this, &val);
    return val;
}

直接呼叫unflatten_binder()函式來完成讀取過程

status_t unflatten_binder(const sp<ProcessState>& proc,
    const Parcel& in, sp<IBinder>* out)
{
    const flat_binder_object* flat = in.readObject(false);
    
    if (flat) {
        switch (flat->type) {
			//如果是Binder實體物件BBinder
            case BINDER_TYPE_BINDER:
                *out = static_cast<IBinder*>(flat->cookie);
                return finish_unflatten_binder(NULL, *flat, in);
			//如果是Binder引用物件BpBinder
            case BINDER_TYPE_HANDLE:
                *out = proc->getStrongProxyForHandle(flat->handle);
                return finish_unflatten_binder(static_cast<BpBinder*>(out->get()), *flat, in);
        }        
    }
    return BAD_TYPE;
}

當服務註冊程序請求查詢服務時,返回該服務的Binder本地物件地址:

fp->binder = ref->node->ptr;  

fp->cookie = ref->node->cookie;

當服務查詢程序不是註冊該服務的程序時,返回Binder驅動為服務查詢程序建立的Binder物件的控制代碼值:

fp->handle = new_ref->desc;

引數in是Java層的Parcel物件reply在C++層對應的Parcel物件,這裡使用in.readObject(false)從Parcel物件中讀取出ServiceManager程序寫入的binder_object,並轉換為flat_binder_object型別指標

const flat_binder_object* Parcel::readObject(bool nullMetaData) const
{
    const size_t DPOS = mDataPos;
    if ((DPOS+sizeof(flat_binder_object)) <= mDataSize) {
        const flat_binder_object* obj = reinterpret_cast<const flat_binder_object*>(mData+DPOS);
        mDataPos = DPOS + sizeof(flat_binder_object);
        if (!nullMetaData && (obj->cookie == NULL && obj->binder == NULL)) {
            return obj;
        }
        
        // Ensure that this object is valid...
        size_t* const OBJS = mObjects;
        const size_t N = mObjectsSize;
        size_t opos = mNextObjectHint;
        
        if (N > 0) {
            // Start at the current hint position, looking for an object at
            // the current data position.
            if (opos < N) {
                while (opos < (N-1) && OBJS[opos] < DPOS) {
                    opos++;
                }
            } else {
                opos = N-1;
            }
            if (OBJS[opos] == DPOS) {
                mNextObjectHint = opos+1;
                ALOGV("readObject Setting data pos of %p to %d\n", this, mDataPos);
                return obj;
            }
            // Look backwards for it...
            while (opos > 0 && OBJS[opos] > DPOS) {
                opos--;
            }
            if (OBJS[opos] == DPOS) {
                // Found it!
                mNextObjectHint = opos+1;
                ALOGV("readObject Setting data pos of %p to %d\n", this, mDataPos);
                return obj;
            }
        }
    }
    return NULL;
}

要理解整個讀取過程,必須先了解Binder物件在Parcel中的儲存方式

readObject()函式從Parcel中讀取到ServiceManager程序返回來的flat_binder_object,函式unflatten_binder()則根據flat_binder_object結構體中的內容生成JavaBBinder物件或者BpBinder物件,函式javaObjectForIBinder()在Android請求註冊服務過程原始碼分析已經詳細介紹了,作用是根據BpBinder物件建立Java層的BinderProxy物件。

readStrongBinder()函式的物件轉換過程: