Home | History | Annotate | Download | only in jni
      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_TAG "CameraMetadata-JNI"
     20 #include <utils/Errors.h>
     21 #include <utils/Log.h>
     22 #include <utils/RefBase.h>
     23 #include <utils/Vector.h>
     24 #include <utils/SortedVector.h>
     25 #include <utils/KeyedVector.h>
     26 #include <stdio.h>
     27 #include <string.h>
     28 #include <vector>
     29 
     30 #include "jni.h"
     31 #include <nativehelper/JNIHelp.h>
     32 #include "android_os_Parcel.h"
     33 #include "core_jni_helpers.h"
     34 #include "android_runtime/android_hardware_camera2_CameraMetadata.h"
     35 
     36 #include <android/hardware/ICameraService.h>
     37 #include <binder/IServiceManager.h>
     38 #include <camera/CameraMetadata.h>
     39 #include <camera_metadata_hidden.h>
     40 #include <camera/VendorTagDescriptor.h>
     41 #include <nativehelper/ScopedUtfChars.h>
     42 #include <nativehelper/ScopedPrimitiveArray.h>
     43 
     44 #include <sys/types.h> // for socketpair
     45 #include <sys/socket.h> // for socketpair
     46 
     47 // fully-qualified class name
     48 #define CAMERA_METADATA_CLASS_NAME "android/hardware/camera2/impl/CameraMetadataNative"
     49 #define CHARACTERISTICS_KEY_CLASS_NAME "android/hardware/camera2/CameraCharacteristics$Key"
     50 #define REQUEST_KEY_CLASS_NAME "android/hardware/camera2/CaptureRequest$Key"
     51 #define RESULT_KEY_CLASS_NAME "android/hardware/camera2/CaptureResult$Key"
     52 
     53 using namespace android;
     54 
     55 static struct metadata_java_key_offsets_t {
     56     jclass mCharacteristicsKey;
     57     jclass mResultKey;
     58     jclass mRequestKey;
     59     jmethodID mCharacteristicsConstr;
     60     jmethodID mResultConstr;
     61     jmethodID mRequestConstr;
     62     jclass mByteArray;
     63     jclass mInt32Array;
     64     jclass mFloatArray;
     65     jclass mInt64Array;
     66     jclass mDoubleArray;
     67     jclass mRationalArray;
     68     jclass mArrayList;
     69     jmethodID mArrayListConstr;
     70     jmethodID mArrayListAdd;
     71 } gMetadataOffsets;
     72 
     73 struct fields_t {
     74     jfieldID    metadata_ptr;
     75 };
     76 
     77 static fields_t fields;
     78 
     79 namespace android {
     80 
     81 status_t CameraMetadata_getNativeMetadata(JNIEnv* env, jobject thiz,
     82         /*out*/CameraMetadata* metadata) {
     83     if (!thiz) {
     84         ALOGE("%s: Invalid java metadata object.", __FUNCTION__);
     85         return BAD_VALUE;
     86     }
     87 
     88     if (!metadata) {
     89         ALOGE("%s: Invalid output metadata object.", __FUNCTION__);
     90         return BAD_VALUE;
     91     }
     92     CameraMetadata* nativePtr = reinterpret_cast<CameraMetadata*>(env->GetLongField(thiz,
     93             fields.metadata_ptr));
     94     if (nativePtr == NULL) {
     95         ALOGE("%s: Invalid native pointer in java metadata object.", __FUNCTION__);
     96         return BAD_VALUE;
     97     }
     98     *metadata = *nativePtr;
     99     return OK;
    100 }
    101 
    102 } /*namespace android*/
    103 
    104 namespace {
    105 struct Helpers {
    106     static size_t getTypeSize(uint8_t type) {
    107         if (type >= NUM_TYPES) {
    108             ALOGE("%s: Invalid type specified (%ud)", __FUNCTION__, type);
    109             return static_cast<size_t>(-1);
    110         }
    111 
    112         return camera_metadata_type_size[type];
    113     }
    114 
    115     static status_t updateAny(CameraMetadata *metadata,
    116                           uint32_t tag,
    117                           uint32_t type,
    118                           const void *data,
    119                           size_t dataBytes) {
    120 
    121         if (type >= NUM_TYPES) {
    122             ALOGE("%s: Invalid type specified (%ud)", __FUNCTION__, type);
    123             return INVALID_OPERATION;
    124         }
    125 
    126         size_t typeSize = getTypeSize(type);
    127 
    128         if (dataBytes % typeSize != 0) {
    129             ALOGE("%s: Expected dataBytes (%zu) to be divisible by typeSize "
    130                   "(%zu)", __FUNCTION__, dataBytes, typeSize);
    131             return BAD_VALUE;
    132         }
    133 
    134         size_t dataCount = dataBytes / typeSize;
    135 
    136         switch(type) {
    137 #define METADATA_UPDATE(runtime_type, compile_type)                            \
    138             case runtime_type: {                                               \
    139                 const compile_type *dataPtr =                                  \
    140                         static_cast<const compile_type*>(data);                \
    141                 return metadata->update(tag, dataPtr, dataCount);              \
    142             }                                                                  \
    143 
    144             METADATA_UPDATE(TYPE_BYTE,     uint8_t);
    145             METADATA_UPDATE(TYPE_INT32,    int32_t);
    146             METADATA_UPDATE(TYPE_FLOAT,    float);
    147             METADATA_UPDATE(TYPE_INT64,    int64_t);
    148             METADATA_UPDATE(TYPE_DOUBLE,   double);
    149             METADATA_UPDATE(TYPE_RATIONAL, camera_metadata_rational_t);
    150 
    151             default: {
    152                 // unreachable
    153                 ALOGE("%s: Unreachable", __FUNCTION__);
    154                 return INVALID_OPERATION;
    155             }
    156         }
    157 
    158 #undef METADATA_UPDATE
    159     }
    160 };
    161 } // namespace {}
    162 
    163 extern "C" {
    164 
    165 static jobject CameraMetadata_getAllVendorKeys(JNIEnv* env, jobject thiz, jclass keyType);
    166 static jint CameraMetadata_getTagFromKey(JNIEnv *env, jobject thiz, jstring keyName, jlong vendorId);
    167 static jint CameraMetadata_getTagFromKeyLocal(JNIEnv *env, jobject thiz, jstring keyName);
    168 static jint CameraMetadata_getTypeFromTag(JNIEnv *env, jobject thiz, jint tag, jlong vendorId);
    169 static jint CameraMetadata_getTypeFromTagLocal(JNIEnv *env, jobject thiz, jint tag);
    170 static jint CameraMetadata_setupGlobalVendorTagDescriptor(JNIEnv *env, jobject thiz);
    171 
    172 // Less safe access to native pointer. Does NOT throw any Java exceptions if NULL.
    173 static CameraMetadata* CameraMetadata_getPointerNoThrow(JNIEnv *env, jobject thiz) {
    174 
    175     if (thiz == NULL) {
    176         return NULL;
    177     }
    178 
    179     return reinterpret_cast<CameraMetadata*>(env->GetLongField(thiz, fields.metadata_ptr));
    180 }
    181 
    182 // Safe access to native pointer from object. Throws if not possible to access.
    183 static CameraMetadata* CameraMetadata_getPointerThrow(JNIEnv *env, jobject thiz,
    184                                                  const char* argName = "this") {
    185 
    186     if (thiz == NULL) {
    187         ALOGV("%s: Throwing java.lang.NullPointerException for null reference",
    188               __FUNCTION__);
    189         jniThrowNullPointerException(env, argName);
    190         return NULL;
    191     }
    192 
    193     CameraMetadata* metadata = CameraMetadata_getPointerNoThrow(env, thiz);
    194     if (metadata == NULL) {
    195         ALOGV("%s: Throwing java.lang.IllegalStateException for closed object",
    196               __FUNCTION__);
    197         jniThrowException(env, "java/lang/IllegalStateException",
    198                             "Metadata object was already closed");
    199         return NULL;
    200     }
    201 
    202     return metadata;
    203 }
    204 
    205 static jlong CameraMetadata_allocate(JNIEnv *env, jobject thiz) {
    206     ALOGV("%s", __FUNCTION__);
    207 
    208     return reinterpret_cast<jlong>(new CameraMetadata());
    209 }
    210 
    211 static jlong CameraMetadata_allocateCopy(JNIEnv *env, jobject thiz,
    212         jobject other) {
    213     ALOGV("%s", __FUNCTION__);
    214 
    215     CameraMetadata* otherMetadata =
    216             CameraMetadata_getPointerThrow(env, other, "other");
    217 
    218     // In case of exception, return
    219     if (otherMetadata == NULL) return NULL;
    220 
    221     // Clone native metadata and return new pointer
    222     return reinterpret_cast<jlong>(new CameraMetadata(*otherMetadata));
    223 }
    224 
    225 
    226 static jboolean CameraMetadata_isEmpty(JNIEnv *env, jobject thiz) {
    227     ALOGV("%s", __FUNCTION__);
    228 
    229     CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
    230 
    231     if (metadata == NULL) {
    232         ALOGW("%s: Returning early due to exception being thrown",
    233                __FUNCTION__);
    234         return JNI_TRUE; // actually throws java exc.
    235     }
    236 
    237     jboolean empty = metadata->isEmpty();
    238 
    239     ALOGV("%s: Empty returned %d, entry count was %zu",
    240           __FUNCTION__, empty, metadata->entryCount());
    241 
    242     return empty;
    243 }
    244 
    245 static jint CameraMetadata_getEntryCount(JNIEnv *env, jobject thiz) {
    246     ALOGV("%s", __FUNCTION__);
    247 
    248     CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
    249 
    250     if (metadata == NULL) return 0; // actually throws java exc.
    251 
    252     return metadata->entryCount();
    253 }
    254 
    255 // idempotent. calling more than once has no effect.
    256 static void CameraMetadata_close(JNIEnv *env, jobject thiz) {
    257     ALOGV("%s", __FUNCTION__);
    258 
    259     CameraMetadata* metadata = CameraMetadata_getPointerNoThrow(env, thiz);
    260 
    261     if (metadata != NULL) {
    262         delete metadata;
    263         env->SetLongField(thiz, fields.metadata_ptr, 0);
    264     }
    265 
    266     LOG_ALWAYS_FATAL_IF(CameraMetadata_getPointerNoThrow(env, thiz) != NULL,
    267                         "Expected the native ptr to be 0 after #close");
    268 }
    269 
    270 static void CameraMetadata_swap(JNIEnv *env, jobject thiz, jobject other) {
    271     ALOGV("%s", __FUNCTION__);
    272 
    273     CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
    274 
    275     // order is important: we can't call another JNI method
    276     // if there is an exception pending
    277     if (metadata == NULL) return;
    278 
    279     CameraMetadata* otherMetadata = CameraMetadata_getPointerThrow(env, other, "other");
    280 
    281     if (otherMetadata == NULL) return;
    282 
    283     metadata->swap(*otherMetadata);
    284 }
    285 
    286 static jbyteArray CameraMetadata_readValues(JNIEnv *env, jobject thiz, jint tag) {
    287     ALOGV("%s (tag = %d)", __FUNCTION__, tag);
    288 
    289     CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
    290     if (metadata == NULL) return NULL;
    291 
    292     const camera_metadata_t *metaBuffer = metadata->getAndLock();
    293     int tagType = get_local_camera_metadata_tag_type(tag, metaBuffer);
    294     metadata->unlock(metaBuffer);
    295     if (tagType == -1) {
    296         jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
    297                              "Tag (%d) did not have a type", tag);
    298         return NULL;
    299     }
    300     size_t tagSize = Helpers::getTypeSize(tagType);
    301 
    302     camera_metadata_entry entry = metadata->find(tag);
    303     if (entry.count == 0) {
    304          if (!metadata->exists(tag)) {
    305              ALOGV("%s: Tag %d does not have any entries", __FUNCTION__, tag);
    306              return NULL;
    307          } else {
    308              // OK: we will return a 0-sized array.
    309              ALOGV("%s: Tag %d had an entry, but it had 0 data", __FUNCTION__,
    310                    tag);
    311          }
    312     }
    313 
    314     jsize byteCount = entry.count * tagSize;
    315     jbyteArray byteArray = env->NewByteArray(byteCount);
    316     if (env->ExceptionCheck()) return NULL;
    317 
    318     // Copy into java array from native array
    319     ScopedByteArrayRW arrayWriter(env, byteArray);
    320     memcpy(arrayWriter.get(), entry.data.u8, byteCount);
    321 
    322     return byteArray;
    323 }
    324 
    325 static void CameraMetadata_writeValues(JNIEnv *env, jobject thiz, jint tag, jbyteArray src) {
    326     ALOGV("%s (tag = %d)", __FUNCTION__, tag);
    327 
    328     CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
    329     if (metadata == NULL) return;
    330 
    331     const camera_metadata_t *metaBuffer = metadata->getAndLock();
    332     int tagType = get_local_camera_metadata_tag_type(tag, metaBuffer);
    333     metadata->unlock(metaBuffer);
    334     if (tagType == -1) {
    335         jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
    336                              "Tag (%d) did not have a type", tag);
    337         return;
    338     }
    339 
    340     status_t res;
    341 
    342     if (src == NULL) {
    343         // If array is NULL, delete the entry
    344         if (metadata->exists(tag)) {
    345             res = metadata->erase(tag);
    346             ALOGV("%s: Erase values (res = %d)", __FUNCTION__, res);
    347         } else {
    348             res = OK;
    349             ALOGV("%s: Don't need to erase", __FUNCTION__);
    350         }
    351     } else {
    352         // Copy from java array into native array
    353         ScopedByteArrayRO arrayReader(env, src);
    354         if (arrayReader.get() == NULL) return;
    355 
    356         res = Helpers::updateAny(metadata, static_cast<uint32_t>(tag),
    357                                  tagType, arrayReader.get(), arrayReader.size());
    358 
    359         ALOGV("%s: Update values (res = %d)", __FUNCTION__, res);
    360     }
    361 
    362     if (res == OK) {
    363         return;
    364     } else if (res == BAD_VALUE) {
    365         jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
    366                              "Src byte array was poorly formed");
    367     } else if (res == INVALID_OPERATION) {
    368         jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
    369                              "Internal error while trying to update metadata");
    370     } else {
    371         jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
    372                              "Unknown error (%d) while trying to update "
    373                             "metadata", res);
    374     }
    375 }
    376 
    377 struct DumpMetadataParams {
    378     int writeFd;
    379     const CameraMetadata* metadata;
    380 };
    381 
    382 static void* CameraMetadata_writeMetadataThread(void* arg) {
    383     DumpMetadataParams* p = static_cast<DumpMetadataParams*>(arg);
    384 
    385     /*
    386      * Write the dumped data, and close the writing side FD.
    387      */
    388     p->metadata->dump(p->writeFd, /*verbosity*/2);
    389 
    390     if (close(p->writeFd) < 0) {
    391         ALOGE("%s: Failed to close writeFd (errno = %#x, message = '%s')",
    392                 __FUNCTION__, errno, strerror(errno));
    393     }
    394 
    395     return NULL;
    396 }
    397 
    398 static void CameraMetadata_dump(JNIEnv *env, jobject thiz) {
    399     ALOGV("%s", __FUNCTION__);
    400     CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
    401     if (metadata == NULL) {
    402         return;
    403     }
    404 
    405     /*
    406      * Create a socket pair for local streaming read/writes.
    407      *
    408      * The metadata will be dumped into the write side,
    409      * and then read back out (and logged) via the read side.
    410      */
    411 
    412     int writeFd, readFd;
    413     {
    414 
    415         int sv[2];
    416         if (socketpair(AF_LOCAL, SOCK_STREAM, /*protocol*/0, &sv[0]) < 0) {
    417             jniThrowExceptionFmt(env, "java/io/IOException",
    418                     "Failed to create socketpair (errno = %#x, message = '%s')",
    419                     errno, strerror(errno));
    420             return;
    421         }
    422         writeFd = sv[0];
    423         readFd = sv[1];
    424     }
    425 
    426     /*
    427      * Create a thread for doing the writing.
    428      *
    429      * The reading and writing must be concurrent, otherwise
    430      * the write will block forever once it exhausts the capped
    431      * buffer size (from getsockopt).
    432      */
    433     pthread_t writeThread;
    434     DumpMetadataParams params = {
    435         writeFd,
    436         metadata
    437     };
    438 
    439     {
    440         int threadRet = pthread_create(&writeThread, /*attr*/NULL,
    441                 CameraMetadata_writeMetadataThread, (void*)&params);
    442 
    443         if (threadRet != 0) {
    444             close(writeFd);
    445             close(readFd);
    446 
    447             jniThrowExceptionFmt(env, "java/io/IOException",
    448                     "Failed to create thread for writing (errno = %#x, message = '%s')",
    449                     threadRet, strerror(threadRet));
    450             return;
    451         }
    452     }
    453 
    454     /*
    455      * Read out a byte until stream is complete. Write completed lines
    456      * to ALOG.
    457      */
    458     {
    459         char out[] = {'\0', '\0'}; // large enough to append as a string
    460         String8 logLine;
    461 
    462         // Read one byte at a time! Very slow but avoids complicated \n scanning.
    463         ssize_t res;
    464         while ((res = TEMP_FAILURE_RETRY(read(readFd, &out[0], /*count*/1))) > 0) {
    465             if (out[0] == '\n') {
    466                 ALOGD("%s", logLine.string());
    467                 logLine.clear();
    468             } else {
    469                 logLine.append(out);
    470             }
    471         }
    472 
    473         if (res < 0) {
    474             jniThrowExceptionFmt(env, "java/io/IOException",
    475                     "Failed to read from fd (errno = %#x, message = '%s')",
    476                     errno, strerror(errno));
    477             //return;
    478         } else if (!logLine.isEmpty()) {
    479             ALOGD("%s", logLine.string());
    480         }
    481 
    482         close(readFd);
    483     }
    484 
    485     int res;
    486 
    487     // Join until thread finishes. Ensures params/metadata is valid until then.
    488     if ((res = pthread_join(writeThread, /*retval*/NULL)) != 0) {
    489         ALOGE("%s: Failed to join thread (errno = %#x, message = '%s')",
    490                 __FUNCTION__, res, strerror(res));
    491     }
    492 }
    493 
    494 static void CameraMetadata_readFromParcel(JNIEnv *env, jobject thiz, jobject parcel) {
    495     ALOGV("%s", __FUNCTION__);
    496     CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
    497     if (metadata == NULL) {
    498         return;
    499     }
    500 
    501     Parcel* parcelNative = parcelForJavaObject(env, parcel);
    502     if (parcelNative == NULL) {
    503         jniThrowNullPointerException(env, "parcel");
    504         return;
    505     }
    506 
    507     status_t err;
    508     if ((err = metadata->readFromParcel(parcelNative)) != OK) {
    509         jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
    510                              "Failed to read from parcel (error code %d)", err);
    511         return;
    512     }
    513 }
    514 
    515 static void CameraMetadata_writeToParcel(JNIEnv *env, jobject thiz, jobject parcel) {
    516     ALOGV("%s", __FUNCTION__);
    517     CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
    518     if (metadata == NULL) {
    519         return;
    520     }
    521 
    522     Parcel* parcelNative = parcelForJavaObject(env, parcel);
    523     if (parcelNative == NULL) {
    524         jniThrowNullPointerException(env, "parcel");
    525         return;
    526     }
    527 
    528     status_t err;
    529     if ((err = metadata->writeToParcel(parcelNative)) != OK) {
    530         jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
    531                                   "Failed to write to parcel (error code %d)", err);
    532         return;
    533     }
    534 }
    535 
    536 } // extern "C"
    537 
    538 //-------------------------------------------------
    539 
    540 static const JNINativeMethod gCameraMetadataMethods[] = {
    541 // static methods
    542   { "nativeGetTagFromKey",
    543     "(Ljava/lang/String;J)I",
    544     (void *)CameraMetadata_getTagFromKey },
    545   { "nativeGetTypeFromTag",
    546     "(IJ)I",
    547     (void *)CameraMetadata_getTypeFromTag },
    548   { "nativeSetupGlobalVendorTagDescriptor",
    549     "()I",
    550     (void*)CameraMetadata_setupGlobalVendorTagDescriptor },
    551 // instance methods
    552   { "nativeAllocate",
    553     "()J",
    554     (void*)CameraMetadata_allocate },
    555   { "nativeAllocateCopy",
    556     "(L" CAMERA_METADATA_CLASS_NAME ";)J",
    557     (void *)CameraMetadata_allocateCopy },
    558   { "nativeIsEmpty",
    559     "()Z",
    560     (void*)CameraMetadata_isEmpty },
    561   { "nativeGetEntryCount",
    562     "()I",
    563     (void*)CameraMetadata_getEntryCount },
    564   { "nativeClose",
    565     "()V",
    566     (void*)CameraMetadata_close },
    567   { "nativeSwap",
    568     "(L" CAMERA_METADATA_CLASS_NAME ";)V",
    569     (void *)CameraMetadata_swap },
    570   { "nativeGetTagFromKeyLocal",
    571     "(Ljava/lang/String;)I",
    572     (void *)CameraMetadata_getTagFromKeyLocal },
    573   { "nativeGetTypeFromTagLocal",
    574     "(I)I",
    575     (void *)CameraMetadata_getTypeFromTagLocal },
    576   { "nativeReadValues",
    577     "(I)[B",
    578     (void *)CameraMetadata_readValues },
    579   { "nativeWriteValues",
    580     "(I[B)V",
    581     (void *)CameraMetadata_writeValues },
    582   { "nativeDump",
    583     "()V",
    584     (void *)CameraMetadata_dump },
    585   { "nativeGetAllVendorKeys",
    586     "(Ljava/lang/Class;)Ljava/util/ArrayList;",
    587     (void *)CameraMetadata_getAllVendorKeys},
    588 // Parcelable interface
    589   { "nativeReadFromParcel",
    590     "(Landroid/os/Parcel;)V",
    591     (void *)CameraMetadata_readFromParcel },
    592   { "nativeWriteToParcel",
    593     "(Landroid/os/Parcel;)V",
    594     (void *)CameraMetadata_writeToParcel },
    595 };
    596 
    597 // Get all the required offsets in java class and register native functions
    598 int register_android_hardware_camera2_CameraMetadata(JNIEnv *env)
    599 {
    600 
    601     // Store global references to Key-related classes and methods used natively
    602     jclass characteristicsKeyClazz = FindClassOrDie(env, CHARACTERISTICS_KEY_CLASS_NAME);
    603     jclass requestKeyClazz = FindClassOrDie(env, REQUEST_KEY_CLASS_NAME);
    604     jclass resultKeyClazz = FindClassOrDie(env, RESULT_KEY_CLASS_NAME);
    605     gMetadataOffsets.mCharacteristicsKey = MakeGlobalRefOrDie(env, characteristicsKeyClazz);
    606     gMetadataOffsets.mRequestKey = MakeGlobalRefOrDie(env, requestKeyClazz);
    607     gMetadataOffsets.mResultKey = MakeGlobalRefOrDie(env, resultKeyClazz);
    608     gMetadataOffsets.mCharacteristicsConstr = GetMethodIDOrDie(env,
    609             gMetadataOffsets.mCharacteristicsKey, "<init>",
    610             "(Ljava/lang/String;Ljava/lang/Class;J)V");
    611     gMetadataOffsets.mRequestConstr = GetMethodIDOrDie(env,
    612             gMetadataOffsets.mRequestKey, "<init>", "(Ljava/lang/String;Ljava/lang/Class;J)V");
    613     gMetadataOffsets.mResultConstr = GetMethodIDOrDie(env,
    614             gMetadataOffsets.mResultKey, "<init>", "(Ljava/lang/String;Ljava/lang/Class;J)V");
    615 
    616     // Store global references for primitive array types used by Keys
    617     jclass byteClazz = FindClassOrDie(env, "[B");
    618     jclass int32Clazz = FindClassOrDie(env, "[I");
    619     jclass floatClazz = FindClassOrDie(env, "[F");
    620     jclass int64Clazz = FindClassOrDie(env, "[J");
    621     jclass doubleClazz = FindClassOrDie(env, "[D");
    622     jclass rationalClazz = FindClassOrDie(env, "[Landroid/util/Rational;");
    623     gMetadataOffsets.mByteArray = MakeGlobalRefOrDie(env, byteClazz);
    624     gMetadataOffsets.mInt32Array = MakeGlobalRefOrDie(env, int32Clazz);
    625     gMetadataOffsets.mFloatArray = MakeGlobalRefOrDie(env, floatClazz);
    626     gMetadataOffsets.mInt64Array = MakeGlobalRefOrDie(env, int64Clazz);
    627     gMetadataOffsets.mDoubleArray = MakeGlobalRefOrDie(env, doubleClazz);
    628     gMetadataOffsets.mRationalArray = MakeGlobalRefOrDie(env, rationalClazz);
    629 
    630     // Store global references for ArrayList methods used
    631     jclass arrayListClazz = FindClassOrDie(env, "java/util/ArrayList");
    632     gMetadataOffsets.mArrayList = MakeGlobalRefOrDie(env, arrayListClazz);
    633     gMetadataOffsets.mArrayListConstr = GetMethodIDOrDie(env, gMetadataOffsets.mArrayList,
    634             "<init>", "(I)V");
    635     gMetadataOffsets.mArrayListAdd = GetMethodIDOrDie(env, gMetadataOffsets.mArrayList,
    636             "add", "(Ljava/lang/Object;)Z");
    637 
    638     jclass cameraMetadataClazz = FindClassOrDie(env, CAMERA_METADATA_CLASS_NAME);
    639     fields.metadata_ptr = GetFieldIDOrDie(env, cameraMetadataClazz, "mMetadataPtr", "J");
    640 
    641     // Register native functions
    642     return RegisterMethodsOrDie(env,
    643             CAMERA_METADATA_CLASS_NAME,
    644             gCameraMetadataMethods,
    645             NELEM(gCameraMetadataMethods));
    646 }
    647 
    648 extern "C" {
    649 
    650 static jint CameraMetadata_getTypeFromTagLocal(JNIEnv *env, jobject thiz, jint tag) {
    651     CameraMetadata* metadata = CameraMetadata_getPointerNoThrow(env, thiz);
    652     metadata_vendor_id_t vendorId = CAMERA_METADATA_INVALID_VENDOR_ID;
    653     if (metadata) {
    654         const camera_metadata_t *metaBuffer = metadata->getAndLock();
    655         vendorId = get_camera_metadata_vendor_id(metaBuffer);
    656         metadata->unlock(metaBuffer);
    657     }
    658 
    659     int tagType = get_local_camera_metadata_tag_type_vendor_id(tag, vendorId);
    660     if (tagType == -1) {
    661         jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
    662                              "Tag (%d) did not have a type", tag);
    663         return -1;
    664     }
    665 
    666     return tagType;
    667 }
    668 
    669 static jint CameraMetadata_getTagFromKeyLocal(JNIEnv *env, jobject thiz, jstring keyName) {
    670     ScopedUtfChars keyScoped(env, keyName);
    671     const char *key = keyScoped.c_str();
    672     if (key == NULL) {
    673         // exception thrown by ScopedUtfChars
    674         return 0;
    675     }
    676     ALOGV("%s (key = '%s')", __FUNCTION__, key);
    677 
    678     uint32_t tag = 0;
    679     sp<VendorTagDescriptor> vTags;
    680     CameraMetadata* metadata = CameraMetadata_getPointerNoThrow(env, thiz);
    681     if (metadata) {
    682         sp<VendorTagDescriptorCache> cache = VendorTagDescriptorCache::getGlobalVendorTagCache();
    683         if (cache.get()) {
    684             const camera_metadata_t *metaBuffer = metadata->getAndLock();
    685             metadata_vendor_id_t vendorId = get_camera_metadata_vendor_id(metaBuffer);
    686             metadata->unlock(metaBuffer);
    687             cache->getVendorTagDescriptor(vendorId, &vTags);
    688         }
    689     }
    690 
    691     status_t res = CameraMetadata::getTagFromName(key, vTags.get(), &tag);
    692     if (res != OK) {
    693         jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
    694                              "Could not find tag for key '%s')", key);
    695     }
    696     return tag;
    697 }
    698 
    699 static jobject CameraMetadata_getAllVendorKeys(JNIEnv* env, jobject thiz, jclass keyType) {
    700     metadata_vendor_id_t vendorId = CAMERA_METADATA_INVALID_VENDOR_ID;
    701     // Get all vendor tags
    702     sp<VendorTagDescriptor> vTags = VendorTagDescriptor::getGlobalVendorTagDescriptor();
    703     if (vTags.get() == nullptr) {
    704         sp<VendorTagDescriptorCache> cache = VendorTagDescriptorCache::getGlobalVendorTagCache();
    705         if (cache.get() == nullptr) {
    706             // No vendor tags.
    707             return nullptr;
    708         }
    709 
    710         CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
    711         if (metadata == NULL) return NULL;
    712 
    713         const camera_metadata_t *metaBuffer = metadata->getAndLock();
    714         vendorId = get_camera_metadata_vendor_id(metaBuffer);
    715         cache->getVendorTagDescriptor(vendorId, &vTags);
    716         metadata->unlock(metaBuffer);
    717         if (vTags.get() == nullptr) {
    718             return nullptr;
    719         }
    720     }
    721 
    722     int count = vTags->getTagCount();
    723     if (count <= 0) {
    724         // No vendor tags.
    725         return NULL;
    726     }
    727 
    728     std::vector<uint32_t> tagIds(count, /*initializer value*/0);
    729     vTags->getTagArray(&tagIds[0]);
    730 
    731     // Which key class/constructor should we use?
    732     jclass keyClazz;
    733     jmethodID keyConstr;
    734     if (env->IsSameObject(keyType, gMetadataOffsets.mCharacteristicsKey)) {
    735         keyClazz = gMetadataOffsets.mCharacteristicsKey;
    736         keyConstr = gMetadataOffsets.mCharacteristicsConstr;
    737     } else if (env->IsSameObject(keyType, gMetadataOffsets.mResultKey)) {
    738         keyClazz = gMetadataOffsets.mResultKey;
    739         keyConstr = gMetadataOffsets.mResultConstr;
    740     } else if (env->IsSameObject(keyType, gMetadataOffsets.mRequestKey)) {
    741         keyClazz = gMetadataOffsets.mRequestKey;
    742         keyConstr = gMetadataOffsets.mRequestConstr;
    743     } else {
    744         jniThrowException(env, "java/lang/IllegalArgumentException",
    745                 "Invalid key class given as argument.");
    746         return NULL;
    747     }
    748 
    749     // Allocate arrayList to return
    750     jobject arrayList = env->NewObject(gMetadataOffsets.mArrayList,
    751             gMetadataOffsets.mArrayListConstr, static_cast<jint>(count));
    752     if (env->ExceptionCheck()) {
    753         return NULL;
    754     }
    755 
    756     for (uint32_t id : tagIds) {
    757         const char* section = vTags->getSectionName(id);
    758         const char* tag = vTags->getTagName(id);
    759         int type = vTags->getTagType(id);
    760 
    761         size_t totalLen = strlen(section) + strlen(tag) + 2;
    762         std::vector<char> fullName(totalLen, 0);
    763         snprintf(&fullName[0], totalLen, "%s.%s", section, tag);
    764 
    765         jstring name = env->NewStringUTF(&fullName[0]);
    766 
    767         if (env->ExceptionCheck()) {
    768             return NULL;
    769         }
    770 
    771         jclass valueClazz;
    772         switch (type) {
    773             case TYPE_BYTE:
    774                 valueClazz = gMetadataOffsets.mByteArray;
    775                 break;
    776             case TYPE_INT32:
    777                 valueClazz = gMetadataOffsets.mInt32Array;
    778                 break;
    779             case TYPE_FLOAT:
    780                 valueClazz = gMetadataOffsets.mFloatArray;
    781                 break;
    782             case TYPE_INT64:
    783                 valueClazz = gMetadataOffsets.mInt64Array;
    784                 break;
    785             case TYPE_DOUBLE:
    786                 valueClazz = gMetadataOffsets.mDoubleArray;
    787                 break;
    788             case TYPE_RATIONAL:
    789                 valueClazz = gMetadataOffsets.mRationalArray;
    790                 break;
    791             default:
    792                 jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
    793                         "Invalid type %d given for key %s", type, &fullName[0]);
    794                 return NULL;
    795         }
    796 
    797         jobject key = env->NewObject(keyClazz, keyConstr, name, valueClazz, vendorId);
    798         if (env->ExceptionCheck()) {
    799             return NULL;
    800         }
    801 
    802         env->CallBooleanMethod(arrayList, gMetadataOffsets.mArrayListAdd, key);
    803         if (env->ExceptionCheck()) {
    804             return NULL;
    805         }
    806 
    807         env->DeleteLocalRef(name);
    808         env->DeleteLocalRef(key);
    809     }
    810 
    811     return arrayList;
    812 }
    813 
    814 static jint CameraMetadata_getTagFromKey(JNIEnv *env, jobject thiz, jstring keyName,
    815         jlong vendorId) {
    816     ScopedUtfChars keyScoped(env, keyName);
    817     const char *key = keyScoped.c_str();
    818     if (key == NULL) {
    819         // exception thrown by ScopedUtfChars
    820         return 0;
    821     }
    822     ALOGV("%s (key = '%s')", __FUNCTION__, key);
    823 
    824     uint32_t tag = 0;
    825     sp<VendorTagDescriptor> vTags =
    826             VendorTagDescriptor::getGlobalVendorTagDescriptor();
    827     if (vTags.get() == nullptr) {
    828         sp<VendorTagDescriptorCache> cache = VendorTagDescriptorCache::getGlobalVendorTagCache();
    829         if (cache.get() != nullptr) {
    830             cache->getVendorTagDescriptor(vendorId, &vTags);
    831         }
    832     }
    833 
    834     status_t res = CameraMetadata::getTagFromName(key, vTags.get(), &tag);
    835     if (res != OK) {
    836         jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
    837                              "Could not find tag for key '%s')", key);
    838     }
    839     return tag;
    840 }
    841 
    842 static jint CameraMetadata_getTypeFromTag(JNIEnv *env, jobject thiz, jint tag, jlong vendorId) {
    843     int tagType = get_local_camera_metadata_tag_type_vendor_id(tag, vendorId);
    844     if (tagType == -1) {
    845         jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
    846                              "Tag (%d) did not have a type", tag);
    847         return -1;
    848     }
    849 
    850     return tagType;
    851 }
    852 
    853 static jint CameraMetadata_setupGlobalVendorTagDescriptor(JNIEnv *env, jobject thiz) {
    854     const String16 NAME("media.camera");
    855     sp<hardware::ICameraService> cameraService;
    856     status_t err = getService(NAME, /*out*/&cameraService);
    857 
    858     if (err != OK) {
    859         ALOGE("%s: Failed to get camera service, received error %s (%d)", __FUNCTION__,
    860                 strerror(-err), err);
    861         return hardware::ICameraService::ERROR_DISCONNECTED;
    862     }
    863 
    864     sp<VendorTagDescriptor> desc = new VendorTagDescriptor();
    865     binder::Status res = cameraService->getCameraVendorTagDescriptor(/*out*/desc.get());
    866 
    867     if (res.serviceSpecificErrorCode() == hardware::ICameraService::ERROR_DISCONNECTED) {
    868         // No camera module available, not an error on devices with no cameras
    869         VendorTagDescriptor::clearGlobalVendorTagDescriptor();
    870         return OK;
    871     } else if (!res.isOk()) {
    872         VendorTagDescriptor::clearGlobalVendorTagDescriptor();
    873         ALOGE("%s: Failed to setup vendor tag descriptors: %s",
    874                 __FUNCTION__, res.toString8().string());
    875         return res.serviceSpecificErrorCode();
    876     }
    877     if (0 < desc->getTagCount()) {
    878         err = VendorTagDescriptor::setAsGlobalVendorTagDescriptor(desc);
    879     } else {
    880         sp<VendorTagDescriptorCache> cache = new VendorTagDescriptorCache();
    881         binder::Status res = cameraService->getCameraVendorTagCache(/*out*/cache.get());
    882         if (res.serviceSpecificErrorCode() == hardware::ICameraService::ERROR_DISCONNECTED) {
    883             // No camera module available, not an error on devices with no cameras
    884             VendorTagDescriptorCache::clearGlobalVendorTagCache();
    885             return OK;
    886         } else if (!res.isOk()) {
    887             VendorTagDescriptorCache::clearGlobalVendorTagCache();
    888             ALOGE("%s: Failed to setup vendor tag cache: %s",
    889                     __FUNCTION__, res.toString8().string());
    890             return res.serviceSpecificErrorCode();
    891         }
    892 
    893         err = VendorTagDescriptorCache::setAsGlobalVendorTagCache(cache);
    894     }
    895 
    896     if (err != OK) {
    897         return hardware::ICameraService::ERROR_INVALID_OPERATION;
    898     }
    899     return OK;
    900 }
    901 
    902 } // extern "C"
    903