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
46static 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
54using namespace android;
55
56static 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
74struct fields_t {
75    jfieldID    metadata_ptr;
76};
77
78static fields_t fields;
79
80namespace android {
81
82status_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
105namespace {
106struct 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
164extern "C" {
165
166static void CameraMetadata_classInit(JNIEnv *env, jobject thiz);
167static jobject CameraMetadata_getAllVendorKeys(JNIEnv* env, jobject thiz, jclass keyType);
168static jint CameraMetadata_getTagFromKey(JNIEnv *env, jobject thiz, jstring keyName);
169static jint CameraMetadata_getTypeFromTag(JNIEnv *env, jobject thiz, jint tag);
170static jint CameraMetadata_setupGlobalVendorTagDescriptor(JNIEnv *env, jobject thiz);
171
172// Less safe access to native pointer. Does NOT throw any Java exceptions if NULL.
173static 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.
183static 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
205static jlong CameraMetadata_allocate(JNIEnv *env, jobject thiz) {
206    ALOGV("%s", __FUNCTION__);
207
208    return reinterpret_cast<jlong>(new CameraMetadata());
209}
210
211static 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
226static 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
245static 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.
256static 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
270static 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
286static 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
323static 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
373struct DumpMetadataParams {
374    int writeFd;
375    const CameraMetadata* metadata;
376};
377
378static 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
394static 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
486static 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
507static 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
532static 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
586struct field {
587    const char *class_name;
588    const char *field_name;
589    const char *field_type;
590    jfieldID   *jfield;
591};
592
593static 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
616int 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
663extern "C" {
664
665static 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
681static 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
782static 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
896static 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
907static 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