/*
* Copyright (C) 2006 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.
*/
package android.os;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;
import android.util.Size;
import android.util.SizeF;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileDescriptor;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamClass;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Container for a message (data and object references) that can
* be sent through an IBinder. A Parcel can contain both flattened data
* that will be unflattened on the other side of the IPC (using the various
* methods here for writing specific types, or the general
* {@link Parcelable} interface), and references to live {@link IBinder}
* objects that will result in the other side receiving a proxy IBinder
* connected with the original IBinder in the Parcel.
*
*
Parcel is not a general-purpose
* serialization mechanism. This class (and the corresponding
* {@link Parcelable} API for placing arbitrary objects into a Parcel) is
* designed as a high-performance IPC transport. As such, it is not
* appropriate to place any Parcel data in to persistent storage: changes
* in the underlying implementation of any of the data in the Parcel can
* render older data unreadable.
*
*
The bulk of the Parcel API revolves around reading and writing data
* of various types. There are six major classes of such functions available.
*
*
Primitives
*
*
The most basic data functions are for writing and reading primitive
* data types: {@link #writeByte}, {@link #readByte}, {@link #writeDouble},
* {@link #readDouble}, {@link #writeFloat}, {@link #readFloat}, {@link #writeInt},
* {@link #readInt}, {@link #writeLong}, {@link #readLong},
* {@link #writeString}, {@link #readString}. Most other
* data operations are built on top of these. The given data is written and
* read using the endianess of the host CPU.
*
*
Primitive Arrays
*
*
There are a variety of methods for reading and writing raw arrays
* of primitive objects, which generally result in writing a 4-byte length
* followed by the primitive data items. The methods for reading can either
* read the data into an existing array, or create and return a new array.
* These available types are:
The {@link Parcelable} protocol provides an extremely efficient (but
* low-level) protocol for objects to write and read themselves from Parcels.
* You can use the direct methods {@link #writeParcelable(Parcelable, int)}
* and {@link #readParcelable(ClassLoader)} or
* {@link #writeParcelableArray} and
* {@link #readParcelableArray(ClassLoader)} to write or read. These
* methods write both the class type and its data to the Parcel, allowing
* that class to be reconstructed from the appropriate class loader when
* later reading.
*
*
There are also some methods that provide a more efficient way to work
* with Parcelables: {@link #writeTypedObject}, {@link #writeTypedArray},
* {@link #writeTypedList}, {@link #readTypedObject},
* {@link #createTypedArray} and {@link #createTypedArrayList}. These methods
* do not write the class information of the original object: instead, the
* caller of the read function must know what type to expect and pass in the
* appropriate {@link Parcelable.Creator Parcelable.Creator} instead to
* properly construct the new object and read its data. (To more efficient
* write and read a single Parceable object that is not null, you can directly
* call {@link Parcelable#writeToParcel Parcelable.writeToParcel} and
* {@link Parcelable.Creator#createFromParcel Parcelable.Creator.createFromParcel}
* yourself.)
*
*
Bundles
*
*
A special type-safe container, called {@link Bundle}, is available
* for key/value maps of heterogeneous values. This has many optimizations
* for improved performance when reading and writing data, and its type-safe
* API avoids difficult to debug type errors when finally marshalling the
* data contents into a Parcel. The methods to use are
* {@link #writeBundle(Bundle)}, {@link #readBundle()}, and
* {@link #readBundle(ClassLoader)}.
*
*
Active Objects
*
*
An unusual feature of Parcel is the ability to read and write active
* objects. For these objects the actual contents of the object is not
* written, rather a special token referencing the object is written. When
* reading the object back from the Parcel, you do not get a new instance of
* the object, but rather a handle that operates on the exact same object that
* was originally written. There are two forms of active objects available.
*
*
{@link Binder} objects are a core facility of Android's general cross-process
* communication system. The {@link IBinder} interface describes an abstract
* protocol with a Binder object. Any such interface can be written in to
* a Parcel, and upon reading you will receive either the original object
* implementing that interface or a special proxy implementation
* that communicates calls back to the original object. The methods to use are
* {@link #writeStrongBinder(IBinder)},
* {@link #writeStrongInterface(IInterface)}, {@link #readStrongBinder()},
* {@link #writeBinderArray(IBinder[])}, {@link #readBinderArray(IBinder[])},
* {@link #createBinderArray()},
* {@link #writeBinderList(List)}, {@link #readBinderList(List)},
* {@link #createBinderArrayList()}.
*
*
FileDescriptor objects, representing raw Linux file descriptor identifiers,
* can be written and {@link ParcelFileDescriptor} objects returned to operate
* on the original file descriptor. The returned file descriptor is a dup
* of the original file descriptor: the object and fd is different, but
* operating on the same underlying file stream, with the same position, etc.
* The methods to use are {@link #writeFileDescriptor(FileDescriptor)},
* {@link #readFileDescriptor()}.
*
*
Untyped Containers
*
*
A final class of methods are for writing and reading standard Java
* containers of arbitrary types. These all revolve around the
* {@link #writeValue(Object)} and {@link #readValue(ClassLoader)} methods
* which define the types of objects allowed. The container methods are
* {@link #writeArray(Object[])}, {@link #readArray(ClassLoader)},
* {@link #writeList(List)}, {@link #readList(List, ClassLoader)},
* {@link #readArrayList(ClassLoader)},
* {@link #writeMap(Map)}, {@link #readMap(Map, ClassLoader)},
* {@link #writeSparseArray(SparseArray)},
* {@link #readSparseArray(ClassLoader)}.
*/
public final class Parcel {
private static final boolean DEBUG_RECYCLE = false;
private static final boolean DEBUG_ARRAY_MAP = false;
private static final String TAG = "Parcel";
@SuppressWarnings({"UnusedDeclaration"})
private long mNativePtr; // used by native code
/**
* Flag indicating if {@link #mNativePtr} was allocated by this object,
* indicating that we're responsible for its lifecycle.
*/
private boolean mOwnsNativeParcelObject;
private RuntimeException mStack;
private static final int POOL_SIZE = 6;
private static final Parcel[] sOwnedPool = new Parcel[POOL_SIZE];
private static final Parcel[] sHolderPool = new Parcel[POOL_SIZE];
private static final int VAL_NULL = -1;
private static final int VAL_STRING = 0;
private static final int VAL_INTEGER = 1;
private static final int VAL_MAP = 2;
private static final int VAL_BUNDLE = 3;
private static final int VAL_PARCELABLE = 4;
private static final int VAL_SHORT = 5;
private static final int VAL_LONG = 6;
private static final int VAL_FLOAT = 7;
private static final int VAL_DOUBLE = 8;
private static final int VAL_BOOLEAN = 9;
private static final int VAL_CHARSEQUENCE = 10;
private static final int VAL_LIST = 11;
private static final int VAL_SPARSEARRAY = 12;
private static final int VAL_BYTEARRAY = 13;
private static final int VAL_STRINGARRAY = 14;
private static final int VAL_IBINDER = 15;
private static final int VAL_PARCELABLEARRAY = 16;
private static final int VAL_OBJECTARRAY = 17;
private static final int VAL_INTARRAY = 18;
private static final int VAL_LONGARRAY = 19;
private static final int VAL_BYTE = 20;
private static final int VAL_SERIALIZABLE = 21;
private static final int VAL_SPARSEBOOLEANARRAY = 22;
private static final int VAL_BOOLEANARRAY = 23;
private static final int VAL_CHARSEQUENCEARRAY = 24;
private static final int VAL_PERSISTABLEBUNDLE = 25;
private static final int VAL_SIZE = 26;
private static final int VAL_SIZEF = 27;
// The initial int32 in a Binder call's reply Parcel header:
private static final int EX_SECURITY = -1;
private static final int EX_BAD_PARCELABLE = -2;
private static final int EX_ILLEGAL_ARGUMENT = -3;
private static final int EX_NULL_POINTER = -4;
private static final int EX_ILLEGAL_STATE = -5;
private static final int EX_NETWORK_MAIN_THREAD = -6;
private static final int EX_UNSUPPORTED_OPERATION = -7;
private static final int EX_HAS_REPLY_HEADER = -128; // special; see below
private static native int nativeDataSize(long nativePtr);
private static native int nativeDataAvail(long nativePtr);
private static native int nativeDataPosition(long nativePtr);
private static native int nativeDataCapacity(long nativePtr);
private static native void nativeSetDataSize(long nativePtr, int size);
private static native void nativeSetDataPosition(long nativePtr, int pos);
private static native void nativeSetDataCapacity(long nativePtr, int size);
private static native boolean nativePushAllowFds(long nativePtr, boolean allowFds);
private static native void nativeRestoreAllowFds(long nativePtr, boolean lastValue);
private static native void nativeWriteByteArray(long nativePtr, byte[] b, int offset, int len);
private static native void nativeWriteBlob(long nativePtr, byte[] b, int offset, int len);
private static native void nativeWriteInt(long nativePtr, int val);
private static native void nativeWriteLong(long nativePtr, long val);
private static native void nativeWriteFloat(long nativePtr, float val);
private static native void nativeWriteDouble(long nativePtr, double val);
private static native void nativeWriteString(long nativePtr, String val);
private static native void nativeWriteStrongBinder(long nativePtr, IBinder val);
private static native void nativeWriteFileDescriptor(long nativePtr, FileDescriptor val);
private static native byte[] nativeCreateByteArray(long nativePtr);
private static native byte[] nativeReadBlob(long nativePtr);
private static native int nativeReadInt(long nativePtr);
private static native long nativeReadLong(long nativePtr);
private static native float nativeReadFloat(long nativePtr);
private static native double nativeReadDouble(long nativePtr);
private static native String nativeReadString(long nativePtr);
private static native IBinder nativeReadStrongBinder(long nativePtr);
private static native FileDescriptor nativeReadFileDescriptor(long nativePtr);
private static native long nativeCreate();
private static native void nativeFreeBuffer(long nativePtr);
private static native void nativeDestroy(long nativePtr);
private static native byte[] nativeMarshall(long nativePtr);
private static native void nativeUnmarshall(
long nativePtr, byte[] data, int offset, int length);
private static native void nativeAppendFrom(
long thisNativePtr, long otherNativePtr, int offset, int length);
private static native boolean nativeHasFileDescriptors(long nativePtr);
private static native void nativeWriteInterfaceToken(long nativePtr, String interfaceName);
private static native void nativeEnforceInterface(long nativePtr, String interfaceName);
private static native long nativeGetBlobAshmemSize(long nativePtr);
public final static Parcelable.Creator STRING_CREATOR
= new Parcelable.Creator() {
public String createFromParcel(Parcel source) {
return source.readString();
}
public String[] newArray(int size) {
return new String[size];
}
};
/**
* Retrieve a new Parcel object from the pool.
*/
public static Parcel obtain() {
final Parcel[] pool = sOwnedPool;
synchronized (pool) {
Parcel p;
for (int i=0; i= {@link #dataSize}. The difference between it and dataSize() is the
* amount of room left until the parcel needs to re-allocate its
* data buffer.
*/
public final int dataCapacity() {
return nativeDataCapacity(mNativePtr);
}
/**
* Change the amount of data in the parcel. Can be either smaller or
* larger than the current size. If larger than the current capacity,
* more memory will be allocated.
*
* @param size The new number of bytes in the Parcel.
*/
public final void setDataSize(int size) {
nativeSetDataSize(mNativePtr, size);
}
/**
* Move the current read/write position in the parcel.
* @param pos New offset in the parcel; must be between 0 and
* {@link #dataSize}.
*/
public final void setDataPosition(int pos) {
nativeSetDataPosition(mNativePtr, pos);
}
/**
* Change the capacity (current available space) of the parcel.
*
* @param size The new capacity of the parcel, in bytes. Can not be
* less than {@link #dataSize} -- that is, you can not drop existing data
* with this method.
*/
public final void setDataCapacity(int size) {
nativeSetDataCapacity(mNativePtr, size);
}
/** @hide */
public final boolean pushAllowFds(boolean allowFds) {
return nativePushAllowFds(mNativePtr, allowFds);
}
/** @hide */
public final void restoreAllowFds(boolean lastValue) {
nativeRestoreAllowFds(mNativePtr, lastValue);
}
/**
* Returns the raw bytes of the parcel.
*
*
The data you retrieve here must not
* be placed in any kind of persistent storage (on local disk, across
* a network, etc). For that, you should use standard serialization
* or another kind of general serialization mechanism. The Parcel
* marshalled representation is highly optimized for local IPC, and as
* such does not attempt to maintain compatibility with data created
* in different versions of the platform.
*/
public final byte[] marshall() {
return nativeMarshall(mNativePtr);
}
/**
* Set the bytes in data to be the raw bytes of this Parcel.
*/
public final void unmarshall(byte[] data, int offset, int length) {
nativeUnmarshall(mNativePtr, data, offset, length);
}
public final void appendFrom(Parcel parcel, int offset, int length) {
nativeAppendFrom(mNativePtr, parcel.mNativePtr, offset, length);
}
/**
* Report whether the parcel contains any marshalled file descriptors.
*/
public final boolean hasFileDescriptors() {
return nativeHasFileDescriptors(mNativePtr);
}
/**
* Store or read an IBinder interface token in the parcel at the current
* {@link #dataPosition}. This is used to validate that the marshalled
* transaction is intended for the target interface.
*/
public final void writeInterfaceToken(String interfaceName) {
nativeWriteInterfaceToken(mNativePtr, interfaceName);
}
public final void enforceInterface(String interfaceName) {
nativeEnforceInterface(mNativePtr, interfaceName);
}
/**
* Write a byte array into the parcel at the current {@link #dataPosition},
* growing {@link #dataCapacity} if needed.
* @param b Bytes to place into the parcel.
*/
public final void writeByteArray(byte[] b) {
writeByteArray(b, 0, (b != null) ? b.length : 0);
}
/**
* Write a byte array into the parcel at the current {@link #dataPosition},
* growing {@link #dataCapacity} if needed.
* @param b Bytes to place into the parcel.
* @param offset Index of first byte to be written.
* @param len Number of bytes to write.
*/
public final void writeByteArray(byte[] b, int offset, int len) {
if (b == null) {
writeInt(-1);
return;
}
Arrays.checkOffsetAndCount(b.length, offset, len);
nativeWriteByteArray(mNativePtr, b, offset, len);
}
/**
* Write a blob of data into the parcel at the current {@link #dataPosition},
* growing {@link #dataCapacity} if needed.
* @param b Bytes to place into the parcel.
* {@hide}
* {@SystemApi}
*/
public final void writeBlob(byte[] b) {
writeBlob(b, 0, (b != null) ? b.length : 0);
}
/**
* Write a blob of data into the parcel at the current {@link #dataPosition},
* growing {@link #dataCapacity} if needed.
* @param b Bytes to place into the parcel.
* @param offset Index of first byte to be written.
* @param len Number of bytes to write.
* {@hide}
* {@SystemApi}
*/
public final void writeBlob(byte[] b, int offset, int len) {
if (b == null) {
writeInt(-1);
return;
}
Arrays.checkOffsetAndCount(b.length, offset, len);
nativeWriteBlob(mNativePtr, b, offset, len);
}
/**
* Write an integer value into the parcel at the current dataPosition(),
* growing dataCapacity() if needed.
*/
public final void writeInt(int val) {
nativeWriteInt(mNativePtr, val);
}
/**
* Write a long integer value into the parcel at the current dataPosition(),
* growing dataCapacity() if needed.
*/
public final void writeLong(long val) {
nativeWriteLong(mNativePtr, val);
}
/**
* Write a floating point value into the parcel at the current
* dataPosition(), growing dataCapacity() if needed.
*/
public final void writeFloat(float val) {
nativeWriteFloat(mNativePtr, val);
}
/**
* Write a double precision floating point value into the parcel at the
* current dataPosition(), growing dataCapacity() if needed.
*/
public final void writeDouble(double val) {
nativeWriteDouble(mNativePtr, val);
}
/**
* Write a string value into the parcel at the current dataPosition(),
* growing dataCapacity() if needed.
*/
public final void writeString(String val) {
nativeWriteString(mNativePtr, val);
}
/**
* Write a CharSequence value into the parcel at the current dataPosition(),
* growing dataCapacity() if needed.
* @hide
*/
public final void writeCharSequence(CharSequence val) {
TextUtils.writeToParcel(val, this, 0);
}
/**
* Write an object into the parcel at the current dataPosition(),
* growing dataCapacity() if needed.
*/
public final void writeStrongBinder(IBinder val) {
nativeWriteStrongBinder(mNativePtr, val);
}
/**
* Write an object into the parcel at the current dataPosition(),
* growing dataCapacity() if needed.
*/
public final void writeStrongInterface(IInterface val) {
writeStrongBinder(val == null ? null : val.asBinder());
}
/**
* Write a FileDescriptor into the parcel at the current dataPosition(),
* growing dataCapacity() if needed.
*
*
The file descriptor will not be closed, which may
* result in file descriptor leaks when objects are returned from Binder
* calls. Use {@link ParcelFileDescriptor#writeToParcel} instead, which
* accepts contextual flags and will close the original file descriptor
* if {@link Parcelable#PARCELABLE_WRITE_RETURN_VALUE} is set.
*/
public final void writeFileDescriptor(FileDescriptor val) {
nativeWriteFileDescriptor(mNativePtr, val);
}
/**
* Write a byte value into the parcel at the current dataPosition(),
* growing dataCapacity() if needed.
*/
public final void writeByte(byte val) {
writeInt(val);
}
/**
* Please use {@link #writeBundle} instead. Flattens a Map into the parcel
* at the current dataPosition(),
* growing dataCapacity() if needed. The Map keys must be String objects.
* The Map values are written using {@link #writeValue} and must follow
* the specification there.
*
*
It is strongly recommended to use {@link #writeBundle} instead of
* this method, since the Bundle class provides a type-safe API that
* allows you to avoid mysterious type errors at the point of marshalling.
*/
public final void writeMap(Map val) {
writeMapInternal((Map) val);
}
/**
* Flatten a Map into the parcel at the current dataPosition(),
* growing dataCapacity() if needed. The Map keys must be String objects.
*/
/* package */ void writeMapInternal(Map val) {
if (val == null) {
writeInt(-1);
return;
}
Set> entries = val.entrySet();
writeInt(entries.size());
for (Map.Entry e : entries) {
writeValue(e.getKey());
writeValue(e.getValue());
}
}
/**
* Flatten an ArrayMap into the parcel at the current dataPosition(),
* growing dataCapacity() if needed. The Map keys must be String objects.
*/
/* package */ void writeArrayMapInternal(ArrayMap val) {
if (val == null) {
writeInt(-1);
return;
}
final int N = val.size();
writeInt(N);
if (DEBUG_ARRAY_MAP) {
RuntimeException here = new RuntimeException("here");
here.fillInStackTrace();
Log.d(TAG, "Writing " + N + " ArrayMap entries", here);
}
int startPos;
for (int i=0; i val) {
writeArrayMapInternal(val);
}
/**
* Flatten a Bundle into the parcel at the current dataPosition(),
* growing dataCapacity() if needed.
*/
public final void writeBundle(Bundle val) {
if (val == null) {
writeInt(-1);
return;
}
val.writeToParcel(this, 0);
}
/**
* Flatten a PersistableBundle into the parcel at the current dataPosition(),
* growing dataCapacity() if needed.
*/
public final void writePersistableBundle(PersistableBundle val) {
if (val == null) {
writeInt(-1);
return;
}
val.writeToParcel(this, 0);
}
/**
* Flatten a Size into the parcel at the current dataPosition(),
* growing dataCapacity() if needed.
*/
public final void writeSize(Size val) {
writeInt(val.getWidth());
writeInt(val.getHeight());
}
/**
* Flatten a SizeF into the parcel at the current dataPosition(),
* growing dataCapacity() if needed.
*/
public final void writeSizeF(SizeF val) {
writeFloat(val.getWidth());
writeFloat(val.getHeight());
}
/**
* Flatten a List into the parcel at the current dataPosition(), growing
* dataCapacity() if needed. The List values are written using
* {@link #writeValue} and must follow the specification there.
*/
public final void writeList(List val) {
if (val == null) {
writeInt(-1);
return;
}
int N = val.size();
int i=0;
writeInt(N);
while (i < N) {
writeValue(val.get(i));
i++;
}
}
/**
* Flatten an Object array into the parcel at the current dataPosition(),
* growing dataCapacity() if needed. The array values are written using
* {@link #writeValue} and must follow the specification there.
*/
public final void writeArray(Object[] val) {
if (val == null) {
writeInt(-1);
return;
}
int N = val.length;
int i=0;
writeInt(N);
while (i < N) {
writeValue(val[i]);
i++;
}
}
/**
* Flatten a generic SparseArray into the parcel at the current
* dataPosition(), growing dataCapacity() if needed. The SparseArray
* values are written using {@link #writeValue} and must follow the
* specification there.
*/
public final void writeSparseArray(SparseArray