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