http://blog.csdn.net/caowenbin/article/details/6532217
一.先从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();