android_os_Parcel.cpp revision 701aae276fb692937c12b9442dc7586b18a1a3f9
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    ScopedUtfChars name8(env, name);
455    if (name8.c_str() == NULL) {
456        return NULL;
457    }
458
459    int flags=0;
460    switch (mode&0x30000000) {
461        case 0:
462        case 0x10000000:
463            flags = O_RDONLY;
464            break;
465        case 0x20000000:
466            flags = O_WRONLY;
467            break;
468        case 0x30000000:
469            flags = O_RDWR;
470            break;
471    }
472
473    if (mode&0x08000000) flags |= O_CREAT;
474    if (mode&0x04000000) flags |= O_TRUNC;
475    if (mode&0x02000000) flags |= O_APPEND;
476
477    int realMode = S_IRWXU|S_IRWXG;
478    if (mode&0x00000001) realMode |= S_IROTH;
479    if (mode&0x00000002) realMode |= S_IWOTH;
480
481    int fd = open(name8.c_str(), flags, realMode);
482    if (fd < 0) {
483        jniThrowException(env, "java/io/FileNotFoundException", strerror(errno));
484        return NULL;
485    }
486    jobject object = jniCreateFileDescriptor(env, fd);
487    if (object == NULL) {
488        close(fd);
489    }
490    return object;
491}
492
493static jobject android_os_Parcel_dupFileDescriptor(JNIEnv* env, jclass clazz, jobject orig)
494{
495    if (orig == NULL) {
496        jniThrowNullPointerException(env, NULL);
497        return NULL;
498    }
499    int origfd = jniGetFDFromFileDescriptor(env, orig);
500    if (origfd < 0) {
501        jniThrowException(env, "java/lang/IllegalArgumentException", "bad FileDescriptor");
502        return NULL;
503    }
504
505    int fd = dup(origfd);
506    if (fd < 0) {
507        jniThrowIOException(env, errno);
508        return NULL;
509    }
510    jobject object = jniCreateFileDescriptor(env, fd);
511    if (object == NULL) {
512        close(fd);
513    }
514    return object;
515}
516
517static void android_os_Parcel_closeFileDescriptor(JNIEnv* env, jclass clazz, jobject object)
518{
519    if (object == NULL) {
520        jniThrowNullPointerException(env, NULL);
521        return;
522    }
523    int fd = jniGetFDFromFileDescriptor(env, object);
524    if (fd >= 0) {
525        jniSetFileDescriptorOfFD(env, object, -1);
526        //ALOGI("Closing ParcelFileDescriptor %d\n", fd);
527        close(fd);
528    }
529}
530
531static void android_os_Parcel_clearFileDescriptor(JNIEnv* env, jclass clazz, jobject object)
532{
533    if (object == NULL) {
534        jniThrowNullPointerException(env, NULL);
535        return;
536    }
537    int fd = jniGetFDFromFileDescriptor(env, object);
538    if (fd >= 0) {
539        jniSetFileDescriptorOfFD(env, object, -1);
540    }
541}
542
543static jlong android_os_Parcel_create(JNIEnv* env, jclass clazz)
544{
545    Parcel* parcel = new Parcel();
546    return reinterpret_cast<jlong>(parcel);
547}
548
549static void android_os_Parcel_freeBuffer(JNIEnv* env, jclass clazz, jlong nativePtr)
550{
551    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
552    if (parcel != NULL) {
553        parcel->freeData();
554    }
555}
556
557static void android_os_Parcel_destroy(JNIEnv* env, jclass clazz, jlong nativePtr)
558{
559    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
560    delete parcel;
561}
562
563static jbyteArray android_os_Parcel_marshall(JNIEnv* env, jclass clazz, jlong nativePtr)
564{
565    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
566    if (parcel == NULL) {
567       return NULL;
568    }
569
570    // do not marshall if there are binder objects in the parcel
571    if (parcel->objectsCount())
572    {
573        jniThrowException(env, "java/lang/RuntimeException", "Tried to marshall a Parcel that contained Binder objects.");
574        return NULL;
575    }
576
577    jbyteArray ret = env->NewByteArray(parcel->dataSize());
578
579    if (ret != NULL)
580    {
581        jbyte* array = (jbyte*)env->GetPrimitiveArrayCritical(ret, 0);
582        if (array != NULL)
583        {
584            memcpy(array, parcel->data(), parcel->dataSize());
585            env->ReleasePrimitiveArrayCritical(ret, array, 0);
586        }
587    }
588
589    return ret;
590}
591
592static void android_os_Parcel_unmarshall(JNIEnv* env, jclass clazz, jlong nativePtr,
593                                         jbyteArray data, jint offset, jint length)
594{
595    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
596    if (parcel == NULL || length < 0) {
597       return;
598    }
599
600    jbyte* array = (jbyte*)env->GetPrimitiveArrayCritical(data, 0);
601    if (array)
602    {
603        parcel->setDataSize(length);
604        parcel->setDataPosition(0);
605
606        void* raw = parcel->writeInplace(length);
607        memcpy(raw, (array + offset), length);
608
609        env->ReleasePrimitiveArrayCritical(data, array, 0);
610    }
611}
612
613static void android_os_Parcel_appendFrom(JNIEnv* env, jclass clazz, jlong thisNativePtr,
614                                         jlong otherNativePtr, jint offset, jint length)
615{
616    Parcel* thisParcel = reinterpret_cast<Parcel*>(thisNativePtr);
617    if (thisParcel == NULL) {
618       return;
619    }
620    Parcel* otherParcel = reinterpret_cast<Parcel*>(otherNativePtr);
621    if (otherParcel == NULL) {
622       return;
623    }
624
625    status_t err = thisParcel->appendFrom(otherParcel, offset, length);
626    if (err != NO_ERROR) {
627        signalExceptionForError(env, clazz, err);
628    }
629}
630
631static jboolean android_os_Parcel_hasFileDescriptors(JNIEnv* env, jclass clazz, jlong nativePtr)
632{
633    jboolean ret = JNI_FALSE;
634    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
635    if (parcel != NULL) {
636        if (parcel->hasFileDescriptors()) {
637            ret = JNI_TRUE;
638        }
639    }
640    return ret;
641}
642
643static void android_os_Parcel_writeInterfaceToken(JNIEnv* env, jclass clazz, jlong nativePtr,
644                                                  jstring name)
645{
646    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
647    if (parcel != NULL) {
648        // In the current implementation, the token is just the serialized interface name that
649        // the caller expects to be invoking
650        const jchar* str = env->GetStringCritical(name, 0);
651        if (str != NULL) {
652            parcel->writeInterfaceToken(String16(
653                  reinterpret_cast<const char16_t*>(str),
654                  env->GetStringLength(name)));
655            env->ReleaseStringCritical(name, str);
656        }
657    }
658}
659
660static void android_os_Parcel_enforceInterface(JNIEnv* env, jclass clazz, jlong nativePtr, jstring name)
661{
662    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
663    if (parcel != NULL) {
664        const jchar* str = env->GetStringCritical(name, 0);
665        if (str) {
666            IPCThreadState* threadState = IPCThreadState::self();
667            const int32_t oldPolicy = threadState->getStrictModePolicy();
668            const bool isValid = parcel->enforceInterface(
669                String16(reinterpret_cast<const char16_t*>(str),
670                         env->GetStringLength(name)),
671                threadState);
672            env->ReleaseStringCritical(name, str);
673            if (isValid) {
674                const int32_t newPolicy = threadState->getStrictModePolicy();
675                if (oldPolicy != newPolicy) {
676                    // Need to keep the Java-level thread-local strict
677                    // mode policy in sync for the libcore
678                    // enforcements, which involves an upcall back
679                    // into Java.  (We can't modify the
680                    // Parcel.enforceInterface signature, as it's
681                    // pseudo-public, and used via AIDL
682                    // auto-generation...)
683                    set_dalvik_blockguard_policy(env, newPolicy);
684                }
685                return;     // everything was correct -> return silently
686            }
687        }
688    }
689
690    // all error conditions wind up here
691    jniThrowException(env, "java/lang/SecurityException",
692            "Binder invocation to an incorrect interface");
693}
694
695static jlong android_os_Parcel_getGlobalAllocSize(JNIEnv* env, jclass clazz)
696{
697    return Parcel::getGlobalAllocSize();
698}
699
700static jlong android_os_Parcel_getGlobalAllocCount(JNIEnv* env, jclass clazz)
701{
702    return Parcel::getGlobalAllocCount();
703}
704
705static jlong android_os_Parcel_getBlobAshmemSize(JNIEnv* env, jclass clazz, jlong nativePtr)
706{
707    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
708    if (parcel != NULL) {
709        return parcel->getBlobAshmemSize();
710    }
711    return 0;
712}
713
714// ----------------------------------------------------------------------------
715
716static const JNINativeMethod gParcelMethods[] = {
717    {"nativeDataSize",            "(J)I", (void*)android_os_Parcel_dataSize},
718    {"nativeDataAvail",           "(J)I", (void*)android_os_Parcel_dataAvail},
719    {"nativeDataPosition",        "(J)I", (void*)android_os_Parcel_dataPosition},
720    {"nativeDataCapacity",        "(J)I", (void*)android_os_Parcel_dataCapacity},
721    {"nativeSetDataSize",         "(JI)V", (void*)android_os_Parcel_setDataSize},
722    {"nativeSetDataPosition",     "(JI)V", (void*)android_os_Parcel_setDataPosition},
723    {"nativeSetDataCapacity",     "(JI)V", (void*)android_os_Parcel_setDataCapacity},
724
725    {"nativePushAllowFds",        "(JZ)Z", (void*)android_os_Parcel_pushAllowFds},
726    {"nativeRestoreAllowFds",     "(JZ)V", (void*)android_os_Parcel_restoreAllowFds},
727
728    {"nativeWriteByteArray",      "(J[BII)V", (void*)android_os_Parcel_writeNative},
729    {"nativeWriteBlob",           "(J[BII)V", (void*)android_os_Parcel_writeBlob},
730    {"nativeWriteInt",            "(JI)V", (void*)android_os_Parcel_writeInt},
731    {"nativeWriteLong",           "(JJ)V", (void*)android_os_Parcel_writeLong},
732    {"nativeWriteFloat",          "(JF)V", (void*)android_os_Parcel_writeFloat},
733    {"nativeWriteDouble",         "(JD)V", (void*)android_os_Parcel_writeDouble},
734    {"nativeWriteString",         "(JLjava/lang/String;)V", (void*)android_os_Parcel_writeString},
735    {"nativeWriteStrongBinder",   "(JLandroid/os/IBinder;)V", (void*)android_os_Parcel_writeStrongBinder},
736    {"nativeWriteFileDescriptor", "(JLjava/io/FileDescriptor;)V", (void*)android_os_Parcel_writeFileDescriptor},
737
738    {"nativeCreateByteArray",     "(J)[B", (void*)android_os_Parcel_createByteArray},
739    {"nativeReadBlob",            "(J)[B", (void*)android_os_Parcel_readBlob},
740    {"nativeReadInt",             "(J)I", (void*)android_os_Parcel_readInt},
741    {"nativeReadLong",            "(J)J", (void*)android_os_Parcel_readLong},
742    {"nativeReadFloat",           "(J)F", (void*)android_os_Parcel_readFloat},
743    {"nativeReadDouble",          "(J)D", (void*)android_os_Parcel_readDouble},
744    {"nativeReadString",          "(J)Ljava/lang/String;", (void*)android_os_Parcel_readString},
745    {"nativeReadStrongBinder",    "(J)Landroid/os/IBinder;", (void*)android_os_Parcel_readStrongBinder},
746    {"nativeReadFileDescriptor",  "(J)Ljava/io/FileDescriptor;", (void*)android_os_Parcel_readFileDescriptor},
747
748    {"openFileDescriptor",        "(Ljava/lang/String;I)Ljava/io/FileDescriptor;", (void*)android_os_Parcel_openFileDescriptor},
749    {"dupFileDescriptor",         "(Ljava/io/FileDescriptor;)Ljava/io/FileDescriptor;", (void*)android_os_Parcel_dupFileDescriptor},
750    {"closeFileDescriptor",       "(Ljava/io/FileDescriptor;)V", (void*)android_os_Parcel_closeFileDescriptor},
751    {"clearFileDescriptor",       "(Ljava/io/FileDescriptor;)V", (void*)android_os_Parcel_clearFileDescriptor},
752
753    {"nativeCreate",              "()J", (void*)android_os_Parcel_create},
754    {"nativeFreeBuffer",          "(J)V", (void*)android_os_Parcel_freeBuffer},
755    {"nativeDestroy",             "(J)V", (void*)android_os_Parcel_destroy},
756
757    {"nativeMarshall",            "(J)[B", (void*)android_os_Parcel_marshall},
758    {"nativeUnmarshall",          "(J[BII)V", (void*)android_os_Parcel_unmarshall},
759    {"nativeAppendFrom",          "(JJII)V", (void*)android_os_Parcel_appendFrom},
760    {"nativeHasFileDescriptors",  "(J)Z", (void*)android_os_Parcel_hasFileDescriptors},
761    {"nativeWriteInterfaceToken", "(JLjava/lang/String;)V", (void*)android_os_Parcel_writeInterfaceToken},
762    {"nativeEnforceInterface",    "(JLjava/lang/String;)V", (void*)android_os_Parcel_enforceInterface},
763
764    {"getGlobalAllocSize",        "()J", (void*)android_os_Parcel_getGlobalAllocSize},
765    {"getGlobalAllocCount",       "()J", (void*)android_os_Parcel_getGlobalAllocCount},
766
767    {"nativeGetBlobAshmemSize",       "(J)J", (void*)android_os_Parcel_getBlobAshmemSize},
768};
769
770const char* const kParcelPathName = "android/os/Parcel";
771
772int register_android_os_Parcel(JNIEnv* env)
773{
774    jclass clazz = FindClassOrDie(env, kParcelPathName);
775
776    gParcelOffsets.clazz = MakeGlobalRefOrDie(env, clazz);
777    gParcelOffsets.mNativePtr = GetFieldIDOrDie(env, clazz, "mNativePtr", "J");
778    gParcelOffsets.obtain = GetStaticMethodIDOrDie(env, clazz, "obtain", "()Landroid/os/Parcel;");
779    gParcelOffsets.recycle = GetMethodIDOrDie(env, clazz, "recycle", "()V");
780
781    return RegisterMethodsOrDie(env, kParcelPathName, gParcelMethods, NELEM(gParcelMethods));
782}
783
784};
785