blob: 45e7c07758a8b548317d4d5d3c650416ba1ca1f3 [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"
Steven Moreland2279b252017-07-19 09:50:45 -070031#include <nativehelper/JNIHelp.h>
Igor Murashkin70725502013-06-25 20:27:06 +000032#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
164static void CameraMetadata_classInit(JNIEnv *env, jobject thiz);
Ruben Brunkc620eb72015-07-29 18:19:11 -0700165static jobject CameraMetadata_getAllVendorKeys(JNIEnv* env, jobject thiz, jclass keyType);
Igor Murashkinb519cc52013-07-02 11:23:44 -0700166static jint CameraMetadata_getTagFromKey(JNIEnv *env, jobject thiz, jstring keyName);
167static jint CameraMetadata_getTypeFromTag(JNIEnv *env, jobject thiz, jint tag);
Ruben Brunk85c43882014-02-21 17:40:51 -0800168static jint CameraMetadata_setupGlobalVendorTagDescriptor(JNIEnv *env, jobject thiz);
Igor Murashkin70725502013-06-25 20:27:06 +0000169
170// Less safe access to native pointer. Does NOT throw any Java exceptions if NULL.
171static CameraMetadata* CameraMetadata_getPointerNoThrow(JNIEnv *env, jobject thiz) {
172
173 if (thiz == NULL) {
174 return NULL;
175 }
176
177 return reinterpret_cast<CameraMetadata*>(env->GetLongField(thiz, fields.metadata_ptr));
178}
179
180// Safe access to native pointer from object. Throws if not possible to access.
181static CameraMetadata* CameraMetadata_getPointerThrow(JNIEnv *env, jobject thiz,
182 const char* argName = "this") {
183
184 if (thiz == NULL) {
185 ALOGV("%s: Throwing java.lang.NullPointerException for null reference",
186 __FUNCTION__);
187 jniThrowNullPointerException(env, argName);
188 return NULL;
189 }
190
191 CameraMetadata* metadata = CameraMetadata_getPointerNoThrow(env, thiz);
192 if (metadata == NULL) {
193 ALOGV("%s: Throwing java.lang.IllegalStateException for closed object",
194 __FUNCTION__);
195 jniThrowException(env, "java/lang/IllegalStateException",
196 "Metadata object was already closed");
197 return NULL;
198 }
199
200 return metadata;
201}
202
203static jlong CameraMetadata_allocate(JNIEnv *env, jobject thiz) {
204 ALOGV("%s", __FUNCTION__);
205
206 return reinterpret_cast<jlong>(new CameraMetadata());
207}
208
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700209static jlong CameraMetadata_allocateCopy(JNIEnv *env, jobject thiz,
210 jobject other) {
211 ALOGV("%s", __FUNCTION__);
212
213 CameraMetadata* otherMetadata =
214 CameraMetadata_getPointerThrow(env, other, "other");
215
216 // In case of exception, return
217 if (otherMetadata == NULL) return NULL;
218
219 // Clone native metadata and return new pointer
220 return reinterpret_cast<jlong>(new CameraMetadata(*otherMetadata));
221}
222
223
Igor Murashkin70725502013-06-25 20:27:06 +0000224static jboolean CameraMetadata_isEmpty(JNIEnv *env, jobject thiz) {
225 ALOGV("%s", __FUNCTION__);
226
227 CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
228
229 if (metadata == NULL) {
230 ALOGW("%s: Returning early due to exception being thrown",
231 __FUNCTION__);
232 return JNI_TRUE; // actually throws java exc.
233 }
234
235 jboolean empty = metadata->isEmpty();
236
Dan Albert46d84442014-11-18 16:07:51 -0800237 ALOGV("%s: Empty returned %d, entry count was %zu",
Igor Murashkin70725502013-06-25 20:27:06 +0000238 __FUNCTION__, empty, metadata->entryCount());
239
240 return empty;
241}
242
243static jint CameraMetadata_getEntryCount(JNIEnv *env, jobject thiz) {
244 ALOGV("%s", __FUNCTION__);
245
246 CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
247
248 if (metadata == NULL) return 0; // actually throws java exc.
249
250 return metadata->entryCount();
251}
252
253// idempotent. calling more than once has no effect.
254static void CameraMetadata_close(JNIEnv *env, jobject thiz) {
255 ALOGV("%s", __FUNCTION__);
256
257 CameraMetadata* metadata = CameraMetadata_getPointerNoThrow(env, thiz);
258
259 if (metadata != NULL) {
260 delete metadata;
261 env->SetLongField(thiz, fields.metadata_ptr, 0);
262 }
263
264 LOG_ALWAYS_FATAL_IF(CameraMetadata_getPointerNoThrow(env, thiz) != NULL,
265 "Expected the native ptr to be 0 after #close");
266}
267
268static void CameraMetadata_swap(JNIEnv *env, jobject thiz, jobject other) {
269 ALOGV("%s", __FUNCTION__);
270
271 CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
272
273 // order is important: we can't call another JNI method
274 // if there is an exception pending
275 if (metadata == NULL) return;
276
277 CameraMetadata* otherMetadata = CameraMetadata_getPointerThrow(env, other, "other");
278
279 if (otherMetadata == NULL) return;
280
281 metadata->swap(*otherMetadata);
282}
283
Igor Murashkinb519cc52013-07-02 11:23:44 -0700284static jbyteArray CameraMetadata_readValues(JNIEnv *env, jobject thiz, jint tag) {
285 ALOGV("%s (tag = %d)", __FUNCTION__, tag);
286
287 CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
288 if (metadata == NULL) return NULL;
289
290 int tagType = get_camera_metadata_tag_type(tag);
291 if (tagType == -1) {
292 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
293 "Tag (%d) did not have a type", tag);
294 return NULL;
295 }
296 size_t tagSize = Helpers::getTypeSize(tagType);
297
298 camera_metadata_entry entry = metadata->find(tag);
299 if (entry.count == 0) {
300 if (!metadata->exists(tag)) {
301 ALOGV("%s: Tag %d does not have any entries", __FUNCTION__, tag);
302 return NULL;
303 } else {
304 // OK: we will return a 0-sized array.
305 ALOGV("%s: Tag %d had an entry, but it had 0 data", __FUNCTION__,
306 tag);
307 }
308 }
309
310 jsize byteCount = entry.count * tagSize;
311 jbyteArray byteArray = env->NewByteArray(byteCount);
312 if (env->ExceptionCheck()) return NULL;
313
314 // Copy into java array from native array
315 ScopedByteArrayRW arrayWriter(env, byteArray);
316 memcpy(arrayWriter.get(), entry.data.u8, byteCount);
317
318 return byteArray;
319}
320
321static void CameraMetadata_writeValues(JNIEnv *env, jobject thiz, jint tag, jbyteArray src) {
322 ALOGV("%s (tag = %d)", __FUNCTION__, tag);
323
324 CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
325 if (metadata == NULL) return;
326
327 int tagType = get_camera_metadata_tag_type(tag);
328 if (tagType == -1) {
329 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
330 "Tag (%d) did not have a type", tag);
331 return;
332 }
Igor Murashkinb519cc52013-07-02 11:23:44 -0700333
334 status_t res;
335
336 if (src == NULL) {
337 // If array is NULL, delete the entry
Igor Murashkin3710db82013-07-18 20:11:17 -0700338 if (metadata->exists(tag)) {
339 res = metadata->erase(tag);
340 ALOGV("%s: Erase values (res = %d)", __FUNCTION__, res);
341 } else {
342 res = OK;
343 ALOGV("%s: Don't need to erase", __FUNCTION__);
344 }
Igor Murashkinb519cc52013-07-02 11:23:44 -0700345 } else {
346 // Copy from java array into native array
347 ScopedByteArrayRO arrayReader(env, src);
348 if (arrayReader.get() == NULL) return;
349
350 res = Helpers::updateAny(metadata, static_cast<uint32_t>(tag),
351 tagType, arrayReader.get(), arrayReader.size());
Igor Murashkin3710db82013-07-18 20:11:17 -0700352
353 ALOGV("%s: Update values (res = %d)", __FUNCTION__, res);
Igor Murashkinb519cc52013-07-02 11:23:44 -0700354 }
355
356 if (res == OK) {
357 return;
358 } else if (res == BAD_VALUE) {
359 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
360 "Src byte array was poorly formed");
361 } else if (res == INVALID_OPERATION) {
362 jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
363 "Internal error while trying to update metadata");
364 } else {
365 jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
366 "Unknown error (%d) while trying to update "
367 "metadata", res);
368 }
369}
370
Igor Murashkind6d65152014-05-19 16:31:02 -0700371struct DumpMetadataParams {
372 int writeFd;
373 const CameraMetadata* metadata;
374};
375
376static void* CameraMetadata_writeMetadataThread(void* arg) {
377 DumpMetadataParams* p = static_cast<DumpMetadataParams*>(arg);
378
379 /*
380 * Write the dumped data, and close the writing side FD.
381 */
382 p->metadata->dump(p->writeFd, /*verbosity*/2);
383
384 if (close(p->writeFd) < 0) {
385 ALOGE("%s: Failed to close writeFd (errno = %#x, message = '%s')",
386 __FUNCTION__, errno, strerror(errno));
387 }
388
389 return NULL;
390}
391
392static void CameraMetadata_dump(JNIEnv *env, jobject thiz) {
393 ALOGV("%s", __FUNCTION__);
394 CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
395 if (metadata == NULL) {
396 return;
397 }
398
399 /*
400 * Create a socket pair for local streaming read/writes.
401 *
402 * The metadata will be dumped into the write side,
403 * and then read back out (and logged) via the read side.
404 */
405
406 int writeFd, readFd;
407 {
408
409 int sv[2];
410 if (socketpair(AF_LOCAL, SOCK_STREAM, /*protocol*/0, &sv[0]) < 0) {
411 jniThrowExceptionFmt(env, "java/io/IOException",
412 "Failed to create socketpair (errno = %#x, message = '%s')",
413 errno, strerror(errno));
414 return;
415 }
416 writeFd = sv[0];
417 readFd = sv[1];
418 }
419
420 /*
421 * Create a thread for doing the writing.
422 *
423 * The reading and writing must be concurrent, otherwise
424 * the write will block forever once it exhausts the capped
425 * buffer size (from getsockopt).
426 */
427 pthread_t writeThread;
428 DumpMetadataParams params = {
429 writeFd,
430 metadata
431 };
432
433 {
434 int threadRet = pthread_create(&writeThread, /*attr*/NULL,
435 CameraMetadata_writeMetadataThread, (void*)&params);
436
437 if (threadRet != 0) {
438 close(writeFd);
439
440 jniThrowExceptionFmt(env, "java/io/IOException",
441 "Failed to create thread for writing (errno = %#x, message = '%s')",
442 threadRet, strerror(threadRet));
443 }
444 }
445
446 /*
447 * Read out a byte until stream is complete. Write completed lines
448 * to ALOG.
449 */
450 {
451 char out[] = {'\0', '\0'}; // large enough to append as a string
452 String8 logLine;
453
454 // Read one byte at a time! Very slow but avoids complicated \n scanning.
455 ssize_t res;
456 while ((res = TEMP_FAILURE_RETRY(read(readFd, &out[0], /*count*/1))) > 0) {
457 if (out[0] == '\n') {
458 ALOGD("%s", logLine.string());
459 logLine.clear();
460 } else {
461 logLine.append(out);
462 }
463 }
464
465 if (res < 0) {
466 jniThrowExceptionFmt(env, "java/io/IOException",
467 "Failed to read from fd (errno = %#x, message = '%s')",
468 errno, strerror(errno));
469 //return;
470 } else if (!logLine.isEmpty()) {
471 ALOGD("%s", logLine.string());
472 }
473 }
474
475 int res;
476
477 // Join until thread finishes. Ensures params/metadata is valid until then.
478 if ((res = pthread_join(writeThread, /*retval*/NULL)) != 0) {
479 ALOGE("%s: Failed to join thread (errno = %#x, message = '%s')",
480 __FUNCTION__, res, strerror(res));
481 }
482}
483
Igor Murashkin70725502013-06-25 20:27:06 +0000484static void CameraMetadata_readFromParcel(JNIEnv *env, jobject thiz, jobject parcel) {
485 ALOGV("%s", __FUNCTION__);
486 CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
487 if (metadata == NULL) {
488 return;
489 }
490
491 Parcel* parcelNative = parcelForJavaObject(env, parcel);
492 if (parcelNative == NULL) {
493 jniThrowNullPointerException(env, "parcel");
494 return;
495 }
496
497 status_t err;
498 if ((err = metadata->readFromParcel(parcelNative)) != OK) {
499 jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
500 "Failed to read from parcel (error code %d)", err);
501 return;
502 }
503}
504
505static void CameraMetadata_writeToParcel(JNIEnv *env, jobject thiz, jobject parcel) {
506 ALOGV("%s", __FUNCTION__);
507 CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
508 if (metadata == NULL) {
509 return;
510 }
511
512 Parcel* parcelNative = parcelForJavaObject(env, parcel);
513 if (parcelNative == NULL) {
514 jniThrowNullPointerException(env, "parcel");
515 return;
516 }
517
518 status_t err;
519 if ((err = metadata->writeToParcel(parcelNative)) != OK) {
520 jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
521 "Failed to write to parcel (error code %d)", err);
522 return;
523 }
524}
525
526} // extern "C"
527
528//-------------------------------------------------
529
Daniel Micay76f6a862015-09-19 17:31:01 -0400530static const JNINativeMethod gCameraMetadataMethods[] = {
Igor Murashkinb519cc52013-07-02 11:23:44 -0700531// static methods
Igor Murashkin70725502013-06-25 20:27:06 +0000532 { "nativeClassInit",
533 "()V",
534 (void *)CameraMetadata_classInit },
Ruben Brunkc620eb72015-07-29 18:19:11 -0700535 { "nativeGetAllVendorKeys",
536 "(Ljava/lang/Class;)Ljava/util/ArrayList;",
537 (void *)CameraMetadata_getAllVendorKeys},
Igor Murashkinb519cc52013-07-02 11:23:44 -0700538 { "nativeGetTagFromKey",
539 "(Ljava/lang/String;)I",
540 (void *)CameraMetadata_getTagFromKey },
541 { "nativeGetTypeFromTag",
542 "(I)I",
543 (void *)CameraMetadata_getTypeFromTag },
Ruben Brunk85c43882014-02-21 17:40:51 -0800544 { "nativeSetupGlobalVendorTagDescriptor",
545 "()I",
546 (void*)CameraMetadata_setupGlobalVendorTagDescriptor },
Igor Murashkinb519cc52013-07-02 11:23:44 -0700547// instance methods
Igor Murashkin70725502013-06-25 20:27:06 +0000548 { "nativeAllocate",
549 "()J",
550 (void*)CameraMetadata_allocate },
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700551 { "nativeAllocateCopy",
552 "(L" CAMERA_METADATA_CLASS_NAME ";)J",
553 (void *)CameraMetadata_allocateCopy },
Igor Murashkin70725502013-06-25 20:27:06 +0000554 { "nativeIsEmpty",
555 "()Z",
556 (void*)CameraMetadata_isEmpty },
557 { "nativeGetEntryCount",
558 "()I",
559 (void*)CameraMetadata_getEntryCount },
560 { "nativeClose",
561 "()V",
562 (void*)CameraMetadata_close },
563 { "nativeSwap",
564 "(L" CAMERA_METADATA_CLASS_NAME ";)V",
565 (void *)CameraMetadata_swap },
Igor Murashkinb519cc52013-07-02 11:23:44 -0700566 { "nativeReadValues",
567 "(I)[B",
568 (void *)CameraMetadata_readValues },
569 { "nativeWriteValues",
570 "(I[B)V",
571 (void *)CameraMetadata_writeValues },
Igor Murashkind6d65152014-05-19 16:31:02 -0700572 { "nativeDump",
573 "()V",
574 (void *)CameraMetadata_dump },
Igor Murashkinb519cc52013-07-02 11:23:44 -0700575// Parcelable interface
Igor Murashkin70725502013-06-25 20:27:06 +0000576 { "nativeReadFromParcel",
577 "(Landroid/os/Parcel;)V",
578 (void *)CameraMetadata_readFromParcel },
579 { "nativeWriteToParcel",
580 "(Landroid/os/Parcel;)V",
581 (void *)CameraMetadata_writeToParcel },
582};
583
584struct field {
585 const char *class_name;
586 const char *field_name;
587 const char *field_type;
588 jfieldID *jfield;
589};
590
591static int find_fields(JNIEnv *env, field *fields, int count)
592{
593 for (int i = 0; i < count; i++) {
594 field *f = &fields[i];
595 jclass clazz = env->FindClass(f->class_name);
596 if (clazz == NULL) {
597 ALOGE("Can't find %s", f->class_name);
598 return -1;
599 }
600
601 jfieldID field = env->GetFieldID(clazz, f->field_name, f->field_type);
602 if (field == NULL) {
603 ALOGE("Can't find %s.%s", f->class_name, f->field_name);
604 return -1;
605 }
606
607 *(f->jfield) = field;
608 }
609
610 return 0;
611}
612
613// Get all the required offsets in java class and register native functions
Eino-Ville Talvala2f1a2e42013-07-25 17:12:05 -0700614int register_android_hardware_camera2_CameraMetadata(JNIEnv *env)
Igor Murashkin70725502013-06-25 20:27:06 +0000615{
Ruben Brunkc620eb72015-07-29 18:19:11 -0700616
617 // Store global references to Key-related classes and methods used natively
618 jclass characteristicsKeyClazz = FindClassOrDie(env, CHARACTERISTICS_KEY_CLASS_NAME);
619 jclass requestKeyClazz = FindClassOrDie(env, REQUEST_KEY_CLASS_NAME);
620 jclass resultKeyClazz = FindClassOrDie(env, RESULT_KEY_CLASS_NAME);
621 gMetadataOffsets.mCharacteristicsKey = MakeGlobalRefOrDie(env, characteristicsKeyClazz);
622 gMetadataOffsets.mRequestKey = MakeGlobalRefOrDie(env, requestKeyClazz);
623 gMetadataOffsets.mResultKey = MakeGlobalRefOrDie(env, resultKeyClazz);
624 gMetadataOffsets.mCharacteristicsConstr = GetMethodIDOrDie(env,
625 gMetadataOffsets.mCharacteristicsKey, "<init>",
626 "(Ljava/lang/String;Ljava/lang/Class;)V");
627 gMetadataOffsets.mRequestConstr = GetMethodIDOrDie(env,
628 gMetadataOffsets.mRequestKey, "<init>", "(Ljava/lang/String;Ljava/lang/Class;)V");
629 gMetadataOffsets.mResultConstr = GetMethodIDOrDie(env,
630 gMetadataOffsets.mResultKey, "<init>", "(Ljava/lang/String;Ljava/lang/Class;)V");
631
632 // Store global references for primitive array types used by Keys
633 jclass byteClazz = FindClassOrDie(env, "[B");
634 jclass int32Clazz = FindClassOrDie(env, "[I");
635 jclass floatClazz = FindClassOrDie(env, "[F");
636 jclass int64Clazz = FindClassOrDie(env, "[J");
637 jclass doubleClazz = FindClassOrDie(env, "[D");
638 jclass rationalClazz = FindClassOrDie(env, "[Landroid/util/Rational;");
639 gMetadataOffsets.mByteArray = MakeGlobalRefOrDie(env, byteClazz);
640 gMetadataOffsets.mInt32Array = MakeGlobalRefOrDie(env, int32Clazz);
641 gMetadataOffsets.mFloatArray = MakeGlobalRefOrDie(env, floatClazz);
642 gMetadataOffsets.mInt64Array = MakeGlobalRefOrDie(env, int64Clazz);
643 gMetadataOffsets.mDoubleArray = MakeGlobalRefOrDie(env, doubleClazz);
644 gMetadataOffsets.mRationalArray = MakeGlobalRefOrDie(env, rationalClazz);
645
646 // Store global references for ArrayList methods used
647 jclass arrayListClazz = FindClassOrDie(env, "java/util/ArrayList");
648 gMetadataOffsets.mArrayList = MakeGlobalRefOrDie(env, arrayListClazz);
649 gMetadataOffsets.mArrayListConstr = GetMethodIDOrDie(env, gMetadataOffsets.mArrayList,
650 "<init>", "(I)V");
651 gMetadataOffsets.mArrayListAdd = GetMethodIDOrDie(env, gMetadataOffsets.mArrayList,
652 "add", "(Ljava/lang/Object;)Z");
653
Igor Murashkin70725502013-06-25 20:27:06 +0000654 // Register native functions
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800655 return RegisterMethodsOrDie(env,
Igor Murashkin70725502013-06-25 20:27:06 +0000656 CAMERA_METADATA_CLASS_NAME,
657 gCameraMetadataMethods,
658 NELEM(gCameraMetadataMethods));
659}
660
661extern "C" {
Ruben Brunkc620eb72015-07-29 18:19:11 -0700662
Igor Murashkin70725502013-06-25 20:27:06 +0000663static void CameraMetadata_classInit(JNIEnv *env, jobject thiz) {
664 // XX: Why do this separately instead of doing it in the register function?
665 ALOGV("%s", __FUNCTION__);
666
667 field fields_to_find[] = {
668 { CAMERA_METADATA_CLASS_NAME, "mMetadataPtr", "J", &fields.metadata_ptr },
669 };
670
671 // Do this here instead of in register_native_methods,
672 // since otherwise it will fail to find the fields.
673 if (find_fields(env, fields_to_find, NELEM(fields_to_find)) < 0)
674 return;
675
Andreas Gampe0f0b4912014-11-12 08:03:48 -0800676 env->FindClass(CAMERA_METADATA_CLASS_NAME);
Igor Murashkin70725502013-06-25 20:27:06 +0000677}
Igor Murashkinb519cc52013-07-02 11:23:44 -0700678
Ruben Brunkc620eb72015-07-29 18:19:11 -0700679static jobject CameraMetadata_getAllVendorKeys(JNIEnv* env, jobject thiz, jclass keyType) {
680
681 // Get all vendor tags
682 sp<VendorTagDescriptor> vTags = VendorTagDescriptor::getGlobalVendorTagDescriptor();
683 if (vTags.get() == nullptr) {
684 // No vendor tags.
685 return NULL;
686 }
687
688 int count = vTags->getTagCount();
689 if (count <= 0) {
690 // No vendor tags.
691 return NULL;
692 }
693
694 std::vector<uint32_t> tagIds(count, /*initializer value*/0);
695 vTags->getTagArray(&tagIds[0]);
696
697 // Which key class/constructor should we use?
698 jclass keyClazz;
699 jmethodID keyConstr;
700 if (env->IsSameObject(keyType, gMetadataOffsets.mCharacteristicsKey)) {
701 keyClazz = gMetadataOffsets.mCharacteristicsKey;
702 keyConstr = gMetadataOffsets.mCharacteristicsConstr;
703 } else if (env->IsSameObject(keyType, gMetadataOffsets.mResultKey)) {
704 keyClazz = gMetadataOffsets.mResultKey;
705 keyConstr = gMetadataOffsets.mResultConstr;
706 } else if (env->IsSameObject(keyType, gMetadataOffsets.mRequestKey)) {
707 keyClazz = gMetadataOffsets.mRequestKey;
708 keyConstr = gMetadataOffsets.mRequestConstr;
709 } else {
710 jniThrowException(env, "java/lang/IllegalArgumentException",
711 "Invalid key class given as argument.");
712 return NULL;
713 }
714
715 // Allocate arrayList to return
716 jobject arrayList = env->NewObject(gMetadataOffsets.mArrayList,
717 gMetadataOffsets.mArrayListConstr, static_cast<jint>(count));
718 if (env->ExceptionCheck()) {
719 return NULL;
720 }
721
722 for (uint32_t id : tagIds) {
723 const char* section = vTags->getSectionName(id);
724 const char* tag = vTags->getTagName(id);
725 int type = vTags->getTagType(id);
726
727 size_t totalLen = strlen(section) + strlen(tag) + 2;
728 std::vector<char> fullName(totalLen, 0);
729 snprintf(&fullName[0], totalLen, "%s.%s", section, tag);
730
731 jstring name = env->NewStringUTF(&fullName[0]);
732
733 if (env->ExceptionCheck()) {
734 return NULL;
735 }
736
737 jclass valueClazz;
738 switch (type) {
739 case TYPE_BYTE:
740 valueClazz = gMetadataOffsets.mByteArray;
741 break;
742 case TYPE_INT32:
743 valueClazz = gMetadataOffsets.mInt32Array;
744 break;
745 case TYPE_FLOAT:
746 valueClazz = gMetadataOffsets.mFloatArray;
747 break;
748 case TYPE_INT64:
749 valueClazz = gMetadataOffsets.mInt64Array;
750 break;
751 case TYPE_DOUBLE:
752 valueClazz = gMetadataOffsets.mDoubleArray;
753 break;
754 case TYPE_RATIONAL:
755 valueClazz = gMetadataOffsets.mRationalArray;
756 break;
757 default:
758 jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
759 "Invalid type %d given for key %s", type, &fullName[0]);
760 return NULL;
761 }
762
763 jobject key = env->NewObject(keyClazz, keyConstr, name, valueClazz);
764 if (env->ExceptionCheck()) {
765 return NULL;
766 }
767
768 env->CallBooleanMethod(arrayList, gMetadataOffsets.mArrayListAdd, key);
769 if (env->ExceptionCheck()) {
770 return NULL;
771 }
772
773 env->DeleteLocalRef(name);
774 env->DeleteLocalRef(key);
775 }
776
777 return arrayList;
778}
779
Igor Murashkinb519cc52013-07-02 11:23:44 -0700780static jint CameraMetadata_getTagFromKey(JNIEnv *env, jobject thiz, jstring keyName) {
781
782 ScopedUtfChars keyScoped(env, keyName);
783 const char *key = keyScoped.c_str();
784 if (key == NULL) {
785 // exception thrown by ScopedUtfChars
786 return 0;
787 }
Igor Murashkinb519cc52013-07-02 11:23:44 -0700788 ALOGV("%s (key = '%s')", __FUNCTION__, key);
789
Ruben Brunk32ef3ae2014-02-21 17:40:51 -0800790 uint32_t tag = 0;
Eino-Ville Talvala376e24a2016-07-15 11:59:51 -0700791 sp<VendorTagDescriptor> vTags =
792 VendorTagDescriptor::getGlobalVendorTagDescriptor();
793 status_t res = CameraMetadata::getTagFromName(key, vTags.get(), &tag);
794 if (res != OK) {
795 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
796 "Could not find tag for key '%s')", key);
Igor Murashkinb519cc52013-07-02 11:23:44 -0700797 }
Igor Murashkinb519cc52013-07-02 11:23:44 -0700798 return tag;
799}
800
801static jint CameraMetadata_getTypeFromTag(JNIEnv *env, jobject thiz, jint tag) {
802 int tagType = get_camera_metadata_tag_type(tag);
803 if (tagType == -1) {
804 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
805 "Tag (%d) did not have a type", tag);
806 return -1;
807 }
808
809 return tagType;
810}
811
Ruben Brunk85c43882014-02-21 17:40:51 -0800812static jint CameraMetadata_setupGlobalVendorTagDescriptor(JNIEnv *env, jobject thiz) {
813 const String16 NAME("media.camera");
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800814 sp<hardware::ICameraService> cameraService;
Ruben Brunk85c43882014-02-21 17:40:51 -0800815 status_t err = getService(NAME, /*out*/&cameraService);
816
817 if (err != OK) {
818 ALOGE("%s: Failed to get camera service, received error %s (%d)", __FUNCTION__,
819 strerror(-err), err);
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800820 return hardware::ICameraService::ERROR_DISCONNECTED;
Ruben Brunk85c43882014-02-21 17:40:51 -0800821 }
822
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800823 sp<VendorTagDescriptor> desc = new VendorTagDescriptor();
824 binder::Status res = cameraService->getCameraVendorTagDescriptor(/*out*/desc.get());
Ruben Brunk85c43882014-02-21 17:40:51 -0800825
Eino-Ville Talvala5f2f8042016-03-03 11:50:39 -0800826 if (res.serviceSpecificErrorCode() == hardware::ICameraService::ERROR_DISCONNECTED) {
827 // No camera module available, not an error on devices with no cameras
Igor Murashkin5614cbe2014-03-17 14:00:55 -0700828 VendorTagDescriptor::clearGlobalVendorTagDescriptor();
Igor Murashkin5614cbe2014-03-17 14:00:55 -0700829 return OK;
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800830 } else if (!res.isOk()) {
Eino-Ville Talvala5f2f8042016-03-03 11:50:39 -0800831 VendorTagDescriptor::clearGlobalVendorTagDescriptor();
832 ALOGE("%s: Failed to setup vendor tag descriptors: %s",
833 __FUNCTION__, res.toString8().string());
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800834 return res.serviceSpecificErrorCode();
Ruben Brunk85c43882014-02-21 17:40:51 -0800835 }
836
837 err = VendorTagDescriptor::setAsGlobalVendorTagDescriptor(desc);
838
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800839 if (err != OK) {
840 return hardware::ICameraService::ERROR_INVALID_OPERATION;
841 }
842 return OK;
Ruben Brunk85c43882014-02-21 17:40:51 -0800843}
844
Igor Murashkin70725502013-06-25 20:27:06 +0000845} // extern "C"