android_os_Parcel.cpp revision 047238ced42eea812de9d39a9f32e94d002bfa5c
1/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "Parcel"
18//#define LOG_NDEBUG 0
19
20#include "android_os_Parcel.h"
21#include "android_util_Binder.h"
22
23#include "JNIHelp.h"
24
25#include <fcntl.h>
26#include <stdio.h>
27#include <sys/stat.h>
28#include <sys/types.h>
29#include <unistd.h>
30
31#include <utils/Atomic.h>
32#include <binder/IInterface.h>
33#include <binder/IPCThreadState.h>
34#include <utils/Log.h>
35#include <utils/SystemClock.h>
36#include <utils/List.h>
37#include <utils/KeyedVector.h>
38#include <cutils/logger.h>
39#include <binder/Parcel.h>
40#include <binder/ProcessState.h>
41#include <binder/IServiceManager.h>
42#include <utils/threads.h>
43#include <utils/String8.h>
44
45#include <ScopedUtfChars.h>
46#include <ScopedLocalRef.h>
47
48#include <android_runtime/AndroidRuntime.h>
49
50//#undef ALOGV
51//#define ALOGV(...) fprintf(stderr, __VA_ARGS__)
52
53#define DEBUG_DEATH 0
54#if DEBUG_DEATH
55#define LOGDEATH ALOGD
56#else
57#define LOGDEATH ALOGV
58#endif
59
60namespace android {
61
62static struct parcel_offsets_t
63{
64    jfieldID mNativePtr;
65} gParcelOffsets;
66
67Parcel* parcelForJavaObject(JNIEnv* env, jobject obj)
68{
69    if (obj) {
70        Parcel* p = (Parcel*)env->GetIntField(obj, gParcelOffsets.mNativePtr);
71        if (p != NULL) {
72            return p;
73        }
74        jniThrowException(env, "java/lang/IllegalStateException", "Parcel has been finalized!");
75    }
76    return NULL;
77}
78
79static jint android_os_Parcel_dataSize(JNIEnv* env, jclass clazz, jint nativePtr)
80{
81    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
82    return parcel ? parcel->dataSize() : 0;
83}
84
85static jint android_os_Parcel_dataAvail(JNIEnv* env, jclass clazz, jint nativePtr)
86{
87    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
88    return parcel ? parcel->dataAvail() : 0;
89}
90
91static jint android_os_Parcel_dataPosition(JNIEnv* env, jclass clazz, jint nativePtr)
92{
93    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
94    return parcel ? parcel->dataPosition() : 0;
95}
96
97static jint android_os_Parcel_dataCapacity(JNIEnv* env, jclass clazz, jint nativePtr)
98{
99    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
100    return parcel ? parcel->dataCapacity() : 0;
101}
102
103static void android_os_Parcel_setDataSize(JNIEnv* env, jclass clazz, jint nativePtr, jint size)
104{
105    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
106    if (parcel != NULL) {
107        const status_t err = parcel->setDataSize(size);
108        if (err != NO_ERROR) {
109            signalExceptionForError(env, clazz, err);
110        }
111    }
112}
113
114static void android_os_Parcel_setDataPosition(JNIEnv* env, jclass clazz, jint nativePtr, jint pos)
115{
116    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
117    if (parcel != NULL) {
118        parcel->setDataPosition(pos);
119    }
120}
121
122static void android_os_Parcel_setDataCapacity(JNIEnv* env, jclass clazz, jint nativePtr, jint size)
123{
124    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
125    if (parcel != NULL) {
126        const status_t err = parcel->setDataCapacity(size);
127        if (err != NO_ERROR) {
128            signalExceptionForError(env, clazz, err);
129        }
130    }
131}
132
133static jboolean android_os_Parcel_pushAllowFds(JNIEnv* env, jclass clazz, jint nativePtr, jboolean allowFds)
134{
135    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
136    jboolean ret = JNI_TRUE;
137    if (parcel != NULL) {
138        ret = (jboolean)parcel->pushAllowFds(allowFds);
139    }
140    return ret;
141}
142
143static void android_os_Parcel_restoreAllowFds(JNIEnv* env, jclass clazz, jint nativePtr, jboolean lastValue)
144{
145    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
146    if (parcel != NULL) {
147        parcel->restoreAllowFds((bool)lastValue);
148    }
149}
150
151static void android_os_Parcel_writeNative(JNIEnv* env, jclass clazz, jint nativePtr, jobject data,
152                                          jint offset, jint length)
153{
154    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
155    if (parcel == NULL) {
156        return;
157    }
158
159    const status_t err = parcel->writeInt32(length);
160    if (err != NO_ERROR) {
161        signalExceptionForError(env, clazz, err);
162        return;
163    }
164
165    void* dest = parcel->writeInplace(length);
166    if (dest == NULL) {
167        signalExceptionForError(env, clazz, NO_MEMORY);
168        return;
169    }
170
171    jbyte* ar = (jbyte*)env->GetPrimitiveArrayCritical((jarray)data, 0);
172    if (ar) {
173        memcpy(dest, ar + offset, length);
174        env->ReleasePrimitiveArrayCritical((jarray)data, ar, 0);
175    }
176}
177
178static void android_os_Parcel_writeInt(JNIEnv* env, jclass clazz, jint nativePtr, jint val) {
179    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
180    const status_t err = parcel->writeInt32(val);
181    if (err != NO_ERROR) {
182        signalExceptionForError(env, clazz, err);
183    }
184}
185
186static void android_os_Parcel_writeLong(JNIEnv* env, jclass clazz, jint nativePtr, jlong val)
187{
188    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
189    if (parcel != NULL) {
190        const status_t err = parcel->writeInt64(val);
191        if (err != NO_ERROR) {
192            signalExceptionForError(env, clazz, err);
193        }
194    }
195}
196
197static void android_os_Parcel_writeFloat(JNIEnv* env, jclass clazz, jint nativePtr, jfloat val)
198{
199    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
200    if (parcel != NULL) {
201        const status_t err = parcel->writeFloat(val);
202        if (err != NO_ERROR) {
203            signalExceptionForError(env, clazz, err);
204        }
205    }
206}
207
208static void android_os_Parcel_writeDouble(JNIEnv* env, jclass clazz, jint nativePtr, jdouble val)
209{
210    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
211    if (parcel != NULL) {
212        const status_t err = parcel->writeDouble(val);
213        if (err != NO_ERROR) {
214            signalExceptionForError(env, clazz, err);
215        }
216    }
217}
218
219static void android_os_Parcel_writeString(JNIEnv* env, jclass clazz, jint nativePtr, jstring val)
220{
221    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
222    if (parcel != NULL) {
223        status_t err = NO_MEMORY;
224        if (val) {
225            const jchar* str = env->GetStringCritical(val, 0);
226            if (str) {
227                err = parcel->writeString16(str, env->GetStringLength(val));
228                env->ReleaseStringCritical(val, str);
229            }
230        } else {
231            err = parcel->writeString16(NULL, 0);
232        }
233        if (err != NO_ERROR) {
234            signalExceptionForError(env, clazz, err);
235        }
236    }
237}
238
239static void android_os_Parcel_writeStrongBinder(JNIEnv* env, jclass clazz, jint nativePtr, jobject object)
240{
241    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
242    if (parcel != NULL) {
243        const status_t err = parcel->writeStrongBinder(ibinderForJavaObject(env, object));
244        if (err != NO_ERROR) {
245            signalExceptionForError(env, clazz, err);
246        }
247    }
248}
249
250static void android_os_Parcel_writeFileDescriptor(JNIEnv* env, jclass clazz, jint nativePtr, jobject object)
251{
252    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
253    if (parcel != NULL) {
254        const status_t err =
255                parcel->writeDupFileDescriptor(jniGetFDFromFileDescriptor(env, object));
256        if (err != NO_ERROR) {
257            signalExceptionForError(env, clazz, err);
258        }
259    }
260}
261
262static jbyteArray android_os_Parcel_createByteArray(JNIEnv* env, jclass clazz, jint nativePtr)
263{
264    jbyteArray ret = NULL;
265
266    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
267    if (parcel != NULL) {
268        int32_t len = parcel->readInt32();
269
270        // sanity check the stored length against the true data size
271        if (len >= 0 && len <= (int32_t)parcel->dataAvail()) {
272            ret = env->NewByteArray(len);
273
274            if (ret != NULL) {
275                jbyte* a2 = (jbyte*)env->GetPrimitiveArrayCritical(ret, 0);
276                if (a2) {
277                    const void* data = parcel->readInplace(len);
278                    memcpy(a2, data, len);
279                    env->ReleasePrimitiveArrayCritical(ret, a2, 0);
280                }
281            }
282        }
283    }
284
285    return ret;
286}
287
288static jint android_os_Parcel_readInt(JNIEnv* env, jclass clazz, jint nativePtr)
289{
290    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
291    if (parcel != NULL) {
292        return parcel->readInt32();
293    }
294    return 0;
295}
296
297static jlong android_os_Parcel_readLong(JNIEnv* env, jclass clazz, jint nativePtr)
298{
299    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
300    if (parcel != NULL) {
301        return parcel->readInt64();
302    }
303    return 0;
304}
305
306static jfloat android_os_Parcel_readFloat(JNIEnv* env, jclass clazz, jint nativePtr)
307{
308    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
309    if (parcel != NULL) {
310        return parcel->readFloat();
311    }
312    return 0;
313}
314
315static jdouble android_os_Parcel_readDouble(JNIEnv* env, jclass clazz, jint nativePtr)
316{
317    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
318    if (parcel != NULL) {
319        return parcel->readDouble();
320    }
321    return 0;
322}
323
324static jstring android_os_Parcel_readString(JNIEnv* env, jclass clazz, jint nativePtr)
325{
326    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
327    if (parcel != NULL) {
328        size_t len;
329        const char16_t* str = parcel->readString16Inplace(&len);
330        if (str) {
331            return env->NewString(str, len);
332        }
333        return NULL;
334    }
335    return NULL;
336}
337
338static jobject android_os_Parcel_readStrongBinder(JNIEnv* env, jclass clazz, jint nativePtr)
339{
340    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
341    if (parcel != NULL) {
342        return javaObjectForIBinder(env, parcel->readStrongBinder());
343    }
344    return NULL;
345}
346
347static jobject android_os_Parcel_readFileDescriptor(JNIEnv* env, jclass clazz, jint nativePtr)
348{
349    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
350    if (parcel != NULL) {
351        int fd = parcel->readFileDescriptor();
352        if (fd < 0) return NULL;
353        fd = dup(fd);
354        if (fd < 0) return NULL;
355        return jniCreateFileDescriptor(env, fd);
356    }
357    return NULL;
358}
359
360static jobject android_os_Parcel_openFileDescriptor(JNIEnv* env, jclass clazz,
361                                                    jstring name, jint mode)
362{
363    if (name == NULL) {
364        jniThrowNullPointerException(env, NULL);
365        return NULL;
366    }
367    const jchar* str = env->GetStringCritical(name, 0);
368    if (str == NULL) {
369        // Whatever, whatever.
370        jniThrowException(env, "java/lang/IllegalStateException", NULL);
371        return NULL;
372    }
373    String8 name8(str, env->GetStringLength(name));
374    env->ReleaseStringCritical(name, str);
375    int flags=0;
376    switch (mode&0x30000000) {
377        case 0:
378        case 0x10000000:
379            flags = O_RDONLY;
380            break;
381        case 0x20000000:
382            flags = O_WRONLY;
383            break;
384        case 0x30000000:
385            flags = O_RDWR;
386            break;
387    }
388
389    if (mode&0x08000000) flags |= O_CREAT;
390    if (mode&0x04000000) flags |= O_TRUNC;
391    if (mode&0x02000000) flags |= O_APPEND;
392
393    int realMode = S_IRWXU|S_IRWXG;
394    if (mode&0x00000001) realMode |= S_IROTH;
395    if (mode&0x00000002) realMode |= S_IWOTH;
396
397    int fd = open(name8.string(), flags, realMode);
398    if (fd < 0) {
399        jniThrowException(env, "java/io/FileNotFoundException", strerror(errno));
400        return NULL;
401    }
402    jobject object = jniCreateFileDescriptor(env, fd);
403    if (object == NULL) {
404        close(fd);
405    }
406    return object;
407}
408
409static jobject android_os_Parcel_dupFileDescriptor(JNIEnv* env, jclass clazz, jobject orig)
410{
411    if (orig == NULL) {
412        jniThrowNullPointerException(env, NULL);
413        return NULL;
414    }
415    int origfd = jniGetFDFromFileDescriptor(env, orig);
416    if (origfd < 0) {
417        jniThrowException(env, "java/lang/IllegalArgumentException", "bad FileDescriptor");
418        return NULL;
419    }
420
421    int fd = dup(origfd);
422    if (fd < 0) {
423        jniThrowIOException(env, errno);
424        return NULL;
425    }
426    jobject object = jniCreateFileDescriptor(env, fd);
427    if (object == NULL) {
428        close(fd);
429    }
430    return object;
431}
432
433static void android_os_Parcel_closeFileDescriptor(JNIEnv* env, jclass clazz, jobject object)
434{
435    if (object == NULL) {
436        jniThrowNullPointerException(env, NULL);
437        return;
438    }
439    int fd = jniGetFDFromFileDescriptor(env, object);
440    if (fd >= 0) {
441        jniSetFileDescriptorOfFD(env, object, -1);
442        //ALOGI("Closing ParcelFileDescriptor %d\n", fd);
443        close(fd);
444    }
445}
446
447static void android_os_Parcel_clearFileDescriptor(JNIEnv* env, jclass clazz, jobject object)
448{
449    if (object == NULL) {
450        jniThrowNullPointerException(env, NULL);
451        return;
452    }
453    int fd = jniGetFDFromFileDescriptor(env, object);
454    if (fd >= 0) {
455        jniSetFileDescriptorOfFD(env, object, -1);
456    }
457}
458
459static jint android_os_Parcel_create(JNIEnv* env, jclass clazz)
460{
461    Parcel* parcel = new Parcel();
462    return reinterpret_cast<jint>(parcel);
463}
464
465static void android_os_Parcel_freeBuffer(JNIEnv* env, jclass clazz, jint nativePtr)
466{
467    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
468    if (parcel != NULL) {
469        parcel->freeData();
470    }
471}
472
473static void android_os_Parcel_destroy(JNIEnv* env, jclass clazz, jint nativePtr)
474{
475    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
476    delete parcel;
477}
478
479static jbyteArray android_os_Parcel_marshall(JNIEnv* env, jclass clazz, jint nativePtr)
480{
481    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
482    if (parcel == NULL) {
483       return NULL;
484    }
485
486    // do not marshall if there are binder objects in the parcel
487    if (parcel->objectsCount())
488    {
489        jniThrowException(env, "java/lang/RuntimeException", "Tried to marshall a Parcel that contained Binder objects.");
490        return NULL;
491    }
492
493    jbyteArray ret = env->NewByteArray(parcel->dataSize());
494
495    if (ret != NULL)
496    {
497        jbyte* array = (jbyte*)env->GetPrimitiveArrayCritical(ret, 0);
498        if (array != NULL)
499        {
500            memcpy(array, parcel->data(), parcel->dataSize());
501            env->ReleasePrimitiveArrayCritical(ret, array, 0);
502        }
503    }
504
505    return ret;
506}
507
508static void android_os_Parcel_unmarshall(JNIEnv* env, jclass clazz, jint nativePtr,
509                                         jbyteArray data, jint offset, jint length)
510{
511    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
512    if (parcel == NULL || length < 0) {
513       return;
514    }
515
516    jbyte* array = (jbyte*)env->GetPrimitiveArrayCritical(data, 0);
517    if (array)
518    {
519        parcel->setDataSize(length);
520        parcel->setDataPosition(0);
521
522        void* raw = parcel->writeInplace(length);
523        memcpy(raw, (array + offset), length);
524
525        env->ReleasePrimitiveArrayCritical(data, array, 0);
526    }
527}
528
529static void android_os_Parcel_appendFrom(JNIEnv* env, jclass clazz, jint thisNativePtr,
530                                         jint otherNativePtr, jint offset, jint length)
531{
532    Parcel* thisParcel = reinterpret_cast<Parcel*>(thisNativePtr);
533    if (thisParcel == NULL) {
534       return;
535    }
536    Parcel* otherParcel = reinterpret_cast<Parcel*>(otherNativePtr);
537    if (otherParcel == NULL) {
538       return;
539    }
540
541    status_t err = thisParcel->appendFrom(otherParcel, offset, length);
542    if (err != NO_ERROR) {
543        signalExceptionForError(env, clazz, err);
544    }
545}
546
547static jboolean android_os_Parcel_hasFileDescriptors(JNIEnv* env, jclass clazz, jint nativePtr)
548{
549    jboolean ret = JNI_FALSE;
550    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
551    if (parcel != NULL) {
552        if (parcel->hasFileDescriptors()) {
553            ret = JNI_TRUE;
554        }
555    }
556    return ret;
557}
558
559static void android_os_Parcel_writeInterfaceToken(JNIEnv* env, jclass clazz, jint nativePtr,
560                                                  jstring name)
561{
562    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
563    if (parcel != NULL) {
564        // In the current implementation, the token is just the serialized interface name that
565        // the caller expects to be invoking
566        const jchar* str = env->GetStringCritical(name, 0);
567        if (str != NULL) {
568            parcel->writeInterfaceToken(String16(str, env->GetStringLength(name)));
569            env->ReleaseStringCritical(name, str);
570        }
571    }
572}
573
574static void android_os_Parcel_enforceInterface(JNIEnv* env, jclass clazz, jint nativePtr, jstring name)
575{
576    jboolean ret = JNI_FALSE;
577
578    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
579    if (parcel != NULL) {
580        const jchar* str = env->GetStringCritical(name, 0);
581        if (str) {
582            IPCThreadState* threadState = IPCThreadState::self();
583            const int32_t oldPolicy = threadState->getStrictModePolicy();
584            const bool isValid = parcel->enforceInterface(
585                String16(str, env->GetStringLength(name)),
586                threadState);
587            env->ReleaseStringCritical(name, str);
588            if (isValid) {
589                const int32_t newPolicy = threadState->getStrictModePolicy();
590                if (oldPolicy != newPolicy) {
591                    // Need to keep the Java-level thread-local strict
592                    // mode policy in sync for the libcore
593                    // enforcements, which involves an upcall back
594                    // into Java.  (We can't modify the
595                    // Parcel.enforceInterface signature, as it's
596                    // pseudo-public, and used via AIDL
597                    // auto-generation...)
598                    set_dalvik_blockguard_policy(env, newPolicy);
599                }
600                return;     // everything was correct -> return silently
601            }
602        }
603    }
604
605    // all error conditions wind up here
606    jniThrowException(env, "java/lang/SecurityException",
607            "Binder invocation to an incorrect interface");
608}
609
610// ----------------------------------------------------------------------------
611
612static const JNINativeMethod gParcelMethods[] = {
613    {"nativeDataSize",            "(I)I", (void*)android_os_Parcel_dataSize},
614    {"nativeDataAvail",           "(I)I", (void*)android_os_Parcel_dataAvail},
615    {"nativeDataPosition",        "(I)I", (void*)android_os_Parcel_dataPosition},
616    {"nativeDataCapacity",        "(I)I", (void*)android_os_Parcel_dataCapacity},
617    {"nativeSetDataSize",         "(II)V", (void*)android_os_Parcel_setDataSize},
618    {"nativeSetDataPosition",     "(II)V", (void*)android_os_Parcel_setDataPosition},
619    {"nativeSetDataCapacity",     "(II)V", (void*)android_os_Parcel_setDataCapacity},
620
621    {"nativePushAllowFds",        "(IZ)Z", (void*)android_os_Parcel_pushAllowFds},
622    {"nativeRestoreAllowFds",     "(IZ)V", (void*)android_os_Parcel_restoreAllowFds},
623
624    {"nativeWriteByteArray",      "(I[BII)V", (void*)android_os_Parcel_writeNative},
625    {"nativeWriteInt",            "(II)V", (void*)android_os_Parcel_writeInt},
626    {"nativeWriteLong",           "(IJ)V", (void*)android_os_Parcel_writeLong},
627    {"nativeWriteFloat",          "(IF)V", (void*)android_os_Parcel_writeFloat},
628    {"nativeWriteDouble",         "(ID)V", (void*)android_os_Parcel_writeDouble},
629    {"nativeWriteString",         "(ILjava/lang/String;)V", (void*)android_os_Parcel_writeString},
630    {"nativeWriteStrongBinder",   "(ILandroid/os/IBinder;)V", (void*)android_os_Parcel_writeStrongBinder},
631    {"nativeWriteFileDescriptor", "(ILjava/io/FileDescriptor;)V", (void*)android_os_Parcel_writeFileDescriptor},
632
633    {"nativeCreateByteArray",     "(I)[B", (void*)android_os_Parcel_createByteArray},
634    {"nativeReadInt",             "(I)I", (void*)android_os_Parcel_readInt},
635    {"nativeReadLong",            "(I)J", (void*)android_os_Parcel_readLong},
636    {"nativeReadFloat",           "(I)F", (void*)android_os_Parcel_readFloat},
637    {"nativeReadDouble",          "(I)D", (void*)android_os_Parcel_readDouble},
638    {"nativeReadString",          "(I)Ljava/lang/String;", (void*)android_os_Parcel_readString},
639    {"nativeReadStrongBinder",    "(I)Landroid/os/IBinder;", (void*)android_os_Parcel_readStrongBinder},
640    {"nativeReadFileDescriptor",  "(I)Ljava/io/FileDescriptor;", (void*)android_os_Parcel_readFileDescriptor},
641
642    {"openFileDescriptor",        "(Ljava/lang/String;I)Ljava/io/FileDescriptor;", (void*)android_os_Parcel_openFileDescriptor},
643    {"dupFileDescriptor",         "(Ljava/io/FileDescriptor;)Ljava/io/FileDescriptor;", (void*)android_os_Parcel_dupFileDescriptor},
644    {"closeFileDescriptor",       "(Ljava/io/FileDescriptor;)V", (void*)android_os_Parcel_closeFileDescriptor},
645    {"clearFileDescriptor",       "(Ljava/io/FileDescriptor;)V", (void*)android_os_Parcel_clearFileDescriptor},
646
647    {"nativeCreate",              "()I", (void*)android_os_Parcel_create},
648    {"nativeFreeBuffer",          "(I)V", (void*)android_os_Parcel_freeBuffer},
649    {"nativeDestroy",             "(I)V", (void*)android_os_Parcel_destroy},
650
651    {"nativeMarshall",            "(I)[B", (void*)android_os_Parcel_marshall},
652    {"nativeUnmarshall",          "(I[BII)V", (void*)android_os_Parcel_unmarshall},
653    {"nativeAppendFrom",          "(IIII)V", (void*)android_os_Parcel_appendFrom},
654    {"nativeHasFileDescriptors",  "(I)Z", (void*)android_os_Parcel_hasFileDescriptors},
655    {"nativeWriteInterfaceToken", "(ILjava/lang/String;)V", (void*)android_os_Parcel_writeInterfaceToken},
656    {"nativeEnforceInterface",    "(ILjava/lang/String;)V", (void*)android_os_Parcel_enforceInterface},
657};
658
659const char* const kParcelPathName = "android/os/Parcel";
660
661int register_android_os_Parcel(JNIEnv* env)
662{
663    jclass clazz;
664
665    clazz = env->FindClass(kParcelPathName);
666    LOG_FATAL_IF(clazz == NULL, "Unable to find class android.os.Parcel");
667
668    gParcelOffsets.mNativePtr
669        = env->GetFieldID(clazz, "mNativePtr", "I");
670
671    return AndroidRuntime::registerNativeMethods(
672        env, kParcelPathName,
673        gParcelMethods, NELEM(gParcelMethods));
674}
675
676};
677