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