static jbyteArray android_os_Parcel_readBlob(JNIEnv* env, jclass clazz, jlong nativePtr) { jbyteArray ret = NULL; Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr); if (parcel != NULL) { int32_t len = parcel->readInt32(); if (len >= 0) { android::Parcel::ReadableBlob blob; android::status_t err = parcel->readBlob(len, &blob); if (err != NO_ERROR) { signalExceptionForError(env, clazz, err); return NULL; } ret = env->NewByteArray(len); if (ret != NULL) { jbyte* a2 = (jbyte*)env->GetPrimitiveArrayCritical(ret, 0); if (a2) { memcpy(a2, blob.data(), len); env->ReleasePrimitiveArrayCritical(ret, a2, 0); } } blob.release(); } } return ret; }
status_t CameraMetadata::readFromParcel(const Parcel& data, camera_metadata_t** out) { status_t err = OK; camera_metadata_t* metadata = NULL; if (out) { *out = NULL; } // See CameraMetadata::writeToParcel for parcel data layout diagram and explanation. // arg0 = blobSize (int32) int32_t blobSizeTmp = -1; if ((err = data.readInt32(&blobSizeTmp)) != OK) { ALOGE("%s: Failed to read metadata size (error %d %s)", __FUNCTION__, err, strerror(-err)); return err; } const size_t blobSize = static_cast<size_t>(blobSizeTmp); const size_t alignment = get_camera_metadata_alignment(); // Special case: zero blob size means zero sized (NULL) metadata. if (blobSize == 0) { ALOGV("%s: Read 0-sized metadata", __FUNCTION__); return OK; } if (blobSize <= alignment) { ALOGE("%s: metadata blob is malformed, blobSize(%zu) should be larger than alignment(%zu)", __FUNCTION__, blobSize, alignment); return BAD_VALUE; } const size_t metadataSize = blobSize - alignment; // NOTE: this doesn't make sense to me. shouldn't the blob // know how big it is? why do we have to specify the size // to Parcel::readBlob ? ReadableBlob blob; // arg1 = metadata (blob) do { if ((err = data.readBlob(blobSize, &blob)) != OK) { ALOGE("%s: Failed to read metadata blob (sized %zu). Possible " " serialization bug. Error %d %s", __FUNCTION__, blobSize, err, strerror(-err)); break; } // arg2 = offset (blob) // Must be after blob since we don't know offset until after writeBlob. int32_t offsetTmp; if ((err = data.readInt32(&offsetTmp)) != OK) { ALOGE("%s: Failed to read metadata offsetTmp (error %d %s)", __FUNCTION__, err, strerror(-err)); break; } const size_t offset = static_cast<size_t>(offsetTmp); if (offset >= alignment) { ALOGE("%s: metadata offset(%zu) should be less than alignment(%zu)", __FUNCTION__, blobSize, alignment); err = BAD_VALUE; break; } const uintptr_t metadataStart = reinterpret_cast<uintptr_t>(blob.data()) + offset; const camera_metadata_t* tmp = reinterpret_cast<const camera_metadata_t*>(metadataStart); ALOGV("%s: alignment is: %zu, metadata start: %p, offset: %zu", __FUNCTION__, alignment, tmp, offset); metadata = allocate_copy_camera_metadata_checked(tmp, metadataSize); if (metadata == NULL) { // We consider that allocation only fails if the validation // also failed, therefore the readFromParcel was a failure. ALOGE("%s: metadata allocation and copy failed", __FUNCTION__); err = BAD_VALUE; } } while(0); blob.release(); if (out) { ALOGV("%s: Set out metadata to %p", __FUNCTION__, metadata); *out = metadata; } else if (metadata != NULL) { ALOGV("%s: Freed camera metadata at %p", __FUNCTION__, metadata); free_camera_metadata(metadata); } return err; }