android_hardware_camera2_CameraMetadata.cpp revision 70c2207c34cf0e6b3b383b1b1500ff5385aa51a6
1/* 2** 3** Copyright 2013, The Android Open Source Project 4** 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 8** 9** http://www.apache.org/licenses/LICENSE-2.0 10** 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. 16*/ 17 18// #define LOG_NDEBUG 0 19// #define LOG_NNDEBUG 0 20#define LOG_TAG "CameraMetadata-JNI" 21#include <utils/Log.h> 22 23#include "jni.h" 24#include "JNIHelp.h" 25#include "android_os_Parcel.h" 26#include "android_runtime/AndroidRuntime.h" 27 28#include <camera/CameraMetadata.h> 29#include <nativehelper/ScopedUtfChars.h> 30#include <nativehelper/ScopedPrimitiveArray.h> 31 32#if defined(LOG_NNDEBUG) 33#if !LOG_NNDEBUG 34#define ALOGVV ALOGV 35#endif 36#else 37#define ALOGVV(...) 38#endif 39 40// fully-qualified class name 41#define CAMERA_METADATA_CLASS_NAME "android/hardware/camera2/impl/CameraMetadataNative" 42 43using namespace android; 44 45struct fields_t { 46 jfieldID metadata_ptr; 47}; 48 49static fields_t fields; 50 51namespace { 52struct Helpers { 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); 57 } 58 59 return camera_metadata_type_size[type]; 60 } 61 62 static status_t updateAny(CameraMetadata *metadata, 63 uint32_t tag, 64 uint32_t type, 65 const void *data, 66 size_t dataBytes) { 67 68 if (type >= NUM_TYPES) { 69 ALOGE("%s: Invalid type specified (%ud)", __FUNCTION__, type); 70 return INVALID_OPERATION; 71 } 72 73 size_t typeSize = getTypeSize(type); 74 75 if (dataBytes % typeSize != 0) { 76 ALOGE("%s: Expected dataBytes (%ud) to be divisible by typeSize " 77 "(%ud)", __FUNCTION__, dataBytes, typeSize); 78 return BAD_VALUE; 79 } 80 81 size_t dataCount = dataBytes / typeSize; 82 83 switch(type) { 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); \ 89 } \ 90 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); 97 98 default: { 99 // unreachable 100 ALOGE("%s: Unreachable", __FUNCTION__); 101 return INVALID_OPERATION; 102 } 103 } 104 105#undef METADATA_UPDATE 106 } 107}; 108} // namespace {} 109 110extern "C" { 111 112static void CameraMetadata_classInit(JNIEnv *env, jobject thiz); 113static jint CameraMetadata_getTagFromKey(JNIEnv *env, jobject thiz, jstring keyName); 114static jint CameraMetadata_getTypeFromTag(JNIEnv *env, jobject thiz, jint tag); 115 116// Less safe access to native pointer. Does NOT throw any Java exceptions if NULL. 117static CameraMetadata* CameraMetadata_getPointerNoThrow(JNIEnv *env, jobject thiz) { 118 119 if (thiz == NULL) { 120 return NULL; 121 } 122 123 return reinterpret_cast<CameraMetadata*>(env->GetLongField(thiz, fields.metadata_ptr)); 124} 125 126// Safe access to native pointer from object. Throws if not possible to access. 127static CameraMetadata* CameraMetadata_getPointerThrow(JNIEnv *env, jobject thiz, 128 const char* argName = "this") { 129 130 if (thiz == NULL) { 131 ALOGV("%s: Throwing java.lang.NullPointerException for null reference", 132 __FUNCTION__); 133 jniThrowNullPointerException(env, argName); 134 return NULL; 135 } 136 137 CameraMetadata* metadata = CameraMetadata_getPointerNoThrow(env, thiz); 138 if (metadata == NULL) { 139 ALOGV("%s: Throwing java.lang.IllegalStateException for closed object", 140 __FUNCTION__); 141 jniThrowException(env, "java/lang/IllegalStateException", 142 "Metadata object was already closed"); 143 return NULL; 144 } 145 146 return metadata; 147} 148 149static jlong CameraMetadata_allocate(JNIEnv *env, jobject thiz) { 150 ALOGV("%s", __FUNCTION__); 151 152 return reinterpret_cast<jlong>(new CameraMetadata()); 153} 154 155static jlong CameraMetadata_allocateCopy(JNIEnv *env, jobject thiz, 156 jobject other) { 157 ALOGV("%s", __FUNCTION__); 158 159 CameraMetadata* otherMetadata = 160 CameraMetadata_getPointerThrow(env, other, "other"); 161 162 // In case of exception, return 163 if (otherMetadata == NULL) return NULL; 164 165 // Clone native metadata and return new pointer 166 return reinterpret_cast<jlong>(new CameraMetadata(*otherMetadata)); 167} 168 169 170static jboolean CameraMetadata_isEmpty(JNIEnv *env, jobject thiz) { 171 ALOGV("%s", __FUNCTION__); 172 173 CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz); 174 175 if (metadata == NULL) { 176 ALOGW("%s: Returning early due to exception being thrown", 177 __FUNCTION__); 178 return JNI_TRUE; // actually throws java exc. 179 } 180 181 jboolean empty = metadata->isEmpty(); 182 183 ALOGV("%s: Empty returned %d, entry count was %d", 184 __FUNCTION__, empty, metadata->entryCount()); 185 186 return empty; 187} 188 189static jint CameraMetadata_getEntryCount(JNIEnv *env, jobject thiz) { 190 ALOGV("%s", __FUNCTION__); 191 192 CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz); 193 194 if (metadata == NULL) return 0; // actually throws java exc. 195 196 return metadata->entryCount(); 197} 198 199// idempotent. calling more than once has no effect. 200static void CameraMetadata_close(JNIEnv *env, jobject thiz) { 201 ALOGV("%s", __FUNCTION__); 202 203 CameraMetadata* metadata = CameraMetadata_getPointerNoThrow(env, thiz); 204 205 if (metadata != NULL) { 206 delete metadata; 207 env->SetLongField(thiz, fields.metadata_ptr, 0); 208 } 209 210 LOG_ALWAYS_FATAL_IF(CameraMetadata_getPointerNoThrow(env, thiz) != NULL, 211 "Expected the native ptr to be 0 after #close"); 212} 213 214static void CameraMetadata_swap(JNIEnv *env, jobject thiz, jobject other) { 215 ALOGV("%s", __FUNCTION__); 216 217 CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz); 218 219 // order is important: we can't call another JNI method 220 // if there is an exception pending 221 if (metadata == NULL) return; 222 223 CameraMetadata* otherMetadata = CameraMetadata_getPointerThrow(env, other, "other"); 224 225 if (otherMetadata == NULL) return; 226 227 metadata->swap(*otherMetadata); 228} 229 230static jbyteArray CameraMetadata_readValues(JNIEnv *env, jobject thiz, jint tag) { 231 ALOGV("%s (tag = %d)", __FUNCTION__, tag); 232 233 CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz); 234 if (metadata == NULL) return NULL; 235 236 int tagType = get_camera_metadata_tag_type(tag); 237 if (tagType == -1) { 238 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", 239 "Tag (%d) did not have a type", tag); 240 return NULL; 241 } 242 size_t tagSize = Helpers::getTypeSize(tagType); 243 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); 248 return NULL; 249 } else { 250 // OK: we will return a 0-sized array. 251 ALOGV("%s: Tag %d had an entry, but it had 0 data", __FUNCTION__, 252 tag); 253 } 254 } 255 256 jsize byteCount = entry.count * tagSize; 257 jbyteArray byteArray = env->NewByteArray(byteCount); 258 if (env->ExceptionCheck()) return NULL; 259 260 // Copy into java array from native array 261 ScopedByteArrayRW arrayWriter(env, byteArray); 262 memcpy(arrayWriter.get(), entry.data.u8, byteCount); 263 264 return byteArray; 265} 266 267static void CameraMetadata_writeValues(JNIEnv *env, jobject thiz, jint tag, jbyteArray src) { 268 ALOGV("%s (tag = %d)", __FUNCTION__, tag); 269 270 CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz); 271 if (metadata == NULL) return; 272 273 int tagType = get_camera_metadata_tag_type(tag); 274 if (tagType == -1) { 275 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", 276 "Tag (%d) did not have a type", tag); 277 return; 278 } 279 size_t tagSize = Helpers::getTypeSize(tagType); 280 281 status_t res; 282 283 if (src == NULL) { 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); 288 } else { 289 res = OK; 290 ALOGV("%s: Don't need to erase", __FUNCTION__); 291 } 292 } else { 293 // Copy from java array into native array 294 ScopedByteArrayRO arrayReader(env, src); 295 if (arrayReader.get() == NULL) return; 296 297 res = Helpers::updateAny(metadata, static_cast<uint32_t>(tag), 298 tagType, arrayReader.get(), arrayReader.size()); 299 300 ALOGV("%s: Update values (res = %d)", __FUNCTION__, res); 301 } 302 303 if (res == OK) { 304 return; 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"); 311 } else { 312 jniThrowExceptionFmt(env, "java/lang/IllegalStateException", 313 "Unknown error (%d) while trying to update " 314 "metadata", res); 315 } 316} 317 318static void CameraMetadata_readFromParcel(JNIEnv *env, jobject thiz, jobject parcel) { 319 ALOGV("%s", __FUNCTION__); 320 CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz); 321 if (metadata == NULL) { 322 return; 323 } 324 325 Parcel* parcelNative = parcelForJavaObject(env, parcel); 326 if (parcelNative == NULL) { 327 jniThrowNullPointerException(env, "parcel"); 328 return; 329 } 330 331 status_t err; 332 if ((err = metadata->readFromParcel(parcelNative)) != OK) { 333 jniThrowExceptionFmt(env, "java/lang/IllegalStateException", 334 "Failed to read from parcel (error code %d)", err); 335 return; 336 } 337} 338 339static void CameraMetadata_writeToParcel(JNIEnv *env, jobject thiz, jobject parcel) { 340 ALOGV("%s", __FUNCTION__); 341 CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz); 342 if (metadata == NULL) { 343 return; 344 } 345 346 Parcel* parcelNative = parcelForJavaObject(env, parcel); 347 if (parcelNative == NULL) { 348 jniThrowNullPointerException(env, "parcel"); 349 return; 350 } 351 352 status_t err; 353 if ((err = metadata->writeToParcel(parcelNative)) != OK) { 354 jniThrowExceptionFmt(env, "java/lang/IllegalStateException", 355 "Failed to write to parcel (error code %d)", err); 356 return; 357 } 358} 359 360} // extern "C" 361 362//------------------------------------------------- 363 364static JNINativeMethod gCameraMetadataMethods[] = { 365// static methods 366 { "nativeClassInit", 367 "()V", 368 (void *)CameraMetadata_classInit }, 369 { "nativeGetTagFromKey", 370 "(Ljava/lang/String;)I", 371 (void *)CameraMetadata_getTagFromKey }, 372 { "nativeGetTypeFromTag", 373 "(I)I", 374 (void *)CameraMetadata_getTypeFromTag }, 375// instance methods 376 { "nativeAllocate", 377 "()J", 378 (void*)CameraMetadata_allocate }, 379 { "nativeAllocateCopy", 380 "(L" CAMERA_METADATA_CLASS_NAME ";)J", 381 (void *)CameraMetadata_allocateCopy }, 382 { "nativeIsEmpty", 383 "()Z", 384 (void*)CameraMetadata_isEmpty }, 385 { "nativeGetEntryCount", 386 "()I", 387 (void*)CameraMetadata_getEntryCount }, 388 { "nativeClose", 389 "()V", 390 (void*)CameraMetadata_close }, 391 { "nativeSwap", 392 "(L" CAMERA_METADATA_CLASS_NAME ";)V", 393 (void *)CameraMetadata_swap }, 394 { "nativeReadValues", 395 "(I)[B", 396 (void *)CameraMetadata_readValues }, 397 { "nativeWriteValues", 398 "(I[B)V", 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 }, 407}; 408 409struct field { 410 const char *class_name; 411 const char *field_name; 412 const char *field_type; 413 jfieldID *jfield; 414}; 415 416static int find_fields(JNIEnv *env, field *fields, int count) 417{ 418 for (int i = 0; i < count; i++) { 419 field *f = &fields[i]; 420 jclass clazz = env->FindClass(f->class_name); 421 if (clazz == NULL) { 422 ALOGE("Can't find %s", f->class_name); 423 return -1; 424 } 425 426 jfieldID field = env->GetFieldID(clazz, f->field_name, f->field_type); 427 if (field == NULL) { 428 ALOGE("Can't find %s.%s", f->class_name, f->field_name); 429 return -1; 430 } 431 432 *(f->jfield) = field; 433 } 434 435 return 0; 436} 437 438// Get all the required offsets in java class and register native functions 439int register_android_hardware_camera2_CameraMetadata(JNIEnv *env) 440{ 441 // Register native functions 442 return AndroidRuntime::registerNativeMethods(env, 443 CAMERA_METADATA_CLASS_NAME, 444 gCameraMetadataMethods, 445 NELEM(gCameraMetadataMethods)); 446} 447 448extern "C" { 449static 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__); 452 453 field fields_to_find[] = { 454 { CAMERA_METADATA_CLASS_NAME, "mMetadataPtr", "J", &fields.metadata_ptr }, 455 }; 456 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) 460 return; 461 462 jclass clazz = env->FindClass(CAMERA_METADATA_CLASS_NAME); 463} 464 465static jint CameraMetadata_getTagFromKey(JNIEnv *env, jobject thiz, jstring keyName) { 466 467 ScopedUtfChars keyScoped(env, keyName); 468 const char *key = keyScoped.c_str(); 469 if (key == NULL) { 470 // exception thrown by ScopedUtfChars 471 return 0; 472 } 473 size_t keyLength = strlen(key); 474 475 ALOGV("%s (key = '%s')", __FUNCTION__, key); 476 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'", 484 __FUNCTION__, str); 485 if (strstr(key, str) == key) { // key begins with the section name 486 size_t strLength = strlen(str); 487 488 ALOGVV("%s: Key begins with section name", __FUNCTION__); 489 490 // section name is the longest we've found so far 491 if (section == NULL || sectionLength < strLength) { 492 section = str; 493 sectionIndex = i; 494 sectionLength = strLength; 495 496 ALOGVV("%s: Found new best section (idx %d)", __FUNCTION__, sectionIndex); 497 } 498 } 499 } 500 501 // TODO: vendor ext 502 // TODO: Make above get_camera_metadata_section_from_name ? 503 504 if (section == NULL) { 505 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", 506 "Could not find section name for key '%s')", key); 507 return 0; 508 } else { 509 ALOGV("%s: Found matched section '%s' (%d)", 510 __FUNCTION__, section, sectionIndex); 511 } 512 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); 518 } 519 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]; 524 525 uint32_t tag; 526 for (tag = tagBegin; tag < tagEnd; ++tag) { 527 const char *tagName = get_camera_metadata_tag_name(tag); 528 529 if (strcmp(keyTagName, tagName) == 0) { 530 ALOGV("%s: Found matched tag '%s' (%d)", 531 __FUNCTION__, tagName, tag); 532 break; 533 } 534 } 535 536 // TODO: vendor ext 537 // TODO: Make above get_camera_metadata_tag_from_name ? 538 539 if (tag == tagEnd) { 540 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", 541 "Could not find tag name for key '%s')", key); 542 return 0; 543 } 544 545 return tag; 546} 547 548static jint CameraMetadata_getTypeFromTag(JNIEnv *env, jobject thiz, jint tag) { 549 int tagType = get_camera_metadata_tag_type(tag); 550 if (tagType == -1) { 551 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", 552 "Tag (%d) did not have a type", tag); 553 return -1; 554 } 555 556 return tagType; 557} 558 559} // extern "C" 560