blob: 43795b8e4ccd9805108e81b795ebe772d25b16e8 [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
19#define LOG_TAG "CameraMetadata-JNI"
Ruben Brunk32ef3ae2014-02-21 17:40:51 -080020#include <utils/Errors.h>
Igor Murashkin70725502013-06-25 20:27:06 +000021#include <utils/Log.h>
Ruben Brunk85c43882014-02-21 17:40:51 -080022#include <utils/RefBase.h>
Ruben Brunk32ef3ae2014-02-21 17:40:51 -080023#include <utils/Vector.h>
24#include <utils/SortedVector.h>
25#include <utils/KeyedVector.h>
Ruben Brunk85c43882014-02-21 17:40:51 -080026#include <string.h>
Igor Murashkin70725502013-06-25 20:27:06 +000027
28#include "jni.h"
29#include "JNIHelp.h"
30#include "android_os_Parcel.h"
Andreas Gampeed6b9df2014-11-20 22:02:20 -080031#include "core_jni_helpers.h"
Ruben Brunkf967a542014-04-28 16:31:11 -070032#include "android_runtime/android_hardware_camera2_CameraMetadata.h"
Igor Murashkin70725502013-06-25 20:27:06 +000033
Ruben Brunk85c43882014-02-21 17:40:51 -080034#include <binder/IServiceManager.h>
Igor Murashkin70725502013-06-25 20:27:06 +000035#include <camera/CameraMetadata.h>
Ruben Brunk85c43882014-02-21 17:40:51 -080036#include <camera/ICameraService.h>
37#include <camera/VendorTagDescriptor.h>
Igor Murashkinb519cc52013-07-02 11:23:44 -070038#include <nativehelper/ScopedUtfChars.h>
39#include <nativehelper/ScopedPrimitiveArray.h>
40
Igor Murashkind6d65152014-05-19 16:31:02 -070041#include <sys/types.h> // for socketpair
42#include <sys/socket.h> // for socketpair
43
Andreas Gampeed6b9df2014-11-20 22:02:20 -080044static const bool kIsDebug = false;
Igor Murashkin70725502013-06-25 20:27:06 +000045
46// fully-qualified class name
Eino-Ville Talvala70c22072013-08-27 12:09:04 -070047#define CAMERA_METADATA_CLASS_NAME "android/hardware/camera2/impl/CameraMetadataNative"
Igor Murashkin70725502013-06-25 20:27:06 +000048
49using namespace android;
50
51struct fields_t {
52 jfieldID metadata_ptr;
53};
54
55static fields_t fields;
56
Ruben Brunkf967a542014-04-28 16:31:11 -070057namespace android {
58
59status_t CameraMetadata_getNativeMetadata(JNIEnv* env, jobject thiz,
60 /*out*/CameraMetadata* metadata) {
61 if (!thiz) {
62 ALOGE("%s: Invalid java metadata object.", __FUNCTION__);
63 return BAD_VALUE;
64 }
65
66 if (!metadata) {
67 ALOGE("%s: Invalid output metadata object.", __FUNCTION__);
68 return BAD_VALUE;
69 }
70 CameraMetadata* nativePtr = reinterpret_cast<CameraMetadata*>(env->GetLongField(thiz,
71 fields.metadata_ptr));
72 if (nativePtr == NULL) {
73 ALOGE("%s: Invalid native pointer in java metadata object.", __FUNCTION__);
74 return BAD_VALUE;
75 }
76 *metadata = *nativePtr;
77 return OK;
78}
79
80} /*namespace android*/
81
Igor Murashkinb519cc52013-07-02 11:23:44 -070082namespace {
83struct Helpers {
84 static size_t getTypeSize(uint8_t type) {
85 if (type >= NUM_TYPES) {
86 ALOGE("%s: Invalid type specified (%ud)", __FUNCTION__, type);
87 return static_cast<size_t>(-1);
88 }
89
90 return camera_metadata_type_size[type];
91 }
92
93 static status_t updateAny(CameraMetadata *metadata,
94 uint32_t tag,
95 uint32_t type,
96 const void *data,
97 size_t dataBytes) {
98
99 if (type >= NUM_TYPES) {
100 ALOGE("%s: Invalid type specified (%ud)", __FUNCTION__, type);
101 return INVALID_OPERATION;
102 }
103
104 size_t typeSize = getTypeSize(type);
105
106 if (dataBytes % typeSize != 0) {
Dan Albert46d84442014-11-18 16:07:51 -0800107 ALOGE("%s: Expected dataBytes (%zu) to be divisible by typeSize "
108 "(%zu)", __FUNCTION__, dataBytes, typeSize);
Igor Murashkinb519cc52013-07-02 11:23:44 -0700109 return BAD_VALUE;
110 }
111
112 size_t dataCount = dataBytes / typeSize;
113
114 switch(type) {
115#define METADATA_UPDATE(runtime_type, compile_type) \
116 case runtime_type: { \
117 const compile_type *dataPtr = \
118 static_cast<const compile_type*>(data); \
119 return metadata->update(tag, dataPtr, dataCount); \
120 } \
121
122 METADATA_UPDATE(TYPE_BYTE, uint8_t);
123 METADATA_UPDATE(TYPE_INT32, int32_t);
124 METADATA_UPDATE(TYPE_FLOAT, float);
125 METADATA_UPDATE(TYPE_INT64, int64_t);
126 METADATA_UPDATE(TYPE_DOUBLE, double);
127 METADATA_UPDATE(TYPE_RATIONAL, camera_metadata_rational_t);
128
129 default: {
130 // unreachable
131 ALOGE("%s: Unreachable", __FUNCTION__);
132 return INVALID_OPERATION;
133 }
134 }
135
136#undef METADATA_UPDATE
137 }
138};
139} // namespace {}
140
Igor Murashkin70725502013-06-25 20:27:06 +0000141extern "C" {
142
143static void CameraMetadata_classInit(JNIEnv *env, jobject thiz);
Igor Murashkinb519cc52013-07-02 11:23:44 -0700144static jint CameraMetadata_getTagFromKey(JNIEnv *env, jobject thiz, jstring keyName);
145static jint CameraMetadata_getTypeFromTag(JNIEnv *env, jobject thiz, jint tag);
Ruben Brunk85c43882014-02-21 17:40:51 -0800146static jint CameraMetadata_setupGlobalVendorTagDescriptor(JNIEnv *env, jobject thiz);
Igor Murashkin70725502013-06-25 20:27:06 +0000147
148// Less safe access to native pointer. Does NOT throw any Java exceptions if NULL.
149static CameraMetadata* CameraMetadata_getPointerNoThrow(JNIEnv *env, jobject thiz) {
150
151 if (thiz == NULL) {
152 return NULL;
153 }
154
155 return reinterpret_cast<CameraMetadata*>(env->GetLongField(thiz, fields.metadata_ptr));
156}
157
158// Safe access to native pointer from object. Throws if not possible to access.
159static CameraMetadata* CameraMetadata_getPointerThrow(JNIEnv *env, jobject thiz,
160 const char* argName = "this") {
161
162 if (thiz == NULL) {
163 ALOGV("%s: Throwing java.lang.NullPointerException for null reference",
164 __FUNCTION__);
165 jniThrowNullPointerException(env, argName);
166 return NULL;
167 }
168
169 CameraMetadata* metadata = CameraMetadata_getPointerNoThrow(env, thiz);
170 if (metadata == NULL) {
171 ALOGV("%s: Throwing java.lang.IllegalStateException for closed object",
172 __FUNCTION__);
173 jniThrowException(env, "java/lang/IllegalStateException",
174 "Metadata object was already closed");
175 return NULL;
176 }
177
178 return metadata;
179}
180
181static jlong CameraMetadata_allocate(JNIEnv *env, jobject thiz) {
182 ALOGV("%s", __FUNCTION__);
183
184 return reinterpret_cast<jlong>(new CameraMetadata());
185}
186
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700187static jlong CameraMetadata_allocateCopy(JNIEnv *env, jobject thiz,
188 jobject other) {
189 ALOGV("%s", __FUNCTION__);
190
191 CameraMetadata* otherMetadata =
192 CameraMetadata_getPointerThrow(env, other, "other");
193
194 // In case of exception, return
195 if (otherMetadata == NULL) return NULL;
196
197 // Clone native metadata and return new pointer
198 return reinterpret_cast<jlong>(new CameraMetadata(*otherMetadata));
199}
200
201
Igor Murashkin70725502013-06-25 20:27:06 +0000202static jboolean CameraMetadata_isEmpty(JNIEnv *env, jobject thiz) {
203 ALOGV("%s", __FUNCTION__);
204
205 CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
206
207 if (metadata == NULL) {
208 ALOGW("%s: Returning early due to exception being thrown",
209 __FUNCTION__);
210 return JNI_TRUE; // actually throws java exc.
211 }
212
213 jboolean empty = metadata->isEmpty();
214
Dan Albert46d84442014-11-18 16:07:51 -0800215 ALOGV("%s: Empty returned %d, entry count was %zu",
Igor Murashkin70725502013-06-25 20:27:06 +0000216 __FUNCTION__, empty, metadata->entryCount());
217
218 return empty;
219}
220
221static jint CameraMetadata_getEntryCount(JNIEnv *env, jobject thiz) {
222 ALOGV("%s", __FUNCTION__);
223
224 CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
225
226 if (metadata == NULL) return 0; // actually throws java exc.
227
228 return metadata->entryCount();
229}
230
231// idempotent. calling more than once has no effect.
232static void CameraMetadata_close(JNIEnv *env, jobject thiz) {
233 ALOGV("%s", __FUNCTION__);
234
235 CameraMetadata* metadata = CameraMetadata_getPointerNoThrow(env, thiz);
236
237 if (metadata != NULL) {
238 delete metadata;
239 env->SetLongField(thiz, fields.metadata_ptr, 0);
240 }
241
242 LOG_ALWAYS_FATAL_IF(CameraMetadata_getPointerNoThrow(env, thiz) != NULL,
243 "Expected the native ptr to be 0 after #close");
244}
245
246static void CameraMetadata_swap(JNIEnv *env, jobject thiz, jobject other) {
247 ALOGV("%s", __FUNCTION__);
248
249 CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
250
251 // order is important: we can't call another JNI method
252 // if there is an exception pending
253 if (metadata == NULL) return;
254
255 CameraMetadata* otherMetadata = CameraMetadata_getPointerThrow(env, other, "other");
256
257 if (otherMetadata == NULL) return;
258
259 metadata->swap(*otherMetadata);
260}
261
Igor Murashkinb519cc52013-07-02 11:23:44 -0700262static jbyteArray CameraMetadata_readValues(JNIEnv *env, jobject thiz, jint tag) {
263 ALOGV("%s (tag = %d)", __FUNCTION__, tag);
264
265 CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
266 if (metadata == NULL) return NULL;
267
268 int tagType = get_camera_metadata_tag_type(tag);
269 if (tagType == -1) {
270 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
271 "Tag (%d) did not have a type", tag);
272 return NULL;
273 }
274 size_t tagSize = Helpers::getTypeSize(tagType);
275
276 camera_metadata_entry entry = metadata->find(tag);
277 if (entry.count == 0) {
278 if (!metadata->exists(tag)) {
279 ALOGV("%s: Tag %d does not have any entries", __FUNCTION__, tag);
280 return NULL;
281 } else {
282 // OK: we will return a 0-sized array.
283 ALOGV("%s: Tag %d had an entry, but it had 0 data", __FUNCTION__,
284 tag);
285 }
286 }
287
288 jsize byteCount = entry.count * tagSize;
289 jbyteArray byteArray = env->NewByteArray(byteCount);
290 if (env->ExceptionCheck()) return NULL;
291
292 // Copy into java array from native array
293 ScopedByteArrayRW arrayWriter(env, byteArray);
294 memcpy(arrayWriter.get(), entry.data.u8, byteCount);
295
296 return byteArray;
297}
298
299static void CameraMetadata_writeValues(JNIEnv *env, jobject thiz, jint tag, jbyteArray src) {
300 ALOGV("%s (tag = %d)", __FUNCTION__, tag);
301
302 CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
303 if (metadata == NULL) return;
304
305 int tagType = get_camera_metadata_tag_type(tag);
306 if (tagType == -1) {
307 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
308 "Tag (%d) did not have a type", tag);
309 return;
310 }
Igor Murashkinb519cc52013-07-02 11:23:44 -0700311
312 status_t res;
313
314 if (src == NULL) {
315 // If array is NULL, delete the entry
Igor Murashkin3710db82013-07-18 20:11:17 -0700316 if (metadata->exists(tag)) {
317 res = metadata->erase(tag);
318 ALOGV("%s: Erase values (res = %d)", __FUNCTION__, res);
319 } else {
320 res = OK;
321 ALOGV("%s: Don't need to erase", __FUNCTION__);
322 }
Igor Murashkinb519cc52013-07-02 11:23:44 -0700323 } else {
324 // Copy from java array into native array
325 ScopedByteArrayRO arrayReader(env, src);
326 if (arrayReader.get() == NULL) return;
327
328 res = Helpers::updateAny(metadata, static_cast<uint32_t>(tag),
329 tagType, arrayReader.get(), arrayReader.size());
Igor Murashkin3710db82013-07-18 20:11:17 -0700330
331 ALOGV("%s: Update values (res = %d)", __FUNCTION__, res);
Igor Murashkinb519cc52013-07-02 11:23:44 -0700332 }
333
334 if (res == OK) {
335 return;
336 } else if (res == BAD_VALUE) {
337 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
338 "Src byte array was poorly formed");
339 } else if (res == INVALID_OPERATION) {
340 jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
341 "Internal error while trying to update metadata");
342 } else {
343 jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
344 "Unknown error (%d) while trying to update "
345 "metadata", res);
346 }
347}
348
Igor Murashkind6d65152014-05-19 16:31:02 -0700349struct DumpMetadataParams {
350 int writeFd;
351 const CameraMetadata* metadata;
352};
353
354static void* CameraMetadata_writeMetadataThread(void* arg) {
355 DumpMetadataParams* p = static_cast<DumpMetadataParams*>(arg);
356
357 /*
358 * Write the dumped data, and close the writing side FD.
359 */
360 p->metadata->dump(p->writeFd, /*verbosity*/2);
361
362 if (close(p->writeFd) < 0) {
363 ALOGE("%s: Failed to close writeFd (errno = %#x, message = '%s')",
364 __FUNCTION__, errno, strerror(errno));
365 }
366
367 return NULL;
368}
369
370static void CameraMetadata_dump(JNIEnv *env, jobject thiz) {
371 ALOGV("%s", __FUNCTION__);
372 CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
373 if (metadata == NULL) {
374 return;
375 }
376
377 /*
378 * Create a socket pair for local streaming read/writes.
379 *
380 * The metadata will be dumped into the write side,
381 * and then read back out (and logged) via the read side.
382 */
383
384 int writeFd, readFd;
385 {
386
387 int sv[2];
388 if (socketpair(AF_LOCAL, SOCK_STREAM, /*protocol*/0, &sv[0]) < 0) {
389 jniThrowExceptionFmt(env, "java/io/IOException",
390 "Failed to create socketpair (errno = %#x, message = '%s')",
391 errno, strerror(errno));
392 return;
393 }
394 writeFd = sv[0];
395 readFd = sv[1];
396 }
397
398 /*
399 * Create a thread for doing the writing.
400 *
401 * The reading and writing must be concurrent, otherwise
402 * the write will block forever once it exhausts the capped
403 * buffer size (from getsockopt).
404 */
405 pthread_t writeThread;
406 DumpMetadataParams params = {
407 writeFd,
408 metadata
409 };
410
411 {
412 int threadRet = pthread_create(&writeThread, /*attr*/NULL,
413 CameraMetadata_writeMetadataThread, (void*)&params);
414
415 if (threadRet != 0) {
416 close(writeFd);
417
418 jniThrowExceptionFmt(env, "java/io/IOException",
419 "Failed to create thread for writing (errno = %#x, message = '%s')",
420 threadRet, strerror(threadRet));
421 }
422 }
423
424 /*
425 * Read out a byte until stream is complete. Write completed lines
426 * to ALOG.
427 */
428 {
429 char out[] = {'\0', '\0'}; // large enough to append as a string
430 String8 logLine;
431
432 // Read one byte at a time! Very slow but avoids complicated \n scanning.
433 ssize_t res;
434 while ((res = TEMP_FAILURE_RETRY(read(readFd, &out[0], /*count*/1))) > 0) {
435 if (out[0] == '\n') {
436 ALOGD("%s", logLine.string());
437 logLine.clear();
438 } else {
439 logLine.append(out);
440 }
441 }
442
443 if (res < 0) {
444 jniThrowExceptionFmt(env, "java/io/IOException",
445 "Failed to read from fd (errno = %#x, message = '%s')",
446 errno, strerror(errno));
447 //return;
448 } else if (!logLine.isEmpty()) {
449 ALOGD("%s", logLine.string());
450 }
451 }
452
453 int res;
454
455 // Join until thread finishes. Ensures params/metadata is valid until then.
456 if ((res = pthread_join(writeThread, /*retval*/NULL)) != 0) {
457 ALOGE("%s: Failed to join thread (errno = %#x, message = '%s')",
458 __FUNCTION__, res, strerror(res));
459 }
460}
461
Igor Murashkin70725502013-06-25 20:27:06 +0000462static void CameraMetadata_readFromParcel(JNIEnv *env, jobject thiz, jobject parcel) {
463 ALOGV("%s", __FUNCTION__);
464 CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
465 if (metadata == NULL) {
466 return;
467 }
468
469 Parcel* parcelNative = parcelForJavaObject(env, parcel);
470 if (parcelNative == NULL) {
471 jniThrowNullPointerException(env, "parcel");
472 return;
473 }
474
475 status_t err;
476 if ((err = metadata->readFromParcel(parcelNative)) != OK) {
477 jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
478 "Failed to read from parcel (error code %d)", err);
479 return;
480 }
481}
482
483static void CameraMetadata_writeToParcel(JNIEnv *env, jobject thiz, jobject parcel) {
484 ALOGV("%s", __FUNCTION__);
485 CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
486 if (metadata == NULL) {
487 return;
488 }
489
490 Parcel* parcelNative = parcelForJavaObject(env, parcel);
491 if (parcelNative == NULL) {
492 jniThrowNullPointerException(env, "parcel");
493 return;
494 }
495
496 status_t err;
497 if ((err = metadata->writeToParcel(parcelNative)) != OK) {
498 jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
499 "Failed to write to parcel (error code %d)", err);
500 return;
501 }
502}
503
504} // extern "C"
505
506//-------------------------------------------------
507
Daniel Micay76f6a862015-09-19 17:31:01 -0400508static const JNINativeMethod gCameraMetadataMethods[] = {
Igor Murashkinb519cc52013-07-02 11:23:44 -0700509// static methods
Igor Murashkin70725502013-06-25 20:27:06 +0000510 { "nativeClassInit",
511 "()V",
512 (void *)CameraMetadata_classInit },
Igor Murashkinb519cc52013-07-02 11:23:44 -0700513 { "nativeGetTagFromKey",
514 "(Ljava/lang/String;)I",
515 (void *)CameraMetadata_getTagFromKey },
516 { "nativeGetTypeFromTag",
517 "(I)I",
518 (void *)CameraMetadata_getTypeFromTag },
Ruben Brunk85c43882014-02-21 17:40:51 -0800519 { "nativeSetupGlobalVendorTagDescriptor",
520 "()I",
521 (void*)CameraMetadata_setupGlobalVendorTagDescriptor },
Igor Murashkinb519cc52013-07-02 11:23:44 -0700522// instance methods
Igor Murashkin70725502013-06-25 20:27:06 +0000523 { "nativeAllocate",
524 "()J",
525 (void*)CameraMetadata_allocate },
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700526 { "nativeAllocateCopy",
527 "(L" CAMERA_METADATA_CLASS_NAME ";)J",
528 (void *)CameraMetadata_allocateCopy },
Igor Murashkin70725502013-06-25 20:27:06 +0000529 { "nativeIsEmpty",
530 "()Z",
531 (void*)CameraMetadata_isEmpty },
532 { "nativeGetEntryCount",
533 "()I",
534 (void*)CameraMetadata_getEntryCount },
535 { "nativeClose",
536 "()V",
537 (void*)CameraMetadata_close },
538 { "nativeSwap",
539 "(L" CAMERA_METADATA_CLASS_NAME ";)V",
540 (void *)CameraMetadata_swap },
Igor Murashkinb519cc52013-07-02 11:23:44 -0700541 { "nativeReadValues",
542 "(I)[B",
543 (void *)CameraMetadata_readValues },
544 { "nativeWriteValues",
545 "(I[B)V",
546 (void *)CameraMetadata_writeValues },
Igor Murashkind6d65152014-05-19 16:31:02 -0700547 { "nativeDump",
548 "()V",
549 (void *)CameraMetadata_dump },
Igor Murashkinb519cc52013-07-02 11:23:44 -0700550// Parcelable interface
Igor Murashkin70725502013-06-25 20:27:06 +0000551 { "nativeReadFromParcel",
552 "(Landroid/os/Parcel;)V",
553 (void *)CameraMetadata_readFromParcel },
554 { "nativeWriteToParcel",
555 "(Landroid/os/Parcel;)V",
556 (void *)CameraMetadata_writeToParcel },
557};
558
559struct field {
560 const char *class_name;
561 const char *field_name;
562 const char *field_type;
563 jfieldID *jfield;
564};
565
566static int find_fields(JNIEnv *env, field *fields, int count)
567{
568 for (int i = 0; i < count; i++) {
569 field *f = &fields[i];
570 jclass clazz = env->FindClass(f->class_name);
571 if (clazz == NULL) {
572 ALOGE("Can't find %s", f->class_name);
573 return -1;
574 }
575
576 jfieldID field = env->GetFieldID(clazz, f->field_name, f->field_type);
577 if (field == NULL) {
578 ALOGE("Can't find %s.%s", f->class_name, f->field_name);
579 return -1;
580 }
581
582 *(f->jfield) = field;
583 }
584
585 return 0;
586}
587
588// Get all the required offsets in java class and register native functions
Eino-Ville Talvala2f1a2e42013-07-25 17:12:05 -0700589int register_android_hardware_camera2_CameraMetadata(JNIEnv *env)
Igor Murashkin70725502013-06-25 20:27:06 +0000590{
591 // Register native functions
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800592 return RegisterMethodsOrDie(env,
Igor Murashkin70725502013-06-25 20:27:06 +0000593 CAMERA_METADATA_CLASS_NAME,
594 gCameraMetadataMethods,
595 NELEM(gCameraMetadataMethods));
596}
597
598extern "C" {
599static void CameraMetadata_classInit(JNIEnv *env, jobject thiz) {
600 // XX: Why do this separately instead of doing it in the register function?
601 ALOGV("%s", __FUNCTION__);
602
603 field fields_to_find[] = {
604 { CAMERA_METADATA_CLASS_NAME, "mMetadataPtr", "J", &fields.metadata_ptr },
605 };
606
607 // Do this here instead of in register_native_methods,
608 // since otherwise it will fail to find the fields.
609 if (find_fields(env, fields_to_find, NELEM(fields_to_find)) < 0)
610 return;
611
Andreas Gampe0f0b4912014-11-12 08:03:48 -0800612 env->FindClass(CAMERA_METADATA_CLASS_NAME);
Igor Murashkin70725502013-06-25 20:27:06 +0000613}
Igor Murashkinb519cc52013-07-02 11:23:44 -0700614
615static jint CameraMetadata_getTagFromKey(JNIEnv *env, jobject thiz, jstring keyName) {
616
617 ScopedUtfChars keyScoped(env, keyName);
618 const char *key = keyScoped.c_str();
619 if (key == NULL) {
620 // exception thrown by ScopedUtfChars
621 return 0;
622 }
623 size_t keyLength = strlen(key);
624
625 ALOGV("%s (key = '%s')", __FUNCTION__, key);
626
Ruben Brunk32ef3ae2014-02-21 17:40:51 -0800627 sp<VendorTagDescriptor> vTags = VendorTagDescriptor::getGlobalVendorTagDescriptor();
628
Igor Murashkin3c40a042014-04-22 15:05:50 -0700629 SortedVector<String8> vendorSections;
630 size_t vendorSectionCount = 0;
631
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700632 if (vTags != NULL) {
Igor Murashkin3c40a042014-04-22 15:05:50 -0700633 vendorSections = vTags->getAllSectionNames();
634 vendorSectionCount = vendorSections.size();
635 }
Ruben Brunk32ef3ae2014-02-21 17:40:51 -0800636
Igor Murashkinb519cc52013-07-02 11:23:44 -0700637 // First, find the section by the longest string match
638 const char *section = NULL;
639 size_t sectionIndex = 0;
640 size_t sectionLength = 0;
Ruben Brunk32ef3ae2014-02-21 17:40:51 -0800641 size_t totalSectionCount = ANDROID_SECTION_COUNT + vendorSectionCount;
642 for (size_t i = 0; i < totalSectionCount; ++i) {
643
644 const char *str = (i < ANDROID_SECTION_COUNT) ? camera_metadata_section_names[i] :
645 vendorSections[i - ANDROID_SECTION_COUNT].string();
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800646 if (kIsDebug) {
647 ALOGV("%s: Trying to match against section '%s'", __FUNCTION__, str);
648 }
Igor Murashkinb519cc52013-07-02 11:23:44 -0700649 if (strstr(key, str) == key) { // key begins with the section name
650 size_t strLength = strlen(str);
651
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800652 if (kIsDebug) {
653 ALOGV("%s: Key begins with section name", __FUNCTION__);
654 }
Igor Murashkinb519cc52013-07-02 11:23:44 -0700655
656 // section name is the longest we've found so far
657 if (section == NULL || sectionLength < strLength) {
658 section = str;
659 sectionIndex = i;
660 sectionLength = strLength;
661
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800662 if (kIsDebug) {
663 ALOGV("%s: Found new best section (%s)", __FUNCTION__, section);
664 }
Igor Murashkinb519cc52013-07-02 11:23:44 -0700665 }
666 }
667 }
668
Igor Murashkinb519cc52013-07-02 11:23:44 -0700669 // TODO: Make above get_camera_metadata_section_from_name ?
670
671 if (section == NULL) {
672 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
673 "Could not find section name for key '%s')", key);
674 return 0;
675 } else {
Dan Albert46d84442014-11-18 16:07:51 -0800676 ALOGV("%s: Found matched section '%s' (%zu)",
Igor Murashkinb519cc52013-07-02 11:23:44 -0700677 __FUNCTION__, section, sectionIndex);
678 }
679
680 // Get the tag name component of the key
681 const char *keyTagName = key + sectionLength + 1; // x.y.z -> z
682 if (sectionLength + 1 >= keyLength) {
683 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
684 "Key length too short for key '%s')", key);
Ruben Brunk32ef3ae2014-02-21 17:40:51 -0800685 return 0;
Igor Murashkinb519cc52013-07-02 11:23:44 -0700686 }
687
688 // Match rest of name against the tag names in that section only
Ruben Brunk32ef3ae2014-02-21 17:40:51 -0800689 uint32_t tag = 0;
690 if (sectionIndex < ANDROID_SECTION_COUNT) {
691 // Match built-in tags (typically android.*)
692 uint32_t tagBegin, tagEnd; // [tagBegin, tagEnd)
693 tagBegin = camera_metadata_section_bounds[sectionIndex][0];
694 tagEnd = camera_metadata_section_bounds[sectionIndex][1];
Igor Murashkinb519cc52013-07-02 11:23:44 -0700695
Ruben Brunk32ef3ae2014-02-21 17:40:51 -0800696 for (tag = tagBegin; tag < tagEnd; ++tag) {
697 const char *tagName = get_camera_metadata_tag_name(tag);
Igor Murashkinb519cc52013-07-02 11:23:44 -0700698
Ruben Brunk32ef3ae2014-02-21 17:40:51 -0800699 if (strcmp(keyTagName, tagName) == 0) {
700 ALOGV("%s: Found matched tag '%s' (%d)",
701 __FUNCTION__, tagName, tag);
702 break;
703 }
704 }
705
706 if (tag == tagEnd) {
707 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
708 "Could not find tag name for key '%s')", key);
709 return 0;
710 }
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700711 } else if (vTags != NULL) {
Ruben Brunk32ef3ae2014-02-21 17:40:51 -0800712 // Match vendor tags (typically com.*)
713 const String8 sectionName(section);
714 const String8 tagName(keyTagName);
715
716 status_t res = OK;
717 if ((res = vTags->lookupTag(tagName, sectionName, &tag)) != OK) {
718 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
719 "%s: No vendor tag matches key '%s'", __FUNCTION__, key);
720 return 0;
Igor Murashkinb519cc52013-07-02 11:23:44 -0700721 }
722 }
723
Igor Murashkinb519cc52013-07-02 11:23:44 -0700724 // TODO: Make above get_camera_metadata_tag_from_name ?
725
Igor Murashkinb519cc52013-07-02 11:23:44 -0700726 return tag;
727}
728
729static jint CameraMetadata_getTypeFromTag(JNIEnv *env, jobject thiz, jint tag) {
730 int tagType = get_camera_metadata_tag_type(tag);
731 if (tagType == -1) {
732 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
733 "Tag (%d) did not have a type", tag);
734 return -1;
735 }
736
737 return tagType;
738}
739
Ruben Brunk85c43882014-02-21 17:40:51 -0800740static jint CameraMetadata_setupGlobalVendorTagDescriptor(JNIEnv *env, jobject thiz) {
741 const String16 NAME("media.camera");
742 sp<ICameraService> cameraService;
743 status_t err = getService(NAME, /*out*/&cameraService);
744
745 if (err != OK) {
746 ALOGE("%s: Failed to get camera service, received error %s (%d)", __FUNCTION__,
747 strerror(-err), err);
748 return err;
749 }
750
751 sp<VendorTagDescriptor> desc;
752 err = cameraService->getCameraVendorTagDescriptor(/*out*/desc);
753
Igor Murashkin5614cbe2014-03-17 14:00:55 -0700754 if (err == -EOPNOTSUPP) {
755 ALOGW("%s: Camera HAL too old; does not support vendor tags", __FUNCTION__);
756 VendorTagDescriptor::clearGlobalVendorTagDescriptor();
757
758 return OK;
759 } else if (err != OK) {
760 ALOGE("%s: Failed to setup vendor tag descriptors, received error %s (%d)",
761 __FUNCTION__, strerror(-err), err);
Ruben Brunk85c43882014-02-21 17:40:51 -0800762 return err;
763 }
764
765 err = VendorTagDescriptor::setAsGlobalVendorTagDescriptor(desc);
766
767 return err;
768}
769
Igor Murashkin70725502013-06-25 20:27:06 +0000770} // extern "C"