2019独角兽企业重金招聘Python工程师标准>>>
一.先从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
*
*
*
* 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
#include
#include
#include
#include
// ---------------------------------------------------------------------------
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& val);
status_t writeWeakBinder(const wp& 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 readStrongBinder() const;
wp 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
status_t readAligned(T *pArg) const;
template T readAligned() const;
template
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& proc,
const flat_binder_object& obj, const void* who);
void release_object(const sp& proc,
const flat_binder_object& obj, const void* who);
void flatten_binder(const sp& proc,
const sp& binder, flat_binder_object* out);
void flatten_binder(const sp& proc,
const wp& binder, flat_binder_object* out);
status_t unflatten_binder(const sp& proc,
const flat_binder_object& flat, sp* out);
status_t unflatten_binder(const sp& proc,
const flat_binder_object& flat, wp* out);
}; // namespace android
// ---------------------------------------------------------------------------
#endif // ANDROID_PARCEL_H
本文的源码使用的是Android 2.1版本。