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