OSDN Git Service

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