OSDN Git Service

Don't crash when primary volume is null in AppCollector.
[android-x86/frameworks-base.git] / core / jni / android_hardware_camera2_CameraMetadata.cpp
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     ALOGV("%s (key = '%s')", __FUNCTION__, key);
791
792     uint32_t tag = 0;
793     sp<VendorTagDescriptor> vTags =
794             VendorTagDescriptor::getGlobalVendorTagDescriptor();
795     status_t res = CameraMetadata::getTagFromName(key, vTags.get(), &tag);
796     if (res != OK) {
797         jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
798                              "Could not find tag for key '%s')", key);
799     }
800     return tag;
801 }
802
803 static jint CameraMetadata_getTypeFromTag(JNIEnv *env, jobject thiz, jint tag) {
804     int tagType = get_camera_metadata_tag_type(tag);
805     if (tagType == -1) {
806         jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
807                              "Tag (%d) did not have a type", tag);
808         return -1;
809     }
810
811     return tagType;
812 }
813
814 static jint CameraMetadata_setupGlobalVendorTagDescriptor(JNIEnv *env, jobject thiz) {
815     const String16 NAME("media.camera");
816     sp<hardware::ICameraService> cameraService;
817     status_t err = getService(NAME, /*out*/&cameraService);
818
819     if (err != OK) {
820         ALOGE("%s: Failed to get camera service, received error %s (%d)", __FUNCTION__,
821                 strerror(-err), err);
822         return hardware::ICameraService::ERROR_DISCONNECTED;
823     }
824
825     sp<VendorTagDescriptor> desc = new VendorTagDescriptor();
826     binder::Status res = cameraService->getCameraVendorTagDescriptor(/*out*/desc.get());
827
828     if (res.serviceSpecificErrorCode() == hardware::ICameraService::ERROR_DISCONNECTED) {
829         // No camera module available, not an error on devices with no cameras
830         VendorTagDescriptor::clearGlobalVendorTagDescriptor();
831         return OK;
832     } else if (!res.isOk()) {
833         VendorTagDescriptor::clearGlobalVendorTagDescriptor();
834         ALOGE("%s: Failed to setup vendor tag descriptors: %s",
835                 __FUNCTION__, res.toString8().string());
836         return res.serviceSpecificErrorCode();
837     }
838
839     err = VendorTagDescriptor::setAsGlobalVendorTagDescriptor(desc);
840
841     if (err != OK) {
842         return hardware::ICameraService::ERROR_INVALID_OPERATION;
843     }
844     return OK;
845 }
846
847 } // extern "C"