2 * Copyright (C) 2012 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #define LOG_TAG "Parcel"
18 //#define LOG_NDEBUG 0
20 #include "android_os_Parcel.h"
21 #include "android_util_Binder.h"
28 #include <sys/types.h>
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>
44 #include <ScopedUtfChars.h>
45 #include <ScopedLocalRef.h>
47 #include <android_runtime/AndroidRuntime.h>
50 //#define ALOGV(...) fprintf(stderr, __VA_ARGS__)
54 #define LOGDEATH ALOGD
56 #define LOGDEATH ALOGV
61 static struct parcel_offsets_t
69 Parcel* parcelForJavaObject(JNIEnv* env, jobject obj)
72 Parcel* p = (Parcel*)env->GetLongField(obj, gParcelOffsets.mNativePtr);
76 jniThrowException(env, "java/lang/IllegalStateException", "Parcel has been finalized!");
81 jobject createJavaParcelObject(JNIEnv* env)
83 return env->CallStaticObjectMethod(gParcelOffsets.clazz, gParcelOffsets.obtain);
86 void recycleJavaParcelObject(JNIEnv* env, jobject parcelObj)
88 env->CallVoidMethod(parcelObj, gParcelOffsets.recycle);
91 static jint android_os_Parcel_dataSize(JNIEnv* env, jclass clazz, jlong nativePtr)
93 Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
94 return parcel ? parcel->dataSize() : 0;
97 static jint android_os_Parcel_dataAvail(JNIEnv* env, jclass clazz, jlong nativePtr)
99 Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
100 return parcel ? parcel->dataAvail() : 0;
103 static jint android_os_Parcel_dataPosition(JNIEnv* env, jclass clazz, jlong nativePtr)
105 Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
106 return parcel ? parcel->dataPosition() : 0;
109 static jint android_os_Parcel_dataCapacity(JNIEnv* env, jclass clazz, jlong nativePtr)
111 Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
112 return parcel ? parcel->dataCapacity() : 0;
115 static void android_os_Parcel_setDataSize(JNIEnv* env, jclass clazz, jlong nativePtr, jint size)
117 Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
118 if (parcel != NULL) {
119 const status_t err = parcel->setDataSize(size);
120 if (err != NO_ERROR) {
121 signalExceptionForError(env, clazz, err);
126 static void android_os_Parcel_setDataPosition(JNIEnv* env, jclass clazz, jlong nativePtr, jint pos)
128 Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
129 if (parcel != NULL) {
130 parcel->setDataPosition(pos);
134 static void android_os_Parcel_setDataCapacity(JNIEnv* env, jclass clazz, jlong nativePtr, jint size)
136 Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
137 if (parcel != NULL) {
138 const status_t err = parcel->setDataCapacity(size);
139 if (err != NO_ERROR) {
140 signalExceptionForError(env, clazz, err);
145 static jboolean android_os_Parcel_pushAllowFds(JNIEnv* env, jclass clazz, jlong nativePtr, jboolean allowFds)
147 Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
148 jboolean ret = JNI_TRUE;
149 if (parcel != NULL) {
150 ret = (jboolean)parcel->pushAllowFds(allowFds);
155 static void android_os_Parcel_restoreAllowFds(JNIEnv* env, jclass clazz, jlong nativePtr, jboolean lastValue)
157 Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
158 if (parcel != NULL) {
159 parcel->restoreAllowFds((bool)lastValue);
163 static void android_os_Parcel_writeNative(JNIEnv* env, jclass clazz, jlong nativePtr, jobject data,
164 jint offset, jint length)
166 Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
167 if (parcel == NULL) {
171 const status_t err = parcel->writeInt32(length);
172 if (err != NO_ERROR) {
173 signalExceptionForError(env, clazz, err);
177 void* dest = parcel->writeInplace(length);
179 signalExceptionForError(env, clazz, NO_MEMORY);
183 jbyte* ar = (jbyte*)env->GetPrimitiveArrayCritical((jarray)data, 0);
185 memcpy(dest, ar + offset, length);
186 env->ReleasePrimitiveArrayCritical((jarray)data, ar, 0);
190 static void android_os_Parcel_writeBlob(JNIEnv* env, jclass clazz, jlong nativePtr, jobject data,
191 jint offset, jint length) {
192 Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
193 if (parcel == NULL) {
198 const status_t err = parcel->writeInt32(-1);
199 if (err != NO_ERROR) {
200 signalExceptionForError(env, clazz, err);
205 const status_t err = parcel->writeInt32(length);
206 if (err != NO_ERROR) {
207 signalExceptionForError(env, clazz, err);
211 android::Parcel::WritableBlob blob;
212 android::status_t err2 = parcel->writeBlob(length, &blob);
213 if (err2 != NO_ERROR) {
214 signalExceptionForError(env, clazz, err2);
218 jbyte* ar = (jbyte*)env->GetPrimitiveArrayCritical((jarray)data, 0);
220 memset(blob.data(), 0, length);
222 memcpy(blob.data(), ar + offset, length);
223 env->ReleasePrimitiveArrayCritical((jarray)data, ar, 0);
229 static void android_os_Parcel_writeInt(JNIEnv* env, jclass clazz, jlong nativePtr, jint val) {
230 Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
231 const status_t err = parcel->writeInt32(val);
232 if (err != NO_ERROR) {
233 signalExceptionForError(env, clazz, err);
237 static void android_os_Parcel_writeLong(JNIEnv* env, jclass clazz, jlong nativePtr, jlong val)
239 Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
240 if (parcel != NULL) {
241 const status_t err = parcel->writeInt64(val);
242 if (err != NO_ERROR) {
243 signalExceptionForError(env, clazz, err);
248 static void android_os_Parcel_writeFloat(JNIEnv* env, jclass clazz, jlong nativePtr, jfloat val)
250 Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
251 if (parcel != NULL) {
252 const status_t err = parcel->writeFloat(val);
253 if (err != NO_ERROR) {
254 signalExceptionForError(env, clazz, err);
259 static void android_os_Parcel_writeDouble(JNIEnv* env, jclass clazz, jlong nativePtr, jdouble val)
261 Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
262 if (parcel != NULL) {
263 const status_t err = parcel->writeDouble(val);
264 if (err != NO_ERROR) {
265 signalExceptionForError(env, clazz, err);
270 static void android_os_Parcel_writeString(JNIEnv* env, jclass clazz, jlong nativePtr, jstring val)
272 Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
273 if (parcel != NULL) {
274 status_t err = NO_MEMORY;
276 const jchar* str = env->GetStringCritical(val, 0);
278 err = parcel->writeString16(str, env->GetStringLength(val));
279 env->ReleaseStringCritical(val, str);
282 err = parcel->writeString16(NULL, 0);
284 if (err != NO_ERROR) {
285 signalExceptionForError(env, clazz, err);
290 static void android_os_Parcel_writeStrongBinder(JNIEnv* env, jclass clazz, jlong nativePtr, jobject object)
292 Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
293 if (parcel != NULL) {
294 const status_t err = parcel->writeStrongBinder(ibinderForJavaObject(env, object));
295 if (err != NO_ERROR) {
296 signalExceptionForError(env, clazz, err);
301 static void android_os_Parcel_writeFileDescriptor(JNIEnv* env, jclass clazz, jlong nativePtr, jobject object)
303 Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
304 if (parcel != NULL) {
306 parcel->writeDupFileDescriptor(jniGetFDFromFileDescriptor(env, object));
307 if (err != NO_ERROR) {
308 signalExceptionForError(env, clazz, err);
313 static jbyteArray android_os_Parcel_createByteArray(JNIEnv* env, jclass clazz, jlong nativePtr)
315 jbyteArray ret = NULL;
317 Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
318 if (parcel != NULL) {
319 int32_t len = parcel->readInt32();
321 // sanity check the stored length against the true data size
322 if (len >= 0 && len <= (int32_t)parcel->dataAvail()) {
323 ret = env->NewByteArray(len);
326 jbyte* a2 = (jbyte*)env->GetPrimitiveArrayCritical(ret, 0);
328 const void* data = parcel->readInplace(len);
329 memcpy(a2, data, len);
330 env->ReleasePrimitiveArrayCritical(ret, a2, 0);
339 static jbyteArray android_os_Parcel_readBlob(JNIEnv* env, jclass clazz, jlong nativePtr)
341 jbyteArray ret = NULL;
343 Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
344 if (parcel != NULL) {
345 int32_t len = parcel->readInt32();
347 android::Parcel::ReadableBlob blob;
348 android::status_t err = parcel->readBlob(len, &blob);
349 if (err != NO_ERROR) {
350 signalExceptionForError(env, clazz, err);
354 ret = env->NewByteArray(len);
356 jbyte* a2 = (jbyte*)env->GetPrimitiveArrayCritical(ret, 0);
358 memcpy(a2, blob.data(), len);
359 env->ReleasePrimitiveArrayCritical(ret, a2, 0);
369 static jint android_os_Parcel_readInt(JNIEnv* env, jclass clazz, jlong nativePtr)
371 Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
372 if (parcel != NULL) {
373 return parcel->readInt32();
378 static jlong android_os_Parcel_readLong(JNIEnv* env, jclass clazz, jlong nativePtr)
380 Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
381 if (parcel != NULL) {
382 return parcel->readInt64();
387 static jfloat android_os_Parcel_readFloat(JNIEnv* env, jclass clazz, jlong nativePtr)
389 Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
390 if (parcel != NULL) {
391 return parcel->readFloat();
396 static jdouble android_os_Parcel_readDouble(JNIEnv* env, jclass clazz, jlong nativePtr)
398 Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
399 if (parcel != NULL) {
400 return parcel->readDouble();
405 static jstring android_os_Parcel_readString(JNIEnv* env, jclass clazz, jlong nativePtr)
407 Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
408 if (parcel != NULL) {
410 const char16_t* str = parcel->readString16Inplace(&len);
412 return env->NewString(str, len);
419 static jobject android_os_Parcel_readStrongBinder(JNIEnv* env, jclass clazz, jlong nativePtr)
421 Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
422 if (parcel != NULL) {
423 return javaObjectForIBinder(env, parcel->readStrongBinder());
428 static jobject android_os_Parcel_readFileDescriptor(JNIEnv* env, jclass clazz, jlong nativePtr)
430 Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
431 if (parcel != NULL) {
432 int fd = parcel->readFileDescriptor();
433 if (fd < 0) return NULL;
435 if (fd < 0) return NULL;
436 return jniCreateFileDescriptor(env, fd);
441 static jobject android_os_Parcel_openFileDescriptor(JNIEnv* env, jclass clazz,
442 jstring name, jint mode)
445 jniThrowNullPointerException(env, NULL);
448 const jchar* str = env->GetStringCritical(name, 0);
450 // Whatever, whatever.
451 jniThrowException(env, "java/lang/IllegalStateException", NULL);
454 String8 name8(str, env->GetStringLength(name));
455 env->ReleaseStringCritical(name, str);
457 switch (mode&0x30000000) {
470 if (mode&0x08000000) flags |= O_CREAT;
471 if (mode&0x04000000) flags |= O_TRUNC;
472 if (mode&0x02000000) flags |= O_APPEND;
474 int realMode = S_IRWXU|S_IRWXG;
475 if (mode&0x00000001) realMode |= S_IROTH;
476 if (mode&0x00000002) realMode |= S_IWOTH;
478 int fd = open(name8.string(), flags, realMode);
480 jniThrowException(env, "java/io/FileNotFoundException", strerror(errno));
483 jobject object = jniCreateFileDescriptor(env, fd);
484 if (object == NULL) {
490 static jobject android_os_Parcel_dupFileDescriptor(JNIEnv* env, jclass clazz, jobject orig)
493 jniThrowNullPointerException(env, NULL);
496 int origfd = jniGetFDFromFileDescriptor(env, orig);
498 jniThrowException(env, "java/lang/IllegalArgumentException", "bad FileDescriptor");
502 int fd = dup(origfd);
504 jniThrowIOException(env, errno);
507 jobject object = jniCreateFileDescriptor(env, fd);
508 if (object == NULL) {
514 static void android_os_Parcel_closeFileDescriptor(JNIEnv* env, jclass clazz, jobject object)
516 if (object == NULL) {
517 jniThrowNullPointerException(env, NULL);
520 int fd = jniGetFDFromFileDescriptor(env, object);
522 jniSetFileDescriptorOfFD(env, object, -1);
523 //ALOGI("Closing ParcelFileDescriptor %d\n", fd);
528 static void android_os_Parcel_clearFileDescriptor(JNIEnv* env, jclass clazz, jobject object)
530 if (object == NULL) {
531 jniThrowNullPointerException(env, NULL);
534 int fd = jniGetFDFromFileDescriptor(env, object);
536 jniSetFileDescriptorOfFD(env, object, -1);
540 static jlong android_os_Parcel_create(JNIEnv* env, jclass clazz)
542 Parcel* parcel = new Parcel();
543 return reinterpret_cast<jlong>(parcel);
546 static void android_os_Parcel_freeBuffer(JNIEnv* env, jclass clazz, jlong nativePtr)
548 Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
549 if (parcel != NULL) {
554 static void android_os_Parcel_destroy(JNIEnv* env, jclass clazz, jlong nativePtr)
556 Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
560 static jbyteArray android_os_Parcel_marshall(JNIEnv* env, jclass clazz, jlong nativePtr)
562 Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
563 if (parcel == NULL) {
567 // do not marshall if there are binder objects in the parcel
568 if (parcel->objectsCount())
570 jniThrowException(env, "java/lang/RuntimeException", "Tried to marshall a Parcel that contained Binder objects.");
574 jbyteArray ret = env->NewByteArray(parcel->dataSize());
578 jbyte* array = (jbyte*)env->GetPrimitiveArrayCritical(ret, 0);
581 memcpy(array, parcel->data(), parcel->dataSize());
582 env->ReleasePrimitiveArrayCritical(ret, array, 0);
589 static void android_os_Parcel_unmarshall(JNIEnv* env, jclass clazz, jlong nativePtr,
590 jbyteArray data, jint offset, jint length)
592 Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
593 if (parcel == NULL || length < 0) {
597 jbyte* array = (jbyte*)env->GetPrimitiveArrayCritical(data, 0);
600 parcel->setDataSize(length);
601 parcel->setDataPosition(0);
603 void* raw = parcel->writeInplace(length);
604 memcpy(raw, (array + offset), length);
606 env->ReleasePrimitiveArrayCritical(data, array, 0);
610 static void android_os_Parcel_appendFrom(JNIEnv* env, jclass clazz, jlong thisNativePtr,
611 jlong otherNativePtr, jint offset, jint length)
613 Parcel* thisParcel = reinterpret_cast<Parcel*>(thisNativePtr);
614 if (thisParcel == NULL) {
617 Parcel* otherParcel = reinterpret_cast<Parcel*>(otherNativePtr);
618 if (otherParcel == NULL) {
622 status_t err = thisParcel->appendFrom(otherParcel, offset, length);
623 if (err != NO_ERROR) {
624 signalExceptionForError(env, clazz, err);
628 static jboolean android_os_Parcel_hasFileDescriptors(JNIEnv* env, jclass clazz, jlong nativePtr)
630 jboolean ret = JNI_FALSE;
631 Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
632 if (parcel != NULL) {
633 if (parcel->hasFileDescriptors()) {
640 static void android_os_Parcel_writeInterfaceToken(JNIEnv* env, jclass clazz, jlong nativePtr,
643 Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
644 if (parcel != NULL) {
645 // In the current implementation, the token is just the serialized interface name that
646 // the caller expects to be invoking
647 const jchar* str = env->GetStringCritical(name, 0);
649 parcel->writeInterfaceToken(String16(str, env->GetStringLength(name)));
650 env->ReleaseStringCritical(name, str);
655 static void android_os_Parcel_enforceInterface(JNIEnv* env, jclass clazz, jlong nativePtr, jstring name)
657 jboolean ret = JNI_FALSE;
659 Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
660 if (parcel != NULL) {
661 const jchar* str = env->GetStringCritical(name, 0);
663 IPCThreadState* threadState = IPCThreadState::self();
664 const int32_t oldPolicy = threadState->getStrictModePolicy();
665 const bool isValid = parcel->enforceInterface(
666 String16(str, env->GetStringLength(name)),
668 env->ReleaseStringCritical(name, str);
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);
681 return; // everything was correct -> return silently
686 // all error conditions wind up here
687 jniThrowException(env, "java/lang/SecurityException",
688 "Binder invocation to an incorrect interface");
691 // ----------------------------------------------------------------------------
693 static const JNINativeMethod gParcelMethods[] = {
694 {"nativeDataSize", "(J)I", (void*)android_os_Parcel_dataSize},
695 {"nativeDataAvail", "(J)I", (void*)android_os_Parcel_dataAvail},
696 {"nativeDataPosition", "(J)I", (void*)android_os_Parcel_dataPosition},
697 {"nativeDataCapacity", "(J)I", (void*)android_os_Parcel_dataCapacity},
698 {"nativeSetDataSize", "(JI)V", (void*)android_os_Parcel_setDataSize},
699 {"nativeSetDataPosition", "(JI)V", (void*)android_os_Parcel_setDataPosition},
700 {"nativeSetDataCapacity", "(JI)V", (void*)android_os_Parcel_setDataCapacity},
702 {"nativePushAllowFds", "(JZ)Z", (void*)android_os_Parcel_pushAllowFds},
703 {"nativeRestoreAllowFds", "(JZ)V", (void*)android_os_Parcel_restoreAllowFds},
705 {"nativeWriteByteArray", "(J[BII)V", (void*)android_os_Parcel_writeNative},
706 {"nativeWriteBlob", "(J[BII)V", (void*)android_os_Parcel_writeBlob},
707 {"nativeWriteInt", "(JI)V", (void*)android_os_Parcel_writeInt},
708 {"nativeWriteLong", "(JJ)V", (void*)android_os_Parcel_writeLong},
709 {"nativeWriteFloat", "(JF)V", (void*)android_os_Parcel_writeFloat},
710 {"nativeWriteDouble", "(JD)V", (void*)android_os_Parcel_writeDouble},
711 {"nativeWriteString", "(JLjava/lang/String;)V", (void*)android_os_Parcel_writeString},
712 {"nativeWriteStrongBinder", "(JLandroid/os/IBinder;)V", (void*)android_os_Parcel_writeStrongBinder},
713 {"nativeWriteFileDescriptor", "(JLjava/io/FileDescriptor;)V", (void*)android_os_Parcel_writeFileDescriptor},
715 {"nativeCreateByteArray", "(J)[B", (void*)android_os_Parcel_createByteArray},
716 {"nativeReadBlob", "(J)[B", (void*)android_os_Parcel_readBlob},
717 {"nativeReadInt", "(J)I", (void*)android_os_Parcel_readInt},
718 {"nativeReadLong", "(J)J", (void*)android_os_Parcel_readLong},
719 {"nativeReadFloat", "(J)F", (void*)android_os_Parcel_readFloat},
720 {"nativeReadDouble", "(J)D", (void*)android_os_Parcel_readDouble},
721 {"nativeReadString", "(J)Ljava/lang/String;", (void*)android_os_Parcel_readString},
722 {"nativeReadStrongBinder", "(J)Landroid/os/IBinder;", (void*)android_os_Parcel_readStrongBinder},
723 {"nativeReadFileDescriptor", "(J)Ljava/io/FileDescriptor;", (void*)android_os_Parcel_readFileDescriptor},
725 {"openFileDescriptor", "(Ljava/lang/String;I)Ljava/io/FileDescriptor;", (void*)android_os_Parcel_openFileDescriptor},
726 {"dupFileDescriptor", "(Ljava/io/FileDescriptor;)Ljava/io/FileDescriptor;", (void*)android_os_Parcel_dupFileDescriptor},
727 {"closeFileDescriptor", "(Ljava/io/FileDescriptor;)V", (void*)android_os_Parcel_closeFileDescriptor},
728 {"clearFileDescriptor", "(Ljava/io/FileDescriptor;)V", (void*)android_os_Parcel_clearFileDescriptor},
730 {"nativeCreate", "()J", (void*)android_os_Parcel_create},
731 {"nativeFreeBuffer", "(J)V", (void*)android_os_Parcel_freeBuffer},
732 {"nativeDestroy", "(J)V", (void*)android_os_Parcel_destroy},
734 {"nativeMarshall", "(J)[B", (void*)android_os_Parcel_marshall},
735 {"nativeUnmarshall", "(J[BII)V", (void*)android_os_Parcel_unmarshall},
736 {"nativeAppendFrom", "(JJII)V", (void*)android_os_Parcel_appendFrom},
737 {"nativeHasFileDescriptors", "(J)Z", (void*)android_os_Parcel_hasFileDescriptors},
738 {"nativeWriteInterfaceToken", "(JLjava/lang/String;)V", (void*)android_os_Parcel_writeInterfaceToken},
739 {"nativeEnforceInterface", "(JLjava/lang/String;)V", (void*)android_os_Parcel_enforceInterface},
742 const char* const kParcelPathName = "android/os/Parcel";
744 int register_android_os_Parcel(JNIEnv* env)
748 clazz = env->FindClass(kParcelPathName);
749 LOG_FATAL_IF(clazz == NULL, "Unable to find class android.os.Parcel");
751 gParcelOffsets.clazz = (jclass) env->NewGlobalRef(clazz);
752 gParcelOffsets.mNativePtr = env->GetFieldID(clazz, "mNativePtr", "J");
753 gParcelOffsets.obtain = env->GetStaticMethodID(clazz, "obtain",
754 "()Landroid/os/Parcel;");
755 gParcelOffsets.recycle = env->GetMethodID(clazz, "recycle", "()V");
757 return AndroidRuntime::registerNativeMethods(
758 env, kParcelPathName,
759 gParcelMethods, NELEM(gParcelMethods));