• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
CameraMetadata_getNativeMetadata(JNIEnv * env,jobject thiz,CameraMetadata * metadata)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 {
getTypeSize__anon8c05f49a0111::Helpers91     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 
updateAny__anon8c05f49a0111::Helpers100     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.
CameraMetadata_getPointerNoThrow(JNIEnv * env,jobject thiz)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.
CameraMetadata_getPointerThrow(JNIEnv * env,jobject thiz,const char * argName="this")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 
CameraMetadata_allocate(JNIEnv * env,jobject thiz)188 static jlong CameraMetadata_allocate(JNIEnv *env, jobject thiz) {
189     ALOGV("%s", __FUNCTION__);
190 
191     return reinterpret_cast<jlong>(new CameraMetadata());
192 }
193 
CameraMetadata_allocateCopy(JNIEnv * env,jobject thiz,jobject other)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 
CameraMetadata_isEmpty(JNIEnv * env,jobject thiz)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 
CameraMetadata_getEntryCount(JNIEnv * env,jobject thiz)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.
CameraMetadata_close(JNIEnv * env,jobject thiz)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 
CameraMetadata_swap(JNIEnv * env,jobject thiz,jobject other)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 
CameraMetadata_readValues(JNIEnv * env,jobject thiz,jint tag)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 
CameraMetadata_writeValues(JNIEnv * env,jobject thiz,jint tag,jbyteArray src)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 
CameraMetadata_writeMetadataThread(void * arg)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 
CameraMetadata_dump(JNIEnv * env,jobject thiz)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 
CameraMetadata_readFromParcel(JNIEnv * env,jobject thiz,jobject parcel)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 
CameraMetadata_writeToParcel(JNIEnv * env,jobject thiz,jobject parcel)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 
find_fields(JNIEnv * env,field * fields,int count)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
register_android_hardware_camera2_CameraMetadata(JNIEnv * env)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" {
CameraMetadata_classInit(JNIEnv * env,jobject thiz)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 
CameraMetadata_getTagFromKey(JNIEnv * env,jobject thiz,jstring keyName)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 
CameraMetadata_getTypeFromTag(JNIEnv * env,jobject thiz,jint tag)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 
CameraMetadata_setupGlobalVendorTagDescriptor(JNIEnv * env,jobject thiz)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