3 ** Copyright 2013, The Android Open Source Project
5 ** Licensed under the Apache License, Version 2.0 (the "License");
6 ** you may not use this file except in compliance with the License.
7 ** You may obtain a copy of the License at
9 ** http://www.apache.org/licenses/LICENSE-2.0
11 ** Unless required by applicable law or agreed to in writing, software
12 ** distributed under the License is distributed on an "AS IS" BASIS,
13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 ** See the License for the specific language governing permissions and
15 ** limitations under the License.
18 // #define LOG_NDEBUG 0
19 // #define LOG_NNDEBUG 0
20 #define LOG_TAG "CameraMetadata-JNI"
21 #include <utils/Log.h>
25 #include "android_os_Parcel.h"
26 #include "android_runtime/AndroidRuntime.h"
28 #include <camera/CameraMetadata.h>
29 #include <nativehelper/ScopedUtfChars.h>
30 #include <nativehelper/ScopedPrimitiveArray.h>
32 #if defined(LOG_NNDEBUG)
40 // fully-qualified class name
41 #define CAMERA_METADATA_CLASS_NAME "android/hardware/camera2/impl/CameraMetadataNative"
43 using namespace android;
46 jfieldID metadata_ptr;
49 static fields_t fields;
53 static size_t getTypeSize(uint8_t type) {
54 if (type >= NUM_TYPES) {
55 ALOGE("%s: Invalid type specified (%ud)", __FUNCTION__, type);
56 return static_cast<size_t>(-1);
59 return camera_metadata_type_size[type];
62 static status_t updateAny(CameraMetadata *metadata,
68 if (type >= NUM_TYPES) {
69 ALOGE("%s: Invalid type specified (%ud)", __FUNCTION__, type);
70 return INVALID_OPERATION;
73 size_t typeSize = getTypeSize(type);
75 if (dataBytes % typeSize != 0) {
76 ALOGE("%s: Expected dataBytes (%ud) to be divisible by typeSize "
77 "(%ud)", __FUNCTION__, dataBytes, typeSize);
81 size_t dataCount = dataBytes / typeSize;
84 #define METADATA_UPDATE(runtime_type, compile_type) \
85 case runtime_type: { \
86 const compile_type *dataPtr = \
87 static_cast<const compile_type*>(data); \
88 return metadata->update(tag, dataPtr, dataCount); \
91 METADATA_UPDATE(TYPE_BYTE, uint8_t);
92 METADATA_UPDATE(TYPE_INT32, int32_t);
93 METADATA_UPDATE(TYPE_FLOAT, float);
94 METADATA_UPDATE(TYPE_INT64, int64_t);
95 METADATA_UPDATE(TYPE_DOUBLE, double);
96 METADATA_UPDATE(TYPE_RATIONAL, camera_metadata_rational_t);
100 ALOGE("%s: Unreachable", __FUNCTION__);
101 return INVALID_OPERATION;
105 #undef METADATA_UPDATE
112 static void CameraMetadata_classInit(JNIEnv *env, jobject thiz);
113 static jint CameraMetadata_getTagFromKey(JNIEnv *env, jobject thiz, jstring keyName);
114 static jint CameraMetadata_getTypeFromTag(JNIEnv *env, jobject thiz, jint tag);
116 // Less safe access to native pointer. Does NOT throw any Java exceptions if NULL.
117 static CameraMetadata* CameraMetadata_getPointerNoThrow(JNIEnv *env, jobject thiz) {
123 return reinterpret_cast<CameraMetadata*>(env->GetLongField(thiz, fields.metadata_ptr));
126 // Safe access to native pointer from object. Throws if not possible to access.
127 static CameraMetadata* CameraMetadata_getPointerThrow(JNIEnv *env, jobject thiz,
128 const char* argName = "this") {
131 ALOGV("%s: Throwing java.lang.NullPointerException for null reference",
133 jniThrowNullPointerException(env, argName);
137 CameraMetadata* metadata = CameraMetadata_getPointerNoThrow(env, thiz);
138 if (metadata == NULL) {
139 ALOGV("%s: Throwing java.lang.IllegalStateException for closed object",
141 jniThrowException(env, "java/lang/IllegalStateException",
142 "Metadata object was already closed");
149 static jlong CameraMetadata_allocate(JNIEnv *env, jobject thiz) {
150 ALOGV("%s", __FUNCTION__);
152 return reinterpret_cast<jlong>(new CameraMetadata());
155 static jlong CameraMetadata_allocateCopy(JNIEnv *env, jobject thiz,
157 ALOGV("%s", __FUNCTION__);
159 CameraMetadata* otherMetadata =
160 CameraMetadata_getPointerThrow(env, other, "other");
162 // In case of exception, return
163 if (otherMetadata == NULL) return NULL;
165 // Clone native metadata and return new pointer
166 return reinterpret_cast<jlong>(new CameraMetadata(*otherMetadata));
170 static jboolean CameraMetadata_isEmpty(JNIEnv *env, jobject thiz) {
171 ALOGV("%s", __FUNCTION__);
173 CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
175 if (metadata == NULL) {
176 ALOGW("%s: Returning early due to exception being thrown",
178 return JNI_TRUE; // actually throws java exc.
181 jboolean empty = metadata->isEmpty();
183 ALOGV("%s: Empty returned %d, entry count was %d",
184 __FUNCTION__, empty, metadata->entryCount());
189 static jint CameraMetadata_getEntryCount(JNIEnv *env, jobject thiz) {
190 ALOGV("%s", __FUNCTION__);
192 CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
194 if (metadata == NULL) return 0; // actually throws java exc.
196 return metadata->entryCount();
199 // idempotent. calling more than once has no effect.
200 static void CameraMetadata_close(JNIEnv *env, jobject thiz) {
201 ALOGV("%s", __FUNCTION__);
203 CameraMetadata* metadata = CameraMetadata_getPointerNoThrow(env, thiz);
205 if (metadata != NULL) {
207 env->SetLongField(thiz, fields.metadata_ptr, 0);
210 LOG_ALWAYS_FATAL_IF(CameraMetadata_getPointerNoThrow(env, thiz) != NULL,
211 "Expected the native ptr to be 0 after #close");
214 static void CameraMetadata_swap(JNIEnv *env, jobject thiz, jobject other) {
215 ALOGV("%s", __FUNCTION__);
217 CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
219 // order is important: we can't call another JNI method
220 // if there is an exception pending
221 if (metadata == NULL) return;
223 CameraMetadata* otherMetadata = CameraMetadata_getPointerThrow(env, other, "other");
225 if (otherMetadata == NULL) return;
227 metadata->swap(*otherMetadata);
230 static jbyteArray CameraMetadata_readValues(JNIEnv *env, jobject thiz, jint tag) {
231 ALOGV("%s (tag = %d)", __FUNCTION__, tag);
233 CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
234 if (metadata == NULL) return NULL;
236 int tagType = get_camera_metadata_tag_type(tag);
238 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
239 "Tag (%d) did not have a type", tag);
242 size_t tagSize = Helpers::getTypeSize(tagType);
244 camera_metadata_entry entry = metadata->find(tag);
245 if (entry.count == 0) {
246 if (!metadata->exists(tag)) {
247 ALOGV("%s: Tag %d does not have any entries", __FUNCTION__, tag);
250 // OK: we will return a 0-sized array.
251 ALOGV("%s: Tag %d had an entry, but it had 0 data", __FUNCTION__,
256 jsize byteCount = entry.count * tagSize;
257 jbyteArray byteArray = env->NewByteArray(byteCount);
258 if (env->ExceptionCheck()) return NULL;
260 // Copy into java array from native array
261 ScopedByteArrayRW arrayWriter(env, byteArray);
262 memcpy(arrayWriter.get(), entry.data.u8, byteCount);
267 static void CameraMetadata_writeValues(JNIEnv *env, jobject thiz, jint tag, jbyteArray src) {
268 ALOGV("%s (tag = %d)", __FUNCTION__, tag);
270 CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
271 if (metadata == NULL) return;
273 int tagType = get_camera_metadata_tag_type(tag);
275 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
276 "Tag (%d) did not have a type", tag);
279 size_t tagSize = Helpers::getTypeSize(tagType);
284 // If array is NULL, delete the entry
285 if (metadata->exists(tag)) {
286 res = metadata->erase(tag);
287 ALOGV("%s: Erase values (res = %d)", __FUNCTION__, res);
290 ALOGV("%s: Don't need to erase", __FUNCTION__);
293 // Copy from java array into native array
294 ScopedByteArrayRO arrayReader(env, src);
295 if (arrayReader.get() == NULL) return;
297 res = Helpers::updateAny(metadata, static_cast<uint32_t>(tag),
298 tagType, arrayReader.get(), arrayReader.size());
300 ALOGV("%s: Update values (res = %d)", __FUNCTION__, res);
305 } else if (res == BAD_VALUE) {
306 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
307 "Src byte array was poorly formed");
308 } else if (res == INVALID_OPERATION) {
309 jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
310 "Internal error while trying to update metadata");
312 jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
313 "Unknown error (%d) while trying to update "
318 static void CameraMetadata_readFromParcel(JNIEnv *env, jobject thiz, jobject parcel) {
319 ALOGV("%s", __FUNCTION__);
320 CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
321 if (metadata == NULL) {
325 Parcel* parcelNative = parcelForJavaObject(env, parcel);
326 if (parcelNative == NULL) {
327 jniThrowNullPointerException(env, "parcel");
332 if ((err = metadata->readFromParcel(parcelNative)) != OK) {
333 jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
334 "Failed to read from parcel (error code %d)", err);
339 static void CameraMetadata_writeToParcel(JNIEnv *env, jobject thiz, jobject parcel) {
340 ALOGV("%s", __FUNCTION__);
341 CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
342 if (metadata == NULL) {
346 Parcel* parcelNative = parcelForJavaObject(env, parcel);
347 if (parcelNative == NULL) {
348 jniThrowNullPointerException(env, "parcel");
353 if ((err = metadata->writeToParcel(parcelNative)) != OK) {
354 jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
355 "Failed to write to parcel (error code %d)", err);
362 //-------------------------------------------------
364 static JNINativeMethod gCameraMetadataMethods[] = {
368 (void *)CameraMetadata_classInit },
369 { "nativeGetTagFromKey",
370 "(Ljava/lang/String;)I",
371 (void *)CameraMetadata_getTagFromKey },
372 { "nativeGetTypeFromTag",
374 (void *)CameraMetadata_getTypeFromTag },
378 (void*)CameraMetadata_allocate },
379 { "nativeAllocateCopy",
380 "(L" CAMERA_METADATA_CLASS_NAME ";)J",
381 (void *)CameraMetadata_allocateCopy },
384 (void*)CameraMetadata_isEmpty },
385 { "nativeGetEntryCount",
387 (void*)CameraMetadata_getEntryCount },
390 (void*)CameraMetadata_close },
392 "(L" CAMERA_METADATA_CLASS_NAME ";)V",
393 (void *)CameraMetadata_swap },
394 { "nativeReadValues",
396 (void *)CameraMetadata_readValues },
397 { "nativeWriteValues",
399 (void *)CameraMetadata_writeValues },
400 // Parcelable interface
401 { "nativeReadFromParcel",
402 "(Landroid/os/Parcel;)V",
403 (void *)CameraMetadata_readFromParcel },
404 { "nativeWriteToParcel",
405 "(Landroid/os/Parcel;)V",
406 (void *)CameraMetadata_writeToParcel },
410 const char *class_name;
411 const char *field_name;
412 const char *field_type;
416 static int find_fields(JNIEnv *env, field *fields, int count)
418 for (int i = 0; i < count; i++) {
419 field *f = &fields[i];
420 jclass clazz = env->FindClass(f->class_name);
422 ALOGE("Can't find %s", f->class_name);
426 jfieldID field = env->GetFieldID(clazz, f->field_name, f->field_type);
428 ALOGE("Can't find %s.%s", f->class_name, f->field_name);
432 *(f->jfield) = field;
438 // Get all the required offsets in java class and register native functions
439 int register_android_hardware_camera2_CameraMetadata(JNIEnv *env)
441 // Register native functions
442 return AndroidRuntime::registerNativeMethods(env,
443 CAMERA_METADATA_CLASS_NAME,
444 gCameraMetadataMethods,
445 NELEM(gCameraMetadataMethods));
449 static void CameraMetadata_classInit(JNIEnv *env, jobject thiz) {
450 // XX: Why do this separately instead of doing it in the register function?
451 ALOGV("%s", __FUNCTION__);
453 field fields_to_find[] = {
454 { CAMERA_METADATA_CLASS_NAME, "mMetadataPtr", "J", &fields.metadata_ptr },
457 // Do this here instead of in register_native_methods,
458 // since otherwise it will fail to find the fields.
459 if (find_fields(env, fields_to_find, NELEM(fields_to_find)) < 0)
462 jclass clazz = env->FindClass(CAMERA_METADATA_CLASS_NAME);
465 static jint CameraMetadata_getTagFromKey(JNIEnv *env, jobject thiz, jstring keyName) {
467 ScopedUtfChars keyScoped(env, keyName);
468 const char *key = keyScoped.c_str();
470 // exception thrown by ScopedUtfChars
473 size_t keyLength = strlen(key);
475 ALOGV("%s (key = '%s')", __FUNCTION__, key);
477 // First, find the section by the longest string match
478 const char *section = NULL;
479 size_t sectionIndex = 0;
480 size_t sectionLength = 0;
481 for (size_t i = 0; i < ANDROID_SECTION_COUNT; ++i) {
482 const char *str = camera_metadata_section_names[i];
483 ALOGVV("%s: Trying to match against section '%s'",
485 if (strstr(key, str) == key) { // key begins with the section name
486 size_t strLength = strlen(str);
488 ALOGVV("%s: Key begins with section name", __FUNCTION__);
490 // section name is the longest we've found so far
491 if (section == NULL || sectionLength < strLength) {
494 sectionLength = strLength;
496 ALOGVV("%s: Found new best section (idx %d)", __FUNCTION__, sectionIndex);
502 // TODO: Make above get_camera_metadata_section_from_name ?
504 if (section == NULL) {
505 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
506 "Could not find section name for key '%s')", key);
509 ALOGV("%s: Found matched section '%s' (%d)",
510 __FUNCTION__, section, sectionIndex);
513 // Get the tag name component of the key
514 const char *keyTagName = key + sectionLength + 1; // x.y.z -> z
515 if (sectionLength + 1 >= keyLength) {
516 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
517 "Key length too short for key '%s')", key);
520 // Match rest of name against the tag names in that section only
521 uint32_t tagBegin, tagEnd; // [tagBegin, tagEnd)
522 tagBegin = camera_metadata_section_bounds[sectionIndex][0];
523 tagEnd = camera_metadata_section_bounds[sectionIndex][1];
526 for (tag = tagBegin; tag < tagEnd; ++tag) {
527 const char *tagName = get_camera_metadata_tag_name(tag);
529 if (strcmp(keyTagName, tagName) == 0) {
530 ALOGV("%s: Found matched tag '%s' (%d)",
531 __FUNCTION__, tagName, tag);
537 // TODO: Make above get_camera_metadata_tag_from_name ?
540 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
541 "Could not find tag name for key '%s')", key);
548 static jint CameraMetadata_getTypeFromTag(JNIEnv *env, jobject thiz, jint tag) {
549 int tagType = get_camera_metadata_tag_type(tag);
551 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
552 "Tag (%d) did not have a type", tag);