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