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