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