Split Parcel JNI details away from Binder.

This is purely a refactoring, with no change to the underlying
functionality.

Change-Id: I41b59f14e57d1cc144274a01f77658d99a1bfe02
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index c389cf7..642988b 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -64,6 +64,7 @@
 	android_os_MemoryFile.cpp \
 	android_os_MessageQueue.cpp \
 	android_os_ParcelFileDescriptor.cpp \
+	android_os_Parcel.cpp \
 	android_os_Power.cpp \
 	android_os_StatFs.cpp \
 	android_os_SystemClock.cpp \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 3067e75..de9fd33 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -130,6 +130,7 @@
 extern int register_android_text_format_Time(JNIEnv* env);
 extern int register_android_os_Debug(JNIEnv* env);
 extern int register_android_os_MessageQueue(JNIEnv* env);
+extern int register_android_os_Parcel(JNIEnv* env);
 extern int register_android_os_ParcelFileDescriptor(JNIEnv *env);
 extern int register_android_os_Power(JNIEnv *env);
 extern int register_android_os_StatFs(JNIEnv *env);
@@ -1094,6 +1095,7 @@
     REG_JNI(register_android_os_Process),
     REG_JNI(register_android_os_SystemProperties),
     REG_JNI(register_android_os_Binder),
+    REG_JNI(register_android_os_Parcel),
     REG_JNI(register_android_view_Display),
     REG_JNI(register_android_view_DisplayEventReceiver),
     REG_JNI(register_android_nio_utils),
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index d1d3b78..5e73a5f 100644
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -7,6 +7,7 @@
 #include "SkUnPreMultiply.h"

 

 #include <binder/Parcel.h>

+#include "android_os_Parcel.h"
 #include "android_util_Binder.h"

 #include "android_nio_utils.h"

 #include "CreateJavaOutputStreamAdaptor.h"

diff --git a/core/jni/android/graphics/Region.cpp b/core/jni/android/graphics/Region.cpp
index 5c6ebdf..866d223 100644
--- a/core/jni/android/graphics/Region.cpp
+++ b/core/jni/android/graphics/Region.cpp
@@ -19,6 +19,7 @@
 #include "GraphicsJNI.h"
 
 #include <binder/Parcel.h>
+#include "android_os_Parcel.h"
 #include "android_util_Binder.h"
 
 #include <jni.h>
diff --git a/core/jni/android_database_CursorWindow.cpp b/core/jni/android_database_CursorWindow.cpp
index 579d6ad..ea02f53 100644
--- a/core/jni/android_database_CursorWindow.cpp
+++ b/core/jni/android_database_CursorWindow.cpp
@@ -31,6 +31,7 @@
 #include <unistd.h>
 
 #include <androidfw/CursorWindow.h>
+#include "android_os_Parcel.h"
 #include "android_util_Binder.h"
 #include "android_database_SQLiteCommon.h"
 
diff --git a/core/jni/android_os_Parcel.cpp b/core/jni/android_os_Parcel.cpp
new file mode 100644
index 0000000..8a99049
--- /dev/null
+++ b/core/jni/android_os_Parcel.cpp
@@ -0,0 +1,701 @@
+/*
+ * Copyright (C) 2012 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 "android_os_Parcel.h"
+#include "android_util_Binder.h"
+
+#include "JNIHelp.h"
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <utils/Atomic.h>
+#include <binder/IInterface.h>
+#include <binder/IPCThreadState.h>
+#include <utils/Log.h>
+#include <utils/SystemClock.h>
+#include <utils/List.h>
+#include <utils/KeyedVector.h>
+#include <cutils/logger.h>
+#include <binder/Parcel.h>
+#include <binder/ProcessState.h>
+#include <binder/IServiceManager.h>
+#include <utils/threads.h>
+#include <utils/String8.h>
+
+#include <ScopedUtfChars.h>
+#include <ScopedLocalRef.h>
+
+#include <android_runtime/AndroidRuntime.h>
+
+//#undef ALOGV
+//#define ALOGV(...) fprintf(stderr, __VA_ARGS__)
+
+#define DEBUG_DEATH 0
+#if DEBUG_DEATH
+#define LOGDEATH ALOGD
+#else
+#define LOGDEATH ALOGV
+#endif
+
+namespace android {
+
+static struct parcel_offsets_t
+{
+    jfieldID mObject;
+    jfieldID mOwnObject;
+} gParcelOffsets;
+
+Parcel* parcelForJavaObject(JNIEnv* env, jobject obj)
+{
+    if (obj) {
+        Parcel* p = (Parcel*)env->GetIntField(obj, gParcelOffsets.mObject);
+        if (p != NULL) {
+            return p;
+        }
+        jniThrowException(env, "java/lang/IllegalStateException", "Parcel has been finalized!");
+    }
+    return NULL;
+}
+
+static jint android_os_Parcel_dataSize(JNIEnv* env, jobject clazz)
+{
+    Parcel* parcel = parcelForJavaObject(env, clazz);
+    return parcel ? parcel->dataSize() : 0;
+}
+
+static jint android_os_Parcel_dataAvail(JNIEnv* env, jobject clazz)
+{
+    Parcel* parcel = parcelForJavaObject(env, clazz);
+    return parcel ? parcel->dataAvail() : 0;
+}
+
+static jint android_os_Parcel_dataPosition(JNIEnv* env, jobject clazz)
+{
+    Parcel* parcel = parcelForJavaObject(env, clazz);
+    return parcel ? parcel->dataPosition() : 0;
+}
+
+static jint android_os_Parcel_dataCapacity(JNIEnv* env, jobject clazz)
+{
+    Parcel* parcel = parcelForJavaObject(env, clazz);
+    return parcel ? parcel->dataCapacity() : 0;
+}
+
+static void android_os_Parcel_setDataSize(JNIEnv* env, jobject clazz, jint size)
+{
+    Parcel* parcel = parcelForJavaObject(env, clazz);
+    if (parcel != NULL) {
+        const status_t err = parcel->setDataSize(size);
+        if (err != NO_ERROR) {
+            signalExceptionForError(env, clazz, err);
+        }
+    }
+}
+
+static void android_os_Parcel_setDataPosition(JNIEnv* env, jobject clazz, jint pos)
+{
+    Parcel* parcel = parcelForJavaObject(env, clazz);
+    if (parcel != NULL) {
+        parcel->setDataPosition(pos);
+    }
+}
+
+static void android_os_Parcel_setDataCapacity(JNIEnv* env, jobject clazz, jint size)
+{
+    Parcel* parcel = parcelForJavaObject(env, clazz);
+    if (parcel != NULL) {
+        const status_t err = parcel->setDataCapacity(size);
+        if (err != NO_ERROR) {
+            signalExceptionForError(env, clazz, err);
+        }
+    }
+}
+
+static jboolean android_os_Parcel_pushAllowFds(JNIEnv* env, jobject clazz, jboolean allowFds)
+{
+    Parcel* parcel = parcelForJavaObject(env, clazz);
+    jboolean ret = JNI_TRUE;
+    if (parcel != NULL) {
+        ret = (jboolean)parcel->pushAllowFds(allowFds);
+    }
+    return ret;
+}
+
+static void android_os_Parcel_restoreAllowFds(JNIEnv* env, jobject clazz, jboolean lastValue)
+{
+    Parcel* parcel = parcelForJavaObject(env, clazz);
+    if (parcel != NULL) {
+        parcel->restoreAllowFds((bool)lastValue);
+    }
+}
+
+static void android_os_Parcel_writeNative(JNIEnv* env, jobject clazz,
+                                          jobject data, jint offset,
+                                          jint length)
+{
+    Parcel* parcel = parcelForJavaObject(env, clazz);
+    if (parcel == NULL) {
+        return;
+    }
+
+    const status_t err = parcel->writeInt32(length);
+    if (err != NO_ERROR) {
+        signalExceptionForError(env, clazz, err);
+        return;
+    }
+
+    void* dest = parcel->writeInplace(length);
+    if (dest == NULL) {
+        signalExceptionForError(env, clazz, NO_MEMORY);
+        return;
+    }
+
+    jbyte* ar = (jbyte*)env->GetPrimitiveArrayCritical((jarray)data, 0);
+    if (ar) {
+        memcpy(dest, ar + offset, length);
+        env->ReleasePrimitiveArrayCritical((jarray)data, ar, 0);
+    }
+}
+
+
+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) {
+            signalExceptionForError(env, clazz, err);
+        }
+    }
+}
+
+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) {
+            signalExceptionForError(env, clazz, err);
+        }
+    }
+}
+
+static void android_os_Parcel_writeFloat(JNIEnv* env, jobject clazz, jfloat val)
+{
+    Parcel* parcel = parcelForJavaObject(env, clazz);
+    if (parcel != NULL) {
+        const status_t err = parcel->writeFloat(val);
+        if (err != NO_ERROR) {
+            signalExceptionForError(env, clazz, err);
+        }
+    }
+}
+
+static void android_os_Parcel_writeDouble(JNIEnv* env, jobject clazz, jdouble val)
+{
+    Parcel* parcel = parcelForJavaObject(env, clazz);
+    if (parcel != NULL) {
+        const status_t err = parcel->writeDouble(val);
+        if (err != NO_ERROR) {
+            signalExceptionForError(env, clazz, err);
+        }
+    }
+}
+
+static void android_os_Parcel_writeString(JNIEnv* env, jobject clazz, jstring val)
+{
+    Parcel* parcel = parcelForJavaObject(env, clazz);
+    if (parcel != NULL) {
+        status_t err = NO_MEMORY;
+        if (val) {
+            const jchar* str = env->GetStringCritical(val, 0);
+            if (str) {
+                err = parcel->writeString16(str, env->GetStringLength(val));
+                env->ReleaseStringCritical(val, str);
+            }
+        } else {
+            err = parcel->writeString16(NULL, 0);
+        }
+        if (err != NO_ERROR) {
+            signalExceptionForError(env, clazz, err);
+        }
+    }
+}
+
+static void android_os_Parcel_writeStrongBinder(JNIEnv* env, jobject clazz, jobject object)
+{
+    Parcel* parcel = parcelForJavaObject(env, clazz);
+    if (parcel != NULL) {
+        const status_t err = parcel->writeStrongBinder(ibinderForJavaObject(env, object));
+        if (err != NO_ERROR) {
+            signalExceptionForError(env, clazz, err);
+        }
+    }
+}
+
+static void android_os_Parcel_writeFileDescriptor(JNIEnv* env, jobject clazz, jobject object)
+{
+    Parcel* parcel = parcelForJavaObject(env, clazz);
+    if (parcel != NULL) {
+        const status_t err =
+                parcel->writeDupFileDescriptor(jniGetFDFromFileDescriptor(env, object));
+        if (err != NO_ERROR) {
+            signalExceptionForError(env, clazz, err);
+        }
+    }
+}
+
+static jbyteArray android_os_Parcel_createByteArray(JNIEnv* env, jobject clazz)
+{
+    jbyteArray ret = NULL;
+
+    Parcel* parcel = parcelForJavaObject(env, clazz);
+    if (parcel != NULL) {
+        int32_t len = parcel->readInt32();
+
+        // sanity check the stored length against the true data size
+        if (len >= 0 && len <= (int32_t)parcel->dataAvail()) {
+            ret = env->NewByteArray(len);
+
+            if (ret != NULL) {
+                jbyte* a2 = (jbyte*)env->GetPrimitiveArrayCritical(ret, 0);
+                if (a2) {
+                    const void* data = parcel->readInplace(len);
+                    memcpy(a2, data, len);
+                    env->ReleasePrimitiveArrayCritical(ret, a2, 0);
+                }
+            }
+        }
+    }
+
+    return ret;
+}
+
+static jint android_os_Parcel_readInt(JNIEnv* env, jobject clazz)
+{
+    Parcel* parcel = parcelForJavaObject(env, clazz);
+    if (parcel != NULL) {
+        return parcel->readInt32();
+    }
+    return 0;
+}
+
+static jlong android_os_Parcel_readLong(JNIEnv* env, jobject clazz)
+{
+    Parcel* parcel = parcelForJavaObject(env, clazz);
+    if (parcel != NULL) {
+        return parcel->readInt64();
+    }
+    return 0;
+}
+
+static jfloat android_os_Parcel_readFloat(JNIEnv* env, jobject clazz)
+{
+    Parcel* parcel = parcelForJavaObject(env, clazz);
+    if (parcel != NULL) {
+        return parcel->readFloat();
+    }
+    return 0;
+}
+
+static jdouble android_os_Parcel_readDouble(JNIEnv* env, jobject clazz)
+{
+    Parcel* parcel = parcelForJavaObject(env, clazz);
+    if (parcel != NULL) {
+        return parcel->readDouble();
+    }
+    return 0;
+}
+
+static jstring android_os_Parcel_readString(JNIEnv* env, jobject clazz)
+{
+    Parcel* parcel = parcelForJavaObject(env, clazz);
+    if (parcel != NULL) {
+        size_t len;
+        const char16_t* str = parcel->readString16Inplace(&len);
+        if (str) {
+            return env->NewString(str, len);
+        }
+        return NULL;
+    }
+    return NULL;
+}
+
+static jobject android_os_Parcel_readStrongBinder(JNIEnv* env, jobject clazz)
+{
+    Parcel* parcel = parcelForJavaObject(env, clazz);
+    if (parcel != NULL) {
+        return javaObjectForIBinder(env, parcel->readStrongBinder());
+    }
+    return NULL;
+}
+
+static jobject android_os_Parcel_readFileDescriptor(JNIEnv* env, jobject clazz)
+{
+    Parcel* parcel = parcelForJavaObject(env, clazz);
+    if (parcel != NULL) {
+        int fd = parcel->readFileDescriptor();
+        if (fd < 0) return NULL;
+        fd = dup(fd);
+        if (fd < 0) return NULL;
+        return jniCreateFileDescriptor(env, fd);
+    }
+    return NULL;
+}
+
+static jobject android_os_Parcel_openFileDescriptor(JNIEnv* env, jobject clazz,
+                                                    jstring name, jint mode)
+{
+    if (name == NULL) {
+        jniThrowNullPointerException(env, NULL);
+        return NULL;
+    }
+    const jchar* str = env->GetStringCritical(name, 0);
+    if (str == NULL) {
+        // Whatever, whatever.
+        jniThrowException(env, "java/lang/IllegalStateException", NULL);
+        return NULL;
+    }
+    String8 name8(str, env->GetStringLength(name));
+    env->ReleaseStringCritical(name, str);
+    int flags=0;
+    switch (mode&0x30000000) {
+        case 0:
+        case 0x10000000:
+            flags = O_RDONLY;
+            break;
+        case 0x20000000:
+            flags = O_WRONLY;
+            break;
+        case 0x30000000:
+            flags = O_RDWR;
+            break;
+    }
+
+    if (mode&0x08000000) flags |= O_CREAT;
+    if (mode&0x04000000) flags |= O_TRUNC;
+    if (mode&0x02000000) flags |= O_APPEND;
+
+    int realMode = S_IRWXU|S_IRWXG;
+    if (mode&0x00000001) realMode |= S_IROTH;
+    if (mode&0x00000002) realMode |= S_IWOTH;
+
+    int fd = open(name8.string(), flags, realMode);
+    if (fd < 0) {
+        jniThrowException(env, "java/io/FileNotFoundException", strerror(errno));
+        return NULL;
+    }
+    jobject object = jniCreateFileDescriptor(env, fd);
+    if (object == NULL) {
+        close(fd);
+    }
+    return object;
+}
+
+static jobject android_os_Parcel_dupFileDescriptor(JNIEnv* env, jobject clazz, jobject orig)
+{
+    if (orig == NULL) {
+        jniThrowNullPointerException(env, NULL);
+        return NULL;
+    }
+    int origfd = jniGetFDFromFileDescriptor(env, orig);
+    if (origfd < 0) {
+        jniThrowException(env, "java/lang/IllegalArgumentException", "bad FileDescriptor");
+        return NULL;
+    }
+
+    int fd = dup(origfd);
+    if (fd < 0) {
+        jniThrowIOException(env, errno);
+        return NULL;
+    }
+    jobject object = jniCreateFileDescriptor(env, fd);
+    if (object == NULL) {
+        close(fd);
+    }
+    return object;
+}
+
+static void android_os_Parcel_closeFileDescriptor(JNIEnv* env, jobject clazz, jobject object)
+{
+    if (object == NULL) {
+        jniThrowNullPointerException(env, NULL);
+        return;
+    }
+    int fd = jniGetFDFromFileDescriptor(env, object);
+    if (fd >= 0) {
+        jniSetFileDescriptorOfFD(env, object, -1);
+        //ALOGI("Closing ParcelFileDescriptor %d\n", fd);
+        close(fd);
+    }
+}
+
+static void android_os_Parcel_clearFileDescriptor(JNIEnv* env, jobject clazz, jobject object)
+{
+    if (object == NULL) {
+        jniThrowNullPointerException(env, NULL);
+        return;
+    }
+    int fd = jniGetFDFromFileDescriptor(env, object);
+    if (fd >= 0) {
+        jniSetFileDescriptorOfFD(env, object, -1);
+    }
+}
+
+static void android_os_Parcel_freeBuffer(JNIEnv* env, jobject clazz)
+{
+    int32_t own = env->GetIntField(clazz, gParcelOffsets.mOwnObject);
+    if (own) {
+        Parcel* parcel = parcelForJavaObject(env, clazz);
+        if (parcel != NULL) {
+            //ALOGI("Parcel.freeBuffer() called for C++ Parcel %p\n", parcel);
+            parcel->freeData();
+        }
+    }
+}
+
+static void android_os_Parcel_init(JNIEnv* env, jobject clazz, jint parcelInt)
+{
+    Parcel* parcel = (Parcel*)parcelInt;
+    int own = 0;
+    if (!parcel) {
+        //ALOGI("Initializing obj %p: creating new Parcel\n", clazz);
+        own = 1;
+        parcel = new Parcel;
+    } else {
+        //ALOGI("Initializing obj %p: given existing Parcel %p\n", clazz, parcel);
+    }
+    if (parcel == NULL) {
+        jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
+        return;
+    }
+    //ALOGI("Initializing obj %p from C++ Parcel %p, own=%d\n", clazz, parcel, own);
+    env->SetIntField(clazz, gParcelOffsets.mOwnObject, own);
+    env->SetIntField(clazz, gParcelOffsets.mObject, (int)parcel);
+}
+
+static void android_os_Parcel_destroy(JNIEnv* env, jobject clazz)
+{
+    int32_t own = env->GetIntField(clazz, gParcelOffsets.mOwnObject);
+    if (own) {
+        Parcel* parcel = parcelForJavaObject(env, clazz);
+        env->SetIntField(clazz, gParcelOffsets.mObject, 0);
+        //ALOGI("Destroying obj %p: deleting C++ Parcel %p\n", clazz, parcel);
+        delete parcel;
+    } else {
+        env->SetIntField(clazz, gParcelOffsets.mObject, 0);
+        //ALOGI("Destroying obj %p: leaving C++ Parcel %p\n", clazz);
+    }
+}
+
+static jbyteArray android_os_Parcel_marshall(JNIEnv* env, jobject clazz)
+{
+    Parcel* parcel = parcelForJavaObject(env, clazz);
+    if (parcel == NULL) {
+       return NULL;
+    }
+
+    // do not marshall if there are binder objects in the parcel
+    if (parcel->objectsCount())
+    {
+        jniThrowException(env, "java/lang/RuntimeException", "Tried to marshall a Parcel that contained Binder objects.");
+        return NULL;
+    }
+
+    jbyteArray ret = env->NewByteArray(parcel->dataSize());
+
+    if (ret != NULL)
+    {
+        jbyte* array = (jbyte*)env->GetPrimitiveArrayCritical(ret, 0);
+        if (array != NULL)
+        {
+            memcpy(array, parcel->data(), parcel->dataSize());
+            env->ReleasePrimitiveArrayCritical(ret, array, 0);
+        }
+    }
+
+    return ret;
+}
+
+static void android_os_Parcel_unmarshall(JNIEnv* env, jobject clazz, jbyteArray data, jint offset, jint length)
+{
+    Parcel* parcel = parcelForJavaObject(env, clazz);
+    if (parcel == NULL || length < 0) {
+       return;
+    }
+
+    jbyte* array = (jbyte*)env->GetPrimitiveArrayCritical(data, 0);
+    if (array)
+    {
+        parcel->setDataSize(length);
+        parcel->setDataPosition(0);
+
+        void* raw = parcel->writeInplace(length);
+        memcpy(raw, (array + offset), length);
+
+        env->ReleasePrimitiveArrayCritical(data, array, 0);
+    }
+}
+
+static void android_os_Parcel_appendFrom(JNIEnv* env, jobject clazz, jobject parcel, jint offset, jint length)
+{
+    Parcel* thisParcel = parcelForJavaObject(env, clazz);
+    if (thisParcel == NULL) {
+       return;
+    }
+    Parcel* otherParcel = parcelForJavaObject(env, parcel);
+    if (otherParcel == NULL) {
+       return;
+    }
+
+    status_t err = thisParcel->appendFrom(otherParcel, offset, length);
+    if (err != NO_ERROR) {
+        signalExceptionForError(env, clazz, err);
+    }
+}
+
+static jboolean android_os_Parcel_hasFileDescriptors(JNIEnv* env, jobject clazz)
+{
+    jboolean ret = JNI_FALSE;
+    Parcel* parcel = parcelForJavaObject(env, clazz);
+    if (parcel != NULL) {
+        if (parcel->hasFileDescriptors()) {
+            ret = JNI_TRUE;
+        }
+    }
+    return ret;
+}
+
+static void android_os_Parcel_writeInterfaceToken(JNIEnv* env, jobject clazz, jstring name)
+{
+    Parcel* parcel = parcelForJavaObject(env, clazz);
+    if (parcel != NULL) {
+        // In the current implementation, the token is just the serialized interface name that
+        // the caller expects to be invoking
+        const jchar* str = env->GetStringCritical(name, 0);
+        if (str != NULL) {
+            parcel->writeInterfaceToken(String16(str, env->GetStringLength(name)));
+            env->ReleaseStringCritical(name, str);
+        }
+    }
+}
+
+static void android_os_Parcel_enforceInterface(JNIEnv* env, jobject clazz, jstring name)
+{
+    jboolean ret = JNI_FALSE;
+
+    Parcel* parcel = parcelForJavaObject(env, clazz);
+    if (parcel != NULL) {
+        const jchar* str = env->GetStringCritical(name, 0);
+        if (str) {
+            IPCThreadState* threadState = IPCThreadState::self();
+            const int32_t oldPolicy = threadState->getStrictModePolicy();
+            const bool isValid = parcel->enforceInterface(
+                String16(str, env->GetStringLength(name)),
+                threadState);
+            env->ReleaseStringCritical(name, str);
+            if (isValid) {
+                const int32_t newPolicy = threadState->getStrictModePolicy();
+                if (oldPolicy != newPolicy) {
+                    // Need to keep the Java-level thread-local strict
+                    // mode policy in sync for the libcore
+                    // enforcements, which involves an upcall back
+                    // into Java.  (We can't modify the
+                    // Parcel.enforceInterface signature, as it's
+                    // pseudo-public, and used via AIDL
+                    // auto-generation...)
+                    set_dalvik_blockguard_policy(env, newPolicy);
+                }
+                return;     // everything was correct -> return silently
+            }
+        }
+    }
+
+    // all error conditions wind up here
+    jniThrowException(env, "java/lang/SecurityException",
+            "Binder invocation to an incorrect interface");
+}
+
+// ----------------------------------------------------------------------------
+
+static const JNINativeMethod gParcelMethods[] = {
+    {"dataSize",            "()I", (void*)android_os_Parcel_dataSize},
+    {"dataAvail",           "()I", (void*)android_os_Parcel_dataAvail},
+    {"dataPosition",        "()I", (void*)android_os_Parcel_dataPosition},
+    {"dataCapacity",        "()I", (void*)android_os_Parcel_dataCapacity},
+    {"setDataSize",         "(I)V", (void*)android_os_Parcel_setDataSize},
+    {"setDataPosition",     "(I)V", (void*)android_os_Parcel_setDataPosition},
+    {"setDataCapacity",     "(I)V", (void*)android_os_Parcel_setDataCapacity},
+    {"pushAllowFds",        "(Z)Z", (void*)android_os_Parcel_pushAllowFds},
+    {"restoreAllowFds",     "(Z)V", (void*)android_os_Parcel_restoreAllowFds},
+    {"writeNative",         "([BII)V", (void*)android_os_Parcel_writeNative},
+    {"writeInt",            "(I)V", (void*)android_os_Parcel_writeInt},
+    {"writeLong",           "(J)V", (void*)android_os_Parcel_writeLong},
+    {"writeFloat",          "(F)V", (void*)android_os_Parcel_writeFloat},
+    {"writeDouble",         "(D)V", (void*)android_os_Parcel_writeDouble},
+    {"writeString",         "(Ljava/lang/String;)V", (void*)android_os_Parcel_writeString},
+    {"writeStrongBinder",   "(Landroid/os/IBinder;)V", (void*)android_os_Parcel_writeStrongBinder},
+    {"writeFileDescriptor", "(Ljava/io/FileDescriptor;)V", (void*)android_os_Parcel_writeFileDescriptor},
+    {"createByteArray",     "()[B", (void*)android_os_Parcel_createByteArray},
+    {"readInt",             "()I", (void*)android_os_Parcel_readInt},
+    {"readLong",            "()J", (void*)android_os_Parcel_readLong},
+    {"readFloat",           "()F", (void*)android_os_Parcel_readFloat},
+    {"readDouble",          "()D", (void*)android_os_Parcel_readDouble},
+    {"readString",          "()Ljava/lang/String;", (void*)android_os_Parcel_readString},
+    {"readStrongBinder",    "()Landroid/os/IBinder;", (void*)android_os_Parcel_readStrongBinder},
+    {"internalReadFileDescriptor",  "()Ljava/io/FileDescriptor;", (void*)android_os_Parcel_readFileDescriptor},
+    {"openFileDescriptor",  "(Ljava/lang/String;I)Ljava/io/FileDescriptor;", (void*)android_os_Parcel_openFileDescriptor},
+    {"dupFileDescriptor",   "(Ljava/io/FileDescriptor;)Ljava/io/FileDescriptor;", (void*)android_os_Parcel_dupFileDescriptor},
+    {"closeFileDescriptor", "(Ljava/io/FileDescriptor;)V", (void*)android_os_Parcel_closeFileDescriptor},
+    {"clearFileDescriptor", "(Ljava/io/FileDescriptor;)V", (void*)android_os_Parcel_clearFileDescriptor},
+    {"freeBuffer",          "()V", (void*)android_os_Parcel_freeBuffer},
+    {"init",                "(I)V", (void*)android_os_Parcel_init},
+    {"destroy",             "()V", (void*)android_os_Parcel_destroy},
+    {"marshall",            "()[B", (void*)android_os_Parcel_marshall},
+    {"unmarshall",          "([BII)V", (void*)android_os_Parcel_unmarshall},
+    {"appendFrom",          "(Landroid/os/Parcel;II)V", (void*)android_os_Parcel_appendFrom},
+    {"hasFileDescriptors",  "()Z", (void*)android_os_Parcel_hasFileDescriptors},
+    {"writeInterfaceToken", "(Ljava/lang/String;)V", (void*)android_os_Parcel_writeInterfaceToken},
+    {"enforceInterface",    "(Ljava/lang/String;)V", (void*)android_os_Parcel_enforceInterface},
+};
+
+const char* const kParcelPathName = "android/os/Parcel";
+
+int register_android_os_Parcel(JNIEnv* env)
+{
+    jclass clazz;
+
+    clazz = env->FindClass(kParcelPathName);
+    LOG_FATAL_IF(clazz == NULL, "Unable to find class android.os.Parcel");
+
+    gParcelOffsets.mObject
+        = env->GetFieldID(clazz, "mObject", "I");
+    gParcelOffsets.mOwnObject
+        = env->GetFieldID(clazz, "mOwnObject", "I");
+
+    return AndroidRuntime::registerNativeMethods(
+        env, kParcelPathName,
+        gParcelMethods, NELEM(gParcelMethods));
+}
+
+};
diff --git a/core/jni/android_os_Parcel.h b/core/jni/android_os_Parcel.h
new file mode 100644
index 0000000..65f3819e
--- /dev/null
+++ b/core/jni/android_os_Parcel.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#include <binder/IBinder.h>
+
+#include "jni.h"
+
+namespace android {
+
+// Conversion from Java Parcel Object to C++ Parcel instance.
+// Note: does not type checking; must guarantee jobject is a Java Parcel
+extern Parcel* parcelForJavaObject(JNIEnv* env, jobject obj);
+
+}
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index e00970a..0f99fb2 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -17,7 +17,9 @@
 #define LOG_TAG "JavaBinder"
 //#define LOG_NDEBUG 0
 
+#include "android_os_Parcel.h"
 #include "android_util_Binder.h"
+
 #include "JNIHelp.h"
 
 #include <fcntl.h>
@@ -127,12 +129,6 @@
 
 // ----------------------------------------------------------------------------
 
-static struct parcel_offsets_t
-{
-    jfieldID mObject;
-    jfieldID mOwnObject;
-} gParcelOffsets;
-
 static struct log_offsets_t
 {
     // Class state.
@@ -232,15 +228,6 @@
     env->DeleteLocalRef(msgstr);
 }
 
-static void set_dalvik_blockguard_policy(JNIEnv* env, jint strict_policy)
-{
-    // Call back into android.os.StrictMode#onBinderStrictModePolicyChange
-    // to sync our state back to it.  See the comments in StrictMode.java.
-    env->CallStaticVoidMethod(gStrictModeCallbackOffsets.mClass,
-                              gStrictModeCallbackOffsets.mCallback,
-                              strict_policy);
-}
-
 class JavaBBinderHolder;
 
 class JavaBBinder : public BBinder
@@ -634,26 +621,23 @@
     return NULL;
 }
 
-Parcel* parcelForJavaObject(JNIEnv* env, jobject obj)
-{
-    if (obj) {
-        Parcel* p = (Parcel*)env->GetIntField(obj, gParcelOffsets.mObject);
-        if (p != NULL) {
-            return p;
-        }
-        jniThrowException(env, "java/lang/IllegalStateException", "Parcel has been finalized!");
-    }
-    return NULL;
-}
-
 jobject newParcelFileDescriptor(JNIEnv* env, jobject fileDesc)
 {
     return env->NewObject(
             gParcelFileDescriptorOffsets.mClass, gParcelFileDescriptorOffsets.mConstructor, fileDesc);
 }
 
-static void signalExceptionForError(JNIEnv* env, jobject obj, status_t err,
-        bool canThrowRemoteException = false)
+void set_dalvik_blockguard_policy(JNIEnv* env, jint strict_policy)
+{
+    // Call back into android.os.StrictMode#onBinderStrictModePolicyChange
+    // to sync our state back to it.  See the comments in StrictMode.java.
+    env->CallStaticVoidMethod(gStrictModeCallbackOffsets.mClass,
+                              gStrictModeCallbackOffsets.mCallback,
+                              strict_policy);
+}
+
+void signalExceptionForError(JNIEnv* env, jobject obj, status_t err,
+        bool canThrowRemoteException)
 {
     switch (err) {
         case UNKNOWN_ERROR:
@@ -1273,612 +1257,15 @@
 // ****************************************************************************
 // ****************************************************************************
 
-static jint android_os_Parcel_dataSize(JNIEnv* env, jobject clazz)
+int register_android_os_Binder(JNIEnv* env)
 {
-    Parcel* parcel = parcelForJavaObject(env, clazz);
-    return parcel ? parcel->dataSize() : 0;
-}
+    if (int_register_android_os_Binder(env) < 0)
+        return -1;
+    if (int_register_android_os_BinderInternal(env) < 0)
+        return -1;
+    if (int_register_android_os_BinderProxy(env) < 0)
+        return -1;
 
-static jint android_os_Parcel_dataAvail(JNIEnv* env, jobject clazz)
-{
-    Parcel* parcel = parcelForJavaObject(env, clazz);
-    return parcel ? parcel->dataAvail() : 0;
-}
-
-static jint android_os_Parcel_dataPosition(JNIEnv* env, jobject clazz)
-{
-    Parcel* parcel = parcelForJavaObject(env, clazz);
-    return parcel ? parcel->dataPosition() : 0;
-}
-
-static jint android_os_Parcel_dataCapacity(JNIEnv* env, jobject clazz)
-{
-    Parcel* parcel = parcelForJavaObject(env, clazz);
-    return parcel ? parcel->dataCapacity() : 0;
-}
-
-static void android_os_Parcel_setDataSize(JNIEnv* env, jobject clazz, jint size)
-{
-    Parcel* parcel = parcelForJavaObject(env, clazz);
-    if (parcel != NULL) {
-        const status_t err = parcel->setDataSize(size);
-        if (err != NO_ERROR) {
-            signalExceptionForError(env, clazz, err);
-        }
-    }
-}
-
-static void android_os_Parcel_setDataPosition(JNIEnv* env, jobject clazz, jint pos)
-{
-    Parcel* parcel = parcelForJavaObject(env, clazz);
-    if (parcel != NULL) {
-        parcel->setDataPosition(pos);
-    }
-}
-
-static void android_os_Parcel_setDataCapacity(JNIEnv* env, jobject clazz, jint size)
-{
-    Parcel* parcel = parcelForJavaObject(env, clazz);
-    if (parcel != NULL) {
-        const status_t err = parcel->setDataCapacity(size);
-        if (err != NO_ERROR) {
-            signalExceptionForError(env, clazz, err);
-        }
-    }
-}
-
-static jboolean android_os_Parcel_pushAllowFds(JNIEnv* env, jobject clazz, jboolean allowFds)
-{
-    Parcel* parcel = parcelForJavaObject(env, clazz);
-    jboolean ret = JNI_TRUE;
-    if (parcel != NULL) {
-        ret = (jboolean)parcel->pushAllowFds(allowFds);
-    }
-    return ret;
-}
-
-static void android_os_Parcel_restoreAllowFds(JNIEnv* env, jobject clazz, jboolean lastValue)
-{
-    Parcel* parcel = parcelForJavaObject(env, clazz);
-    if (parcel != NULL) {
-        parcel->restoreAllowFds((bool)lastValue);
-    }
-}
-
-static void android_os_Parcel_writeNative(JNIEnv* env, jobject clazz,
-                                          jobject data, jint offset,
-                                          jint length)
-{
-    Parcel* parcel = parcelForJavaObject(env, clazz);
-    if (parcel == NULL) {
-        return;
-    }
-
-    const status_t err = parcel->writeInt32(length);
-    if (err != NO_ERROR) {
-        signalExceptionForError(env, clazz, err);
-        return;
-    }
-
-    void* dest = parcel->writeInplace(length);
-    if (dest == NULL) {
-        signalExceptionForError(env, clazz, NO_MEMORY);
-        return;
-    }
-
-    jbyte* ar = (jbyte*)env->GetPrimitiveArrayCritical((jarray)data, 0);
-    if (ar) {
-        memcpy(dest, ar + offset, length);
-        env->ReleasePrimitiveArrayCritical((jarray)data, ar, 0);
-    }
-}
-
-
-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) {
-            signalExceptionForError(env, clazz, err);
-        }
-    }
-}
-
-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) {
-            signalExceptionForError(env, clazz, err);
-        }
-    }
-}
-
-static void android_os_Parcel_writeFloat(JNIEnv* env, jobject clazz, jfloat val)
-{
-    Parcel* parcel = parcelForJavaObject(env, clazz);
-    if (parcel != NULL) {
-        const status_t err = parcel->writeFloat(val);
-        if (err != NO_ERROR) {
-            signalExceptionForError(env, clazz, err);
-        }
-    }
-}
-
-static void android_os_Parcel_writeDouble(JNIEnv* env, jobject clazz, jdouble val)
-{
-    Parcel* parcel = parcelForJavaObject(env, clazz);
-    if (parcel != NULL) {
-        const status_t err = parcel->writeDouble(val);
-        if (err != NO_ERROR) {
-            signalExceptionForError(env, clazz, err);
-        }
-    }
-}
-
-static void android_os_Parcel_writeString(JNIEnv* env, jobject clazz, jstring val)
-{
-    Parcel* parcel = parcelForJavaObject(env, clazz);
-    if (parcel != NULL) {
-        status_t err = NO_MEMORY;
-        if (val) {
-            const jchar* str = env->GetStringCritical(val, 0);
-            if (str) {
-                err = parcel->writeString16(str, env->GetStringLength(val));
-                env->ReleaseStringCritical(val, str);
-            }
-        } else {
-            err = parcel->writeString16(NULL, 0);
-        }
-        if (err != NO_ERROR) {
-            signalExceptionForError(env, clazz, err);
-        }
-    }
-}
-
-static void android_os_Parcel_writeStrongBinder(JNIEnv* env, jobject clazz, jobject object)
-{
-    Parcel* parcel = parcelForJavaObject(env, clazz);
-    if (parcel != NULL) {
-        const status_t err = parcel->writeStrongBinder(ibinderForJavaObject(env, object));
-        if (err != NO_ERROR) {
-            signalExceptionForError(env, clazz, err);
-        }
-    }
-}
-
-static void android_os_Parcel_writeFileDescriptor(JNIEnv* env, jobject clazz, jobject object)
-{
-    Parcel* parcel = parcelForJavaObject(env, clazz);
-    if (parcel != NULL) {
-        const status_t err =
-                parcel->writeDupFileDescriptor(jniGetFDFromFileDescriptor(env, object));
-        if (err != NO_ERROR) {
-            signalExceptionForError(env, clazz, err);
-        }
-    }
-}
-
-static jbyteArray android_os_Parcel_createByteArray(JNIEnv* env, jobject clazz)
-{
-    jbyteArray ret = NULL;
-
-    Parcel* parcel = parcelForJavaObject(env, clazz);
-    if (parcel != NULL) {
-        int32_t len = parcel->readInt32();
-
-        // sanity check the stored length against the true data size
-        if (len >= 0 && len <= (int32_t)parcel->dataAvail()) {
-            ret = env->NewByteArray(len);
-
-            if (ret != NULL) {
-                jbyte* a2 = (jbyte*)env->GetPrimitiveArrayCritical(ret, 0);
-                if (a2) {
-                    const void* data = parcel->readInplace(len);
-                    memcpy(a2, data, len);
-                    env->ReleasePrimitiveArrayCritical(ret, a2, 0);
-                }
-            }
-        }
-    }
-
-    return ret;
-}
-
-static jint android_os_Parcel_readInt(JNIEnv* env, jobject clazz)
-{
-    Parcel* parcel = parcelForJavaObject(env, clazz);
-    if (parcel != NULL) {
-        return parcel->readInt32();
-    }
-    return 0;
-}
-
-static jlong android_os_Parcel_readLong(JNIEnv* env, jobject clazz)
-{
-    Parcel* parcel = parcelForJavaObject(env, clazz);
-    if (parcel != NULL) {
-        return parcel->readInt64();
-    }
-    return 0;
-}
-
-static jfloat android_os_Parcel_readFloat(JNIEnv* env, jobject clazz)
-{
-    Parcel* parcel = parcelForJavaObject(env, clazz);
-    if (parcel != NULL) {
-        return parcel->readFloat();
-    }
-    return 0;
-}
-
-static jdouble android_os_Parcel_readDouble(JNIEnv* env, jobject clazz)
-{
-    Parcel* parcel = parcelForJavaObject(env, clazz);
-    if (parcel != NULL) {
-        return parcel->readDouble();
-    }
-    return 0;
-}
-
-static jstring android_os_Parcel_readString(JNIEnv* env, jobject clazz)
-{
-    Parcel* parcel = parcelForJavaObject(env, clazz);
-    if (parcel != NULL) {
-        size_t len;
-        const char16_t* str = parcel->readString16Inplace(&len);
-        if (str) {
-            return env->NewString(str, len);
-        }
-        return NULL;
-    }
-    return NULL;
-}
-
-static jobject android_os_Parcel_readStrongBinder(JNIEnv* env, jobject clazz)
-{
-    Parcel* parcel = parcelForJavaObject(env, clazz);
-    if (parcel != NULL) {
-        return javaObjectForIBinder(env, parcel->readStrongBinder());
-    }
-    return NULL;
-}
-
-static jobject android_os_Parcel_readFileDescriptor(JNIEnv* env, jobject clazz)
-{
-    Parcel* parcel = parcelForJavaObject(env, clazz);
-    if (parcel != NULL) {
-        int fd = parcel->readFileDescriptor();
-        if (fd < 0) return NULL;
-        fd = dup(fd);
-        if (fd < 0) return NULL;
-        return jniCreateFileDescriptor(env, fd);
-    }
-    return NULL;
-}
-
-static jobject android_os_Parcel_openFileDescriptor(JNIEnv* env, jobject clazz,
-                                                    jstring name, jint mode)
-{
-    if (name == NULL) {
-        jniThrowNullPointerException(env, NULL);
-        return NULL;
-    }
-    const jchar* str = env->GetStringCritical(name, 0);
-    if (str == NULL) {
-        // Whatever, whatever.
-        jniThrowException(env, "java/lang/IllegalStateException", NULL);
-        return NULL;
-    }
-    String8 name8(str, env->GetStringLength(name));
-    env->ReleaseStringCritical(name, str);
-    int flags=0;
-    switch (mode&0x30000000) {
-        case 0:
-        case 0x10000000:
-            flags = O_RDONLY;
-            break;
-        case 0x20000000:
-            flags = O_WRONLY;
-            break;
-        case 0x30000000:
-            flags = O_RDWR;
-            break;
-    }
-
-    if (mode&0x08000000) flags |= O_CREAT;
-    if (mode&0x04000000) flags |= O_TRUNC;
-    if (mode&0x02000000) flags |= O_APPEND;
-
-    int realMode = S_IRWXU|S_IRWXG;
-    if (mode&0x00000001) realMode |= S_IROTH;
-    if (mode&0x00000002) realMode |= S_IWOTH;
-
-    int fd = open(name8.string(), flags, realMode);
-    if (fd < 0) {
-        jniThrowException(env, "java/io/FileNotFoundException", strerror(errno));
-        return NULL;
-    }
-    jobject object = jniCreateFileDescriptor(env, fd);
-    if (object == NULL) {
-        close(fd);
-    }
-    return object;
-}
-
-static jobject android_os_Parcel_dupFileDescriptor(JNIEnv* env, jobject clazz, jobject orig)
-{
-    if (orig == NULL) {
-        jniThrowNullPointerException(env, NULL);
-        return NULL;
-    }
-    int origfd = jniGetFDFromFileDescriptor(env, orig);
-    if (origfd < 0) {
-        jniThrowException(env, "java/lang/IllegalArgumentException", "bad FileDescriptor");
-        return NULL;
-    }
-
-    int fd = dup(origfd);
-    if (fd < 0) {
-        jniThrowIOException(env, errno);
-        return NULL;
-    }
-    jobject object = jniCreateFileDescriptor(env, fd);
-    if (object == NULL) {
-        close(fd);
-    }
-    return object;
-}
-
-static void android_os_Parcel_closeFileDescriptor(JNIEnv* env, jobject clazz, jobject object)
-{
-    if (object == NULL) {
-        jniThrowNullPointerException(env, NULL);
-        return;
-    }
-    int fd = jniGetFDFromFileDescriptor(env, object);
-    if (fd >= 0) {
-        jniSetFileDescriptorOfFD(env, object, -1);
-        //ALOGI("Closing ParcelFileDescriptor %d\n", fd);
-        close(fd);
-    }
-}
-
-static void android_os_Parcel_clearFileDescriptor(JNIEnv* env, jobject clazz, jobject object)
-{
-    if (object == NULL) {
-        jniThrowNullPointerException(env, NULL);
-        return;
-    }
-    int fd = jniGetFDFromFileDescriptor(env, object);
-    if (fd >= 0) {
-        jniSetFileDescriptorOfFD(env, object, -1);
-    }
-}
-
-static void android_os_Parcel_freeBuffer(JNIEnv* env, jobject clazz)
-{
-    int32_t own = env->GetIntField(clazz, gParcelOffsets.mOwnObject);
-    if (own) {
-        Parcel* parcel = parcelForJavaObject(env, clazz);
-        if (parcel != NULL) {
-            //ALOGI("Parcel.freeBuffer() called for C++ Parcel %p\n", parcel);
-            parcel->freeData();
-        }
-    }
-}
-
-static void android_os_Parcel_init(JNIEnv* env, jobject clazz, jint parcelInt)
-{
-    Parcel* parcel = (Parcel*)parcelInt;
-    int own = 0;
-    if (!parcel) {
-        //ALOGI("Initializing obj %p: creating new Parcel\n", clazz);
-        own = 1;
-        parcel = new Parcel;
-    } else {
-        //ALOGI("Initializing obj %p: given existing Parcel %p\n", clazz, parcel);
-    }
-    if (parcel == NULL) {
-        jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
-        return;
-    }
-    //ALOGI("Initializing obj %p from C++ Parcel %p, own=%d\n", clazz, parcel, own);
-    env->SetIntField(clazz, gParcelOffsets.mOwnObject, own);
-    env->SetIntField(clazz, gParcelOffsets.mObject, (int)parcel);
-}
-
-static void android_os_Parcel_destroy(JNIEnv* env, jobject clazz)
-{
-    int32_t own = env->GetIntField(clazz, gParcelOffsets.mOwnObject);
-    if (own) {
-        Parcel* parcel = parcelForJavaObject(env, clazz);
-        env->SetIntField(clazz, gParcelOffsets.mObject, 0);
-        //ALOGI("Destroying obj %p: deleting C++ Parcel %p\n", clazz, parcel);
-        delete parcel;
-    } else {
-        env->SetIntField(clazz, gParcelOffsets.mObject, 0);
-        //ALOGI("Destroying obj %p: leaving C++ Parcel %p\n", clazz);
-    }
-}
-
-static jbyteArray android_os_Parcel_marshall(JNIEnv* env, jobject clazz)
-{
-    Parcel* parcel = parcelForJavaObject(env, clazz);
-    if (parcel == NULL) {
-       return NULL;
-    }
-
-    // do not marshall if there are binder objects in the parcel
-    if (parcel->objectsCount())
-    {
-        jniThrowException(env, "java/lang/RuntimeException", "Tried to marshall a Parcel that contained Binder objects.");
-        return NULL;
-    }
-
-    jbyteArray ret = env->NewByteArray(parcel->dataSize());
-
-    if (ret != NULL)
-    {
-        jbyte* array = (jbyte*)env->GetPrimitiveArrayCritical(ret, 0);
-        if (array != NULL)
-        {
-            memcpy(array, parcel->data(), parcel->dataSize());
-            env->ReleasePrimitiveArrayCritical(ret, array, 0);
-        }
-    }
-
-    return ret;
-}
-
-static void android_os_Parcel_unmarshall(JNIEnv* env, jobject clazz, jbyteArray data, jint offset, jint length)
-{
-    Parcel* parcel = parcelForJavaObject(env, clazz);
-    if (parcel == NULL || length < 0) {
-       return;
-    }
-
-    jbyte* array = (jbyte*)env->GetPrimitiveArrayCritical(data, 0);
-    if (array)
-    {
-        parcel->setDataSize(length);
-        parcel->setDataPosition(0);
-
-        void* raw = parcel->writeInplace(length);
-        memcpy(raw, (array + offset), length);
-
-        env->ReleasePrimitiveArrayCritical(data, array, 0);
-    }
-}
-
-static void android_os_Parcel_appendFrom(JNIEnv* env, jobject clazz, jobject parcel, jint offset, jint length)
-{
-    Parcel* thisParcel = parcelForJavaObject(env, clazz);
-    if (thisParcel == NULL) {
-       return;
-    }
-    Parcel* otherParcel = parcelForJavaObject(env, parcel);
-    if (otherParcel == NULL) {
-       return;
-    }
-
-    status_t err = thisParcel->appendFrom(otherParcel, offset, length);
-    if (err != NO_ERROR) {
-        signalExceptionForError(env, clazz, err);
-    }
-}
-
-static jboolean android_os_Parcel_hasFileDescriptors(JNIEnv* env, jobject clazz)
-{
-    jboolean ret = JNI_FALSE;
-    Parcel* parcel = parcelForJavaObject(env, clazz);
-    if (parcel != NULL) {
-        if (parcel->hasFileDescriptors()) {
-            ret = JNI_TRUE;
-        }
-    }
-    return ret;
-}
-
-static void android_os_Parcel_writeInterfaceToken(JNIEnv* env, jobject clazz, jstring name)
-{
-    Parcel* parcel = parcelForJavaObject(env, clazz);
-    if (parcel != NULL) {
-        // In the current implementation, the token is just the serialized interface name that
-        // the caller expects to be invoking
-        const jchar* str = env->GetStringCritical(name, 0);
-        if (str != NULL) {
-            parcel->writeInterfaceToken(String16(str, env->GetStringLength(name)));
-            env->ReleaseStringCritical(name, str);
-        }
-    }
-}
-
-static void android_os_Parcel_enforceInterface(JNIEnv* env, jobject clazz, jstring name)
-{
-    jboolean ret = JNI_FALSE;
-
-    Parcel* parcel = parcelForJavaObject(env, clazz);
-    if (parcel != NULL) {
-        const jchar* str = env->GetStringCritical(name, 0);
-        if (str) {
-            IPCThreadState* threadState = IPCThreadState::self();
-            const int32_t oldPolicy = threadState->getStrictModePolicy();
-            const bool isValid = parcel->enforceInterface(
-                String16(str, env->GetStringLength(name)),
-                threadState);
-            env->ReleaseStringCritical(name, str);
-            if (isValid) {
-                const int32_t newPolicy = threadState->getStrictModePolicy();
-                if (oldPolicy != newPolicy) {
-                    // Need to keep the Java-level thread-local strict
-                    // mode policy in sync for the libcore
-                    // enforcements, which involves an upcall back
-                    // into Java.  (We can't modify the
-                    // Parcel.enforceInterface signature, as it's
-                    // pseudo-public, and used via AIDL
-                    // auto-generation...)
-                    set_dalvik_blockguard_policy(env, newPolicy);
-                }
-                return;     // everything was correct -> return silently
-            }
-        }
-    }
-
-    // all error conditions wind up here
-    jniThrowException(env, "java/lang/SecurityException",
-            "Binder invocation to an incorrect interface");
-}
-
-// ----------------------------------------------------------------------------
-
-static const JNINativeMethod gParcelMethods[] = {
-    {"dataSize",            "()I", (void*)android_os_Parcel_dataSize},
-    {"dataAvail",           "()I", (void*)android_os_Parcel_dataAvail},
-    {"dataPosition",        "()I", (void*)android_os_Parcel_dataPosition},
-    {"dataCapacity",        "()I", (void*)android_os_Parcel_dataCapacity},
-    {"setDataSize",         "(I)V", (void*)android_os_Parcel_setDataSize},
-    {"setDataPosition",     "(I)V", (void*)android_os_Parcel_setDataPosition},
-    {"setDataCapacity",     "(I)V", (void*)android_os_Parcel_setDataCapacity},
-    {"pushAllowFds",        "(Z)Z", (void*)android_os_Parcel_pushAllowFds},
-    {"restoreAllowFds",     "(Z)V", (void*)android_os_Parcel_restoreAllowFds},
-    {"writeNative",         "([BII)V", (void*)android_os_Parcel_writeNative},
-    {"writeInt",            "(I)V", (void*)android_os_Parcel_writeInt},
-    {"writeLong",           "(J)V", (void*)android_os_Parcel_writeLong},
-    {"writeFloat",          "(F)V", (void*)android_os_Parcel_writeFloat},
-    {"writeDouble",         "(D)V", (void*)android_os_Parcel_writeDouble},
-    {"writeString",         "(Ljava/lang/String;)V", (void*)android_os_Parcel_writeString},
-    {"writeStrongBinder",   "(Landroid/os/IBinder;)V", (void*)android_os_Parcel_writeStrongBinder},
-    {"writeFileDescriptor", "(Ljava/io/FileDescriptor;)V", (void*)android_os_Parcel_writeFileDescriptor},
-    {"createByteArray",     "()[B", (void*)android_os_Parcel_createByteArray},
-    {"readInt",             "()I", (void*)android_os_Parcel_readInt},
-    {"readLong",            "()J", (void*)android_os_Parcel_readLong},
-    {"readFloat",           "()F", (void*)android_os_Parcel_readFloat},
-    {"readDouble",          "()D", (void*)android_os_Parcel_readDouble},
-    {"readString",          "()Ljava/lang/String;", (void*)android_os_Parcel_readString},
-    {"readStrongBinder",    "()Landroid/os/IBinder;", (void*)android_os_Parcel_readStrongBinder},
-    {"internalReadFileDescriptor",  "()Ljava/io/FileDescriptor;", (void*)android_os_Parcel_readFileDescriptor},
-    {"openFileDescriptor",  "(Ljava/lang/String;I)Ljava/io/FileDescriptor;", (void*)android_os_Parcel_openFileDescriptor},
-    {"dupFileDescriptor",   "(Ljava/io/FileDescriptor;)Ljava/io/FileDescriptor;", (void*)android_os_Parcel_dupFileDescriptor},
-    {"closeFileDescriptor", "(Ljava/io/FileDescriptor;)V", (void*)android_os_Parcel_closeFileDescriptor},
-    {"clearFileDescriptor", "(Ljava/io/FileDescriptor;)V", (void*)android_os_Parcel_clearFileDescriptor},
-    {"freeBuffer",          "()V", (void*)android_os_Parcel_freeBuffer},
-    {"init",                "(I)V", (void*)android_os_Parcel_init},
-    {"destroy",             "()V", (void*)android_os_Parcel_destroy},
-    {"marshall",            "()[B", (void*)android_os_Parcel_marshall},
-    {"unmarshall",          "([BII)V", (void*)android_os_Parcel_unmarshall},
-    {"appendFrom",          "(Landroid/os/Parcel;II)V", (void*)android_os_Parcel_appendFrom},
-    {"hasFileDescriptors",  "()Z", (void*)android_os_Parcel_hasFileDescriptors},
-    {"writeInterfaceToken", "(Ljava/lang/String;)V", (void*)android_os_Parcel_writeInterfaceToken},
-    {"enforceInterface",    "(Ljava/lang/String;)V", (void*)android_os_Parcel_enforceInterface},
-};
-
-const char* const kParcelPathName = "android/os/Parcel";
-
-static int int_register_android_os_Parcel(JNIEnv* env)
-{
     jclass clazz;
 
     clazz = env->FindClass("android/util/Log");
@@ -1894,14 +1281,6 @@
     gParcelFileDescriptorOffsets.mConstructor
         = env->GetMethodID(clazz, "<init>", "(Ljava/io/FileDescriptor;)V");
 
-    clazz = env->FindClass(kParcelPathName);
-    LOG_FATAL_IF(clazz == NULL, "Unable to find class android.os.Parcel");
-
-    gParcelOffsets.mObject
-        = env->GetFieldID(clazz, "mObject", "I");
-    gParcelOffsets.mOwnObject
-        = env->GetFieldID(clazz, "mOwnObject", "I");
-
     clazz = env->FindClass("android/os/StrictMode");
     LOG_FATAL_IF(clazz == NULL, "Unable to find class android.os.StrictMode");
     gStrictModeCallbackOffsets.mClass = (jclass) env->NewGlobalRef(clazz);
@@ -1910,20 +1289,5 @@
     LOG_FATAL_IF(gStrictModeCallbackOffsets.mCallback == NULL,
                  "Unable to find strict mode callback.");
 
-    return AndroidRuntime::registerNativeMethods(
-        env, kParcelPathName,
-        gParcelMethods, NELEM(gParcelMethods));
-}
-
-int register_android_os_Binder(JNIEnv* env)
-{
-    if (int_register_android_os_Binder(env) < 0)
-        return -1;
-    if (int_register_android_os_BinderInternal(env) < 0)
-        return -1;
-    if (int_register_android_os_BinderProxy(env) < 0)
-        return -1;
-    if (int_register_android_os_Parcel(env) < 0)
-        return -1;
     return 0;
 }
diff --git a/core/jni/android_util_Binder.h b/core/jni/android_util_Binder.h
index 0122691..ca320ef 100644
--- a/core/jni/android_util_Binder.h
+++ b/core/jni/android_util_Binder.h
@@ -15,6 +15,9 @@
 ** limitations under the License.
 */
 
+#ifndef ANDROID_UTIL_BINDER_H
+#define ANDROID_UTIL_BINDER_H
+
 #include <binder/IBinder.h>
 
 #include "jni.h"
@@ -25,10 +28,13 @@
 extern jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val);
 extern sp<IBinder> ibinderForJavaObject(JNIEnv* env, jobject obj);
 
-// Conversion from Java Parcel Object to C++ Parcel instance.
-// Note: does not type checking; must guarantee jobject is a Java Parcel
-extern Parcel* parcelForJavaObject(JNIEnv* env, jobject obj);
-
 extern jobject newParcelFileDescriptor(JNIEnv* env, jobject fileDesc);
 
+extern void set_dalvik_blockguard_policy(JNIEnv* env, jint strict_policy);
+
+extern void signalExceptionForError(JNIEnv* env, jobject obj, status_t err,
+        bool canThrowRemoteException = false);
+
 }
+
+#endif
diff --git a/core/jni/android_view_InputChannel.cpp b/core/jni/android_view_InputChannel.cpp
index 8350e73..9c44a59 100644
--- a/core/jni/android_view_InputChannel.cpp
+++ b/core/jni/android_view_InputChannel.cpp
@@ -23,6 +23,7 @@
 #include <utils/Log.h>
 #include <androidfw/InputTransport.h>
 #include "android_view_InputChannel.h"
+#include "android_os_Parcel.h"
 #include "android_util_Binder.h"
 
 namespace android {
diff --git a/core/jni/android_view_MotionEvent.cpp b/core/jni/android_view_MotionEvent.cpp
index 0fb1b17..e69fb74 100644
--- a/core/jni/android_view_MotionEvent.cpp
+++ b/core/jni/android_view_MotionEvent.cpp
@@ -21,6 +21,7 @@
 #include <android_runtime/AndroidRuntime.h>
 #include <utils/Log.h>
 #include <androidfw/Input.h>
+#include "android_os_Parcel.h"
 #include "android_view_MotionEvent.h"
 #include "android_util_Binder.h"
 #include "android/graphics/Matrix.h"