一.先从Serialize说起

我们都知道JAVA中的Serialize机制,译成串行化、序列化……,其作用是能将数据对象存入字节流其中,在须要时又一次生成对象。主要应用是利用外部存储设备保存对象状态,以及通过网络传输对象等。

二.Android中的新的序列化机制

在Android系统中,定位为针对内存受限的设备,因此对性能要求更高,另外系统中採用了新的IPC(进程间通信)机制,必定要求使用性能更出色的对象传输方式。在这种环境下,Parcel被设计出来,其定位就是轻量级的高效的对象序列化和反序列化机制。

三.Parcel类的背后

在Framework中有parcel类,源代码路径是:

Frameworks/base/core/java/android/os/Parcel.java

典型的源代码片断例如以下:

/** * Write an integer value into the parcel at the current dataPosition(), * growing dataCapacity() if needed. */ public final native void writeInt(int val); /** * Write a long integer value into the parcel at the current dataPosition(), * growing dataCapacity() if needed. */ public final native void writeLong(long val);

从中我们看到,从这个源程序文件里我们看不到真正的功能是怎样实现的,必须透过JNI往下走了。于是,Frameworks/base/core/jni/android_util_Binder.cpp中找到了线索

static void android_os_Parcel_writeInt(JNIEnv* env, jobject clazz, jint val) { Parcel* parcel = parcelForJavaObject(env, clazz); if (parcel != NULL) { const status_t err = parcel->writeInt32(val); if (err != NO_ERROR) { jniThrowException(env, "java/lang/OutOfMemoryError", NULL); } } } static void android_os_Parcel_writeLong(JNIEnv* env, jobject clazz, jlong val) { Parcel* parcel = parcelForJavaObject(env, clazz); if (parcel != NULL) { const status_t err = parcel->writeInt64(val); if (err != NO_ERROR) { jniThrowException(env, "java/lang/OutOfMemoryError", NULL); } } }

从这里我们能够得到的信息是函数的实现依赖于Parcel指针,因此还须要找到Parcel的类定义,注意,这里的类已经是用C++语言实现的了。

找到Frameworks/base/include/binder/parcel.h和Frameworks/base/libs/binder/parcel.cpp。最终找到了最终的实现代码了。

有兴趣的朋友能够自己读一下,不难理解,这里把主要的思路总结一下:

1.       整个读写全是在内存中进行,主要是通过malloc()、realloc()、memcpy()等内存操作进行,所以效率比JAVA序列化中使用外部存储器会高非常多;

2.       读写时是4字节对齐的,能够看到#define PAD_SIZE(s) (((s)+3)&~3)这句宏定义就是在做这件事情;

3.       假设预分配的空间不够时newSize = ((mDataSize+len)*3)/2;会一次多分配50%;

4.       对于普通数据,使用的是mData内存地址,对于IBinder类型的数据以及FileDescriptor使用的是mObjects内存地址。后者是通过flatten_binder()和unflatten_binder()实现的,目的是反序列化时读出的对象就是原对象而不用又一次new一个新对象。

好了,这就是Parcel背后的动作,全是在一块内存里进行读写操作,就不啰嗦了,把parcel的代码贴在这供没有源代码的朋友參考吧。接下来我会用一个小DEMO演示一下Parcel类在应用程序中的使用,详见《探索Android中的Parcel机制(下)》。

/* * Copyright (C) 2005 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ANDROID_PARCEL_H #define ANDROID_PARCEL_H #include <cutils/native_handle.h> #include <utils/Errors.h> #include <utils/RefBase.h> #include <utils/String16.h> #include <utils/Vector.h> // --------------------------------------------------------------------------- namespace android { class IBinder; class ProcessState; class String8; class TextOutput; class Flattenable; struct flat_binder_object; // defined in support_p/binder_module.h class Parcel { public: Parcel(); ~Parcel(); const uint8_t* data() const; size_t dataSize() const; size_t dataAvail() const; size_t dataPosition() const; size_t dataCapacity() const; status_t setDataSize(size_t size); void setDataPosition(size_t pos) const; status_t setDataCapacity(size_t size); status_t setData(const uint8_t* buffer, size_t len); status_t appendFrom(Parcel *parcel, size_t start, size_t len); bool hasFileDescriptors() const; status_t writeInterfaceToken(const String16& interface); bool enforceInterface(const String16& interface) const; bool checkInterface(IBinder*) const; void freeData(); const size_t* objects() const; size_t objectsCount() const; status_t errorCheck() const; void setError(status_t err); status_t write(const void* data, size_t len); void* writeInplace(size_t len); status_t writeUnpadded(const void* data, size_t len); status_t writeInt32(int32_t val); status_t writeInt64(int64_t val); status_t writeFloat(float val); status_t writeDouble(double val); status_t writeIntPtr(intptr_t val); status_t writeCString(const char* str); status_t writeString8(const String8& str); status_t writeString16(const String16& str); status_t writeString16(const char16_t* str, size_t len); status_t writeStrongBinder(const sp<IBinder>& val); status_t writeWeakBinder(const wp<IBinder>& val); status_t write(const Flattenable& val); // Place a native_handle into the parcel (the native_handle's file- // descriptors are dup'ed, so it is safe to delete the native_handle // when this function returns). // Doesn't take ownership of the native_handle. status_t writeNativeHandle(const native_handle* handle); // Place a file descriptor into the parcel. The given fd must remain // valid for the lifetime of the parcel. status_t writeFileDescriptor(int fd); // Place a file descriptor into the parcel. A dup of the fd is made, which // will be closed once the parcel is destroyed. status_t writeDupFileDescriptor(int fd); status_t writeObject(const flat_binder_object& val, bool nullMetaData); void remove(size_t start, size_t amt); status_t read(void* outData, size_t len) const; const void* readInplace(size_t len) const; int32_t readInt32() const; status_t readInt32(int32_t *pArg) const; int64_t readInt64() const; status_t readInt64(int64_t *pArg) const; float readFloat() const; status_t readFloat(float *pArg) const; double readDouble() const; status_t readDouble(double *pArg) const; intptr_t readIntPtr() const; status_t readIntPtr(intptr_t *pArg) const; const char* readCString() const; String8 readString8() const; String16 readString16() const; const char16_t* readString16Inplace(size_t* outLen) const; sp<IBinder> readStrongBinder() const; wp<IBinder> readWeakBinder() const; status_t read(Flattenable& val) const; // Retrieve native_handle from the parcel. This returns a copy of the // parcel's native_handle (the caller takes ownership). The caller // must free the native_handle with native_handle_close() and // native_handle_delete(). native_handle* readNativeHandle() const; // Retrieve a file descriptor from the parcel. This returns the raw fd // in the parcel, which you do not own -- use dup() to get your own copy. int readFileDescriptor() const; const flat_binder_object* readObject(bool nullMetaData) const; // Explicitly close all file descriptors in the parcel. void closeFileDescriptors(); typedef void (*release_func)(Parcel* parcel, const uint8_t* data, size_t dataSize, const size_t* objects, size_t objectsSize, void* cookie); const uint8_t* ipcData() const; size_t ipcDataSize() const; const size_t* ipcObjects() const; size_t ipcObjectsCount() const; void ipcSetDataReference(const uint8_t* data, size_t dataSize, const size_t* objects, size_t objectsCount, release_func relFunc, void* relCookie); void print(TextOutput& to, uint32_t flags = 0) const; private: Parcel(const Parcel& o); Parcel& operator=(const Parcel& o); status_t finishWrite(size_t len); void releaseObjects(); void acquireObjects(); status_t growData(size_t len); status_t restartWrite(size_t desired); status_t continueWrite(size_t desired); void freeDataNoInit(); void initState(); void scanForFds() const; template<class T> status_t readAligned(T *pArg) const; template<class T> T readAligned() const; template<class T> status_t writeAligned(T val); status_t mError; uint8_t* mData; size_t mDataSize; size_t mDataCapacity; mutable size_t mDataPos; size_t* mObjects; size_t mObjectsSize; size_t mObjectsCapacity; mutable size_t mNextObjectHint; mutable bool mFdsKnown; mutable bool mHasFds; release_func mOwner; void* mOwnerCookie; }; // --------------------------------------------------------------------------- inline TextOutput& operator<<(TextOutput& to, const Parcel& parcel) { parcel.print(to); return to; } // --------------------------------------------------------------------------- // Generic acquire and release of objects. void acquire_object(const sp<ProcessState>& proc, const flat_binder_object& obj, const void* who); void release_object(const sp<ProcessState>& proc, const flat_binder_object& obj, const void* who); void flatten_binder(const sp<ProcessState>& proc, const sp<IBinder>& binder, flat_binder_object* out); void flatten_binder(const sp<ProcessState>& proc, const wp<IBinder>& binder, flat_binder_object* out); status_t unflatten_binder(const sp<ProcessState>& proc, const flat_binder_object& flat, sp<IBinder>* out); status_t unflatten_binder(const sp<ProcessState>& proc, const flat_binder_object& flat, wp<IBinder>* out); }; // namespace android // --------------------------------------------------------------------------- #endif // ANDROID_PARCEL_H

/* * Copyright (C) 2005 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "Parcel" //#define LOG_NDEBUG 0 #include <binder/Parcel.h> #include <binder/Binder.h> #include <binder/BpBinder.h> #include <utils/Debug.h> #include <binder/ProcessState.h> #include <utils/Log.h> #include <utils/String8.h> #include <utils/String16.h> #include <utils/TextOutput.h> #include <utils/misc.h> #include <utils/Flattenable.h> #include <private/binder/binder_module.h> #include <stdio.h> #include <stdlib.h> #include <stdint.h> #ifndef INT32_MAX #define INT32_MAX ((int32_t)(2147483647)) #endif #define LOG_REFS(...) //#define LOG_REFS(...) LOG(LOG_DEBUG, "Parcel", __VA_ARGS__) // --------------------------------------------------------------------------- #define PAD_SIZE(s) (((s)+3)&~3) // XXX This can be made public if we want to provide // support for typed data. struct small_flat_data { uint32_t type; uint32_t data; }; namespace android { void acquire_object(const sp<ProcessState>& proc, const flat_binder_object& obj, const void* who) { switch (obj.type) { case BINDER_TYPE_BINDER: if (obj.binder) { LOG_REFS("Parcel %p acquiring reference on local %p", who, obj.cookie); static_cast<IBinder*>(obj.cookie)->incStrong(who); } return; case BINDER_TYPE_WEAK_BINDER: if (obj.binder) static_cast<RefBase::weakref_type*>(obj.binder)->incWeak(who); return; case BINDER_TYPE_HANDLE: { const sp<IBinder> b = proc->getStrongProxyForHandle(obj.handle); if (b != NULL) { LOG_REFS("Parcel %p acquiring reference on remote %p", who, b.get()); b->incStrong(who); } return; } case BINDER_TYPE_WEAK_HANDLE: { const wp<IBinder> b = proc->getWeakProxyForHandle(obj.handle); if (b != NULL) b.get_refs()->incWeak(who); return; } case BINDER_TYPE_FD: { // intentionally blank -- nothing to do to acquire this, but we do // recognize it as a legitimate object type. return; } } LOGD("Invalid object type 0x%08lx", obj.type); } void release_object(const sp<ProcessState>& proc, const flat_binder_object& obj, const void* who) { switch (obj.type) { case BINDER_TYPE_BINDER: if (obj.binder) { LOG_REFS("Parcel %p releasing reference on local %p", who, obj.cookie); static_cast<IBinder*>(obj.cookie)->decStrong(who); } return; case BINDER_TYPE_WEAK_BINDER: if (obj.binder) static_cast<RefBase::weakref_type*>(obj.binder)->decWeak(who); return; case BINDER_TYPE_HANDLE: { const sp<IBinder> b = proc->getStrongProxyForHandle(obj.handle); if (b != NULL) { LOG_REFS("Parcel %p releasing reference on remote %p", who, b.get()); b->decStrong(who); } return; } case BINDER_TYPE_WEAK_HANDLE: { const wp<IBinder> b = proc->getWeakProxyForHandle(obj.handle); if (b != NULL) b.get_refs()->decWeak(who); return; } case BINDER_TYPE_FD: { if (obj.cookie != (void*)0) close(obj.handle); return; } } LOGE("Invalid object type 0x%08lx", obj.type); } inline static status_t finish_flatten_binder( const sp<IBinder>& binder, const flat_binder_object& flat, Parcel* out) { return out->writeObject(flat, false); } status_t flatten_binder(const sp<ProcessState>& proc, const sp<IBinder>& binder, Parcel* out) { flat_binder_object obj; obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS; if (binder != NULL) { IBinder *local = binder->localBinder(); if (!local) { BpBinder *proxy = binder->remoteBinder(); if (proxy == NULL) { LOGE("null proxy"); } const int32_t handle = proxy ? proxy->handle() : 0; obj.type = BINDER_TYPE_HANDLE; obj.handle = handle; obj.cookie = NULL; } 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); } status_t flatten_binder(const sp<ProcessState>& proc, const wp<IBinder>& binder, Parcel* out) { flat_binder_object obj; obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS; if (binder != NULL) { sp<IBinder> real = binder.promote(); if (real != NULL) { IBinder *local = real->localBinder(); if (!local) { BpBinder *proxy = real->remoteBinder(); if (proxy == NULL) { LOGE("null proxy"); } const int32_t handle = proxy ? proxy->handle() : 0; obj.type = BINDER_TYPE_WEAK_HANDLE; obj.handle = handle; obj.cookie = NULL; } else { obj.type = BINDER_TYPE_WEAK_BINDER; obj.binder = binder.get_refs(); obj.cookie = binder.unsafe_get(); } return finish_flatten_binder(real, obj, out); } // XXX How to deal? In order to flatten the given binder, // we need to probe it for information, which requires a primary // reference... but we don't have one. // // The OpenBinder implementation uses a dynamic_cast<> here, // but we can't do that with the different reference counting // implementation we are using. LOGE("Unable to unflatten Binder weak reference!"); obj.type = BINDER_TYPE_BINDER; obj.binder = NULL; obj.cookie = NULL; return finish_flatten_binder(NULL, obj, out); } else { obj.type = BINDER_TYPE_BINDER; obj.binder = NULL; obj.cookie = NULL; return finish_flatten_binder(NULL, obj, out); } } inline static status_t finish_unflatten_binder( BpBinder* proxy, const flat_binder_object& flat, const Parcel& in) { return NO_ERROR; } 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) { case BINDER_TYPE_BINDER: *out = static_cast<IBinder*>(flat->cookie); return finish_unflatten_binder(NULL, *flat, in); case BINDER_TYPE_HANDLE: *out = proc->getStrongProxyForHandle(flat->handle); return finish_unflatten_binder( static_cast<BpBinder*>(out->get()), *flat, in); } } return BAD_TYPE; } status_t unflatten_binder(const sp<ProcessState>& proc, const Parcel& in, wp<IBinder>* out) { const flat_binder_object* flat = in.readObject(false); if (flat) { switch (flat->type) { case BINDER_TYPE_BINDER: *out = static_cast<IBinder*>(flat->cookie); return finish_unflatten_binder(NULL, *flat, in); case BINDER_TYPE_WEAK_BINDER: if (flat->binder != NULL) { out->set_object_and_refs( static_cast<IBinder*>(flat->cookie), static_cast<RefBase::weakref_type*>(flat->binder)); } else { *out = NULL; } return finish_unflatten_binder(NULL, *flat, in); case BINDER_TYPE_HANDLE: case BINDER_TYPE_WEAK_HANDLE: *out = proc->getWeakProxyForHandle(flat->handle); return finish_unflatten_binder( static_cast<BpBinder*>(out->unsafe_get()), *flat, in); } } return BAD_TYPE; } // --------------------------------------------------------------------------- Parcel::Parcel() { initState(); } Parcel::~Parcel() { freeDataNoInit(); } const uint8_t* Parcel::data() const { return mData; } size_t Parcel::dataSize() const { return (mDataSize > mDataPos ? mDataSize : mDataPos); } size_t Parcel::dataAvail() const { // TODO: decide what to do about the possibility that this can // report an available-data size that exceeds a Java int's max // positive value, causing havoc. Fortunately this will only // happen if someone constructs a Parcel containing more than two // gigabytes of data, which on typical phone hardware is simply // not possible. return dataSize() - dataPosition(); } size_t Parcel::dataPosition() const { return mDataPos; } size_t Parcel::dataCapacity() const { return mDataCapacity; } status_t Parcel::setDataSize(size_t size) { status_t err; err = continueWrite(size); if (err == NO_ERROR) { mDataSize = size; LOGV("setDataSize Setting data size of %p to %d/n", this, mDataSize); } return err; } void Parcel::setDataPosition(size_t pos) const { mDataPos = pos; mNextObjectHint = 0; } status_t Parcel::setDataCapacity(size_t size) { if (size > mDataSize) return continueWrite(size); return NO_ERROR; } status_t Parcel::setData(const uint8_t* buffer, size_t len) { status_t err = restartWrite(len); if (err == NO_ERROR) { memcpy(const_cast<uint8_t*>(data()), buffer, len); mDataSize = len; mFdsKnown = false; } return err; } status_t Parcel::appendFrom(Parcel *parcel, size_t offset, size_t len) { const sp<ProcessState> proc(ProcessState::self()); status_t err; uint8_t *data = parcel->mData; size_t *objects = parcel->mObjects; size_t size = parcel->mObjectsSize; int startPos = mDataPos; int firstIndex = -1, lastIndex = -2; if (len == 0) { return NO_ERROR; } // range checks against the source parcel size if ((offset > parcel->mDataSize) || (len > parcel->mDataSize) || (offset + len > parcel->mDataSize)) { return BAD_VALUE; } // Count objects in range for (int i = 0; i < (int) size; i++) { size_t off = objects[i]; if ((off >= offset) && (off < offset + len)) { if (firstIndex == -1) { firstIndex = i; } lastIndex = i; } } int numObjects = lastIndex - firstIndex + 1; // grow data err = growData(len); if (err != NO_ERROR) { return err; } // append data memcpy(mData + mDataPos, data + offset, len); mDataPos += len; mDataSize += len; if (numObjects > 0) { // grow objects if (mObjectsCapacity < mObjectsSize + numObjects) { int newSize = ((mObjectsSize + numObjects)*3)/2; size_t *objects = (size_t*)realloc(mObjects, newSize*sizeof(size_t)); if (objects == (size_t*)0) { return NO_MEMORY; } mObjects = objects; mObjectsCapacity = newSize; } // append and acquire objects int idx = mObjectsSize; for (int i = firstIndex; i <= lastIndex; i++) { size_t off = objects[i] - offset + startPos; mObjects[idx++] = off; mObjectsSize++; flat_binder_object* flat = reinterpret_cast<flat_binder_object*>(mData + off); acquire_object(proc, *flat, this); if (flat->type == BINDER_TYPE_FD) { // If this is a file descriptor, we need to dup it so the // new Parcel now owns its own fd, and can declare that we // officially know we have fds. flat->handle = dup(flat->handle); flat->cookie = (void*)1; mHasFds = mFdsKnown = true; } } } return NO_ERROR; } bool Parcel::hasFileDescriptors() const { if (!mFdsKnown) { scanForFds(); } return mHasFds; } status_t Parcel::writeInterfaceToken(const String16& interface) { // currently the interface identification token is just its name as a string return writeString16(interface); } bool Parcel::checkInterface(IBinder* binder) const { return enforceInterface(binder->getInterfaceDescriptor()); } bool Parcel::enforceInterface(const String16& interface) const { const String16 str(readString16()); if (str == interface) { return true; } else { LOGW("**** enforceInterface() expected '%s' but read '%s'/n", String8(interface).string(), String8(str).string()); return false; } } const size_t* Parcel::objects() const { return mObjects; } size_t Parcel::objectsCount() const { return mObjectsSize; } status_t Parcel::errorCheck() const { return mError; } void Parcel::setError(status_t err) { mError = err; } status_t Parcel::finishWrite(size_t len) { //printf("Finish write of %d/n", len); mDataPos += len; LOGV("finishWrite Setting data pos of %p to %d/n", this, mDataPos); if (mDataPos > mDataSize) { mDataSize = mDataPos; LOGV("finishWrite Setting data size of %p to %d/n", this, mDataSize); } //printf("New pos=%d, size=%d/n", mDataPos, mDataSize); return NO_ERROR; } status_t Parcel::writeUnpadded(const void* data, size_t len) { size_t end = mDataPos + len; if (end < mDataPos) { // integer overflow return BAD_VALUE; } if (end <= mDataCapacity) { restart_write: memcpy(mData+mDataPos, data, len); return finishWrite(len); } status_t err = growData(len); if (err == NO_ERROR) goto restart_write; return err; } status_t Parcel::write(const void* data, size_t len) { void* const d = writeInplace(len); if (d) { memcpy(d, data, len); return NO_ERROR; } return mError; } void* Parcel::writeInplace(size_t len) { const size_t padded = PAD_SIZE(len); // sanity check for integer overflow if (mDataPos+padded < mDataPos) { return NULL; } if ((mDataPos+padded) <= mDataCapacity) { restart_write: //printf("Writing %ld bytes, padded to %ld/n", len, padded); uint8_t* const data = mData+mDataPos; // Need to pad at end? if (padded != len) { #if BYTE_ORDER == BIG_ENDIAN static const uint32_t mask[4] = { 0x00000000, 0xffffff00, 0xffff0000, 0xff000000 }; #endif #if BYTE_ORDER == LITTLE_ENDIAN static const uint32_t mask[4] = { 0x00000000, 0x00ffffff, 0x0000ffff, 0x000000ff }; #endif //printf("Applying pad mask: %p to %p/n", (void*)mask[padded-len], // *reinterpret_cast<void**>(data+padded-4)); *reinterpret_cast<uint32_t*>(data+padded-4) &= mask[padded-len]; } finishWrite(padded); return data; } status_t err = growData(padded); if (err == NO_ERROR) goto restart_write; return NULL; } status_t Parcel::writeInt32(int32_t val) { return writeAligned(val); } status_t Parcel::writeInt64(int64_t val) { return writeAligned(val); } status_t Parcel::writeFloat(float val) { return writeAligned(val); } status_t Parcel::writeDouble(double val) { return writeAligned(val); } status_t Parcel::writeIntPtr(intptr_t val) { return writeAligned(val); } status_t Parcel::writeCString(const char* str) { return write(str, strlen(str)+1); } status_t Parcel::writeString8(const String8& str) { status_t err = writeInt32(str.bytes()); if (err == NO_ERROR) { err = write(str.string(), str.bytes()+1); } return err; } status_t Parcel::writeString16(const String16& str) { return writeString16(str.string(), str.size()); } 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::writeStrongBinder(const sp<IBinder>& val) { return flatten_binder(ProcessState::self(), val, this); } status_t Parcel::writeWeakBinder(const wp<IBinder>& val) { return flatten_binder(ProcessState::self(), val, this); } status_t Parcel::writeNativeHandle(const native_handle* handle) { if (!handle || handle->version != sizeof(native_handle)) return BAD_TYPE; status_t err; err = writeInt32(handle->numFds); if (err != NO_ERROR) return err; err = writeInt32(handle->numInts); if (err != NO_ERROR) return err; for (int i=0 ; err==NO_ERROR && i<handle->numFds ; i++) err = writeDupFileDescriptor(handle->data[i]); if (err != NO_ERROR) { LOGD("write native handle, write dup fd failed"); return err; } err = write(handle->data + handle->numFds, sizeof(int)*handle->numInts); return err; } status_t Parcel::writeFileDescriptor(int fd) { flat_binder_object obj; obj.type = BINDER_TYPE_FD; obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS; obj.handle = fd; obj.cookie = (void*)0; return writeObject(obj, true); } status_t Parcel::writeDupFileDescriptor(int fd) { flat_binder_object obj; obj.type = BINDER_TYPE_FD; obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS; obj.handle = dup(fd); obj.cookie = (void*)1; return writeObject(obj, true); } status_t Parcel::write(const Flattenable& val) { status_t err; // size if needed size_t len = val.getFlattenedSize(); size_t fd_count = val.getFdCount(); err = this->writeInt32(len); if (err) return err; err = this->writeInt32(fd_count); if (err) return err; // payload void* buf = this->writeInplace(PAD_SIZE(len)); if (buf == NULL) return BAD_VALUE; int* fds = NULL; if (fd_count) { fds = new int[fd_count]; } err = val.flatten(buf, len, fds, fd_count); for (size_t i=0 ; i<fd_count && err==NO_ERROR ; i++) { err = this->writeDupFileDescriptor( fds[i] ); } if (fd_count) { delete [] fds; } return err; } 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) { 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; } void Parcel::remove(size_t start, size_t amt) { LOG_ALWAYS_FATAL("Parcel::remove() not yet implemented!"); } status_t Parcel::read(void* outData, size_t len) const { if ((mDataPos+PAD_SIZE(len)) >= mDataPos && (mDataPos+PAD_SIZE(len)) <= mDataSize) { memcpy(outData, mData+mDataPos, len); mDataPos += PAD_SIZE(len); LOGV("read Setting data pos of %p to %d/n", this, mDataPos); return NO_ERROR; } return NOT_ENOUGH_DATA; } const void* Parcel::readInplace(size_t len) const { if ((mDataPos+PAD_SIZE(len)) >= mDataPos && (mDataPos+PAD_SIZE(len)) <= mDataSize) { const void* data = mData+mDataPos; mDataPos += PAD_SIZE(len); LOGV("readInplace Setting data pos of %p to %d/n", this, mDataPos); return data; } return NULL; } template<class T> status_t Parcel::readAligned(T *pArg) const { COMPILE_TIME_ASSERT_FUNCTION_SCOPE(PAD_SIZE(sizeof(T)) == sizeof(T)); if ((mDataPos+sizeof(T)) <= mDataSize) { const void* data = mData+mDataPos; mDataPos += sizeof(T); *pArg = *reinterpret_cast<const T*>(data); return NO_ERROR; } else { return NOT_ENOUGH_DATA; } } template<class T> T Parcel::readAligned() const { T result; if (readAligned(&result) != NO_ERROR) { result = 0; } return result; } template<class T> status_t Parcel::writeAligned(T val) { COMPILE_TIME_ASSERT_FUNCTION_SCOPE(PAD_SIZE(sizeof(T)) == sizeof(T)); if ((mDataPos+sizeof(val)) <= mDataCapacity) { restart_write: *reinterpret_cast<T*>(mData+mDataPos) = val; return finishWrite(sizeof(val)); } status_t err = growData(sizeof(val)); if (err == NO_ERROR) goto restart_write; return err; } status_t Parcel::readInt32(int32_t *pArg) const { return readAligned(pArg); } int32_t Parcel::readInt32() const { return readAligned<int32_t>(); } status_t Parcel::readInt64(int64_t *pArg) const { return readAligned(pArg); } int64_t Parcel::readInt64() const { return readAligned<int64_t>(); } status_t Parcel::readFloat(float *pArg) const { return readAligned(pArg); } float Parcel::readFloat() const { return readAligned<float>(); } status_t Parcel::readDouble(double *pArg) const { return readAligned(pArg); } double Parcel::readDouble() const { return readAligned<double>(); } status_t Parcel::readIntPtr(intptr_t *pArg) const { return readAligned(pArg); } intptr_t Parcel::readIntPtr() const { return readAligned<intptr_t>(); } const char* Parcel::readCString() const { const size_t avail = mDataSize-mDataPos; if (avail > 0) { const char* str = reinterpret_cast<const char*>(mData+mDataPos); // is the string's trailing NUL within the parcel's valid bounds? const char* eos = reinterpret_cast<const char*>(memchr(str, 0, avail)); if (eos) { const size_t len = eos - str; mDataPos += PAD_SIZE(len+1); LOGV("readCString Setting data pos of %p to %d/n", this, mDataPos); return str; } } return NULL; } String8 Parcel::readString8() const { int32_t size = readInt32(); // watch for potential int overflow adding 1 for trailing NUL if (size > 0 && size < INT32_MAX) { const char* str = (const char*)readInplace(size+1); if (str) return String8(str, size); } return String8(); } String16 Parcel::readString16() const { size_t len; const char16_t* str = readString16Inplace(&len); if (str) return String16(str, len); LOGE("Reading a NULL string not supported here."); return String16(); } const char16_t* Parcel::readString16Inplace(size_t* outLen) const { int32_t size = readInt32(); // watch for potential int overflow from size+1 if (size >= 0 && size < INT32_MAX) { *outLen = size; const char16_t* str = (const char16_t*)readInplace((size+1)*sizeof(char16_t)); if (str != NULL) { return str; } } *outLen = 0; return NULL; } sp<IBinder> Parcel::readStrongBinder() const { sp<IBinder> val; unflatten_binder(ProcessState::self(), *this, &val); return val; } wp<IBinder> Parcel::readWeakBinder() const { wp<IBinder> val; unflatten_binder(ProcessState::self(), *this, &val); return val; } native_handle* Parcel::readNativeHandle() const { int numFds, numInts; status_t err; err = readInt32(&numFds); if (err != NO_ERROR) return 0; err = readInt32(&numInts); if (err != NO_ERROR) return 0; native_handle* h = native_handle_create(numFds, numInts); for (int i=0 ; err==NO_ERROR && i<numFds ; i++) { h->data[i] = dup(readFileDescriptor()); if (h->data[i] < 0) err = BAD_VALUE; } err = read(h->data + numFds, sizeof(int)*numInts); if (err != NO_ERROR) { native_handle_close(h); native_handle_delete(h); h = 0; } return h; } int Parcel::readFileDescriptor() const { const flat_binder_object* flat = readObject(true); if (flat) { switch (flat->type) { case BINDER_TYPE_FD: //LOGI("Returning file descriptor %ld from parcel %p/n", flat->handle, this); return flat->handle; } } return BAD_TYPE; } status_t Parcel::read(Flattenable& val) const { // size const size_t len = this->readInt32(); const size_t fd_count = this->readInt32(); // payload void const* buf = this->readInplace(PAD_SIZE(len)); if (buf == NULL) return BAD_VALUE; int* fds = NULL; if (fd_count) { fds = new int[fd_count]; } status_t err = NO_ERROR; for (size_t i=0 ; i<fd_count && err==NO_ERROR ; i++) { fds[i] = dup(this->readFileDescriptor()); if (fds[i] < 0) err = BAD_VALUE; } if (err == NO_ERROR) { err = val.unflatten(buf, len, fds, fd_count); } if (fd_count) { delete [] fds; } return err; } 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)) { // When transferring a NULL object, we don't write it into // the object list, so we don't want to check for it when // reading. LOGV("readObject Setting data pos of %p to %d/n", this, mDataPos); 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) { LOGV("Parcel %p looking for obj at %d, hint=%d/n", this, DPOS, opos); // 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) { // Found it! LOGV("Parcel found obj %d at index %d with forward search", this, DPOS, opos); mNextObjectHint = opos+1; LOGV("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! LOGV("Parcel found obj %d at index %d with backward search", this, DPOS, opos); mNextObjectHint = opos+1; LOGV("readObject Setting data pos of %p to %d/n", this, mDataPos); return obj; } } LOGW("Attempt to read object from Parcel %p at offset %d that is not in the object list", this, DPOS); } return NULL; } void Parcel::closeFileDescriptors() { size_t i = mObjectsSize; if (i > 0) { //LOGI("Closing file descriptors for %d objects...", mObjectsSize); } while (i > 0) { i--; const flat_binder_object* flat = reinterpret_cast<flat_binder_object*>(mData+mObjects[i]); if (flat->type == BINDER_TYPE_FD) { //LOGI("Closing fd: %ld/n", flat->handle); close(flat->handle); } } } const uint8_t* Parcel::ipcData() const { return mData; } size_t Parcel::ipcDataSize() const { return (mDataSize > mDataPos ? mDataSize : mDataPos); } const size_t* Parcel::ipcObjects() const { return mObjects; } size_t Parcel::ipcObjectsCount() const { return mObjectsSize; } void Parcel::ipcSetDataReference(const uint8_t* data, size_t dataSize, const size_t* objects, size_t objectsCount, release_func relFunc, void* relCookie) { freeDataNoInit(); mError = NO_ERROR; mData = const_cast<uint8_t*>(data); mDataSize = mDataCapacity = dataSize; //LOGI("setDataReference Setting data size of %p to %lu (pid=%d)/n", this, mDataSize, getpid()); mDataPos = 0; LOGV("setDataReference Setting data pos of %p to %d/n", this, mDataPos); mObjects = const_cast<size_t*>(objects); mObjectsSize = mObjectsCapacity = objectsCount; mNextObjectHint = 0; mOwner = relFunc; mOwnerCookie = relCookie; scanForFds(); } void Parcel::print(TextOutput& to, uint32_t flags) const { to << "Parcel("; if (errorCheck() != NO_ERROR) { const status_t err = errorCheck(); to << "Error: " << (void*)err << " /"" << strerror(-err) << "/""; } else if (dataSize() > 0) { const uint8_t* DATA = data(); to << indent << HexDump(DATA, dataSize()) << dedent; const size_t* OBJS = objects(); const size_t N = objectsCount(); for (size_t i=0; i<N; i++) { const flat_binder_object* flat = reinterpret_cast<const flat_binder_object*>(DATA+OBJS[i]); to << endl << "Object #" << i << " @ " << (void*)OBJS[i] << ": " << TypeCode(flat->type & 0x7f7f7f00) << " = " << flat->binder; } } else { to << "NULL"; } to << ")"; } void Parcel::releaseObjects() { const sp<ProcessState> proc(ProcessState::self()); size_t i = mObjectsSize; uint8_t* const data = mData; size_t* const objects = mObjects; while (i > 0) { i--; const flat_binder_object* flat = reinterpret_cast<flat_binder_object*>(data+objects[i]); release_object(proc, *flat, this); } } void Parcel::acquireObjects() { const sp<ProcessState> proc(ProcessState::self()); size_t i = mObjectsSize; uint8_t* const data = mData; size_t* const objects = mObjects; while (i > 0) { i--; const flat_binder_object* flat = reinterpret_cast<flat_binder_object*>(data+objects[i]); acquire_object(proc, *flat, this); } } void Parcel::freeData() { freeDataNoInit(); initState(); } void Parcel::freeDataNoInit() { if (mOwner) { //LOGI("Freeing data ref of %p (pid=%d)/n", this, getpid()); mOwner(this, mData, mDataSize, mObjects, mObjectsSize, mOwnerCookie); } else { releaseObjects(); if (mData) free(mData); if (mObjects) free(mObjects); } } status_t Parcel::growData(size_t len) { size_t newSize = ((mDataSize+len)*3)/2; return (newSize <= mDataSize) ? (status_t) NO_MEMORY : continueWrite(newSize); } status_t Parcel::restartWrite(size_t desired) { if (mOwner) { freeData(); return continueWrite(desired); } uint8_t* data = (uint8_t*)realloc(mData, desired); if (!data && desired > mDataCapacity) { mError = NO_MEMORY; return NO_MEMORY; } releaseObjects(); if (data) { mData = data; mDataCapacity = desired; } mDataSize = mDataPos = 0; LOGV("restartWrite Setting data size of %p to %d/n", this, mDataSize); LOGV("restartWrite Setting data pos of %p to %d/n", this, mDataPos); free(mObjects); mObjects = NULL; mObjectsSize = mObjectsCapacity = 0; mNextObjectHint = 0; mHasFds = false; mFdsKnown = true; return NO_ERROR; } status_t Parcel::continueWrite(size_t desired) { // If shrinking, first adjust for any objects that appear // after the new data size. size_t objectsSize = mObjectsSize; if (desired < mDataSize) { if (desired == 0) { objectsSize = 0; } else { while (objectsSize > 0) { if (mObjects[objectsSize-1] < desired) break; objectsSize--; } } } if (mOwner) { // If the size is going to zero, just release the owner's data. if (desired == 0) { freeData(); return NO_ERROR; } // If there is a different owner, we need to take // posession. uint8_t* data = (uint8_t*)malloc(desired); if (!data) { mError = NO_MEMORY; return NO_MEMORY; } size_t* objects = NULL; if (objectsSize) { objects = (size_t*)malloc(objectsSize*sizeof(size_t)); if (!objects) { mError = NO_MEMORY; return NO_MEMORY; } // Little hack to only acquire references on objects // we will be keeping. 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)); } //LOGI("Freeing data ref of %p (pid=%d)/n", this, getpid()); mOwner(this, mData, mDataSize, mObjects, mObjectsSize, mOwnerCookie); mOwner = NULL; mData = data; mObjects = objects; mDataSize = (mDataSize < desired) ? mDataSize : desired; LOGV("continueWrite Setting data size of %p to %d/n", this, mDataSize); mDataCapacity = desired; mObjectsSize = mObjectsCapacity = objectsSize; mNextObjectHint = 0; } else if (mData) { if (objectsSize < mObjectsSize) { // Need to release refs on any objects we are dropping. const sp<ProcessState> proc(ProcessState::self()); 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; } // We own the data, so we can just do a realloc(). 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 { mDataSize = desired; LOGV("continueWrite Setting data size of %p to %d/n", this, mDataSize); if (mDataPos > desired) { mDataPos = desired; LOGV("continueWrite Setting data pos of %p to %d/n", this, mDataPos); } } } else { // This is the first data. Easy! uint8_t* data = (uint8_t*)malloc(desired); if (!data) { mError = NO_MEMORY; return NO_MEMORY; } if(!(mDataCapacity == 0 && mObjects == NULL && mObjectsCapacity == 0)) { LOGE("continueWrite: %d/%p/%d/%d", mDataCapacity, mObjects, mObjectsCapacity, desired); } mData = data; mDataSize = mDataPos = 0; LOGV("continueWrite Setting data size of %p to %d/n", this, mDataSize); LOGV("continueWrite Setting data pos of %p to %d/n", this, mDataPos); mDataCapacity = desired; } return NO_ERROR; } void Parcel::initState() { mError = NO_ERROR; mData = 0; mDataSize = 0; mDataCapacity = 0; mDataPos = 0; LOGV("initState Setting data size of %p to %d/n", this, mDataSize); LOGV("initState Setting data pos of %p to %d/n", this, mDataPos); mObjects = NULL; mObjectsSize = 0; mObjectsCapacity = 0; mNextObjectHint = 0; mHasFds = false; mFdsKnown = true; mOwner = NULL; } void Parcel::scanForFds() const { bool hasFds = false; for (size_t i=0; i<mObjectsSize; i++) { const flat_binder_object* flat = reinterpret_cast<const flat_binder_object*>(mData + mObjects[i]); if (flat->type == BINDER_TYPE_FD) { hasFds = true; break; } } mHasFds = hasFds; mFdsKnown = true; } }; // namespace android

本文的源代码使用的是Android 2.1版本号。

——欢迎转载,请注明出处 http://blog.csdn.net/caowenbin ——

探索Android中的Parcel机制(上)相关推荐

  1. 探索Android中的Parcel机制(上) .

    一.先从Serialize说起 我们都知道JAVA中的Serialize机制,译成串行化.序列化--,其作用是能将数据对象存入字节流当中,在需要时重新生成对象.主要应用是利用外部存储设备保存对象状态, ...

  2. 探索Android中的Parcel机制(下)

    上一篇中我们透过源码看到了Parcel背后的机制,本质上把它当成一个Serialize就可以了,只是它是在内存中完成的序列化和反序列化,利用的是连续的内存空间,因此会更加高效. 我们接下来要说的是Pa ...

  3. 浅析Android中的消息机制

    在分析Android消息机制之前,我们先来看一段代码: [java] view plaincopy public class MainActivity extends Activity impleme ...

  4. android classloader异常,Android中ClassLoader类加载机制

    Android中apk的构建过程 构建apk 如图 所示,典型 Android 应用模块的构建流程通常依循下列步骤: 编译器将您的源代码转换成 DEX(Dalvik Executable) 文件(其中 ...

  5. Android中Alarm的机制

    本次给大家分析的是Android中Alarm的机制所用源码为最新的Android4.4.4.首先简单介绍如何使用Alarm并给出其工作原理,接着分析Alarm和Timer以及Handler在完成定时任 ...

  6. android系统的alarm机制,Android中Alarm的机制

    本次给大家分析的是Android中Alarm的机制所用源码为最新的Android4.4.4.首先简单介绍如何使用Alarm并给出其工作原理,接着分析Alarm和Timer以及Handler在完成定时任 ...

  7. Android中的消息机制

    Android 中的消息机制其实就是指的是 Handler 消息机制以及附带的 Looper 和 MessageQueue 的工作流程. 1.Android 为什么提供Handler? 解决子线程不能 ...

  8. 重温Android中的消息机制

    引入: 提到Android中的消息机制,大家应该都不陌生,我们在开发中不可避免的要和它打交道.从我们开发的角度来看,Handler是Android消息机制的上层接口.我们在平时的开发中只需要和Hand ...

  9. Android中的IPC机制

    Android IPC简介 IPC是Inter-Process Communication的缩写,含义就是进程间通信或者跨进程通信,是指两个进程之间进行数据交换的过程.那么什么是进程,什么是线程,进程 ...

最新文章

  1. 分类问题中的“维数灾难” - robotMax
  2. ssh vim中不小心按下ctrl+s
  3. php 钩子,php钩子原理是什么
  4. 更新!机器学习手推笔记《规则学习》
  5. 圆形指示器radialIndicator控件的使用
  6. java GoF 的 23 种设计模式的分类和功能
  7. 专业好用的数据恢复软件推荐
  8. 设计模式-结构型模式(读书笔记)
  9. android 手机头提示消息,正确的手机头部声明(android,iphone)
  10. Excel数据透视表学习
  11. 姓名拼音首字母缩写_2020年顶级网络安全首字母缩写
  12. 一分钟教你解决——浏览器代理服务器被篡改
  13. 在校学生适合的云服务器有哪些?
  14. 最新杭州地铁开通时间表
  15. 腾讯信鸽集成华为厂商通道
  16. android h5富文本编辑器,H5富文本编辑器的详细介绍
  17. AT8637S(PHS/EN输入接口单通道0.8A低压H桥IC)
  18. Java EE开发基础
  19. 3.文件系统组成和基本操作
  20. 关于MySQL 出现问题:1264 - Out of range value for column 'columns' at row 167

热门文章

  1. String.Split()函数
  2. 基于NopCommerce的开源电商系统改造总结
  3. Python 列表(数组)初识
  4. activiti主要API对象
  5. SQL Server 跨域访问
  6. 基于经验的SOA成功原则
  7. 威尔士柯基犬,计算机视觉,以及深度学习的力量
  8. iOS9 Search API 之 Spotlight
  9. 使用 icon 字体图标出现小方块问题
  10. 洛谷P4550 收集邮票(概率期望)