blob: 79353299d7a87b7dd937bbd22e3180c4c47178b3 [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) {
114 ALOGE("%s: Expected dataBytes (%ud) to be divisible by typeSize "
115 "(%ud)", __FUNCTION__, dataBytes, typeSize);
116 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
222 ALOGV("%s: Empty returned %d, entry count was %d",
223 __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 }
318 size_t tagSize = Helpers::getTypeSize(tagType);
319
320 status_t res;
321
322 if (src == NULL) {
323 // If array is NULL, delete the entry
Igor Murashkin3710db82013-07-18 20:11:17 -0700324 if (metadata->exists(tag)) {
325 res = metadata->erase(tag);
326 ALOGV("%s: Erase values (res = %d)", __FUNCTION__, res);
327 } else {
328 res = OK;
329 ALOGV("%s: Don't need to erase", __FUNCTION__);
330 }
Igor Murashkinb519cc52013-07-02 11:23:44 -0700331 } else {
332 // Copy from java array into native array
333 ScopedByteArrayRO arrayReader(env, src);
334 if (arrayReader.get() == NULL) return;
335
336 res = Helpers::updateAny(metadata, static_cast<uint32_t>(tag),
337 tagType, arrayReader.get(), arrayReader.size());
Igor Murashkin3710db82013-07-18 20:11:17 -0700338
339 ALOGV("%s: Update values (res = %d)", __FUNCTION__, res);
Igor Murashkinb519cc52013-07-02 11:23:44 -0700340 }
341
342 if (res == OK) {
343 return;
344 } else if (res == BAD_VALUE) {
345 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
346 "Src byte array was poorly formed");
347 } else if (res == INVALID_OPERATION) {
348 jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
349 "Internal error while trying to update metadata");
350 } else {
351 jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
352 "Unknown error (%d) while trying to update "
353 "metadata", res);
354 }
355}
356
Igor Murashkind6d65152014-05-19 16:31:02 -0700357struct DumpMetadataParams {
358 int writeFd;
359 const CameraMetadata* metadata;
360};
361
362static void* CameraMetadata_writeMetadataThread(void* arg) {
363 DumpMetadataParams* p = static_cast<DumpMetadataParams*>(arg);
364
365 /*
366 * Write the dumped data, and close the writing side FD.
367 */
368 p->metadata->dump(p->writeFd, /*verbosity*/2);
369
370 if (close(p->writeFd) < 0) {
371 ALOGE("%s: Failed to close writeFd (errno = %#x, message = '%s')",
372 __FUNCTION__, errno, strerror(errno));
373 }
374
375 return NULL;
376}
377
378static void CameraMetadata_dump(JNIEnv *env, jobject thiz) {
379 ALOGV("%s", __FUNCTION__);
380 CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
381 if (metadata == NULL) {
382 return;
383 }
384
385 /*
386 * Create a socket pair for local streaming read/writes.
387 *
388 * The metadata will be dumped into the write side,
389 * and then read back out (and logged) via the read side.
390 */
391
392 int writeFd, readFd;
393 {
394
395 int sv[2];
396 if (socketpair(AF_LOCAL, SOCK_STREAM, /*protocol*/0, &sv[0]) < 0) {
397 jniThrowExceptionFmt(env, "java/io/IOException",
398 "Failed to create socketpair (errno = %#x, message = '%s')",
399 errno, strerror(errno));
400 return;
401 }
402 writeFd = sv[0];
403 readFd = sv[1];
404 }
405
406 /*
407 * Create a thread for doing the writing.
408 *
409 * The reading and writing must be concurrent, otherwise
410 * the write will block forever once it exhausts the capped
411 * buffer size (from getsockopt).
412 */
413 pthread_t writeThread;
414 DumpMetadataParams params = {
415 writeFd,
416 metadata
417 };
418
419 {
420 int threadRet = pthread_create(&writeThread, /*attr*/NULL,
421 CameraMetadata_writeMetadataThread, (void*)&params);
422
423 if (threadRet != 0) {
424 close(writeFd);
425
426 jniThrowExceptionFmt(env, "java/io/IOException",
427 "Failed to create thread for writing (errno = %#x, message = '%s')",
428 threadRet, strerror(threadRet));
429 }
430 }
431
432 /*
433 * Read out a byte until stream is complete. Write completed lines
434 * to ALOG.
435 */
436 {
437 char out[] = {'\0', '\0'}; // large enough to append as a string
438 String8 logLine;
439
440 // Read one byte at a time! Very slow but avoids complicated \n scanning.
441 ssize_t res;
442 while ((res = TEMP_FAILURE_RETRY(read(readFd, &out[0], /*count*/1))) > 0) {
443 if (out[0] == '\n') {
444 ALOGD("%s", logLine.string());
445 logLine.clear();
446 } else {
447 logLine.append(out);
448 }
449 }
450
451 if (res < 0) {
452 jniThrowExceptionFmt(env, "java/io/IOException",
453 "Failed to read from fd (errno = %#x, message = '%s')",
454 errno, strerror(errno));
455 //return;
456 } else if (!logLine.isEmpty()) {
457 ALOGD("%s", logLine.string());
458 }
459 }
460
461 int res;
462
463 // Join until thread finishes. Ensures params/metadata is valid until then.
464 if ((res = pthread_join(writeThread, /*retval*/NULL)) != 0) {
465 ALOGE("%s: Failed to join thread (errno = %#x, message = '%s')",
466 __FUNCTION__, res, strerror(res));
467 }
468}
469
Igor Murashkin70725502013-06-25 20:27:06 +0000470static void CameraMetadata_readFromParcel(JNIEnv *env, jobject thiz, jobject parcel) {
471 ALOGV("%s", __FUNCTION__);
472 CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
473 if (metadata == NULL) {
474 return;
475 }
476
477 Parcel* parcelNative = parcelForJavaObject(env, parcel);
478 if (parcelNative == NULL) {
479 jniThrowNullPointerException(env, "parcel");
480 return;
481 }
482
483 status_t err;
484 if ((err = metadata->readFromParcel(parcelNative)) != OK) {
485 jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
486 "Failed to read from parcel (error code %d)", err);
487 return;
488 }
489}
490
491static void CameraMetadata_writeToParcel(JNIEnv *env, jobject thiz, jobject parcel) {
492 ALOGV("%s", __FUNCTION__);
493 CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
494 if (metadata == NULL) {
495 return;
496 }
497
498 Parcel* parcelNative = parcelForJavaObject(env, parcel);
499 if (parcelNative == NULL) {
500 jniThrowNullPointerException(env, "parcel");
501 return;
502 }
503
504 status_t err;
505 if ((err = metadata->writeToParcel(parcelNative)) != OK) {
506 jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
507 "Failed to write to parcel (error code %d)", err);
508 return;
509 }
510}
511
512} // extern "C"
513
514//-------------------------------------------------
515
516static JNINativeMethod gCameraMetadataMethods[] = {
Igor Murashkinb519cc52013-07-02 11:23:44 -0700517// static methods
Igor Murashkin70725502013-06-25 20:27:06 +0000518 { "nativeClassInit",
519 "()V",
520 (void *)CameraMetadata_classInit },
Igor Murashkinb519cc52013-07-02 11:23:44 -0700521 { "nativeGetTagFromKey",
522 "(Ljava/lang/String;)I",
523 (void *)CameraMetadata_getTagFromKey },
524 { "nativeGetTypeFromTag",
525 "(I)I",
526 (void *)CameraMetadata_getTypeFromTag },
Ruben Brunk85c43882014-02-21 17:40:51 -0800527 { "nativeSetupGlobalVendorTagDescriptor",
528 "()I",
529 (void*)CameraMetadata_setupGlobalVendorTagDescriptor },
Igor Murashkinb519cc52013-07-02 11:23:44 -0700530// instance methods
Igor Murashkin70725502013-06-25 20:27:06 +0000531 { "nativeAllocate",
532 "()J",
533 (void*)CameraMetadata_allocate },
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700534 { "nativeAllocateCopy",
535 "(L" CAMERA_METADATA_CLASS_NAME ";)J",
536 (void *)CameraMetadata_allocateCopy },
Igor Murashkin70725502013-06-25 20:27:06 +0000537 { "nativeIsEmpty",
538 "()Z",
539 (void*)CameraMetadata_isEmpty },
540 { "nativeGetEntryCount",
541 "()I",
542 (void*)CameraMetadata_getEntryCount },
543 { "nativeClose",
544 "()V",
545 (void*)CameraMetadata_close },
546 { "nativeSwap",
547 "(L" CAMERA_METADATA_CLASS_NAME ";)V",
548 (void *)CameraMetadata_swap },
Igor Murashkinb519cc52013-07-02 11:23:44 -0700549 { "nativeReadValues",
550 "(I)[B",
551 (void *)CameraMetadata_readValues },
552 { "nativeWriteValues",
553 "(I[B)V",
554 (void *)CameraMetadata_writeValues },
Igor Murashkind6d65152014-05-19 16:31:02 -0700555 { "nativeDump",
556 "()V",
557 (void *)CameraMetadata_dump },
Igor Murashkinb519cc52013-07-02 11:23:44 -0700558// Parcelable interface
Igor Murashkin70725502013-06-25 20:27:06 +0000559 { "nativeReadFromParcel",
560 "(Landroid/os/Parcel;)V",
561 (void *)CameraMetadata_readFromParcel },
562 { "nativeWriteToParcel",
563 "(Landroid/os/Parcel;)V",
564 (void *)CameraMetadata_writeToParcel },
565};
566
567struct field {
568 const char *class_name;
569 const char *field_name;
570 const char *field_type;
571 jfieldID *jfield;
572};
573
574static int find_fields(JNIEnv *env, field *fields, int count)
575{
576 for (int i = 0; i < count; i++) {
577 field *f = &fields[i];
578 jclass clazz = env->FindClass(f->class_name);
579 if (clazz == NULL) {
580 ALOGE("Can't find %s", f->class_name);
581 return -1;
582 }
583
584 jfieldID field = env->GetFieldID(clazz, f->field_name, f->field_type);
585 if (field == NULL) {
586 ALOGE("Can't find %s.%s", f->class_name, f->field_name);
587 return -1;
588 }
589
590 *(f->jfield) = field;
591 }
592
593 return 0;
594}
595
596// Get all the required offsets in java class and register native functions
Eino-Ville Talvala2f1a2e42013-07-25 17:12:05 -0700597int register_android_hardware_camera2_CameraMetadata(JNIEnv *env)
Igor Murashkin70725502013-06-25 20:27:06 +0000598{
599 // Register native functions
600 return AndroidRuntime::registerNativeMethods(env,
601 CAMERA_METADATA_CLASS_NAME,
602 gCameraMetadataMethods,
603 NELEM(gCameraMetadataMethods));
604}
605
606extern "C" {
607static void CameraMetadata_classInit(JNIEnv *env, jobject thiz) {
608 // XX: Why do this separately instead of doing it in the register function?
609 ALOGV("%s", __FUNCTION__);
610
611 field fields_to_find[] = {
612 { CAMERA_METADATA_CLASS_NAME, "mMetadataPtr", "J", &fields.metadata_ptr },
613 };
614
615 // Do this here instead of in register_native_methods,
616 // since otherwise it will fail to find the fields.
617 if (find_fields(env, fields_to_find, NELEM(fields_to_find)) < 0)
618 return;
619
620 jclass clazz = env->FindClass(CAMERA_METADATA_CLASS_NAME);
621}
Igor Murashkinb519cc52013-07-02 11:23:44 -0700622
623static jint CameraMetadata_getTagFromKey(JNIEnv *env, jobject thiz, jstring keyName) {
624
625 ScopedUtfChars keyScoped(env, keyName);
626 const char *key = keyScoped.c_str();
627 if (key == NULL) {
628 // exception thrown by ScopedUtfChars
629 return 0;
630 }
631 size_t keyLength = strlen(key);
632
633 ALOGV("%s (key = '%s')", __FUNCTION__, key);
634
Ruben Brunk32ef3ae2014-02-21 17:40:51 -0800635 sp<VendorTagDescriptor> vTags = VendorTagDescriptor::getGlobalVendorTagDescriptor();
636
Igor Murashkin3c40a042014-04-22 15:05:50 -0700637 SortedVector<String8> vendorSections;
638 size_t vendorSectionCount = 0;
639
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700640 if (vTags != NULL) {
Igor Murashkin3c40a042014-04-22 15:05:50 -0700641 vendorSections = vTags->getAllSectionNames();
642 vendorSectionCount = vendorSections.size();
643 }
Ruben Brunk32ef3ae2014-02-21 17:40:51 -0800644
Igor Murashkinb519cc52013-07-02 11:23:44 -0700645 // First, find the section by the longest string match
646 const char *section = NULL;
647 size_t sectionIndex = 0;
648 size_t sectionLength = 0;
Ruben Brunk32ef3ae2014-02-21 17:40:51 -0800649 size_t totalSectionCount = ANDROID_SECTION_COUNT + vendorSectionCount;
650 for (size_t i = 0; i < totalSectionCount; ++i) {
651
652 const char *str = (i < ANDROID_SECTION_COUNT) ? camera_metadata_section_names[i] :
653 vendorSections[i - ANDROID_SECTION_COUNT].string();
Igor Murashkinb519cc52013-07-02 11:23:44 -0700654 ALOGVV("%s: Trying to match against section '%s'",
655 __FUNCTION__, str);
656 if (strstr(key, str) == key) { // key begins with the section name
657 size_t strLength = strlen(str);
658
659 ALOGVV("%s: Key begins with section name", __FUNCTION__);
660
661 // section name is the longest we've found so far
662 if (section == NULL || sectionLength < strLength) {
663 section = str;
664 sectionIndex = i;
665 sectionLength = strLength;
666
Ruben Brunk32ef3ae2014-02-21 17:40:51 -0800667 ALOGVV("%s: Found new best section (%s)", __FUNCTION__, section);
Igor Murashkinb519cc52013-07-02 11:23:44 -0700668 }
669 }
670 }
671
Igor Murashkinb519cc52013-07-02 11:23:44 -0700672 // TODO: Make above get_camera_metadata_section_from_name ?
673
674 if (section == NULL) {
675 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
676 "Could not find section name for key '%s')", key);
677 return 0;
678 } else {
679 ALOGV("%s: Found matched section '%s' (%d)",
680 __FUNCTION__, section, sectionIndex);
681 }
682
683 // Get the tag name component of the key
684 const char *keyTagName = key + sectionLength + 1; // x.y.z -> z
685 if (sectionLength + 1 >= keyLength) {
686 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
687 "Key length too short for key '%s')", key);
Ruben Brunk32ef3ae2014-02-21 17:40:51 -0800688 return 0;
Igor Murashkinb519cc52013-07-02 11:23:44 -0700689 }
690
691 // Match rest of name against the tag names in that section only
Ruben Brunk32ef3ae2014-02-21 17:40:51 -0800692 uint32_t tag = 0;
693 if (sectionIndex < ANDROID_SECTION_COUNT) {
694 // Match built-in tags (typically android.*)
695 uint32_t tagBegin, tagEnd; // [tagBegin, tagEnd)
696 tagBegin = camera_metadata_section_bounds[sectionIndex][0];
697 tagEnd = camera_metadata_section_bounds[sectionIndex][1];
Igor Murashkinb519cc52013-07-02 11:23:44 -0700698
Ruben Brunk32ef3ae2014-02-21 17:40:51 -0800699 for (tag = tagBegin; tag < tagEnd; ++tag) {
700 const char *tagName = get_camera_metadata_tag_name(tag);
Igor Murashkinb519cc52013-07-02 11:23:44 -0700701
Ruben Brunk32ef3ae2014-02-21 17:40:51 -0800702 if (strcmp(keyTagName, tagName) == 0) {
703 ALOGV("%s: Found matched tag '%s' (%d)",
704 __FUNCTION__, tagName, tag);
705 break;
706 }
707 }
708
709 if (tag == tagEnd) {
710 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
711 "Could not find tag name for key '%s')", key);
712 return 0;
713 }
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700714 } else if (vTags != NULL) {
Ruben Brunk32ef3ae2014-02-21 17:40:51 -0800715 // Match vendor tags (typically com.*)
716 const String8 sectionName(section);
717 const String8 tagName(keyTagName);
718
719 status_t res = OK;
720 if ((res = vTags->lookupTag(tagName, sectionName, &tag)) != OK) {
721 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
722 "%s: No vendor tag matches key '%s'", __FUNCTION__, key);
723 return 0;
Igor Murashkinb519cc52013-07-02 11:23:44 -0700724 }
725 }
726
Igor Murashkinb519cc52013-07-02 11:23:44 -0700727 // TODO: Make above get_camera_metadata_tag_from_name ?
728
Igor Murashkinb519cc52013-07-02 11:23:44 -0700729 return tag;
730}
731
732static jint CameraMetadata_getTypeFromTag(JNIEnv *env, jobject thiz, jint tag) {
733 int tagType = get_camera_metadata_tag_type(tag);
734 if (tagType == -1) {
735 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
736 "Tag (%d) did not have a type", tag);
737 return -1;
738 }
739
740 return tagType;
741}
742
Ruben Brunk85c43882014-02-21 17:40:51 -0800743static jint CameraMetadata_setupGlobalVendorTagDescriptor(JNIEnv *env, jobject thiz) {
744 const String16 NAME("media.camera");
745 sp<ICameraService> cameraService;
746 status_t err = getService(NAME, /*out*/&cameraService);
747
748 if (err != OK) {
749 ALOGE("%s: Failed to get camera service, received error %s (%d)", __FUNCTION__,
750 strerror(-err), err);
751 return err;
752 }
753
754 sp<VendorTagDescriptor> desc;
755 err = cameraService->getCameraVendorTagDescriptor(/*out*/desc);
756
Igor Murashkin5614cbe2014-03-17 14:00:55 -0700757 if (err == -EOPNOTSUPP) {
758 ALOGW("%s: Camera HAL too old; does not support vendor tags", __FUNCTION__);
759 VendorTagDescriptor::clearGlobalVendorTagDescriptor();
760
761 return OK;
762 } else if (err != OK) {
763 ALOGE("%s: Failed to setup vendor tag descriptors, received error %s (%d)",
764 __FUNCTION__, strerror(-err), err);
Ruben Brunk85c43882014-02-21 17:40:51 -0800765 return err;
766 }
767
768 err = VendorTagDescriptor::setAsGlobalVendorTagDescriptor(desc);
769
770 return err;
771}
772
Igor Murashkin70725502013-06-25 20:27:06 +0000773} // extern "C"