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