一.先从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版本。

最新文章

  1. 自己动手之使用反射和泛型,动态读取XML创建类实例并赋值
  2. iOS Wi-Fi
  3. 使用Innosetup制作安装包的一些技巧
  4. Android ViewHolder的作用与用法
  5. BZOJ4340 : BJOI2015 隐身术
  6. css样式表:样式分类,选择器。样式属性,格式与布局
  7. 中颖4位MCU的减法汇编指令
  8. postgresql异常快速定位
  9. 用supervisor控制celery时的脚本
  10. ADO.NET 快速入门(二):执行命令
  11. Codeforces Beta Round #51 A. Flea travel 水题
  12. uva 10739
  13. JQ实现复选框的全选反选不选
  14. oschina娱乐游戏
  15. c#与java中byte字节的区别及转换方法
  16. dwz框架---(2)表单回调函数
  17. Users is not mapped(Hibernate实体类采用注解)
  18. VUE中v-on:click事件中获取当前dom元素
  19. Retry模式
  20. Reverse Words in a String leetcode java

热门文章

  1. pip配置阿里云源
  2. 125K低频唤醒芯片SI393可替代AS3933,GS3933
  3. vue eslint修改为4个空格
  4. python 对列表中任意两个数进行操作 (python operate any two elements in list)
  5. 58. jdk1.5新特性之静态导入
  6. 高性能js之js文件的加载与解析
  7. pandas for python
  8. WebStorm编辑器
  9. js实现超简单sku组合算法
  10. STM32嵌入式开发学习笔记(七):串口通信(下)