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