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