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