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 "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/VendorTagDescriptor.h>
     40 #include <nativehelper/ScopedUtfChars.h>
     41 #include <nativehelper/ScopedPrimitiveArray.h>
     42 
     43 #include <sys/types.h> // for socketpair
     44 #include <sys/socket.h> // for socketpair
     45 
     46 static const bool kIsDebug = false;
     47 
     48 // fully-qualified class name
     49 #define CAMERA_METADATA_CLASS_NAME "android/hardware/camera2/impl/CameraMetadataNative"
     50 #define CHARACTERISTICS_KEY_CLASS_NAME "android/hardware/camera2/CameraCharacteristics$Key"
     51 #define REQUEST_KEY_CLASS_NAME "android/hardware/camera2/CaptureRequest$Key"
     52 #define RESULT_KEY_CLASS_NAME "android/hardware/camera2/CaptureResult$Key"
     53 
     54 using namespace android;
     55 
     56 static struct metadata_java_key_offsets_t {
     57     jclass mCharacteristicsKey;
     58     jclass mResultKey;
     59     jclass mRequestKey;
     60     jmethodID mCharacteristicsConstr;
     61     jmethodID mResultConstr;
     62     jmethodID mRequestConstr;
     63     jclass mByteArray;
     64     jclass mInt32Array;
     65     jclass mFloatArray;
     66     jclass mInt64Array;
     67     jclass mDoubleArray;
     68     jclass mRationalArray;
     69     jclass mArrayList;
     70     jmethodID mArrayListConstr;
     71     jmethodID mArrayListAdd;
     72 } gMetadataOffsets;
     73 
     74 struct fields_t {
     75     jfieldID    metadata_ptr;
     76 };
     77 
     78 static fields_t fields;
     79 
     80 namespace android {
     81 
     82 status_t CameraMetadata_getNativeMetadata(JNIEnv* env, jobject thiz,
     83         /*out*/CameraMetadata* metadata) {
     84     if (!thiz) {
     85         ALOGE("%s: Invalid java metadata object.", __FUNCTION__);
     86         return BAD_VALUE;
     87     }
     88 
     89     if (!metadata) {
     90         ALOGE("%s: Invalid output metadata object.", __FUNCTION__);
     91         return BAD_VALUE;
     92     }
     93     CameraMetadata* nativePtr = reinterpret_cast<CameraMetadata*>(env->GetLongField(thiz,
     94             fields.metadata_ptr));
     95     if (nativePtr == NULL) {
     96         ALOGE("%s: Invalid native pointer in java metadata object.", __FUNCTION__);
     97         return BAD_VALUE;
     98     }
     99     *metadata = *nativePtr;
    100     return OK;
    101 }
    102 
    103 } /*namespace android*/
    104 
    105 namespace {
    106 struct Helpers {
    107     static size_t getTypeSize(uint8_t type) {
    108         if (type >= NUM_TYPES) {
    109             ALOGE("%s: Invalid type specified (%ud)", __FUNCTION__, type);
    110             return static_cast<size_t>(-1);
    111         }
    112 
    113         return camera_metadata_type_size[type];
    114     }
    115 
    116     static status_t updateAny(CameraMetadata *metadata,
    117                           uint32_t tag,
    118                           uint32_t type,
    119                           const void *data,
    120                           size_t dataBytes) {
    121 
    122         if (type >= NUM_TYPES) {
    123             ALOGE("%s: Invalid type specified (%ud)", __FUNCTION__, type);
    124             return INVALID_OPERATION;
    125         }
    126 
    127         size_t typeSize = getTypeSize(type);
    128 
    129         if (dataBytes % typeSize != 0) {
    130             ALOGE("%s: Expected dataBytes (%zu) to be divisible by typeSize "
    131                   "(%zu)", __FUNCTION__, dataBytes, typeSize);
    132             return BAD_VALUE;
    133         }
    134 
    135         size_t dataCount = dataBytes / typeSize;
    136 
    137         switch(type) {
    138 #define METADATA_UPDATE(runtime_type, compile_type)                            \
    139             case runtime_type: {                                               \
    140                 const compile_type *dataPtr =                                  \
    141                         static_cast<const compile_type*>(data);                \
    142                 return metadata->update(tag, dataPtr, dataCount);              \
    143             }                                                                  \
    144 
    145             METADATA_UPDATE(TYPE_BYTE,     uint8_t);
    146             METADATA_UPDATE(TYPE_INT32,    int32_t);
    147             METADATA_UPDATE(TYPE_FLOAT,    float);
    148             METADATA_UPDATE(TYPE_INT64,    int64_t);
    149             METADATA_UPDATE(TYPE_DOUBLE,   double);
    150             METADATA_UPDATE(TYPE_RATIONAL, camera_metadata_rational_t);
    151 
    152             default: {
    153                 // unreachable
    154                 ALOGE("%s: Unreachable", __FUNCTION__);
    155                 return INVALID_OPERATION;
    156             }
    157         }
    158 
    159 #undef METADATA_UPDATE
    160     }
    161 };
    162 } // namespace {}
    163 
    164 extern "C" {
    165 
    166 static void CameraMetadata_classInit(JNIEnv *env, jobject thiz);
    167 static jobject CameraMetadata_getAllVendorKeys(JNIEnv* env, jobject thiz, jclass keyType);
    168 static jint CameraMetadata_getTagFromKey(JNIEnv *env, jobject thiz, jstring keyName);
    169 static jint CameraMetadata_getTypeFromTag(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     int tagType = get_camera_metadata_tag_type(tag);
    293     if (tagType == -1) {
    294         jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
    295                              "Tag (%d) did not have a type", tag);
    296         return NULL;
    297     }
    298     size_t tagSize = Helpers::getTypeSize(tagType);
    299 
    300     camera_metadata_entry entry = metadata->find(tag);
    301     if (entry.count == 0) {
    302          if (!metadata->exists(tag)) {
    303              ALOGV("%s: Tag %d does not have any entries", __FUNCTION__, tag);
    304              return NULL;
    305          } else {
    306              // OK: we will return a 0-sized array.
    307              ALOGV("%s: Tag %d had an entry, but it had 0 data", __FUNCTION__,
    308                    tag);
    309          }
    310     }
    311 
    312     jsize byteCount = entry.count * tagSize;
    313     jbyteArray byteArray = env->NewByteArray(byteCount);
    314     if (env->ExceptionCheck()) return NULL;
    315 
    316     // Copy into java array from native array
    317     ScopedByteArrayRW arrayWriter(env, byteArray);
    318     memcpy(arrayWriter.get(), entry.data.u8, byteCount);
    319 
    320     return byteArray;
    321 }
    322 
    323 static void CameraMetadata_writeValues(JNIEnv *env, jobject thiz, jint tag, jbyteArray src) {
    324     ALOGV("%s (tag = %d)", __FUNCTION__, tag);
    325 
    326     CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
    327     if (metadata == NULL) return;
    328 
    329     int tagType = get_camera_metadata_tag_type(tag);
    330     if (tagType == -1) {
    331         jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
    332                              "Tag (%d) did not have a type", tag);
    333         return;
    334     }
    335 
    336     status_t res;
    337 
    338     if (src == NULL) {
    339         // If array is NULL, delete the entry
    340         if (metadata->exists(tag)) {
    341             res = metadata->erase(tag);
    342             ALOGV("%s: Erase values (res = %d)", __FUNCTION__, res);
    343         } else {
    344             res = OK;
    345             ALOGV("%s: Don't need to erase", __FUNCTION__);
    346         }
    347     } else {
    348         // Copy from java array into native array
    349         ScopedByteArrayRO arrayReader(env, src);
    350         if (arrayReader.get() == NULL) return;
    351 
    352         res = Helpers::updateAny(metadata, static_cast<uint32_t>(tag),
    353                                  tagType, arrayReader.get(), arrayReader.size());
    354 
    355         ALOGV("%s: Update values (res = %d)", __FUNCTION__, res);
    356     }
    357 
    358     if (res == OK) {
    359         return;
    360     } else if (res == BAD_VALUE) {
    361         jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
    362                              "Src byte array was poorly formed");
    363     } else if (res == INVALID_OPERATION) {
    364         jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
    365                              "Internal error while trying to update metadata");
    366     } else {
    367         jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
    368                              "Unknown error (%d) while trying to update "
    369                             "metadata", res);
    370     }
    371 }
    372 
    373 struct DumpMetadataParams {
    374     int writeFd;
    375     const CameraMetadata* metadata;
    376 };
    377 
    378 static void* CameraMetadata_writeMetadataThread(void* arg) {
    379     DumpMetadataParams* p = static_cast<DumpMetadataParams*>(arg);
    380 
    381     /*
    382      * Write the dumped data, and close the writing side FD.
    383      */
    384     p->metadata->dump(p->writeFd, /*verbosity*/2);
    385 
    386     if (close(p->writeFd) < 0) {
    387         ALOGE("%s: Failed to close writeFd (errno = %#x, message = '%s')",
    388                 __FUNCTION__, errno, strerror(errno));
    389     }
    390 
    391     return NULL;
    392 }
    393 
    394 static void CameraMetadata_dump(JNIEnv *env, jobject thiz) {
    395     ALOGV("%s", __FUNCTION__);
    396     CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
    397     if (metadata == NULL) {
    398         return;
    399     }
    400 
    401     /*
    402      * Create a socket pair for local streaming read/writes.
    403      *
    404      * The metadata will be dumped into the write side,
    405      * and then read back out (and logged) via the read side.
    406      */
    407 
    408     int writeFd, readFd;
    409     {
    410 
    411         int sv[2];
    412         if (socketpair(AF_LOCAL, SOCK_STREAM, /*protocol*/0, &sv[0]) < 0) {
    413             jniThrowExceptionFmt(env, "java/io/IOException",
    414                     "Failed to create socketpair (errno = %#x, message = '%s')",
    415                     errno, strerror(errno));
    416             return;
    417         }
    418         writeFd = sv[0];
    419         readFd = sv[1];
    420     }
    421 
    422     /*
    423      * Create a thread for doing the writing.
    424      *
    425      * The reading and writing must be concurrent, otherwise
    426      * the write will block forever once it exhausts the capped
    427      * buffer size (from getsockopt).
    428      */
    429     pthread_t writeThread;
    430     DumpMetadataParams params = {
    431         writeFd,
    432         metadata
    433     };
    434 
    435     {
    436         int threadRet = pthread_create(&writeThread, /*attr*/NULL,
    437                 CameraMetadata_writeMetadataThread, (void*)&params);
    438 
    439         if (threadRet != 0) {
    440             close(writeFd);
    441 
    442             jniThrowExceptionFmt(env, "java/io/IOException",
    443                     "Failed to create thread for writing (errno = %#x, message = '%s')",
    444                     threadRet, strerror(threadRet));
    445         }
    446     }
    447 
    448     /*
    449      * Read out a byte until stream is complete. Write completed lines
    450      * to ALOG.
    451      */
    452     {
    453         char out[] = {'\0', '\0'}; // large enough to append as a string
    454         String8 logLine;
    455 
    456         // Read one byte at a time! Very slow but avoids complicated \n scanning.
    457         ssize_t res;
    458         while ((res = TEMP_FAILURE_RETRY(read(readFd, &out[0], /*count*/1))) > 0) {
    459             if (out[0] == '\n') {
    460                 ALOGD("%s", logLine.string());
    461                 logLine.clear();
    462             } else {
    463                 logLine.append(out);
    464             }
    465         }
    466 
    467         if (res < 0) {
    468             jniThrowExceptionFmt(env, "java/io/IOException",
    469                     "Failed to read from fd (errno = %#x, message = '%s')",
    470                     errno, strerror(errno));
    471             //return;
    472         } else if (!logLine.isEmpty()) {
    473             ALOGD("%s", logLine.string());
    474         }
    475     }
    476 
    477     int res;
    478 
    479     // Join until thread finishes. Ensures params/metadata is valid until then.
    480     if ((res = pthread_join(writeThread, /*retval*/NULL)) != 0) {
    481         ALOGE("%s: Failed to join thread (errno = %#x, message = '%s')",
    482                 __FUNCTION__, res, strerror(res));
    483     }
    484 }
    485 
    486 static void CameraMetadata_readFromParcel(JNIEnv *env, jobject thiz, jobject parcel) {
    487     ALOGV("%s", __FUNCTION__);
    488     CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
    489     if (metadata == NULL) {
    490         return;
    491     }
    492 
    493     Parcel* parcelNative = parcelForJavaObject(env, parcel);
    494     if (parcelNative == NULL) {
    495         jniThrowNullPointerException(env, "parcel");
    496         return;
    497     }
    498 
    499     status_t err;
    500     if ((err = metadata->readFromParcel(parcelNative)) != OK) {
    501         jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
    502                              "Failed to read from parcel (error code %d)", err);
    503         return;
    504     }
    505 }
    506 
    507 static void CameraMetadata_writeToParcel(JNIEnv *env, jobject thiz, jobject parcel) {
    508     ALOGV("%s", __FUNCTION__);
    509     CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
    510     if (metadata == NULL) {
    511         return;
    512     }
    513 
    514     Parcel* parcelNative = parcelForJavaObject(env, parcel);
    515     if (parcelNative == NULL) {
    516         jniThrowNullPointerException(env, "parcel");
    517         return;
    518     }
    519 
    520     status_t err;
    521     if ((err = metadata->writeToParcel(parcelNative)) != OK) {
    522         jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
    523                                   "Failed to write to parcel (error code %d)", err);
    524         return;
    525     }
    526 }
    527 
    528 } // extern "C"
    529 
    530 //-------------------------------------------------
    531 
    532 static const JNINativeMethod gCameraMetadataMethods[] = {
    533 // static methods
    534   { "nativeClassInit",
    535     "()V",
    536     (void *)CameraMetadata_classInit },
    537   { "nativeGetAllVendorKeys",
    538     "(Ljava/lang/Class;)Ljava/util/ArrayList;",
    539     (void *)CameraMetadata_getAllVendorKeys},
    540   { "nativeGetTagFromKey",
    541     "(Ljava/lang/String;)I",
    542     (void *)CameraMetadata_getTagFromKey },
    543   { "nativeGetTypeFromTag",
    544     "(I)I",
    545     (void *)CameraMetadata_getTypeFromTag },
    546   { "nativeSetupGlobalVendorTagDescriptor",
    547     "()I",
    548     (void*)CameraMetadata_setupGlobalVendorTagDescriptor },
    549 // instance methods
    550   { "nativeAllocate",
    551     "()J",
    552     (void*)CameraMetadata_allocate },
    553   { "nativeAllocateCopy",
    554     "(L" CAMERA_METADATA_CLASS_NAME ";)J",
    555     (void *)CameraMetadata_allocateCopy },
    556   { "nativeIsEmpty",
    557     "()Z",
    558     (void*)CameraMetadata_isEmpty },
    559   { "nativeGetEntryCount",
    560     "()I",
    561     (void*)CameraMetadata_getEntryCount },
    562   { "nativeClose",
    563     "()V",
    564     (void*)CameraMetadata_close },
    565   { "nativeSwap",
    566     "(L" CAMERA_METADATA_CLASS_NAME ";)V",
    567     (void *)CameraMetadata_swap },
    568   { "nativeReadValues",
    569     "(I)[B",
    570     (void *)CameraMetadata_readValues },
    571   { "nativeWriteValues",
    572     "(I[B)V",
    573     (void *)CameraMetadata_writeValues },
    574   { "nativeDump",
    575     "()V",
    576     (void *)CameraMetadata_dump },
    577 // Parcelable interface
    578   { "nativeReadFromParcel",
    579     "(Landroid/os/Parcel;)V",
    580     (void *)CameraMetadata_readFromParcel },
    581   { "nativeWriteToParcel",
    582     "(Landroid/os/Parcel;)V",
    583     (void *)CameraMetadata_writeToParcel },
    584 };
    585 
    586 struct field {
    587     const char *class_name;
    588     const char *field_name;
    589     const char *field_type;
    590     jfieldID   *jfield;
    591 };
    592 
    593 static int find_fields(JNIEnv *env, field *fields, int count)
    594 {
    595     for (int i = 0; i < count; i++) {
    596         field *f = &fields[i];
    597         jclass clazz = env->FindClass(f->class_name);
    598         if (clazz == NULL) {
    599             ALOGE("Can't find %s", f->class_name);
    600             return -1;
    601         }
    602 
    603         jfieldID field = env->GetFieldID(clazz, f->field_name, f->field_type);
    604         if (field == NULL) {
    605             ALOGE("Can't find %s.%s", f->class_name, f->field_name);
    606             return -1;
    607         }
    608 
    609         *(f->jfield) = field;
    610     }
    611 
    612     return 0;
    613 }
    614 
    615 // Get all the required offsets in java class and register native functions
    616 int register_android_hardware_camera2_CameraMetadata(JNIEnv *env)
    617 {
    618 
    619     // Store global references to Key-related classes and methods used natively
    620     jclass characteristicsKeyClazz = FindClassOrDie(env, CHARACTERISTICS_KEY_CLASS_NAME);
    621     jclass requestKeyClazz = FindClassOrDie(env, REQUEST_KEY_CLASS_NAME);
    622     jclass resultKeyClazz = FindClassOrDie(env, RESULT_KEY_CLASS_NAME);
    623     gMetadataOffsets.mCharacteristicsKey = MakeGlobalRefOrDie(env, characteristicsKeyClazz);
    624     gMetadataOffsets.mRequestKey = MakeGlobalRefOrDie(env, requestKeyClazz);
    625     gMetadataOffsets.mResultKey = MakeGlobalRefOrDie(env, resultKeyClazz);
    626     gMetadataOffsets.mCharacteristicsConstr = GetMethodIDOrDie(env,
    627             gMetadataOffsets.mCharacteristicsKey, "<init>",
    628             "(Ljava/lang/String;Ljava/lang/Class;)V");
    629     gMetadataOffsets.mRequestConstr = GetMethodIDOrDie(env,
    630             gMetadataOffsets.mRequestKey, "<init>", "(Ljava/lang/String;Ljava/lang/Class;)V");
    631     gMetadataOffsets.mResultConstr = GetMethodIDOrDie(env,
    632             gMetadataOffsets.mResultKey, "<init>", "(Ljava/lang/String;Ljava/lang/Class;)V");
    633 
    634     // Store global references for primitive array types used by Keys
    635     jclass byteClazz = FindClassOrDie(env, "[B");
    636     jclass int32Clazz = FindClassOrDie(env, "[I");
    637     jclass floatClazz = FindClassOrDie(env, "[F");
    638     jclass int64Clazz = FindClassOrDie(env, "[J");
    639     jclass doubleClazz = FindClassOrDie(env, "[D");
    640     jclass rationalClazz = FindClassOrDie(env, "[Landroid/util/Rational;");
    641     gMetadataOffsets.mByteArray = MakeGlobalRefOrDie(env, byteClazz);
    642     gMetadataOffsets.mInt32Array = MakeGlobalRefOrDie(env, int32Clazz);
    643     gMetadataOffsets.mFloatArray = MakeGlobalRefOrDie(env, floatClazz);
    644     gMetadataOffsets.mInt64Array = MakeGlobalRefOrDie(env, int64Clazz);
    645     gMetadataOffsets.mDoubleArray = MakeGlobalRefOrDie(env, doubleClazz);
    646     gMetadataOffsets.mRationalArray = MakeGlobalRefOrDie(env, rationalClazz);
    647 
    648     // Store global references for ArrayList methods used
    649     jclass arrayListClazz = FindClassOrDie(env, "java/util/ArrayList");
    650     gMetadataOffsets.mArrayList = MakeGlobalRefOrDie(env, arrayListClazz);
    651     gMetadataOffsets.mArrayListConstr = GetMethodIDOrDie(env, gMetadataOffsets.mArrayList,
    652             "<init>", "(I)V");
    653     gMetadataOffsets.mArrayListAdd = GetMethodIDOrDie(env, gMetadataOffsets.mArrayList,
    654             "add", "(Ljava/lang/Object;)Z");
    655 
    656     // Register native functions
    657     return RegisterMethodsOrDie(env,
    658             CAMERA_METADATA_CLASS_NAME,
    659             gCameraMetadataMethods,
    660             NELEM(gCameraMetadataMethods));
    661 }
    662 
    663 extern "C" {
    664 
    665 static void CameraMetadata_classInit(JNIEnv *env, jobject thiz) {
    666     // XX: Why do this separately instead of doing it in the register function?
    667     ALOGV("%s", __FUNCTION__);
    668 
    669     field fields_to_find[] = {
    670         { CAMERA_METADATA_CLASS_NAME, "mMetadataPtr", "J", &fields.metadata_ptr },
    671     };
    672 
    673     // Do this here instead of in register_native_methods,
    674     // since otherwise it will fail to find the fields.
    675     if (find_fields(env, fields_to_find, NELEM(fields_to_find)) < 0)
    676         return;
    677 
    678     env->FindClass(CAMERA_METADATA_CLASS_NAME);
    679 }
    680 
    681 static jobject CameraMetadata_getAllVendorKeys(JNIEnv* env, jobject thiz, jclass keyType) {
    682 
    683     // Get all vendor tags
    684     sp<VendorTagDescriptor> vTags = VendorTagDescriptor::getGlobalVendorTagDescriptor();
    685     if (vTags.get() == nullptr) {
    686         // No vendor tags.
    687         return NULL;
    688     }
    689 
    690     int count = vTags->getTagCount();
    691     if (count <= 0) {
    692         // No vendor tags.
    693         return NULL;
    694     }
    695 
    696     std::vector<uint32_t> tagIds(count, /*initializer value*/0);
    697     vTags->getTagArray(&tagIds[0]);
    698 
    699     // Which key class/constructor should we use?
    700     jclass keyClazz;
    701     jmethodID keyConstr;
    702     if (env->IsSameObject(keyType, gMetadataOffsets.mCharacteristicsKey)) {
    703         keyClazz = gMetadataOffsets.mCharacteristicsKey;
    704         keyConstr = gMetadataOffsets.mCharacteristicsConstr;
    705     } else if (env->IsSameObject(keyType, gMetadataOffsets.mResultKey)) {
    706         keyClazz = gMetadataOffsets.mResultKey;
    707         keyConstr = gMetadataOffsets.mResultConstr;
    708     } else if (env->IsSameObject(keyType, gMetadataOffsets.mRequestKey)) {
    709         keyClazz = gMetadataOffsets.mRequestKey;
    710         keyConstr = gMetadataOffsets.mRequestConstr;
    711     } else {
    712         jniThrowException(env, "java/lang/IllegalArgumentException",
    713                 "Invalid key class given as argument.");
    714         return NULL;
    715     }
    716 
    717     // Allocate arrayList to return
    718     jobject arrayList = env->NewObject(gMetadataOffsets.mArrayList,
    719             gMetadataOffsets.mArrayListConstr, static_cast<jint>(count));
    720     if (env->ExceptionCheck()) {
    721         return NULL;
    722     }
    723 
    724     for (uint32_t id : tagIds) {
    725         const char* section = vTags->getSectionName(id);
    726         const char* tag = vTags->getTagName(id);
    727         int type = vTags->getTagType(id);
    728 
    729         size_t totalLen = strlen(section) + strlen(tag) + 2;
    730         std::vector<char> fullName(totalLen, 0);
    731         snprintf(&fullName[0], totalLen, "%s.%s", section, tag);
    732 
    733         jstring name = env->NewStringUTF(&fullName[0]);
    734 
    735         if (env->ExceptionCheck()) {
    736             return NULL;
    737         }
    738 
    739         jclass valueClazz;
    740         switch (type) {
    741             case TYPE_BYTE:
    742                 valueClazz = gMetadataOffsets.mByteArray;
    743                 break;
    744             case TYPE_INT32:
    745                 valueClazz = gMetadataOffsets.mInt32Array;
    746                 break;
    747             case TYPE_FLOAT:
    748                 valueClazz = gMetadataOffsets.mFloatArray;
    749                 break;
    750             case TYPE_INT64:
    751                 valueClazz = gMetadataOffsets.mInt64Array;
    752                 break;
    753             case TYPE_DOUBLE:
    754                 valueClazz = gMetadataOffsets.mDoubleArray;
    755                 break;
    756             case TYPE_RATIONAL:
    757                 valueClazz = gMetadataOffsets.mRationalArray;
    758                 break;
    759             default:
    760                 jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
    761                         "Invalid type %d given for key %s", type, &fullName[0]);
    762                 return NULL;
    763         }
    764 
    765         jobject key = env->NewObject(keyClazz, keyConstr, name, valueClazz);
    766         if (env->ExceptionCheck()) {
    767             return NULL;
    768         }
    769 
    770         env->CallBooleanMethod(arrayList, gMetadataOffsets.mArrayListAdd, key);
    771         if (env->ExceptionCheck()) {
    772             return NULL;
    773         }
    774 
    775         env->DeleteLocalRef(name);
    776         env->DeleteLocalRef(key);
    777     }
    778 
    779     return arrayList;
    780 }
    781 
    782 static jint CameraMetadata_getTagFromKey(JNIEnv *env, jobject thiz, jstring keyName) {
    783 
    784     ScopedUtfChars keyScoped(env, keyName);
    785     const char *key = keyScoped.c_str();
    786     if (key == NULL) {
    787         // exception thrown by ScopedUtfChars
    788         return 0;
    789     }
    790     size_t keyLength = strlen(key);
    791 
    792     ALOGV("%s (key = '%s')", __FUNCTION__, key);
    793 
    794     sp<VendorTagDescriptor> vTags = VendorTagDescriptor::getGlobalVendorTagDescriptor();
    795 
    796     SortedVector<String8> vendorSections;
    797     size_t vendorSectionCount = 0;
    798 
    799     if (vTags != NULL) {
    800         vendorSections = vTags->getAllSectionNames();
    801         vendorSectionCount = vendorSections.size();
    802     }
    803 
    804     // First, find the section by the longest string match
    805     const char *section = NULL;
    806     size_t sectionIndex = 0;
    807     size_t sectionLength = 0;
    808     size_t totalSectionCount = ANDROID_SECTION_COUNT + vendorSectionCount;
    809     for (size_t i = 0; i < totalSectionCount; ++i) {
    810 
    811         const char *str = (i < ANDROID_SECTION_COUNT) ? camera_metadata_section_names[i] :
    812                 vendorSections[i - ANDROID_SECTION_COUNT].string();
    813         if (kIsDebug) {
    814             ALOGV("%s: Trying to match against section '%s'", __FUNCTION__, str);
    815         }
    816         if (strstr(key, str) == key) { // key begins with the section name
    817             size_t strLength = strlen(str);
    818 
    819             if (kIsDebug) {
    820                 ALOGV("%s: Key begins with section name", __FUNCTION__);
    821             }
    822 
    823             // section name is the longest we've found so far
    824             if (section == NULL || sectionLength < strLength) {
    825                 section = str;
    826                 sectionIndex = i;
    827                 sectionLength = strLength;
    828 
    829                 if (kIsDebug) {
    830                     ALOGV("%s: Found new best section (%s)", __FUNCTION__, section);
    831                 }
    832             }
    833         }
    834     }
    835 
    836     // TODO: Make above get_camera_metadata_section_from_name ?
    837 
    838     if (section == NULL) {
    839         jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
    840                              "Could not find section name for key '%s')", key);
    841         return 0;
    842     } else {
    843         ALOGV("%s: Found matched section '%s' (%zu)",
    844               __FUNCTION__, section, sectionIndex);
    845     }
    846 
    847     // Get the tag name component of the key
    848     const char *keyTagName = key + sectionLength + 1; // x.y.z -> z
    849     if (sectionLength + 1 >= keyLength) {
    850         jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
    851                              "Key length too short for key '%s')", key);
    852         return 0;
    853     }
    854 
    855     // Match rest of name against the tag names in that section only
    856     uint32_t tag = 0;
    857     if (sectionIndex < ANDROID_SECTION_COUNT) {
    858         // Match built-in tags (typically android.*)
    859         uint32_t tagBegin, tagEnd; // [tagBegin, tagEnd)
    860         tagBegin = camera_metadata_section_bounds[sectionIndex][0];
    861         tagEnd = camera_metadata_section_bounds[sectionIndex][1];
    862 
    863         for (tag = tagBegin; tag < tagEnd; ++tag) {
    864             const char *tagName = get_camera_metadata_tag_name(tag);
    865 
    866             if (strcmp(keyTagName, tagName) == 0) {
    867                 ALOGV("%s: Found matched tag '%s' (%d)",
    868                       __FUNCTION__, tagName, tag);
    869                 break;
    870             }
    871         }
    872 
    873         if (tag == tagEnd) {
    874             jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
    875                                  "Could not find tag name for key '%s')", key);
    876             return 0;
    877         }
    878     } else if (vTags != NULL) {
    879         // Match vendor tags (typically com.*)
    880         const String8 sectionName(section);
    881         const String8 tagName(keyTagName);
    882 
    883         status_t res = OK;
    884         if ((res = vTags->lookupTag(tagName, sectionName, &tag)) != OK) {
    885             jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
    886                     "%s: No vendor tag matches key '%s'", __FUNCTION__, key);
    887             return 0;
    888         }
    889     }
    890 
    891     // TODO: Make above get_camera_metadata_tag_from_name ?
    892 
    893     return tag;
    894 }
    895 
    896 static jint CameraMetadata_getTypeFromTag(JNIEnv *env, jobject thiz, jint tag) {
    897     int tagType = get_camera_metadata_tag_type(tag);
    898     if (tagType == -1) {
    899         jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
    900                              "Tag (%d) did not have a type", tag);
    901         return -1;
    902     }
    903 
    904     return tagType;
    905 }
    906 
    907 static jint CameraMetadata_setupGlobalVendorTagDescriptor(JNIEnv *env, jobject thiz) {
    908     const String16 NAME("media.camera");
    909     sp<hardware::ICameraService> cameraService;
    910     status_t err = getService(NAME, /*out*/&cameraService);
    911 
    912     if (err != OK) {
    913         ALOGE("%s: Failed to get camera service, received error %s (%d)", __FUNCTION__,
    914                 strerror(-err), err);
    915         return hardware::ICameraService::ERROR_DISCONNECTED;
    916     }
    917 
    918     sp<VendorTagDescriptor> desc = new VendorTagDescriptor();
    919     binder::Status res = cameraService->getCameraVendorTagDescriptor(/*out*/desc.get());
    920 
    921     if (res.serviceSpecificErrorCode() == hardware::ICameraService::ERROR_DISCONNECTED) {
    922         // No camera module available, not an error on devices with no cameras
    923         VendorTagDescriptor::clearGlobalVendorTagDescriptor();
    924         return OK;
    925     } else if (!res.isOk()) {
    926         VendorTagDescriptor::clearGlobalVendorTagDescriptor();
    927         ALOGE("%s: Failed to setup vendor tag descriptors: %s",
    928                 __FUNCTION__, res.toString8().string());
    929         return res.serviceSpecificErrorCode();
    930     }
    931 
    932     err = VendorTagDescriptor::setAsGlobalVendorTagDescriptor(desc);
    933 
    934     if (err != OK) {
    935         return hardware::ICameraService::ERROR_INVALID_OPERATION;
    936     }
    937     return OK;
    938 }
    939 
    940 } // extern "C"
    941