android_hardware_camera2_CameraMetadata.cpp revision e03a7eab1d08c821a516f1c07d29a77797acab68
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/Errors.h> 22#include <utils/Log.h> 23#include <utils/RefBase.h> 24#include <utils/Vector.h> 25#include <utils/SortedVector.h> 26#include <utils/KeyedVector.h> 27#include <string.h> 28 29#include "jni.h" 30#include "JNIHelp.h" 31#include "android_os_Parcel.h" 32#include "android_runtime/AndroidRuntime.h" 33 34#include <binder/IServiceManager.h> 35#include <camera/CameraMetadata.h> 36#include <camera/ICameraService.h> 37#include <camera/VendorTagDescriptor.h> 38#include <nativehelper/ScopedUtfChars.h> 39#include <nativehelper/ScopedPrimitiveArray.h> 40 41#if defined(LOG_NNDEBUG) 42#if !LOG_NNDEBUG 43#define ALOGVV ALOGV 44#endif 45#else 46#define ALOGVV(...) 47#endif 48 49// fully-qualified class name 50#define CAMERA_METADATA_CLASS_NAME "android/hardware/camera2/impl/CameraMetadataNative" 51 52using namespace android; 53 54struct fields_t { 55 jfieldID metadata_ptr; 56}; 57 58static fields_t fields; 59 60namespace { 61struct Helpers { 62 static size_t getTypeSize(uint8_t type) { 63 if (type >= NUM_TYPES) { 64 ALOGE("%s: Invalid type specified (%ud)", __FUNCTION__, type); 65 return static_cast<size_t>(-1); 66 } 67 68 return camera_metadata_type_size[type]; 69 } 70 71 static status_t updateAny(CameraMetadata *metadata, 72 uint32_t tag, 73 uint32_t type, 74 const void *data, 75 size_t dataBytes) { 76 77 if (type >= NUM_TYPES) { 78 ALOGE("%s: Invalid type specified (%ud)", __FUNCTION__, type); 79 return INVALID_OPERATION; 80 } 81 82 size_t typeSize = getTypeSize(type); 83 84 if (dataBytes % typeSize != 0) { 85 ALOGE("%s: Expected dataBytes (%ud) to be divisible by typeSize " 86 "(%ud)", __FUNCTION__, dataBytes, typeSize); 87 return BAD_VALUE; 88 } 89 90 size_t dataCount = dataBytes / typeSize; 91 92 switch(type) { 93#define METADATA_UPDATE(runtime_type, compile_type) \ 94 case runtime_type: { \ 95 const compile_type *dataPtr = \ 96 static_cast<const compile_type*>(data); \ 97 return metadata->update(tag, dataPtr, dataCount); \ 98 } \ 99 100 METADATA_UPDATE(TYPE_BYTE, uint8_t); 101 METADATA_UPDATE(TYPE_INT32, int32_t); 102 METADATA_UPDATE(TYPE_FLOAT, float); 103 METADATA_UPDATE(TYPE_INT64, int64_t); 104 METADATA_UPDATE(TYPE_DOUBLE, double); 105 METADATA_UPDATE(TYPE_RATIONAL, camera_metadata_rational_t); 106 107 default: { 108 // unreachable 109 ALOGE("%s: Unreachable", __FUNCTION__); 110 return INVALID_OPERATION; 111 } 112 } 113 114#undef METADATA_UPDATE 115 } 116}; 117} // namespace {} 118 119extern "C" { 120 121static void CameraMetadata_classInit(JNIEnv *env, jobject thiz); 122static jint CameraMetadata_getTagFromKey(JNIEnv *env, jobject thiz, jstring keyName); 123static jint CameraMetadata_getTypeFromTag(JNIEnv *env, jobject thiz, jint tag); 124static jint CameraMetadata_setupGlobalVendorTagDescriptor(JNIEnv *env, jobject thiz); 125 126// Less safe access to native pointer. Does NOT throw any Java exceptions if NULL. 127static CameraMetadata* CameraMetadata_getPointerNoThrow(JNIEnv *env, jobject thiz) { 128 129 if (thiz == NULL) { 130 return NULL; 131 } 132 133 return reinterpret_cast<CameraMetadata*>(env->GetLongField(thiz, fields.metadata_ptr)); 134} 135 136// Safe access to native pointer from object. Throws if not possible to access. 137static CameraMetadata* CameraMetadata_getPointerThrow(JNIEnv *env, jobject thiz, 138 const char* argName = "this") { 139 140 if (thiz == NULL) { 141 ALOGV("%s: Throwing java.lang.NullPointerException for null reference", 142 __FUNCTION__); 143 jniThrowNullPointerException(env, argName); 144 return NULL; 145 } 146 147 CameraMetadata* metadata = CameraMetadata_getPointerNoThrow(env, thiz); 148 if (metadata == NULL) { 149 ALOGV("%s: Throwing java.lang.IllegalStateException for closed object", 150 __FUNCTION__); 151 jniThrowException(env, "java/lang/IllegalStateException", 152 "Metadata object was already closed"); 153 return NULL; 154 } 155 156 return metadata; 157} 158 159static jlong CameraMetadata_allocate(JNIEnv *env, jobject thiz) { 160 ALOGV("%s", __FUNCTION__); 161 162 return reinterpret_cast<jlong>(new CameraMetadata()); 163} 164 165static jlong CameraMetadata_allocateCopy(JNIEnv *env, jobject thiz, 166 jobject other) { 167 ALOGV("%s", __FUNCTION__); 168 169 CameraMetadata* otherMetadata = 170 CameraMetadata_getPointerThrow(env, other, "other"); 171 172 // In case of exception, return 173 if (otherMetadata == NULL) return NULL; 174 175 // Clone native metadata and return new pointer 176 return reinterpret_cast<jlong>(new CameraMetadata(*otherMetadata)); 177} 178 179 180static jboolean CameraMetadata_isEmpty(JNIEnv *env, jobject thiz) { 181 ALOGV("%s", __FUNCTION__); 182 183 CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz); 184 185 if (metadata == NULL) { 186 ALOGW("%s: Returning early due to exception being thrown", 187 __FUNCTION__); 188 return JNI_TRUE; // actually throws java exc. 189 } 190 191 jboolean empty = metadata->isEmpty(); 192 193 ALOGV("%s: Empty returned %d, entry count was %d", 194 __FUNCTION__, empty, metadata->entryCount()); 195 196 return empty; 197} 198 199static jint CameraMetadata_getEntryCount(JNIEnv *env, jobject thiz) { 200 ALOGV("%s", __FUNCTION__); 201 202 CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz); 203 204 if (metadata == NULL) return 0; // actually throws java exc. 205 206 return metadata->entryCount(); 207} 208 209// idempotent. calling more than once has no effect. 210static void CameraMetadata_close(JNIEnv *env, jobject thiz) { 211 ALOGV("%s", __FUNCTION__); 212 213 CameraMetadata* metadata = CameraMetadata_getPointerNoThrow(env, thiz); 214 215 if (metadata != NULL) { 216 delete metadata; 217 env->SetLongField(thiz, fields.metadata_ptr, 0); 218 } 219 220 LOG_ALWAYS_FATAL_IF(CameraMetadata_getPointerNoThrow(env, thiz) != NULL, 221 "Expected the native ptr to be 0 after #close"); 222} 223 224static void CameraMetadata_swap(JNIEnv *env, jobject thiz, jobject other) { 225 ALOGV("%s", __FUNCTION__); 226 227 CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz); 228 229 // order is important: we can't call another JNI method 230 // if there is an exception pending 231 if (metadata == NULL) return; 232 233 CameraMetadata* otherMetadata = CameraMetadata_getPointerThrow(env, other, "other"); 234 235 if (otherMetadata == NULL) return; 236 237 metadata->swap(*otherMetadata); 238} 239 240static jbyteArray CameraMetadata_readValues(JNIEnv *env, jobject thiz, jint tag) { 241 ALOGV("%s (tag = %d)", __FUNCTION__, tag); 242 243 CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz); 244 if (metadata == NULL) return NULL; 245 246 int tagType = get_camera_metadata_tag_type(tag); 247 if (tagType == -1) { 248 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", 249 "Tag (%d) did not have a type", tag); 250 return NULL; 251 } 252 size_t tagSize = Helpers::getTypeSize(tagType); 253 254 camera_metadata_entry entry = metadata->find(tag); 255 if (entry.count == 0) { 256 if (!metadata->exists(tag)) { 257 ALOGV("%s: Tag %d does not have any entries", __FUNCTION__, tag); 258 return NULL; 259 } else { 260 // OK: we will return a 0-sized array. 261 ALOGV("%s: Tag %d had an entry, but it had 0 data", __FUNCTION__, 262 tag); 263 } 264 } 265 266 jsize byteCount = entry.count * tagSize; 267 jbyteArray byteArray = env->NewByteArray(byteCount); 268 if (env->ExceptionCheck()) return NULL; 269 270 // Copy into java array from native array 271 ScopedByteArrayRW arrayWriter(env, byteArray); 272 memcpy(arrayWriter.get(), entry.data.u8, byteCount); 273 274 return byteArray; 275} 276 277static void CameraMetadata_writeValues(JNIEnv *env, jobject thiz, jint tag, jbyteArray src) { 278 ALOGV("%s (tag = %d)", __FUNCTION__, tag); 279 280 CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz); 281 if (metadata == NULL) return; 282 283 int tagType = get_camera_metadata_tag_type(tag); 284 if (tagType == -1) { 285 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", 286 "Tag (%d) did not have a type", tag); 287 return; 288 } 289 size_t tagSize = Helpers::getTypeSize(tagType); 290 291 status_t res; 292 293 if (src == NULL) { 294 // If array is NULL, delete the entry 295 if (metadata->exists(tag)) { 296 res = metadata->erase(tag); 297 ALOGV("%s: Erase values (res = %d)", __FUNCTION__, res); 298 } else { 299 res = OK; 300 ALOGV("%s: Don't need to erase", __FUNCTION__); 301 } 302 } else { 303 // Copy from java array into native array 304 ScopedByteArrayRO arrayReader(env, src); 305 if (arrayReader.get() == NULL) return; 306 307 res = Helpers::updateAny(metadata, static_cast<uint32_t>(tag), 308 tagType, arrayReader.get(), arrayReader.size()); 309 310 ALOGV("%s: Update values (res = %d)", __FUNCTION__, res); 311 } 312 313 if (res == OK) { 314 return; 315 } else if (res == BAD_VALUE) { 316 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", 317 "Src byte array was poorly formed"); 318 } else if (res == INVALID_OPERATION) { 319 jniThrowExceptionFmt(env, "java/lang/IllegalStateException", 320 "Internal error while trying to update metadata"); 321 } else { 322 jniThrowExceptionFmt(env, "java/lang/IllegalStateException", 323 "Unknown error (%d) while trying to update " 324 "metadata", res); 325 } 326} 327 328static void CameraMetadata_readFromParcel(JNIEnv *env, jobject thiz, jobject parcel) { 329 ALOGV("%s", __FUNCTION__); 330 CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz); 331 if (metadata == NULL) { 332 return; 333 } 334 335 Parcel* parcelNative = parcelForJavaObject(env, parcel); 336 if (parcelNative == NULL) { 337 jniThrowNullPointerException(env, "parcel"); 338 return; 339 } 340 341 status_t err; 342 if ((err = metadata->readFromParcel(parcelNative)) != OK) { 343 jniThrowExceptionFmt(env, "java/lang/IllegalStateException", 344 "Failed to read from parcel (error code %d)", err); 345 return; 346 } 347} 348 349static void CameraMetadata_writeToParcel(JNIEnv *env, jobject thiz, jobject parcel) { 350 ALOGV("%s", __FUNCTION__); 351 CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz); 352 if (metadata == NULL) { 353 return; 354 } 355 356 Parcel* parcelNative = parcelForJavaObject(env, parcel); 357 if (parcelNative == NULL) { 358 jniThrowNullPointerException(env, "parcel"); 359 return; 360 } 361 362 status_t err; 363 if ((err = metadata->writeToParcel(parcelNative)) != OK) { 364 jniThrowExceptionFmt(env, "java/lang/IllegalStateException", 365 "Failed to write to parcel (error code %d)", err); 366 return; 367 } 368} 369 370} // extern "C" 371 372//------------------------------------------------- 373 374static JNINativeMethod gCameraMetadataMethods[] = { 375// static methods 376 { "nativeClassInit", 377 "()V", 378 (void *)CameraMetadata_classInit }, 379 { "nativeGetTagFromKey", 380 "(Ljava/lang/String;)I", 381 (void *)CameraMetadata_getTagFromKey }, 382 { "nativeGetTypeFromTag", 383 "(I)I", 384 (void *)CameraMetadata_getTypeFromTag }, 385 { "nativeSetupGlobalVendorTagDescriptor", 386 "()I", 387 (void*)CameraMetadata_setupGlobalVendorTagDescriptor }, 388// instance methods 389 { "nativeAllocate", 390 "()J", 391 (void*)CameraMetadata_allocate }, 392 { "nativeAllocateCopy", 393 "(L" CAMERA_METADATA_CLASS_NAME ";)J", 394 (void *)CameraMetadata_allocateCopy }, 395 { "nativeIsEmpty", 396 "()Z", 397 (void*)CameraMetadata_isEmpty }, 398 { "nativeGetEntryCount", 399 "()I", 400 (void*)CameraMetadata_getEntryCount }, 401 { "nativeClose", 402 "()V", 403 (void*)CameraMetadata_close }, 404 { "nativeSwap", 405 "(L" CAMERA_METADATA_CLASS_NAME ";)V", 406 (void *)CameraMetadata_swap }, 407 { "nativeReadValues", 408 "(I)[B", 409 (void *)CameraMetadata_readValues }, 410 { "nativeWriteValues", 411 "(I[B)V", 412 (void *)CameraMetadata_writeValues }, 413// Parcelable interface 414 { "nativeReadFromParcel", 415 "(Landroid/os/Parcel;)V", 416 (void *)CameraMetadata_readFromParcel }, 417 { "nativeWriteToParcel", 418 "(Landroid/os/Parcel;)V", 419 (void *)CameraMetadata_writeToParcel }, 420}; 421 422struct field { 423 const char *class_name; 424 const char *field_name; 425 const char *field_type; 426 jfieldID *jfield; 427}; 428 429static int find_fields(JNIEnv *env, field *fields, int count) 430{ 431 for (int i = 0; i < count; i++) { 432 field *f = &fields[i]; 433 jclass clazz = env->FindClass(f->class_name); 434 if (clazz == NULL) { 435 ALOGE("Can't find %s", f->class_name); 436 return -1; 437 } 438 439 jfieldID field = env->GetFieldID(clazz, f->field_name, f->field_type); 440 if (field == NULL) { 441 ALOGE("Can't find %s.%s", f->class_name, f->field_name); 442 return -1; 443 } 444 445 *(f->jfield) = field; 446 } 447 448 return 0; 449} 450 451// Get all the required offsets in java class and register native functions 452int register_android_hardware_camera2_CameraMetadata(JNIEnv *env) 453{ 454 // Register native functions 455 return AndroidRuntime::registerNativeMethods(env, 456 CAMERA_METADATA_CLASS_NAME, 457 gCameraMetadataMethods, 458 NELEM(gCameraMetadataMethods)); 459} 460 461extern "C" { 462static void CameraMetadata_classInit(JNIEnv *env, jobject thiz) { 463 // XX: Why do this separately instead of doing it in the register function? 464 ALOGV("%s", __FUNCTION__); 465 466 field fields_to_find[] = { 467 { CAMERA_METADATA_CLASS_NAME, "mMetadataPtr", "J", &fields.metadata_ptr }, 468 }; 469 470 // Do this here instead of in register_native_methods, 471 // since otherwise it will fail to find the fields. 472 if (find_fields(env, fields_to_find, NELEM(fields_to_find)) < 0) 473 return; 474 475 jclass clazz = env->FindClass(CAMERA_METADATA_CLASS_NAME); 476} 477 478static jint CameraMetadata_getTagFromKey(JNIEnv *env, jobject thiz, jstring keyName) { 479 480 ScopedUtfChars keyScoped(env, keyName); 481 const char *key = keyScoped.c_str(); 482 if (key == NULL) { 483 // exception thrown by ScopedUtfChars 484 return 0; 485 } 486 size_t keyLength = strlen(key); 487 488 ALOGV("%s (key = '%s')", __FUNCTION__, key); 489 490 sp<VendorTagDescriptor> vTags = VendorTagDescriptor::getGlobalVendorTagDescriptor(); 491 492 SortedVector<String8> vendorSections = vTags->getAllSectionNames(); 493 size_t vendorSectionCount = vendorSections.size(); 494 495 // First, find the section by the longest string match 496 const char *section = NULL; 497 size_t sectionIndex = 0; 498 size_t sectionLength = 0; 499 size_t totalSectionCount = ANDROID_SECTION_COUNT + vendorSectionCount; 500 for (size_t i = 0; i < totalSectionCount; ++i) { 501 502 const char *str = (i < ANDROID_SECTION_COUNT) ? camera_metadata_section_names[i] : 503 vendorSections[i - ANDROID_SECTION_COUNT].string(); 504 ALOGVV("%s: Trying to match against section '%s'", 505 __FUNCTION__, str); 506 if (strstr(key, str) == key) { // key begins with the section name 507 size_t strLength = strlen(str); 508 509 ALOGVV("%s: Key begins with section name", __FUNCTION__); 510 511 // section name is the longest we've found so far 512 if (section == NULL || sectionLength < strLength) { 513 section = str; 514 sectionIndex = i; 515 sectionLength = strLength; 516 517 ALOGVV("%s: Found new best section (%s)", __FUNCTION__, section); 518 } 519 } 520 } 521 522 // TODO: Make above get_camera_metadata_section_from_name ? 523 524 if (section == NULL) { 525 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", 526 "Could not find section name for key '%s')", key); 527 return 0; 528 } else { 529 ALOGV("%s: Found matched section '%s' (%d)", 530 __FUNCTION__, section, sectionIndex); 531 } 532 533 // Get the tag name component of the key 534 const char *keyTagName = key + sectionLength + 1; // x.y.z -> z 535 if (sectionLength + 1 >= keyLength) { 536 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", 537 "Key length too short for key '%s')", key); 538 return 0; 539 } 540 541 // Match rest of name against the tag names in that section only 542 uint32_t tag = 0; 543 if (sectionIndex < ANDROID_SECTION_COUNT) { 544 // Match built-in tags (typically android.*) 545 uint32_t tagBegin, tagEnd; // [tagBegin, tagEnd) 546 tagBegin = camera_metadata_section_bounds[sectionIndex][0]; 547 tagEnd = camera_metadata_section_bounds[sectionIndex][1]; 548 549 for (tag = tagBegin; tag < tagEnd; ++tag) { 550 const char *tagName = get_camera_metadata_tag_name(tag); 551 552 if (strcmp(keyTagName, tagName) == 0) { 553 ALOGV("%s: Found matched tag '%s' (%d)", 554 __FUNCTION__, tagName, tag); 555 break; 556 } 557 } 558 559 if (tag == tagEnd) { 560 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", 561 "Could not find tag name for key '%s')", key); 562 return 0; 563 } 564 } else { 565 // Match vendor tags (typically com.*) 566 const String8 sectionName(section); 567 const String8 tagName(keyTagName); 568 569 status_t res = OK; 570 if ((res = vTags->lookupTag(tagName, sectionName, &tag)) != OK) { 571 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", 572 "%s: No vendor tag matches key '%s'", __FUNCTION__, key); 573 return 0; 574 } 575 } 576 577 // TODO: Make above get_camera_metadata_tag_from_name ? 578 579 return tag; 580} 581 582static jint CameraMetadata_getTypeFromTag(JNIEnv *env, jobject thiz, jint tag) { 583 int tagType = get_camera_metadata_tag_type(tag); 584 if (tagType == -1) { 585 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", 586 "Tag (%d) did not have a type", tag); 587 return -1; 588 } 589 590 return tagType; 591} 592 593static jint CameraMetadata_setupGlobalVendorTagDescriptor(JNIEnv *env, jobject thiz) { 594 const String16 NAME("media.camera"); 595 sp<ICameraService> cameraService; 596 status_t err = getService(NAME, /*out*/&cameraService); 597 598 if (err != OK) { 599 ALOGE("%s: Failed to get camera service, received error %s (%d)", __FUNCTION__, 600 strerror(-err), err); 601 return err; 602 } 603 604 sp<VendorTagDescriptor> desc; 605 err = cameraService->getCameraVendorTagDescriptor(/*out*/desc); 606 607 if (err == -EOPNOTSUPP) { 608 ALOGW("%s: Camera HAL too old; does not support vendor tags", __FUNCTION__); 609 VendorTagDescriptor::clearGlobalVendorTagDescriptor(); 610 611 return OK; 612 } else if (err != OK) { 613 ALOGE("%s: Failed to setup vendor tag descriptors, received error %s (%d)", 614 __FUNCTION__, strerror(-err), err); 615 return err; 616 } 617 618 err = VendorTagDescriptor::setAsGlobalVendorTagDescriptor(desc); 619 620 return err; 621} 622 623} // extern "C" 624