blob: 957f95cc266f474823e06c707a76ec549057ec0e [file] [log] [blame]
Igor Murashkin70725502013-06-25 20:27:06 +00001/*
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
Igor Murashkinb519cc52013-07-02 11:23:44 -070019// #define LOG_NNDEBUG 0
Igor Murashkin70725502013-06-25 20:27:06 +000020#define LOG_TAG "CameraMetadata-JNI"
21#include <utils/Log.h>
Ruben Brunk85c43882014-02-21 17:40:51 -080022#include <utils/RefBase.h>
23#include <string.h>
Igor Murashkin70725502013-06-25 20:27:06 +000024
25#include "jni.h"
26#include "JNIHelp.h"
27#include "android_os_Parcel.h"
28#include "android_runtime/AndroidRuntime.h"
29
Ruben Brunk85c43882014-02-21 17:40:51 -080030#include <binder/IServiceManager.h>
Igor Murashkin70725502013-06-25 20:27:06 +000031#include <camera/CameraMetadata.h>
Ruben Brunk85c43882014-02-21 17:40:51 -080032#include <camera/ICameraService.h>
33#include <camera/VendorTagDescriptor.h>
Igor Murashkinb519cc52013-07-02 11:23:44 -070034#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
Igor Murashkin70725502013-06-25 20:27:06 +000044
45// fully-qualified class name
Eino-Ville Talvala70c22072013-08-27 12:09:04 -070046#define CAMERA_METADATA_CLASS_NAME "android/hardware/camera2/impl/CameraMetadataNative"
Igor Murashkin70725502013-06-25 20:27:06 +000047
48using namespace android;
49
50struct fields_t {
51 jfieldID metadata_ptr;
52};
53
54static fields_t fields;
55
Igor Murashkinb519cc52013-07-02 11:23:44 -070056namespace {
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
Igor Murashkin70725502013-06-25 20:27:06 +0000115extern "C" {
116
117static void CameraMetadata_classInit(JNIEnv *env, jobject thiz);
Igor Murashkinb519cc52013-07-02 11:23:44 -0700118static jint CameraMetadata_getTagFromKey(JNIEnv *env, jobject thiz, jstring keyName);
119static jint CameraMetadata_getTypeFromTag(JNIEnv *env, jobject thiz, jint tag);
Ruben Brunk85c43882014-02-21 17:40:51 -0800120static jint CameraMetadata_setupGlobalVendorTagDescriptor(JNIEnv *env, jobject thiz);
Igor Murashkin70725502013-06-25 20:27:06 +0000121
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
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700161static 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
Igor Murashkin70725502013-06-25 20:27:06 +0000176static 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
Igor Murashkinb519cc52013-07-02 11:23:44 -0700236static 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
Igor Murashkin3710db82013-07-18 20:11:17 -0700291 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 }
Igor Murashkinb519cc52013-07-02 11:23:44 -0700298 } 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());
Igor Murashkin3710db82013-07-18 20:11:17 -0700305
306 ALOGV("%s: Update values (res = %d)", __FUNCTION__, res);
Igor Murashkinb519cc52013-07-02 11:23:44 -0700307 }
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
Igor Murashkin70725502013-06-25 20:27:06 +0000324static 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[] = {
Igor Murashkinb519cc52013-07-02 11:23:44 -0700371// static methods
Igor Murashkin70725502013-06-25 20:27:06 +0000372 { "nativeClassInit",
373 "()V",
374 (void *)CameraMetadata_classInit },
Igor Murashkinb519cc52013-07-02 11:23:44 -0700375 { "nativeGetTagFromKey",
376 "(Ljava/lang/String;)I",
377 (void *)CameraMetadata_getTagFromKey },
378 { "nativeGetTypeFromTag",
379 "(I)I",
380 (void *)CameraMetadata_getTypeFromTag },
Ruben Brunk85c43882014-02-21 17:40:51 -0800381 { "nativeSetupGlobalVendorTagDescriptor",
382 "()I",
383 (void*)CameraMetadata_setupGlobalVendorTagDescriptor },
Igor Murashkinb519cc52013-07-02 11:23:44 -0700384// instance methods
Igor Murashkin70725502013-06-25 20:27:06 +0000385 { "nativeAllocate",
386 "()J",
387 (void*)CameraMetadata_allocate },
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700388 { "nativeAllocateCopy",
389 "(L" CAMERA_METADATA_CLASS_NAME ";)J",
390 (void *)CameraMetadata_allocateCopy },
Igor Murashkin70725502013-06-25 20:27:06 +0000391 { "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 },
Igor Murashkinb519cc52013-07-02 11:23:44 -0700403 { "nativeReadValues",
404 "(I)[B",
405 (void *)CameraMetadata_readValues },
406 { "nativeWriteValues",
407 "(I[B)V",
408 (void *)CameraMetadata_writeValues },
409// Parcelable interface
Igor Murashkin70725502013-06-25 20:27:06 +0000410 { "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
Eino-Ville Talvala2f1a2e42013-07-25 17:12:05 -0700448int register_android_hardware_camera2_CameraMetadata(JNIEnv *env)
Igor Murashkin70725502013-06-25 20:27:06 +0000449{
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}
Igor Murashkinb519cc52013-07-02 11:23:44 -0700473
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
Ruben Brunk85c43882014-02-21 17:40:51 -0800568static 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
Igor Murashkin5614cbe2014-03-17 14:00:55 -0700582 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);
Ruben Brunk85c43882014-02-21 17:40:51 -0800590 return err;
591 }
592
593 err = VendorTagDescriptor::setAsGlobalVendorTagDescriptor(desc);
594
595 return err;
596}
597
Igor Murashkin70725502013-06-25 20:27:06 +0000598} // extern "C"