android_os_Parcel.cpp revision 849ea026824d51761591a18cf6689d755f70bda4
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, false, &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    if (parcel != NULL) {
234        const status_t err = parcel->writeInt32(val);
235        if (err != NO_ERROR) {
236            signalExceptionForError(env, clazz, err);
237        }
238    }
239}
240
241static void android_os_Parcel_writeLong(JNIEnv* env, jclass clazz, jlong nativePtr, jlong val)
242{
243    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
244    if (parcel != NULL) {
245        const status_t err = parcel->writeInt64(val);
246        if (err != NO_ERROR) {
247            signalExceptionForError(env, clazz, err);
248        }
249    }
250}
251
252static void android_os_Parcel_writeFloat(JNIEnv* env, jclass clazz, jlong nativePtr, jfloat val)
253{
254    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
255    if (parcel != NULL) {
256        const status_t err = parcel->writeFloat(val);
257        if (err != NO_ERROR) {
258            signalExceptionForError(env, clazz, err);
259        }
260    }
261}
262
263static void android_os_Parcel_writeDouble(JNIEnv* env, jclass clazz, jlong nativePtr, jdouble val)
264{
265    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
266    if (parcel != NULL) {
267        const status_t err = parcel->writeDouble(val);
268        if (err != NO_ERROR) {
269            signalExceptionForError(env, clazz, err);
270        }
271    }
272}
273
274static void android_os_Parcel_writeString(JNIEnv* env, jclass clazz, jlong nativePtr, jstring val)
275{
276    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
277    if (parcel != NULL) {
278        status_t err = NO_MEMORY;
279        if (val) {
280            const jchar* str = env->GetStringCritical(val, 0);
281            if (str) {
282                err = parcel->writeString16(
283                    reinterpret_cast<const char16_t*>(str),
284                    env->GetStringLength(val));
285                env->ReleaseStringCritical(val, str);
286            }
287        } else {
288            err = parcel->writeString16(NULL, 0);
289        }
290        if (err != NO_ERROR) {
291            signalExceptionForError(env, clazz, err);
292        }
293    }
294}
295
296static void android_os_Parcel_writeStrongBinder(JNIEnv* env, jclass clazz, jlong nativePtr, jobject object)
297{
298    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
299    if (parcel != NULL) {
300        const status_t err = parcel->writeStrongBinder(ibinderForJavaObject(env, object));
301        if (err != NO_ERROR) {
302            signalExceptionForError(env, clazz, err);
303        }
304    }
305}
306
307static void android_os_Parcel_writeFileDescriptor(JNIEnv* env, jclass clazz, jlong nativePtr, jobject object)
308{
309    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
310    if (parcel != NULL) {
311        const status_t err =
312                parcel->writeDupFileDescriptor(jniGetFDFromFileDescriptor(env, object));
313        if (err != NO_ERROR) {
314            signalExceptionForError(env, clazz, err);
315        }
316    }
317}
318
319static jbyteArray android_os_Parcel_createByteArray(JNIEnv* env, jclass clazz, jlong nativePtr)
320{
321    jbyteArray ret = NULL;
322
323    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
324    if (parcel != NULL) {
325        int32_t len = parcel->readInt32();
326
327        // sanity check the stored length against the true data size
328        if (len >= 0 && len <= (int32_t)parcel->dataAvail()) {
329            ret = env->NewByteArray(len);
330
331            if (ret != NULL) {
332                jbyte* a2 = (jbyte*)env->GetPrimitiveArrayCritical(ret, 0);
333                if (a2) {
334                    const void* data = parcel->readInplace(len);
335                    memcpy(a2, data, len);
336                    env->ReleasePrimitiveArrayCritical(ret, a2, 0);
337                }
338            }
339        }
340    }
341
342    return ret;
343}
344
345static jbyteArray android_os_Parcel_readBlob(JNIEnv* env, jclass clazz, jlong nativePtr)
346{
347    jbyteArray ret = NULL;
348
349    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
350    if (parcel != NULL) {
351        int32_t len = parcel->readInt32();
352        if (len >= 0) {
353            android::Parcel::ReadableBlob blob;
354            android::status_t err = parcel->readBlob(len, &blob);
355            if (err != NO_ERROR) {
356                signalExceptionForError(env, clazz, err);
357                return NULL;
358            }
359
360            ret = env->NewByteArray(len);
361            if (ret != NULL) {
362                jbyte* a2 = (jbyte*)env->GetPrimitiveArrayCritical(ret, 0);
363                if (a2) {
364                    memcpy(a2, blob.data(), len);
365                    env->ReleasePrimitiveArrayCritical(ret, a2, 0);
366                }
367            }
368            blob.release();
369        }
370    }
371
372    return ret;
373}
374
375static jint android_os_Parcel_readInt(JNIEnv* env, jclass clazz, jlong nativePtr)
376{
377    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
378    if (parcel != NULL) {
379        return parcel->readInt32();
380    }
381    return 0;
382}
383
384static jlong android_os_Parcel_readLong(JNIEnv* env, jclass clazz, jlong nativePtr)
385{
386    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
387    if (parcel != NULL) {
388        return parcel->readInt64();
389    }
390    return 0;
391}
392
393static jfloat android_os_Parcel_readFloat(JNIEnv* env, jclass clazz, jlong nativePtr)
394{
395    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
396    if (parcel != NULL) {
397        return parcel->readFloat();
398    }
399    return 0;
400}
401
402static jdouble android_os_Parcel_readDouble(JNIEnv* env, jclass clazz, jlong nativePtr)
403{
404    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
405    if (parcel != NULL) {
406        return parcel->readDouble();
407    }
408    return 0;
409}
410
411static jstring android_os_Parcel_readString(JNIEnv* env, jclass clazz, jlong nativePtr)
412{
413    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
414    if (parcel != NULL) {
415        size_t len;
416        const char16_t* str = parcel->readString16Inplace(&len);
417        if (str) {
418            return env->NewString(reinterpret_cast<const jchar*>(str), len);
419        }
420        return NULL;
421    }
422    return NULL;
423}
424
425static jobject android_os_Parcel_readStrongBinder(JNIEnv* env, jclass clazz, jlong nativePtr)
426{
427    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
428    if (parcel != NULL) {
429        return javaObjectForIBinder(env, parcel->readStrongBinder());
430    }
431    return NULL;
432}
433
434static jobject android_os_Parcel_readFileDescriptor(JNIEnv* env, jclass clazz, jlong nativePtr)
435{
436    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
437    if (parcel != NULL) {
438        int fd = parcel->readFileDescriptor();
439        if (fd < 0) return NULL;
440        fd = dup(fd);
441        if (fd < 0) return NULL;
442        return jniCreateFileDescriptor(env, fd);
443    }
444    return NULL;
445}
446
447static jobject android_os_Parcel_openFileDescriptor(JNIEnv* env, jclass clazz,
448                                                    jstring name, jint mode)
449{
450    if (name == NULL) {
451        jniThrowNullPointerException(env, NULL);
452        return NULL;
453    }
454    const jchar* str = env->GetStringCritical(name, 0);
455    if (str == NULL) {
456        // Whatever, whatever.
457        jniThrowException(env, "java/lang/IllegalStateException", NULL);
458        return NULL;
459    }
460    String8 name8(reinterpret_cast<const char16_t*>(str),
461                  env->GetStringLength(name));
462    env->ReleaseStringCritical(name, str);
463    int flags=0;
464    switch (mode&0x30000000) {
465        case 0:
466        case 0x10000000:
467            flags = O_RDONLY;
468            break;
469        case 0x20000000:
470            flags = O_WRONLY;
471            break;
472        case 0x30000000:
473            flags = O_RDWR;
474            break;
475    }
476
477    if (mode&0x08000000) flags |= O_CREAT;
478    if (mode&0x04000000) flags |= O_TRUNC;
479    if (mode&0x02000000) flags |= O_APPEND;
480
481    int realMode = S_IRWXU|S_IRWXG;
482    if (mode&0x00000001) realMode |= S_IROTH;
483    if (mode&0x00000002) realMode |= S_IWOTH;
484
485    int fd = open(name8.string(), flags, realMode);
486    if (fd < 0) {
487        jniThrowException(env, "java/io/FileNotFoundException", strerror(errno));
488        return NULL;
489    }
490    jobject object = jniCreateFileDescriptor(env, fd);
491    if (object == NULL) {
492        close(fd);
493    }
494    return object;
495}
496
497static jobject android_os_Parcel_dupFileDescriptor(JNIEnv* env, jclass clazz, jobject orig)
498{
499    if (orig == NULL) {
500        jniThrowNullPointerException(env, NULL);
501        return NULL;
502    }
503    int origfd = jniGetFDFromFileDescriptor(env, orig);
504    if (origfd < 0) {
505        jniThrowException(env, "java/lang/IllegalArgumentException", "bad FileDescriptor");
506        return NULL;
507    }
508
509    int fd = dup(origfd);
510    if (fd < 0) {
511        jniThrowIOException(env, errno);
512        return NULL;
513    }
514    jobject object = jniCreateFileDescriptor(env, fd);
515    if (object == NULL) {
516        close(fd);
517    }
518    return object;
519}
520
521static void android_os_Parcel_closeFileDescriptor(JNIEnv* env, jclass clazz, jobject object)
522{
523    if (object == NULL) {
524        jniThrowNullPointerException(env, NULL);
525        return;
526    }
527    int fd = jniGetFDFromFileDescriptor(env, object);
528    if (fd >= 0) {
529        jniSetFileDescriptorOfFD(env, object, -1);
530        //ALOGI("Closing ParcelFileDescriptor %d\n", fd);
531        close(fd);
532    }
533}
534
535static void android_os_Parcel_clearFileDescriptor(JNIEnv* env, jclass clazz, jobject object)
536{
537    if (object == NULL) {
538        jniThrowNullPointerException(env, NULL);
539        return;
540    }
541    int fd = jniGetFDFromFileDescriptor(env, object);
542    if (fd >= 0) {
543        jniSetFileDescriptorOfFD(env, object, -1);
544    }
545}
546
547static jlong android_os_Parcel_create(JNIEnv* env, jclass clazz)
548{
549    Parcel* parcel = new Parcel();
550    return reinterpret_cast<jlong>(parcel);
551}
552
553static void android_os_Parcel_freeBuffer(JNIEnv* env, jclass clazz, jlong nativePtr)
554{
555    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
556    if (parcel != NULL) {
557        parcel->freeData();
558    }
559}
560
561static void android_os_Parcel_destroy(JNIEnv* env, jclass clazz, jlong nativePtr)
562{
563    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
564    delete parcel;
565}
566
567static jbyteArray android_os_Parcel_marshall(JNIEnv* env, jclass clazz, jlong nativePtr)
568{
569    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
570    if (parcel == NULL) {
571       return NULL;
572    }
573
574    // do not marshall if there are binder objects in the parcel
575    if (parcel->objectsCount())
576    {
577        jniThrowException(env, "java/lang/RuntimeException", "Tried to marshall a Parcel that contained Binder objects.");
578        return NULL;
579    }
580
581    jbyteArray ret = env->NewByteArray(parcel->dataSize());
582
583    if (ret != NULL)
584    {
585        jbyte* array = (jbyte*)env->GetPrimitiveArrayCritical(ret, 0);
586        if (array != NULL)
587        {
588            memcpy(array, parcel->data(), parcel->dataSize());
589            env->ReleasePrimitiveArrayCritical(ret, array, 0);
590        }
591    }
592
593    return ret;
594}
595
596static void android_os_Parcel_unmarshall(JNIEnv* env, jclass clazz, jlong nativePtr,
597                                         jbyteArray data, jint offset, jint length)
598{
599    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
600    if (parcel == NULL || length < 0) {
601       return;
602    }
603
604    jbyte* array = (jbyte*)env->GetPrimitiveArrayCritical(data, 0);
605    if (array)
606    {
607        parcel->setDataSize(length);
608        parcel->setDataPosition(0);
609
610        void* raw = parcel->writeInplace(length);
611        memcpy(raw, (array + offset), length);
612
613        env->ReleasePrimitiveArrayCritical(data, array, 0);
614    }
615}
616
617static void android_os_Parcel_appendFrom(JNIEnv* env, jclass clazz, jlong thisNativePtr,
618                                         jlong otherNativePtr, jint offset, jint length)
619{
620    Parcel* thisParcel = reinterpret_cast<Parcel*>(thisNativePtr);
621    if (thisParcel == NULL) {
622       return;
623    }
624    Parcel* otherParcel = reinterpret_cast<Parcel*>(otherNativePtr);
625    if (otherParcel == NULL) {
626       return;
627    }
628
629    status_t err = thisParcel->appendFrom(otherParcel, offset, length);
630    if (err != NO_ERROR) {
631        signalExceptionForError(env, clazz, err);
632    }
633}
634
635static jboolean android_os_Parcel_hasFileDescriptors(JNIEnv* env, jclass clazz, jlong nativePtr)
636{
637    jboolean ret = JNI_FALSE;
638    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
639    if (parcel != NULL) {
640        if (parcel->hasFileDescriptors()) {
641            ret = JNI_TRUE;
642        }
643    }
644    return ret;
645}
646
647static void android_os_Parcel_writeInterfaceToken(JNIEnv* env, jclass clazz, jlong nativePtr,
648                                                  jstring name)
649{
650    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
651    if (parcel != NULL) {
652        // In the current implementation, the token is just the serialized interface name that
653        // the caller expects to be invoking
654        const jchar* str = env->GetStringCritical(name, 0);
655        if (str != NULL) {
656            parcel->writeInterfaceToken(String16(
657                  reinterpret_cast<const char16_t*>(str),
658                  env->GetStringLength(name)));
659            env->ReleaseStringCritical(name, str);
660        }
661    }
662}
663
664static void android_os_Parcel_enforceInterface(JNIEnv* env, jclass clazz, jlong nativePtr, jstring name)
665{
666    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
667    if (parcel != NULL) {
668        const jchar* str = env->GetStringCritical(name, 0);
669        if (str) {
670            IPCThreadState* threadState = IPCThreadState::self();
671            const int32_t oldPolicy = threadState->getStrictModePolicy();
672            const bool isValid = parcel->enforceInterface(
673                String16(reinterpret_cast<const char16_t*>(str),
674                         env->GetStringLength(name)),
675                threadState);
676            env->ReleaseStringCritical(name, str);
677            if (isValid) {
678                const int32_t newPolicy = threadState->getStrictModePolicy();
679                if (oldPolicy != newPolicy) {
680                    // Need to keep the Java-level thread-local strict
681                    // mode policy in sync for the libcore
682                    // enforcements, which involves an upcall back
683                    // into Java.  (We can't modify the
684                    // Parcel.enforceInterface signature, as it's
685                    // pseudo-public, and used via AIDL
686                    // auto-generation...)
687                    set_dalvik_blockguard_policy(env, newPolicy);
688                }
689                return;     // everything was correct -> return silently
690            }
691        }
692    }
693
694    // all error conditions wind up here
695    jniThrowException(env, "java/lang/SecurityException",
696            "Binder invocation to an incorrect interface");
697}
698
699static jlong android_os_Parcel_getGlobalAllocSize(JNIEnv* env, jclass clazz)
700{
701    return Parcel::getGlobalAllocSize();
702}
703
704static jlong android_os_Parcel_getGlobalAllocCount(JNIEnv* env, jclass clazz)
705{
706    return Parcel::getGlobalAllocCount();
707}
708
709static jlong android_os_Parcel_getBlobAshmemSize(JNIEnv* env, jclass clazz, jlong nativePtr)
710{
711    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
712    if (parcel != NULL) {
713        return parcel->getBlobAshmemSize();
714    }
715    return 0;
716}
717
718// ----------------------------------------------------------------------------
719
720static const JNINativeMethod gParcelMethods[] = {
721    {"nativeDataSize",            "(J)I", (void*)android_os_Parcel_dataSize},
722    {"nativeDataAvail",           "(J)I", (void*)android_os_Parcel_dataAvail},
723    {"nativeDataPosition",        "(J)I", (void*)android_os_Parcel_dataPosition},
724    {"nativeDataCapacity",        "(J)I", (void*)android_os_Parcel_dataCapacity},
725    {"nativeSetDataSize",         "(JI)V", (void*)android_os_Parcel_setDataSize},
726    {"nativeSetDataPosition",     "(JI)V", (void*)android_os_Parcel_setDataPosition},
727    {"nativeSetDataCapacity",     "(JI)V", (void*)android_os_Parcel_setDataCapacity},
728
729    {"nativePushAllowFds",        "(JZ)Z", (void*)android_os_Parcel_pushAllowFds},
730    {"nativeRestoreAllowFds",     "(JZ)V", (void*)android_os_Parcel_restoreAllowFds},
731
732    {"nativeWriteByteArray",      "(J[BII)V", (void*)android_os_Parcel_writeNative},
733    {"nativeWriteBlob",           "(J[BII)V", (void*)android_os_Parcel_writeBlob},
734    {"nativeWriteInt",            "(JI)V", (void*)android_os_Parcel_writeInt},
735    {"nativeWriteLong",           "(JJ)V", (void*)android_os_Parcel_writeLong},
736    {"nativeWriteFloat",          "(JF)V", (void*)android_os_Parcel_writeFloat},
737    {"nativeWriteDouble",         "(JD)V", (void*)android_os_Parcel_writeDouble},
738    {"nativeWriteString",         "(JLjava/lang/String;)V", (void*)android_os_Parcel_writeString},
739    {"nativeWriteStrongBinder",   "(JLandroid/os/IBinder;)V", (void*)android_os_Parcel_writeStrongBinder},
740    {"nativeWriteFileDescriptor", "(JLjava/io/FileDescriptor;)V", (void*)android_os_Parcel_writeFileDescriptor},
741
742    {"nativeCreateByteArray",     "(J)[B", (void*)android_os_Parcel_createByteArray},
743    {"nativeReadBlob",            "(J)[B", (void*)android_os_Parcel_readBlob},
744    {"nativeReadInt",             "(J)I", (void*)android_os_Parcel_readInt},
745    {"nativeReadLong",            "(J)J", (void*)android_os_Parcel_readLong},
746    {"nativeReadFloat",           "(J)F", (void*)android_os_Parcel_readFloat},
747    {"nativeReadDouble",          "(J)D", (void*)android_os_Parcel_readDouble},
748    {"nativeReadString",          "(J)Ljava/lang/String;", (void*)android_os_Parcel_readString},
749    {"nativeReadStrongBinder",    "(J)Landroid/os/IBinder;", (void*)android_os_Parcel_readStrongBinder},
750    {"nativeReadFileDescriptor",  "(J)Ljava/io/FileDescriptor;", (void*)android_os_Parcel_readFileDescriptor},
751
752    {"openFileDescriptor",        "(Ljava/lang/String;I)Ljava/io/FileDescriptor;", (void*)android_os_Parcel_openFileDescriptor},
753    {"dupFileDescriptor",         "(Ljava/io/FileDescriptor;)Ljava/io/FileDescriptor;", (void*)android_os_Parcel_dupFileDescriptor},
754    {"closeFileDescriptor",       "(Ljava/io/FileDescriptor;)V", (void*)android_os_Parcel_closeFileDescriptor},
755    {"clearFileDescriptor",       "(Ljava/io/FileDescriptor;)V", (void*)android_os_Parcel_clearFileDescriptor},
756
757    {"nativeCreate",              "()J", (void*)android_os_Parcel_create},
758    {"nativeFreeBuffer",          "(J)V", (void*)android_os_Parcel_freeBuffer},
759    {"nativeDestroy",             "(J)V", (void*)android_os_Parcel_destroy},
760
761    {"nativeMarshall",            "(J)[B", (void*)android_os_Parcel_marshall},
762    {"nativeUnmarshall",          "(J[BII)V", (void*)android_os_Parcel_unmarshall},
763    {"nativeAppendFrom",          "(JJII)V", (void*)android_os_Parcel_appendFrom},
764    {"nativeHasFileDescriptors",  "(J)Z", (void*)android_os_Parcel_hasFileDescriptors},
765    {"nativeWriteInterfaceToken", "(JLjava/lang/String;)V", (void*)android_os_Parcel_writeInterfaceToken},
766    {"nativeEnforceInterface",    "(JLjava/lang/String;)V", (void*)android_os_Parcel_enforceInterface},
767
768    {"getGlobalAllocSize",        "()J", (void*)android_os_Parcel_getGlobalAllocSize},
769    {"getGlobalAllocCount",       "()J", (void*)android_os_Parcel_getGlobalAllocCount},
770
771    {"nativeGetBlobAshmemSize",       "(J)J", (void*)android_os_Parcel_getBlobAshmemSize},
772};
773
774const char* const kParcelPathName = "android/os/Parcel";
775
776int register_android_os_Parcel(JNIEnv* env)
777{
778    jclass clazz = FindClassOrDie(env, kParcelPathName);
779
780    gParcelOffsets.clazz = MakeGlobalRefOrDie(env, clazz);
781    gParcelOffsets.mNativePtr = GetFieldIDOrDie(env, clazz, "mNativePtr", "J");
782    gParcelOffsets.obtain = GetStaticMethodIDOrDie(env, clazz, "obtain", "()Landroid/os/Parcel;");
783    gParcelOffsets.recycle = GetMethodIDOrDie(env, clazz, "recycle", "()V");
784
785    return RegisterMethodsOrDie(env, kParcelPathName, gParcelMethods, NELEM(gParcelMethods));
786}
787
788};
789