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