blob: 78a5735279ea1b716956cde39752919da400b8e0 [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 Brunkc620eb72015-07-29 18:19:11 -070026#include <stdio.h>
Ruben Brunk85c43882014-02-21 17:40:51 -080027#include <string.h>
Ruben Brunkc620eb72015-07-29 18:19:11 -070028#include <vector>
Igor Murashkin70725502013-06-25 20:27:06 +000029
30#include "jni.h"
31#include "JNIHelp.h"
32#include "android_os_Parcel.h"
Andreas Gampeed6b9df2014-11-20 22:02:20 -080033#include "core_jni_helpers.h"
Ruben Brunkf967a542014-04-28 16:31:11 -070034#include "android_runtime/android_hardware_camera2_CameraMetadata.h"
Igor Murashkin70725502013-06-25 20:27:06 +000035
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -080036#include <android/hardware/ICameraService.h>
Ruben Brunk85c43882014-02-21 17:40:51 -080037#include <binder/IServiceManager.h>
Igor Murashkin70725502013-06-25 20:27:06 +000038#include <camera/CameraMetadata.h>
Ruben Brunk85c43882014-02-21 17:40:51 -080039#include <camera/VendorTagDescriptor.h>
Igor Murashkinb519cc52013-07-02 11:23:44 -070040#include <nativehelper/ScopedUtfChars.h>
41#include <nativehelper/ScopedPrimitiveArray.h>
42
Igor Murashkind6d65152014-05-19 16:31:02 -070043#include <sys/types.h> // for socketpair
44#include <sys/socket.h> // for socketpair
45
Igor Murashkin70725502013-06-25 20:27:06 +000046// fully-qualified class name
Eino-Ville Talvala70c22072013-08-27 12:09:04 -070047#define CAMERA_METADATA_CLASS_NAME "android/hardware/camera2/impl/CameraMetadataNative"
Ruben Brunkc620eb72015-07-29 18:19:11 -070048#define CHARACTERISTICS_KEY_CLASS_NAME "android/hardware/camera2/CameraCharacteristics$Key"
49#define REQUEST_KEY_CLASS_NAME "android/hardware/camera2/CaptureRequest$Key"
50#define RESULT_KEY_CLASS_NAME "android/hardware/camera2/CaptureResult$Key"
Igor Murashkin70725502013-06-25 20:27:06 +000051
52using namespace android;
53
Ruben Brunkc620eb72015-07-29 18:19:11 -070054static struct metadata_java_key_offsets_t {
55 jclass mCharacteristicsKey;
56 jclass mResultKey;
57 jclass mRequestKey;
58 jmethodID mCharacteristicsConstr;
59 jmethodID mResultConstr;
60 jmethodID mRequestConstr;
61 jclass mByteArray;
62 jclass mInt32Array;
63 jclass mFloatArray;
64 jclass mInt64Array;
65 jclass mDoubleArray;
66 jclass mRationalArray;
67 jclass mArrayList;
68 jmethodID mArrayListConstr;
69 jmethodID mArrayListAdd;
70} gMetadataOffsets;
71
Igor Murashkin70725502013-06-25 20:27:06 +000072struct fields_t {
73 jfieldID metadata_ptr;
74};
75
76static fields_t fields;
77
Ruben Brunkf967a542014-04-28 16:31:11 -070078namespace android {
79
80status_t CameraMetadata_getNativeMetadata(JNIEnv* env, jobject thiz,
81 /*out*/CameraMetadata* metadata) {
82 if (!thiz) {
83 ALOGE("%s: Invalid java metadata object.", __FUNCTION__);
84 return BAD_VALUE;
85 }
86
87 if (!metadata) {
88 ALOGE("%s: Invalid output metadata object.", __FUNCTION__);
89 return BAD_VALUE;
90 }
91 CameraMetadata* nativePtr = reinterpret_cast<CameraMetadata*>(env->GetLongField(thiz,
92 fields.metadata_ptr));
93 if (nativePtr == NULL) {
94 ALOGE("%s: Invalid native pointer in java metadata object.", __FUNCTION__);
95 return BAD_VALUE;
96 }
97 *metadata = *nativePtr;
98 return OK;
99}
100
101} /*namespace android*/
102
Igor Murashkinb519cc52013-07-02 11:23:44 -0700103namespace {
104struct Helpers {
105 static size_t getTypeSize(uint8_t type) {
106 if (type >= NUM_TYPES) {
107 ALOGE("%s: Invalid type specified (%ud)", __FUNCTION__, type);
108 return static_cast<size_t>(-1);
109 }
110
111 return camera_metadata_type_size[type];
112 }
113
114 static status_t updateAny(CameraMetadata *metadata,
115 uint32_t tag,
116 uint32_t type,
117 const void *data,
118 size_t dataBytes) {
119
120 if (type >= NUM_TYPES) {
121 ALOGE("%s: Invalid type specified (%ud)", __FUNCTION__, type);
122 return INVALID_OPERATION;
123 }
124
125 size_t typeSize = getTypeSize(type);
126
127 if (dataBytes % typeSize != 0) {
Dan Albert46d84442014-11-18 16:07:51 -0800128 ALOGE("%s: Expected dataBytes (%zu) to be divisible by typeSize "
129 "(%zu)", __FUNCTION__, dataBytes, typeSize);
Igor Murashkinb519cc52013-07-02 11:23:44 -0700130 return BAD_VALUE;
131 }
132
133 size_t dataCount = dataBytes / typeSize;
134
135 switch(type) {
136#define METADATA_UPDATE(runtime_type, compile_type) \
137 case runtime_type: { \
138 const compile_type *dataPtr = \
139 static_cast<const compile_type*>(data); \
140 return metadata->update(tag, dataPtr, dataCount); \
141 } \
142
143 METADATA_UPDATE(TYPE_BYTE, uint8_t);
144 METADATA_UPDATE(TYPE_INT32, int32_t);
145 METADATA_UPDATE(TYPE_FLOAT, float);
146 METADATA_UPDATE(TYPE_INT64, int64_t);
147 METADATA_UPDATE(TYPE_DOUBLE, double);
148 METADATA_UPDATE(TYPE_RATIONAL, camera_metadata_rational_t);
149
150 default: {
151 // unreachable
152 ALOGE("%s: Unreachable", __FUNCTION__);
153 return INVALID_OPERATION;
154 }
155 }
156
157#undef METADATA_UPDATE
158 }
159};
160} // namespace {}
161
Igor Murashkin70725502013-06-25 20:27:06 +0000162extern "C" {
163
Ruben Brunkc620eb72015-07-29 18:19:11 -0700164static jobject CameraMetadata_getAllVendorKeys(JNIEnv* env, jobject thiz, jclass keyType);
Igor Murashkinb519cc52013-07-02 11:23:44 -0700165static jint CameraMetadata_getTagFromKey(JNIEnv *env, jobject thiz, jstring keyName);
166static jint CameraMetadata_getTypeFromTag(JNIEnv *env, jobject thiz, jint tag);
Ruben Brunk85c43882014-02-21 17:40:51 -0800167static jint CameraMetadata_setupGlobalVendorTagDescriptor(JNIEnv *env, jobject thiz);
Igor Murashkin70725502013-06-25 20:27:06 +0000168
169// Less safe access to native pointer. Does NOT throw any Java exceptions if NULL.
170static CameraMetadata* CameraMetadata_getPointerNoThrow(JNIEnv *env, jobject thiz) {
171
172 if (thiz == NULL) {
173 return NULL;
174 }
175
176 return reinterpret_cast<CameraMetadata*>(env->GetLongField(thiz, fields.metadata_ptr));
177}
178
179// Safe access to native pointer from object. Throws if not possible to access.
180static CameraMetadata* CameraMetadata_getPointerThrow(JNIEnv *env, jobject thiz,
181 const char* argName = "this") {
182
183 if (thiz == NULL) {
184 ALOGV("%s: Throwing java.lang.NullPointerException for null reference",
185 __FUNCTION__);
186 jniThrowNullPointerException(env, argName);
187 return NULL;
188 }
189
190 CameraMetadata* metadata = CameraMetadata_getPointerNoThrow(env, thiz);
191 if (metadata == NULL) {
192 ALOGV("%s: Throwing java.lang.IllegalStateException for closed object",
193 __FUNCTION__);
194 jniThrowException(env, "java/lang/IllegalStateException",
195 "Metadata object was already closed");
196 return NULL;
197 }
198
199 return metadata;
200}
201
202static jlong CameraMetadata_allocate(JNIEnv *env, jobject thiz) {
203 ALOGV("%s", __FUNCTION__);
204
205 return reinterpret_cast<jlong>(new CameraMetadata());
206}
207
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700208static jlong CameraMetadata_allocateCopy(JNIEnv *env, jobject thiz,
209 jobject other) {
210 ALOGV("%s", __FUNCTION__);
211
212 CameraMetadata* otherMetadata =
213 CameraMetadata_getPointerThrow(env, other, "other");
214
215 // In case of exception, return
216 if (otherMetadata == NULL) return NULL;
217
218 // Clone native metadata and return new pointer
219 return reinterpret_cast<jlong>(new CameraMetadata(*otherMetadata));
220}
221
222
Igor Murashkin70725502013-06-25 20:27:06 +0000223static jboolean CameraMetadata_isEmpty(JNIEnv *env, jobject thiz) {
224 ALOGV("%s", __FUNCTION__);
225
226 CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
227
228 if (metadata == NULL) {
229 ALOGW("%s: Returning early due to exception being thrown",
230 __FUNCTION__);
231 return JNI_TRUE; // actually throws java exc.
232 }
233
234 jboolean empty = metadata->isEmpty();
235
Dan Albert46d84442014-11-18 16:07:51 -0800236 ALOGV("%s: Empty returned %d, entry count was %zu",
Igor Murashkin70725502013-06-25 20:27:06 +0000237 __FUNCTION__, empty, metadata->entryCount());
238
239 return empty;
240}
241
242static jint CameraMetadata_getEntryCount(JNIEnv *env, jobject thiz) {
243 ALOGV("%s", __FUNCTION__);
244
245 CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
246
247 if (metadata == NULL) return 0; // actually throws java exc.
248
249 return metadata->entryCount();
250}
251
252// idempotent. calling more than once has no effect.
253static void CameraMetadata_close(JNIEnv *env, jobject thiz) {
254 ALOGV("%s", __FUNCTION__);
255
256 CameraMetadata* metadata = CameraMetadata_getPointerNoThrow(env, thiz);
257
258 if (metadata != NULL) {
259 delete metadata;
260 env->SetLongField(thiz, fields.metadata_ptr, 0);
261 }
262
263 LOG_ALWAYS_FATAL_IF(CameraMetadata_getPointerNoThrow(env, thiz) != NULL,
264 "Expected the native ptr to be 0 after #close");
265}
266
267static void CameraMetadata_swap(JNIEnv *env, jobject thiz, jobject other) {
268 ALOGV("%s", __FUNCTION__);
269
270 CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
271
272 // order is important: we can't call another JNI method
273 // if there is an exception pending
274 if (metadata == NULL) return;
275
276 CameraMetadata* otherMetadata = CameraMetadata_getPointerThrow(env, other, "other");
277
278 if (otherMetadata == NULL) return;
279
280 metadata->swap(*otherMetadata);
281}
282
Igor Murashkinb519cc52013-07-02 11:23:44 -0700283static jbyteArray CameraMetadata_readValues(JNIEnv *env, jobject thiz, jint tag) {
284 ALOGV("%s (tag = %d)", __FUNCTION__, tag);
285
286 CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
287 if (metadata == NULL) return NULL;
288
289 int tagType = get_camera_metadata_tag_type(tag);
290 if (tagType == -1) {
291 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
292 "Tag (%d) did not have a type", tag);
293 return NULL;
294 }
295 size_t tagSize = Helpers::getTypeSize(tagType);
296
297 camera_metadata_entry entry = metadata->find(tag);
298 if (entry.count == 0) {
299 if (!metadata->exists(tag)) {
300 ALOGV("%s: Tag %d does not have any entries", __FUNCTION__, tag);
301 return NULL;
302 } else {
303 // OK: we will return a 0-sized array.
304 ALOGV("%s: Tag %d had an entry, but it had 0 data", __FUNCTION__,
305 tag);
306 }
307 }
308
309 jsize byteCount = entry.count * tagSize;
310 jbyteArray byteArray = env->NewByteArray(byteCount);
311 if (env->ExceptionCheck()) return NULL;
312
313 // Copy into java array from native array
314 ScopedByteArrayRW arrayWriter(env, byteArray);
315 memcpy(arrayWriter.get(), entry.data.u8, byteCount);
316
317 return byteArray;
318}
319
320static void CameraMetadata_writeValues(JNIEnv *env, jobject thiz, jint tag, jbyteArray src) {
321 ALOGV("%s (tag = %d)", __FUNCTION__, tag);
322
323 CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
324 if (metadata == NULL) return;
325
326 int tagType = get_camera_metadata_tag_type(tag);
327 if (tagType == -1) {
328 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
329 "Tag (%d) did not have a type", tag);
330 return;
331 }
Igor Murashkinb519cc52013-07-02 11:23:44 -0700332
333 status_t res;
334
335 if (src == NULL) {
336 // If array is NULL, delete the entry
Igor Murashkin3710db82013-07-18 20:11:17 -0700337 if (metadata->exists(tag)) {
338 res = metadata->erase(tag);
339 ALOGV("%s: Erase values (res = %d)", __FUNCTION__, res);
340 } else {
341 res = OK;
342 ALOGV("%s: Don't need to erase", __FUNCTION__);
343 }
Igor Murashkinb519cc52013-07-02 11:23:44 -0700344 } else {
345 // Copy from java array into native array
346 ScopedByteArrayRO arrayReader(env, src);
347 if (arrayReader.get() == NULL) return;
348
349 res = Helpers::updateAny(metadata, static_cast<uint32_t>(tag),
350 tagType, arrayReader.get(), arrayReader.size());
Igor Murashkin3710db82013-07-18 20:11:17 -0700351
352 ALOGV("%s: Update values (res = %d)", __FUNCTION__, res);
Igor Murashkinb519cc52013-07-02 11:23:44 -0700353 }
354
355 if (res == OK) {
356 return;
357 } else if (res == BAD_VALUE) {
358 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
359 "Src byte array was poorly formed");
360 } else if (res == INVALID_OPERATION) {
361 jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
362 "Internal error while trying to update metadata");
363 } else {
364 jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
365 "Unknown error (%d) while trying to update "
366 "metadata", res);
367 }
368}
369
Igor Murashkind6d65152014-05-19 16:31:02 -0700370struct DumpMetadataParams {
371 int writeFd;
372 const CameraMetadata* metadata;
373};
374
375static void* CameraMetadata_writeMetadataThread(void* arg) {
376 DumpMetadataParams* p = static_cast<DumpMetadataParams*>(arg);
377
378 /*
379 * Write the dumped data, and close the writing side FD.
380 */
381 p->metadata->dump(p->writeFd, /*verbosity*/2);
382
383 if (close(p->writeFd) < 0) {
384 ALOGE("%s: Failed to close writeFd (errno = %#x, message = '%s')",
385 __FUNCTION__, errno, strerror(errno));
386 }
387
388 return NULL;
389}
390
391static void CameraMetadata_dump(JNIEnv *env, jobject thiz) {
392 ALOGV("%s", __FUNCTION__);
393 CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
394 if (metadata == NULL) {
395 return;
396 }
397
398 /*
399 * Create a socket pair for local streaming read/writes.
400 *
401 * The metadata will be dumped into the write side,
402 * and then read back out (and logged) via the read side.
403 */
404
405 int writeFd, readFd;
406 {
407
408 int sv[2];
409 if (socketpair(AF_LOCAL, SOCK_STREAM, /*protocol*/0, &sv[0]) < 0) {
410 jniThrowExceptionFmt(env, "java/io/IOException",
411 "Failed to create socketpair (errno = %#x, message = '%s')",
412 errno, strerror(errno));
413 return;
414 }
415 writeFd = sv[0];
416 readFd = sv[1];
417 }
418
419 /*
420 * Create a thread for doing the writing.
421 *
422 * The reading and writing must be concurrent, otherwise
423 * the write will block forever once it exhausts the capped
424 * buffer size (from getsockopt).
425 */
426 pthread_t writeThread;
427 DumpMetadataParams params = {
428 writeFd,
429 metadata
430 };
431
432 {
433 int threadRet = pthread_create(&writeThread, /*attr*/NULL,
434 CameraMetadata_writeMetadataThread, (void*)&params);
435
436 if (threadRet != 0) {
437 close(writeFd);
438
439 jniThrowExceptionFmt(env, "java/io/IOException",
440 "Failed to create thread for writing (errno = %#x, message = '%s')",
441 threadRet, strerror(threadRet));
442 }
443 }
444
445 /*
446 * Read out a byte until stream is complete. Write completed lines
447 * to ALOG.
448 */
449 {
450 char out[] = {'\0', '\0'}; // large enough to append as a string
451 String8 logLine;
452
453 // Read one byte at a time! Very slow but avoids complicated \n scanning.
454 ssize_t res;
455 while ((res = TEMP_FAILURE_RETRY(read(readFd, &out[0], /*count*/1))) > 0) {
456 if (out[0] == '\n') {
457 ALOGD("%s", logLine.string());
458 logLine.clear();
459 } else {
460 logLine.append(out);
461 }
462 }
463
464 if (res < 0) {
465 jniThrowExceptionFmt(env, "java/io/IOException",
466 "Failed to read from fd (errno = %#x, message = '%s')",
467 errno, strerror(errno));
468 //return;
469 } else if (!logLine.isEmpty()) {
470 ALOGD("%s", logLine.string());
471 }
472 }
473
474 int res;
475
476 // Join until thread finishes. Ensures params/metadata is valid until then.
477 if ((res = pthread_join(writeThread, /*retval*/NULL)) != 0) {
478 ALOGE("%s: Failed to join thread (errno = %#x, message = '%s')",
479 __FUNCTION__, res, strerror(res));
480 }
481}
482
Igor Murashkin70725502013-06-25 20:27:06 +0000483static void CameraMetadata_readFromParcel(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->readFromParcel(parcelNative)) != OK) {
498 jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
499 "Failed to read from parcel (error code %d)", err);
500 return;
501 }
502}
503
504static void CameraMetadata_writeToParcel(JNIEnv *env, jobject thiz, jobject parcel) {
505 ALOGV("%s", __FUNCTION__);
506 CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
507 if (metadata == NULL) {
508 return;
509 }
510
511 Parcel* parcelNative = parcelForJavaObject(env, parcel);
512 if (parcelNative == NULL) {
513 jniThrowNullPointerException(env, "parcel");
514 return;
515 }
516
517 status_t err;
518 if ((err = metadata->writeToParcel(parcelNative)) != OK) {
519 jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
520 "Failed to write to parcel (error code %d)", err);
521 return;
522 }
523}
524
525} // extern "C"
526
527//-------------------------------------------------
528
Daniel Micay76f6a862015-09-19 17:31:01 -0400529static const JNINativeMethod gCameraMetadataMethods[] = {
Igor Murashkinb519cc52013-07-02 11:23:44 -0700530// static methods
Ruben Brunkc620eb72015-07-29 18:19:11 -0700531 { "nativeGetAllVendorKeys",
532 "(Ljava/lang/Class;)Ljava/util/ArrayList;",
533 (void *)CameraMetadata_getAllVendorKeys},
Igor Murashkinb519cc52013-07-02 11:23:44 -0700534 { "nativeGetTagFromKey",
535 "(Ljava/lang/String;)I",
536 (void *)CameraMetadata_getTagFromKey },
537 { "nativeGetTypeFromTag",
538 "(I)I",
539 (void *)CameraMetadata_getTypeFromTag },
Ruben Brunk85c43882014-02-21 17:40:51 -0800540 { "nativeSetupGlobalVendorTagDescriptor",
541 "()I",
542 (void*)CameraMetadata_setupGlobalVendorTagDescriptor },
Igor Murashkinb519cc52013-07-02 11:23:44 -0700543// instance methods
Igor Murashkin70725502013-06-25 20:27:06 +0000544 { "nativeAllocate",
545 "()J",
546 (void*)CameraMetadata_allocate },
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700547 { "nativeAllocateCopy",
548 "(L" CAMERA_METADATA_CLASS_NAME ";)J",
549 (void *)CameraMetadata_allocateCopy },
Igor Murashkin70725502013-06-25 20:27:06 +0000550 { "nativeIsEmpty",
551 "()Z",
552 (void*)CameraMetadata_isEmpty },
553 { "nativeGetEntryCount",
554 "()I",
555 (void*)CameraMetadata_getEntryCount },
556 { "nativeClose",
557 "()V",
558 (void*)CameraMetadata_close },
559 { "nativeSwap",
560 "(L" CAMERA_METADATA_CLASS_NAME ";)V",
561 (void *)CameraMetadata_swap },
Igor Murashkinb519cc52013-07-02 11:23:44 -0700562 { "nativeReadValues",
563 "(I)[B",
564 (void *)CameraMetadata_readValues },
565 { "nativeWriteValues",
566 "(I[B)V",
567 (void *)CameraMetadata_writeValues },
Igor Murashkind6d65152014-05-19 16:31:02 -0700568 { "nativeDump",
569 "()V",
570 (void *)CameraMetadata_dump },
Igor Murashkinb519cc52013-07-02 11:23:44 -0700571// Parcelable interface
Igor Murashkin70725502013-06-25 20:27:06 +0000572 { "nativeReadFromParcel",
573 "(Landroid/os/Parcel;)V",
574 (void *)CameraMetadata_readFromParcel },
575 { "nativeWriteToParcel",
576 "(Landroid/os/Parcel;)V",
577 (void *)CameraMetadata_writeToParcel },
578};
579
Igor Murashkin70725502013-06-25 20:27:06 +0000580// Get all the required offsets in java class and register native functions
Eino-Ville Talvala2f1a2e42013-07-25 17:12:05 -0700581int register_android_hardware_camera2_CameraMetadata(JNIEnv *env)
Igor Murashkin70725502013-06-25 20:27:06 +0000582{
Ruben Brunkc620eb72015-07-29 18:19:11 -0700583
584 // Store global references to Key-related classes and methods used natively
585 jclass characteristicsKeyClazz = FindClassOrDie(env, CHARACTERISTICS_KEY_CLASS_NAME);
586 jclass requestKeyClazz = FindClassOrDie(env, REQUEST_KEY_CLASS_NAME);
587 jclass resultKeyClazz = FindClassOrDie(env, RESULT_KEY_CLASS_NAME);
588 gMetadataOffsets.mCharacteristicsKey = MakeGlobalRefOrDie(env, characteristicsKeyClazz);
589 gMetadataOffsets.mRequestKey = MakeGlobalRefOrDie(env, requestKeyClazz);
590 gMetadataOffsets.mResultKey = MakeGlobalRefOrDie(env, resultKeyClazz);
591 gMetadataOffsets.mCharacteristicsConstr = GetMethodIDOrDie(env,
592 gMetadataOffsets.mCharacteristicsKey, "<init>",
593 "(Ljava/lang/String;Ljava/lang/Class;)V");
594 gMetadataOffsets.mRequestConstr = GetMethodIDOrDie(env,
595 gMetadataOffsets.mRequestKey, "<init>", "(Ljava/lang/String;Ljava/lang/Class;)V");
596 gMetadataOffsets.mResultConstr = GetMethodIDOrDie(env,
597 gMetadataOffsets.mResultKey, "<init>", "(Ljava/lang/String;Ljava/lang/Class;)V");
598
599 // Store global references for primitive array types used by Keys
600 jclass byteClazz = FindClassOrDie(env, "[B");
601 jclass int32Clazz = FindClassOrDie(env, "[I");
602 jclass floatClazz = FindClassOrDie(env, "[F");
603 jclass int64Clazz = FindClassOrDie(env, "[J");
604 jclass doubleClazz = FindClassOrDie(env, "[D");
605 jclass rationalClazz = FindClassOrDie(env, "[Landroid/util/Rational;");
606 gMetadataOffsets.mByteArray = MakeGlobalRefOrDie(env, byteClazz);
607 gMetadataOffsets.mInt32Array = MakeGlobalRefOrDie(env, int32Clazz);
608 gMetadataOffsets.mFloatArray = MakeGlobalRefOrDie(env, floatClazz);
609 gMetadataOffsets.mInt64Array = MakeGlobalRefOrDie(env, int64Clazz);
610 gMetadataOffsets.mDoubleArray = MakeGlobalRefOrDie(env, doubleClazz);
611 gMetadataOffsets.mRationalArray = MakeGlobalRefOrDie(env, rationalClazz);
612
613 // Store global references for ArrayList methods used
614 jclass arrayListClazz = FindClassOrDie(env, "java/util/ArrayList");
615 gMetadataOffsets.mArrayList = MakeGlobalRefOrDie(env, arrayListClazz);
616 gMetadataOffsets.mArrayListConstr = GetMethodIDOrDie(env, gMetadataOffsets.mArrayList,
617 "<init>", "(I)V");
618 gMetadataOffsets.mArrayListAdd = GetMethodIDOrDie(env, gMetadataOffsets.mArrayList,
619 "add", "(Ljava/lang/Object;)Z");
620
Andreas Gampe08e6c342017-02-16 15:10:20 -0800621 jclass cameraMetadataClazz = FindClassOrDie(env, CAMERA_METADATA_CLASS_NAME);
622 fields.metadata_ptr = GetFieldIDOrDie(env, cameraMetadataClazz, "mMetadataPtr", "J");
623
Igor Murashkin70725502013-06-25 20:27:06 +0000624 // Register native functions
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800625 return RegisterMethodsOrDie(env,
Igor Murashkin70725502013-06-25 20:27:06 +0000626 CAMERA_METADATA_CLASS_NAME,
627 gCameraMetadataMethods,
628 NELEM(gCameraMetadataMethods));
629}
630
631extern "C" {
Ruben Brunkc620eb72015-07-29 18:19:11 -0700632
Ruben Brunkc620eb72015-07-29 18:19:11 -0700633static jobject CameraMetadata_getAllVendorKeys(JNIEnv* env, jobject thiz, jclass keyType) {
634
635 // Get all vendor tags
636 sp<VendorTagDescriptor> vTags = VendorTagDescriptor::getGlobalVendorTagDescriptor();
637 if (vTags.get() == nullptr) {
638 // No vendor tags.
639 return NULL;
640 }
641
642 int count = vTags->getTagCount();
643 if (count <= 0) {
644 // No vendor tags.
645 return NULL;
646 }
647
648 std::vector<uint32_t> tagIds(count, /*initializer value*/0);
649 vTags->getTagArray(&tagIds[0]);
650
651 // Which key class/constructor should we use?
652 jclass keyClazz;
653 jmethodID keyConstr;
654 if (env->IsSameObject(keyType, gMetadataOffsets.mCharacteristicsKey)) {
655 keyClazz = gMetadataOffsets.mCharacteristicsKey;
656 keyConstr = gMetadataOffsets.mCharacteristicsConstr;
657 } else if (env->IsSameObject(keyType, gMetadataOffsets.mResultKey)) {
658 keyClazz = gMetadataOffsets.mResultKey;
659 keyConstr = gMetadataOffsets.mResultConstr;
660 } else if (env->IsSameObject(keyType, gMetadataOffsets.mRequestKey)) {
661 keyClazz = gMetadataOffsets.mRequestKey;
662 keyConstr = gMetadataOffsets.mRequestConstr;
663 } else {
664 jniThrowException(env, "java/lang/IllegalArgumentException",
665 "Invalid key class given as argument.");
666 return NULL;
667 }
668
669 // Allocate arrayList to return
670 jobject arrayList = env->NewObject(gMetadataOffsets.mArrayList,
671 gMetadataOffsets.mArrayListConstr, static_cast<jint>(count));
672 if (env->ExceptionCheck()) {
673 return NULL;
674 }
675
676 for (uint32_t id : tagIds) {
677 const char* section = vTags->getSectionName(id);
678 const char* tag = vTags->getTagName(id);
679 int type = vTags->getTagType(id);
680
681 size_t totalLen = strlen(section) + strlen(tag) + 2;
682 std::vector<char> fullName(totalLen, 0);
683 snprintf(&fullName[0], totalLen, "%s.%s", section, tag);
684
685 jstring name = env->NewStringUTF(&fullName[0]);
686
687 if (env->ExceptionCheck()) {
688 return NULL;
689 }
690
691 jclass valueClazz;
692 switch (type) {
693 case TYPE_BYTE:
694 valueClazz = gMetadataOffsets.mByteArray;
695 break;
696 case TYPE_INT32:
697 valueClazz = gMetadataOffsets.mInt32Array;
698 break;
699 case TYPE_FLOAT:
700 valueClazz = gMetadataOffsets.mFloatArray;
701 break;
702 case TYPE_INT64:
703 valueClazz = gMetadataOffsets.mInt64Array;
704 break;
705 case TYPE_DOUBLE:
706 valueClazz = gMetadataOffsets.mDoubleArray;
707 break;
708 case TYPE_RATIONAL:
709 valueClazz = gMetadataOffsets.mRationalArray;
710 break;
711 default:
712 jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
713 "Invalid type %d given for key %s", type, &fullName[0]);
714 return NULL;
715 }
716
717 jobject key = env->NewObject(keyClazz, keyConstr, name, valueClazz);
718 if (env->ExceptionCheck()) {
719 return NULL;
720 }
721
722 env->CallBooleanMethod(arrayList, gMetadataOffsets.mArrayListAdd, key);
723 if (env->ExceptionCheck()) {
724 return NULL;
725 }
726
727 env->DeleteLocalRef(name);
728 env->DeleteLocalRef(key);
729 }
730
731 return arrayList;
732}
733
Igor Murashkinb519cc52013-07-02 11:23:44 -0700734static jint CameraMetadata_getTagFromKey(JNIEnv *env, jobject thiz, jstring keyName) {
735
736 ScopedUtfChars keyScoped(env, keyName);
737 const char *key = keyScoped.c_str();
738 if (key == NULL) {
739 // exception thrown by ScopedUtfChars
740 return 0;
741 }
Igor Murashkinb519cc52013-07-02 11:23:44 -0700742 ALOGV("%s (key = '%s')", __FUNCTION__, key);
743
Ruben Brunk32ef3ae2014-02-21 17:40:51 -0800744 uint32_t tag = 0;
Eino-Ville Talvala376e24a2016-07-15 11:59:51 -0700745 sp<VendorTagDescriptor> vTags =
746 VendorTagDescriptor::getGlobalVendorTagDescriptor();
747 status_t res = CameraMetadata::getTagFromName(key, vTags.get(), &tag);
748 if (res != OK) {
749 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
750 "Could not find tag for key '%s')", key);
Igor Murashkinb519cc52013-07-02 11:23:44 -0700751 }
Igor Murashkinb519cc52013-07-02 11:23:44 -0700752 return tag;
753}
754
755static jint CameraMetadata_getTypeFromTag(JNIEnv *env, jobject thiz, jint tag) {
756 int tagType = get_camera_metadata_tag_type(tag);
757 if (tagType == -1) {
758 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
759 "Tag (%d) did not have a type", tag);
760 return -1;
761 }
762
763 return tagType;
764}
765
Ruben Brunk85c43882014-02-21 17:40:51 -0800766static jint CameraMetadata_setupGlobalVendorTagDescriptor(JNIEnv *env, jobject thiz) {
767 const String16 NAME("media.camera");
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800768 sp<hardware::ICameraService> cameraService;
Ruben Brunk85c43882014-02-21 17:40:51 -0800769 status_t err = getService(NAME, /*out*/&cameraService);
770
771 if (err != OK) {
772 ALOGE("%s: Failed to get camera service, received error %s (%d)", __FUNCTION__,
773 strerror(-err), err);
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800774 return hardware::ICameraService::ERROR_DISCONNECTED;
Ruben Brunk85c43882014-02-21 17:40:51 -0800775 }
776
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800777 sp<VendorTagDescriptor> desc = new VendorTagDescriptor();
778 binder::Status res = cameraService->getCameraVendorTagDescriptor(/*out*/desc.get());
Ruben Brunk85c43882014-02-21 17:40:51 -0800779
Eino-Ville Talvala5f2f8042016-03-03 11:50:39 -0800780 if (res.serviceSpecificErrorCode() == hardware::ICameraService::ERROR_DISCONNECTED) {
781 // No camera module available, not an error on devices with no cameras
Igor Murashkin5614cbe2014-03-17 14:00:55 -0700782 VendorTagDescriptor::clearGlobalVendorTagDescriptor();
Igor Murashkin5614cbe2014-03-17 14:00:55 -0700783 return OK;
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800784 } else if (!res.isOk()) {
Eino-Ville Talvala5f2f8042016-03-03 11:50:39 -0800785 VendorTagDescriptor::clearGlobalVendorTagDescriptor();
786 ALOGE("%s: Failed to setup vendor tag descriptors: %s",
787 __FUNCTION__, res.toString8().string());
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800788 return res.serviceSpecificErrorCode();
Ruben Brunk85c43882014-02-21 17:40:51 -0800789 }
790
791 err = VendorTagDescriptor::setAsGlobalVendorTagDescriptor(desc);
792
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800793 if (err != OK) {
794 return hardware::ICameraService::ERROR_INVALID_OPERATION;
795 }
796 return OK;
Ruben Brunk85c43882014-02-21 17:40:51 -0800797}
798
Igor Murashkin70725502013-06-25 20:27:06 +0000799} // extern "C"