blob: 9132690d7168866fe7236af027b05b92f6e65560 [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"
Ruben Brunk32ef3ae2014-02-21 17:40:51 -080021#include <utils/Errors.h>
Igor Murashkin70725502013-06-25 20:27:06 +000022#include <utils/Log.h>
Ruben Brunk85c43882014-02-21 17:40:51 -080023#include <utils/RefBase.h>
Ruben Brunk32ef3ae2014-02-21 17:40:51 -080024#include <utils/Vector.h>
25#include <utils/SortedVector.h>
26#include <utils/KeyedVector.h>
Ruben Brunk85c43882014-02-21 17:40:51 -080027#include <string.h>
Igor Murashkin70725502013-06-25 20:27:06 +000028
29#include "jni.h"
30#include "JNIHelp.h"
31#include "android_os_Parcel.h"
32#include "android_runtime/AndroidRuntime.h"
Ruben Brunkf967a542014-04-28 16:31:11 -070033#include "android_runtime/android_hardware_camera2_CameraMetadata.h"
Igor Murashkin70725502013-06-25 20:27:06 +000034
Ruben Brunk85c43882014-02-21 17:40:51 -080035#include <binder/IServiceManager.h>
Igor Murashkin70725502013-06-25 20:27:06 +000036#include <camera/CameraMetadata.h>
Ruben Brunk85c43882014-02-21 17:40:51 -080037#include <camera/ICameraService.h>
38#include <camera/VendorTagDescriptor.h>
Igor Murashkinb519cc52013-07-02 11:23:44 -070039#include <nativehelper/ScopedUtfChars.h>
40#include <nativehelper/ScopedPrimitiveArray.h>
41
Igor Murashkind6d65152014-05-19 16:31:02 -070042#include <sys/types.h> // for socketpair
43#include <sys/socket.h> // for socketpair
44
Igor Murashkinb519cc52013-07-02 11:23:44 -070045#if defined(LOG_NNDEBUG)
46#if !LOG_NNDEBUG
47#define ALOGVV ALOGV
48#endif
49#else
50#define ALOGVV(...)
51#endif
Igor Murashkin70725502013-06-25 20:27:06 +000052
53// fully-qualified class name
Eino-Ville Talvala70c22072013-08-27 12:09:04 -070054#define CAMERA_METADATA_CLASS_NAME "android/hardware/camera2/impl/CameraMetadataNative"
Igor Murashkin70725502013-06-25 20:27:06 +000055
56using namespace android;
57
58struct fields_t {
59 jfieldID metadata_ptr;
60};
61
62static fields_t fields;
63
Ruben Brunkf967a542014-04-28 16:31:11 -070064namespace android {
65
66status_t CameraMetadata_getNativeMetadata(JNIEnv* env, jobject thiz,
67 /*out*/CameraMetadata* metadata) {
68 if (!thiz) {
69 ALOGE("%s: Invalid java metadata object.", __FUNCTION__);
70 return BAD_VALUE;
71 }
72
73 if (!metadata) {
74 ALOGE("%s: Invalid output metadata object.", __FUNCTION__);
75 return BAD_VALUE;
76 }
77 CameraMetadata* nativePtr = reinterpret_cast<CameraMetadata*>(env->GetLongField(thiz,
78 fields.metadata_ptr));
79 if (nativePtr == NULL) {
80 ALOGE("%s: Invalid native pointer in java metadata object.", __FUNCTION__);
81 return BAD_VALUE;
82 }
83 *metadata = *nativePtr;
84 return OK;
85}
86
87} /*namespace android*/
88
Igor Murashkinb519cc52013-07-02 11:23:44 -070089namespace {
90struct Helpers {
91 static size_t getTypeSize(uint8_t type) {
92 if (type >= NUM_TYPES) {
93 ALOGE("%s: Invalid type specified (%ud)", __FUNCTION__, type);
94 return static_cast<size_t>(-1);
95 }
96
97 return camera_metadata_type_size[type];
98 }
99
100 static status_t updateAny(CameraMetadata *metadata,
101 uint32_t tag,
102 uint32_t type,
103 const void *data,
104 size_t dataBytes) {
105
106 if (type >= NUM_TYPES) {
107 ALOGE("%s: Invalid type specified (%ud)", __FUNCTION__, type);
108 return INVALID_OPERATION;
109 }
110
111 size_t typeSize = getTypeSize(type);
112
113 if (dataBytes % typeSize != 0) {
Dan Albert46d84442014-11-18 16:07:51 -0800114 ALOGE("%s: Expected dataBytes (%zu) to be divisible by typeSize "
115 "(%zu)", __FUNCTION__, dataBytes, typeSize);
Igor Murashkinb519cc52013-07-02 11:23:44 -0700116 return BAD_VALUE;
117 }
118
119 size_t dataCount = dataBytes / typeSize;
120
121 switch(type) {
122#define METADATA_UPDATE(runtime_type, compile_type) \
123 case runtime_type: { \
124 const compile_type *dataPtr = \
125 static_cast<const compile_type*>(data); \
126 return metadata->update(tag, dataPtr, dataCount); \
127 } \
128
129 METADATA_UPDATE(TYPE_BYTE, uint8_t);
130 METADATA_UPDATE(TYPE_INT32, int32_t);
131 METADATA_UPDATE(TYPE_FLOAT, float);
132 METADATA_UPDATE(TYPE_INT64, int64_t);
133 METADATA_UPDATE(TYPE_DOUBLE, double);
134 METADATA_UPDATE(TYPE_RATIONAL, camera_metadata_rational_t);
135
136 default: {
137 // unreachable
138 ALOGE("%s: Unreachable", __FUNCTION__);
139 return INVALID_OPERATION;
140 }
141 }
142
143#undef METADATA_UPDATE
144 }
145};
146} // namespace {}
147
Igor Murashkin70725502013-06-25 20:27:06 +0000148extern "C" {
149
150static void CameraMetadata_classInit(JNIEnv *env, jobject thiz);
Igor Murashkinb519cc52013-07-02 11:23:44 -0700151static jint CameraMetadata_getTagFromKey(JNIEnv *env, jobject thiz, jstring keyName);
152static jint CameraMetadata_getTypeFromTag(JNIEnv *env, jobject thiz, jint tag);
Ruben Brunk85c43882014-02-21 17:40:51 -0800153static jint CameraMetadata_setupGlobalVendorTagDescriptor(JNIEnv *env, jobject thiz);
Igor Murashkin70725502013-06-25 20:27:06 +0000154
155// Less safe access to native pointer. Does NOT throw any Java exceptions if NULL.
156static CameraMetadata* CameraMetadata_getPointerNoThrow(JNIEnv *env, jobject thiz) {
157
158 if (thiz == NULL) {
159 return NULL;
160 }
161
162 return reinterpret_cast<CameraMetadata*>(env->GetLongField(thiz, fields.metadata_ptr));
163}
164
165// Safe access to native pointer from object. Throws if not possible to access.
166static CameraMetadata* CameraMetadata_getPointerThrow(JNIEnv *env, jobject thiz,
167 const char* argName = "this") {
168
169 if (thiz == NULL) {
170 ALOGV("%s: Throwing java.lang.NullPointerException for null reference",
171 __FUNCTION__);
172 jniThrowNullPointerException(env, argName);
173 return NULL;
174 }
175
176 CameraMetadata* metadata = CameraMetadata_getPointerNoThrow(env, thiz);
177 if (metadata == NULL) {
178 ALOGV("%s: Throwing java.lang.IllegalStateException for closed object",
179 __FUNCTION__);
180 jniThrowException(env, "java/lang/IllegalStateException",
181 "Metadata object was already closed");
182 return NULL;
183 }
184
185 return metadata;
186}
187
188static jlong CameraMetadata_allocate(JNIEnv *env, jobject thiz) {
189 ALOGV("%s", __FUNCTION__);
190
191 return reinterpret_cast<jlong>(new CameraMetadata());
192}
193
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700194static jlong CameraMetadata_allocateCopy(JNIEnv *env, jobject thiz,
195 jobject other) {
196 ALOGV("%s", __FUNCTION__);
197
198 CameraMetadata* otherMetadata =
199 CameraMetadata_getPointerThrow(env, other, "other");
200
201 // In case of exception, return
202 if (otherMetadata == NULL) return NULL;
203
204 // Clone native metadata and return new pointer
205 return reinterpret_cast<jlong>(new CameraMetadata(*otherMetadata));
206}
207
208
Igor Murashkin70725502013-06-25 20:27:06 +0000209static jboolean CameraMetadata_isEmpty(JNIEnv *env, jobject thiz) {
210 ALOGV("%s", __FUNCTION__);
211
212 CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
213
214 if (metadata == NULL) {
215 ALOGW("%s: Returning early due to exception being thrown",
216 __FUNCTION__);
217 return JNI_TRUE; // actually throws java exc.
218 }
219
220 jboolean empty = metadata->isEmpty();
221
Dan Albert46d84442014-11-18 16:07:51 -0800222 ALOGV("%s: Empty returned %d, entry count was %zu",
Igor Murashkin70725502013-06-25 20:27:06 +0000223 __FUNCTION__, empty, metadata->entryCount());
224
225 return empty;
226}
227
228static jint CameraMetadata_getEntryCount(JNIEnv *env, jobject thiz) {
229 ALOGV("%s", __FUNCTION__);
230
231 CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
232
233 if (metadata == NULL) return 0; // actually throws java exc.
234
235 return metadata->entryCount();
236}
237
238// idempotent. calling more than once has no effect.
239static void CameraMetadata_close(JNIEnv *env, jobject thiz) {
240 ALOGV("%s", __FUNCTION__);
241
242 CameraMetadata* metadata = CameraMetadata_getPointerNoThrow(env, thiz);
243
244 if (metadata != NULL) {
245 delete metadata;
246 env->SetLongField(thiz, fields.metadata_ptr, 0);
247 }
248
249 LOG_ALWAYS_FATAL_IF(CameraMetadata_getPointerNoThrow(env, thiz) != NULL,
250 "Expected the native ptr to be 0 after #close");
251}
252
253static void CameraMetadata_swap(JNIEnv *env, jobject thiz, jobject other) {
254 ALOGV("%s", __FUNCTION__);
255
256 CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
257
258 // order is important: we can't call another JNI method
259 // if there is an exception pending
260 if (metadata == NULL) return;
261
262 CameraMetadata* otherMetadata = CameraMetadata_getPointerThrow(env, other, "other");
263
264 if (otherMetadata == NULL) return;
265
266 metadata->swap(*otherMetadata);
267}
268
Igor Murashkinb519cc52013-07-02 11:23:44 -0700269static jbyteArray CameraMetadata_readValues(JNIEnv *env, jobject thiz, jint tag) {
270 ALOGV("%s (tag = %d)", __FUNCTION__, tag);
271
272 CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
273 if (metadata == NULL) return NULL;
274
275 int tagType = get_camera_metadata_tag_type(tag);
276 if (tagType == -1) {
277 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
278 "Tag (%d) did not have a type", tag);
279 return NULL;
280 }
281 size_t tagSize = Helpers::getTypeSize(tagType);
282
283 camera_metadata_entry entry = metadata->find(tag);
284 if (entry.count == 0) {
285 if (!metadata->exists(tag)) {
286 ALOGV("%s: Tag %d does not have any entries", __FUNCTION__, tag);
287 return NULL;
288 } else {
289 // OK: we will return a 0-sized array.
290 ALOGV("%s: Tag %d had an entry, but it had 0 data", __FUNCTION__,
291 tag);
292 }
293 }
294
295 jsize byteCount = entry.count * tagSize;
296 jbyteArray byteArray = env->NewByteArray(byteCount);
297 if (env->ExceptionCheck()) return NULL;
298
299 // Copy into java array from native array
300 ScopedByteArrayRW arrayWriter(env, byteArray);
301 memcpy(arrayWriter.get(), entry.data.u8, byteCount);
302
303 return byteArray;
304}
305
306static void CameraMetadata_writeValues(JNIEnv *env, jobject thiz, jint tag, jbyteArray src) {
307 ALOGV("%s (tag = %d)", __FUNCTION__, tag);
308
309 CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
310 if (metadata == NULL) return;
311
312 int tagType = get_camera_metadata_tag_type(tag);
313 if (tagType == -1) {
314 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
315 "Tag (%d) did not have a type", tag);
316 return;
317 }
Igor Murashkinb519cc52013-07-02 11:23:44 -0700318
319 status_t res;
320
321 if (src == NULL) {
322 // If array is NULL, delete the entry
Igor Murashkin3710db82013-07-18 20:11:17 -0700323 if (metadata->exists(tag)) {
324 res = metadata->erase(tag);
325 ALOGV("%s: Erase values (res = %d)", __FUNCTION__, res);
326 } else {
327 res = OK;
328 ALOGV("%s: Don't need to erase", __FUNCTION__);
329 }
Igor Murashkinb519cc52013-07-02 11:23:44 -0700330 } else {
331 // Copy from java array into native array
332 ScopedByteArrayRO arrayReader(env, src);
333 if (arrayReader.get() == NULL) return;
334
335 res = Helpers::updateAny(metadata, static_cast<uint32_t>(tag),
336 tagType, arrayReader.get(), arrayReader.size());
Igor Murashkin3710db82013-07-18 20:11:17 -0700337
338 ALOGV("%s: Update values (res = %d)", __FUNCTION__, res);
Igor Murashkinb519cc52013-07-02 11:23:44 -0700339 }
340
341 if (res == OK) {
342 return;
343 } else if (res == BAD_VALUE) {
344 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
345 "Src byte array was poorly formed");
346 } else if (res == INVALID_OPERATION) {
347 jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
348 "Internal error while trying to update metadata");
349 } else {
350 jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
351 "Unknown error (%d) while trying to update "
352 "metadata", res);
353 }
354}
355
Igor Murashkind6d65152014-05-19 16:31:02 -0700356struct DumpMetadataParams {
357 int writeFd;
358 const CameraMetadata* metadata;
359};
360
361static void* CameraMetadata_writeMetadataThread(void* arg) {
362 DumpMetadataParams* p = static_cast<DumpMetadataParams*>(arg);
363
364 /*
365 * Write the dumped data, and close the writing side FD.
366 */
367 p->metadata->dump(p->writeFd, /*verbosity*/2);
368
369 if (close(p->writeFd) < 0) {
370 ALOGE("%s: Failed to close writeFd (errno = %#x, message = '%s')",
371 __FUNCTION__, errno, strerror(errno));
372 }
373
374 return NULL;
375}
376
377static void CameraMetadata_dump(JNIEnv *env, jobject thiz) {
378 ALOGV("%s", __FUNCTION__);
379 CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
380 if (metadata == NULL) {
381 return;
382 }
383
384 /*
385 * Create a socket pair for local streaming read/writes.
386 *
387 * The metadata will be dumped into the write side,
388 * and then read back out (and logged) via the read side.
389 */
390
391 int writeFd, readFd;
392 {
393
394 int sv[2];
395 if (socketpair(AF_LOCAL, SOCK_STREAM, /*protocol*/0, &sv[0]) < 0) {
396 jniThrowExceptionFmt(env, "java/io/IOException",
397 "Failed to create socketpair (errno = %#x, message = '%s')",
398 errno, strerror(errno));
399 return;
400 }
401 writeFd = sv[0];
402 readFd = sv[1];
403 }
404
405 /*
406 * Create a thread for doing the writing.
407 *
408 * The reading and writing must be concurrent, otherwise
409 * the write will block forever once it exhausts the capped
410 * buffer size (from getsockopt).
411 */
412 pthread_t writeThread;
413 DumpMetadataParams params = {
414 writeFd,
415 metadata
416 };
417
418 {
419 int threadRet = pthread_create(&writeThread, /*attr*/NULL,
420 CameraMetadata_writeMetadataThread, (void*)&params);
421
422 if (threadRet != 0) {
423 close(writeFd);
424
425 jniThrowExceptionFmt(env, "java/io/IOException",
426 "Failed to create thread for writing (errno = %#x, message = '%s')",
427 threadRet, strerror(threadRet));
428 }
429 }
430
431 /*
432 * Read out a byte until stream is complete. Write completed lines
433 * to ALOG.
434 */
435 {
436 char out[] = {'\0', '\0'}; // large enough to append as a string
437 String8 logLine;
438
439 // Read one byte at a time! Very slow but avoids complicated \n scanning.
440 ssize_t res;
441 while ((res = TEMP_FAILURE_RETRY(read(readFd, &out[0], /*count*/1))) > 0) {
442 if (out[0] == '\n') {
443 ALOGD("%s", logLine.string());
444 logLine.clear();
445 } else {
446 logLine.append(out);
447 }
448 }
449
450 if (res < 0) {
451 jniThrowExceptionFmt(env, "java/io/IOException",
452 "Failed to read from fd (errno = %#x, message = '%s')",
453 errno, strerror(errno));
454 //return;
455 } else if (!logLine.isEmpty()) {
456 ALOGD("%s", logLine.string());
457 }
458 }
459
460 int res;
461
462 // Join until thread finishes. Ensures params/metadata is valid until then.
463 if ((res = pthread_join(writeThread, /*retval*/NULL)) != 0) {
464 ALOGE("%s: Failed to join thread (errno = %#x, message = '%s')",
465 __FUNCTION__, res, strerror(res));
466 }
467}
468
Igor Murashkin70725502013-06-25 20:27:06 +0000469static void CameraMetadata_readFromParcel(JNIEnv *env, jobject thiz, jobject parcel) {
470 ALOGV("%s", __FUNCTION__);
471 CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
472 if (metadata == NULL) {
473 return;
474 }
475
476 Parcel* parcelNative = parcelForJavaObject(env, parcel);
477 if (parcelNative == NULL) {
478 jniThrowNullPointerException(env, "parcel");
479 return;
480 }
481
482 status_t err;
483 if ((err = metadata->readFromParcel(parcelNative)) != OK) {
484 jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
485 "Failed to read from parcel (error code %d)", err);
486 return;
487 }
488}
489
490static void CameraMetadata_writeToParcel(JNIEnv *env, jobject thiz, jobject parcel) {
491 ALOGV("%s", __FUNCTION__);
492 CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
493 if (metadata == NULL) {
494 return;
495 }
496
497 Parcel* parcelNative = parcelForJavaObject(env, parcel);
498 if (parcelNative == NULL) {
499 jniThrowNullPointerException(env, "parcel");
500 return;
501 }
502
503 status_t err;
504 if ((err = metadata->writeToParcel(parcelNative)) != OK) {
505 jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
506 "Failed to write to parcel (error code %d)", err);
507 return;
508 }
509}
510
511} // extern "C"
512
513//-------------------------------------------------
514
515static JNINativeMethod gCameraMetadataMethods[] = {
Igor Murashkinb519cc52013-07-02 11:23:44 -0700516// static methods
Igor Murashkin70725502013-06-25 20:27:06 +0000517 { "nativeClassInit",
518 "()V",
519 (void *)CameraMetadata_classInit },
Igor Murashkinb519cc52013-07-02 11:23:44 -0700520 { "nativeGetTagFromKey",
521 "(Ljava/lang/String;)I",
522 (void *)CameraMetadata_getTagFromKey },
523 { "nativeGetTypeFromTag",
524 "(I)I",
525 (void *)CameraMetadata_getTypeFromTag },
Ruben Brunk85c43882014-02-21 17:40:51 -0800526 { "nativeSetupGlobalVendorTagDescriptor",
527 "()I",
528 (void*)CameraMetadata_setupGlobalVendorTagDescriptor },
Igor Murashkinb519cc52013-07-02 11:23:44 -0700529// instance methods
Igor Murashkin70725502013-06-25 20:27:06 +0000530 { "nativeAllocate",
531 "()J",
532 (void*)CameraMetadata_allocate },
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700533 { "nativeAllocateCopy",
534 "(L" CAMERA_METADATA_CLASS_NAME ";)J",
535 (void *)CameraMetadata_allocateCopy },
Igor Murashkin70725502013-06-25 20:27:06 +0000536 { "nativeIsEmpty",
537 "()Z",
538 (void*)CameraMetadata_isEmpty },
539 { "nativeGetEntryCount",
540 "()I",
541 (void*)CameraMetadata_getEntryCount },
542 { "nativeClose",
543 "()V",
544 (void*)CameraMetadata_close },
545 { "nativeSwap",
546 "(L" CAMERA_METADATA_CLASS_NAME ";)V",
547 (void *)CameraMetadata_swap },
Igor Murashkinb519cc52013-07-02 11:23:44 -0700548 { "nativeReadValues",
549 "(I)[B",
550 (void *)CameraMetadata_readValues },
551 { "nativeWriteValues",
552 "(I[B)V",
553 (void *)CameraMetadata_writeValues },
Igor Murashkind6d65152014-05-19 16:31:02 -0700554 { "nativeDump",
555 "()V",
556 (void *)CameraMetadata_dump },
Igor Murashkinb519cc52013-07-02 11:23:44 -0700557// Parcelable interface
Igor Murashkin70725502013-06-25 20:27:06 +0000558 { "nativeReadFromParcel",
559 "(Landroid/os/Parcel;)V",
560 (void *)CameraMetadata_readFromParcel },
561 { "nativeWriteToParcel",
562 "(Landroid/os/Parcel;)V",
563 (void *)CameraMetadata_writeToParcel },
564};
565
566struct field {
567 const char *class_name;
568 const char *field_name;
569 const char *field_type;
570 jfieldID *jfield;
571};
572
573static int find_fields(JNIEnv *env, field *fields, int count)
574{
575 for (int i = 0; i < count; i++) {
576 field *f = &fields[i];
577 jclass clazz = env->FindClass(f->class_name);
578 if (clazz == NULL) {
579 ALOGE("Can't find %s", f->class_name);
580 return -1;
581 }
582
583 jfieldID field = env->GetFieldID(clazz, f->field_name, f->field_type);
584 if (field == NULL) {
585 ALOGE("Can't find %s.%s", f->class_name, f->field_name);
586 return -1;
587 }
588
589 *(f->jfield) = field;
590 }
591
592 return 0;
593}
594
595// Get all the required offsets in java class and register native functions
Eino-Ville Talvala2f1a2e42013-07-25 17:12:05 -0700596int register_android_hardware_camera2_CameraMetadata(JNIEnv *env)
Igor Murashkin70725502013-06-25 20:27:06 +0000597{
598 // Register native functions
599 return AndroidRuntime::registerNativeMethods(env,
600 CAMERA_METADATA_CLASS_NAME,
601 gCameraMetadataMethods,
602 NELEM(gCameraMetadataMethods));
603}
604
605extern "C" {
606static void CameraMetadata_classInit(JNIEnv *env, jobject thiz) {
607 // XX: Why do this separately instead of doing it in the register function?
608 ALOGV("%s", __FUNCTION__);
609
610 field fields_to_find[] = {
611 { CAMERA_METADATA_CLASS_NAME, "mMetadataPtr", "J", &fields.metadata_ptr },
612 };
613
614 // Do this here instead of in register_native_methods,
615 // since otherwise it will fail to find the fields.
616 if (find_fields(env, fields_to_find, NELEM(fields_to_find)) < 0)
617 return;
618
Andreas Gampe0f0b4912014-11-12 08:03:48 -0800619 env->FindClass(CAMERA_METADATA_CLASS_NAME);
Igor Murashkin70725502013-06-25 20:27:06 +0000620}
Igor Murashkinb519cc52013-07-02 11:23:44 -0700621
622static jint CameraMetadata_getTagFromKey(JNIEnv *env, jobject thiz, jstring keyName) {
623
624 ScopedUtfChars keyScoped(env, keyName);
625 const char *key = keyScoped.c_str();
626 if (key == NULL) {
627 // exception thrown by ScopedUtfChars
628 return 0;
629 }
630 size_t keyLength = strlen(key);
631
632 ALOGV("%s (key = '%s')", __FUNCTION__, key);
633
Ruben Brunk32ef3ae2014-02-21 17:40:51 -0800634 sp<VendorTagDescriptor> vTags = VendorTagDescriptor::getGlobalVendorTagDescriptor();
635
Igor Murashkin3c40a042014-04-22 15:05:50 -0700636 SortedVector<String8> vendorSections;
637 size_t vendorSectionCount = 0;
638
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700639 if (vTags != NULL) {
Igor Murashkin3c40a042014-04-22 15:05:50 -0700640 vendorSections = vTags->getAllSectionNames();
641 vendorSectionCount = vendorSections.size();
642 }
Ruben Brunk32ef3ae2014-02-21 17:40:51 -0800643
Igor Murashkinb519cc52013-07-02 11:23:44 -0700644 // First, find the section by the longest string match
645 const char *section = NULL;
646 size_t sectionIndex = 0;
647 size_t sectionLength = 0;
Ruben Brunk32ef3ae2014-02-21 17:40:51 -0800648 size_t totalSectionCount = ANDROID_SECTION_COUNT + vendorSectionCount;
649 for (size_t i = 0; i < totalSectionCount; ++i) {
650
651 const char *str = (i < ANDROID_SECTION_COUNT) ? camera_metadata_section_names[i] :
652 vendorSections[i - ANDROID_SECTION_COUNT].string();
Igor Murashkinb519cc52013-07-02 11:23:44 -0700653 ALOGVV("%s: Trying to match against section '%s'",
654 __FUNCTION__, str);
655 if (strstr(key, str) == key) { // key begins with the section name
656 size_t strLength = strlen(str);
657
658 ALOGVV("%s: Key begins with section name", __FUNCTION__);
659
660 // section name is the longest we've found so far
661 if (section == NULL || sectionLength < strLength) {
662 section = str;
663 sectionIndex = i;
664 sectionLength = strLength;
665
Ruben Brunk32ef3ae2014-02-21 17:40:51 -0800666 ALOGVV("%s: Found new best section (%s)", __FUNCTION__, section);
Igor Murashkinb519cc52013-07-02 11:23:44 -0700667 }
668 }
669 }
670
Igor Murashkinb519cc52013-07-02 11:23:44 -0700671 // TODO: Make above get_camera_metadata_section_from_name ?
672
673 if (section == NULL) {
674 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
675 "Could not find section name for key '%s')", key);
676 return 0;
677 } else {
Dan Albert46d84442014-11-18 16:07:51 -0800678 ALOGV("%s: Found matched section '%s' (%zu)",
Igor Murashkinb519cc52013-07-02 11:23:44 -0700679 __FUNCTION__, section, sectionIndex);
680 }
681
682 // Get the tag name component of the key
683 const char *keyTagName = key + sectionLength + 1; // x.y.z -> z
684 if (sectionLength + 1 >= keyLength) {
685 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
686 "Key length too short for key '%s')", key);
Ruben Brunk32ef3ae2014-02-21 17:40:51 -0800687 return 0;
Igor Murashkinb519cc52013-07-02 11:23:44 -0700688 }
689
690 // Match rest of name against the tag names in that section only
Ruben Brunk32ef3ae2014-02-21 17:40:51 -0800691 uint32_t tag = 0;
692 if (sectionIndex < ANDROID_SECTION_COUNT) {
693 // Match built-in tags (typically android.*)
694 uint32_t tagBegin, tagEnd; // [tagBegin, tagEnd)
695 tagBegin = camera_metadata_section_bounds[sectionIndex][0];
696 tagEnd = camera_metadata_section_bounds[sectionIndex][1];
Igor Murashkinb519cc52013-07-02 11:23:44 -0700697
Ruben Brunk32ef3ae2014-02-21 17:40:51 -0800698 for (tag = tagBegin; tag < tagEnd; ++tag) {
699 const char *tagName = get_camera_metadata_tag_name(tag);
Igor Murashkinb519cc52013-07-02 11:23:44 -0700700
Ruben Brunk32ef3ae2014-02-21 17:40:51 -0800701 if (strcmp(keyTagName, tagName) == 0) {
702 ALOGV("%s: Found matched tag '%s' (%d)",
703 __FUNCTION__, tagName, tag);
704 break;
705 }
706 }
707
708 if (tag == tagEnd) {
709 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
710 "Could not find tag name for key '%s')", key);
711 return 0;
712 }
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700713 } else if (vTags != NULL) {
Ruben Brunk32ef3ae2014-02-21 17:40:51 -0800714 // Match vendor tags (typically com.*)
715 const String8 sectionName(section);
716 const String8 tagName(keyTagName);
717
718 status_t res = OK;
719 if ((res = vTags->lookupTag(tagName, sectionName, &tag)) != OK) {
720 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
721 "%s: No vendor tag matches key '%s'", __FUNCTION__, key);
722 return 0;
Igor Murashkinb519cc52013-07-02 11:23:44 -0700723 }
724 }
725
Igor Murashkinb519cc52013-07-02 11:23:44 -0700726 // TODO: Make above get_camera_metadata_tag_from_name ?
727
Igor Murashkinb519cc52013-07-02 11:23:44 -0700728 return tag;
729}
730
731static jint CameraMetadata_getTypeFromTag(JNIEnv *env, jobject thiz, jint tag) {
732 int tagType = get_camera_metadata_tag_type(tag);
733 if (tagType == -1) {
734 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
735 "Tag (%d) did not have a type", tag);
736 return -1;
737 }
738
739 return tagType;
740}
741
Ruben Brunk85c43882014-02-21 17:40:51 -0800742static jint CameraMetadata_setupGlobalVendorTagDescriptor(JNIEnv *env, jobject thiz) {
743 const String16 NAME("media.camera");
744 sp<ICameraService> cameraService;
745 status_t err = getService(NAME, /*out*/&cameraService);
746
747 if (err != OK) {
748 ALOGE("%s: Failed to get camera service, received error %s (%d)", __FUNCTION__,
749 strerror(-err), err);
750 return err;
751 }
752
753 sp<VendorTagDescriptor> desc;
754 err = cameraService->getCameraVendorTagDescriptor(/*out*/desc);
755
Igor Murashkin5614cbe2014-03-17 14:00:55 -0700756 if (err == -EOPNOTSUPP) {
757 ALOGW("%s: Camera HAL too old; does not support vendor tags", __FUNCTION__);
758 VendorTagDescriptor::clearGlobalVendorTagDescriptor();
759
760 return OK;
761 } else if (err != OK) {
762 ALOGE("%s: Failed to setup vendor tag descriptors, received error %s (%d)",
763 __FUNCTION__, strerror(-err), err);
Ruben Brunk85c43882014-02-21 17:40:51 -0800764 return err;
765 }
766
767 err = VendorTagDescriptor::setAsGlobalVendorTagDescriptor(desc);
768
769 return err;
770}
771
Igor Murashkin70725502013-06-25 20:27:06 +0000772} // extern "C"