blob: fad5b0e9ca0fcf7587c0fb3a82498fe0a6ef6370 [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>
Emilian Peevde62d842017-03-23 19:20:40 +000039#include <camera_metadata_hidden.h>
Ruben Brunk85c43882014-02-21 17:40:51 -080040#include <camera/VendorTagDescriptor.h>
Igor Murashkinb519cc52013-07-02 11:23:44 -070041#include <nativehelper/ScopedUtfChars.h>
42#include <nativehelper/ScopedPrimitiveArray.h>
43
Igor Murashkind6d65152014-05-19 16:31:02 -070044#include <sys/types.h> // for socketpair
45#include <sys/socket.h> // for socketpair
46
Igor Murashkin70725502013-06-25 20:27:06 +000047// fully-qualified class name
Eino-Ville Talvala70c22072013-08-27 12:09:04 -070048#define CAMERA_METADATA_CLASS_NAME "android/hardware/camera2/impl/CameraMetadataNative"
Ruben Brunkc620eb72015-07-29 18:19:11 -070049#define CHARACTERISTICS_KEY_CLASS_NAME "android/hardware/camera2/CameraCharacteristics$Key"
50#define REQUEST_KEY_CLASS_NAME "android/hardware/camera2/CaptureRequest$Key"
51#define RESULT_KEY_CLASS_NAME "android/hardware/camera2/CaptureResult$Key"
Igor Murashkin70725502013-06-25 20:27:06 +000052
53using namespace android;
54
Ruben Brunkc620eb72015-07-29 18:19:11 -070055static struct metadata_java_key_offsets_t {
56 jclass mCharacteristicsKey;
57 jclass mResultKey;
58 jclass mRequestKey;
59 jmethodID mCharacteristicsConstr;
60 jmethodID mResultConstr;
61 jmethodID mRequestConstr;
62 jclass mByteArray;
63 jclass mInt32Array;
64 jclass mFloatArray;
65 jclass mInt64Array;
66 jclass mDoubleArray;
67 jclass mRationalArray;
68 jclass mArrayList;
69 jmethodID mArrayListConstr;
70 jmethodID mArrayListAdd;
71} gMetadataOffsets;
72
Igor Murashkin70725502013-06-25 20:27:06 +000073struct fields_t {
74 jfieldID metadata_ptr;
75};
76
77static fields_t fields;
78
Ruben Brunkf967a542014-04-28 16:31:11 -070079namespace android {
80
81status_t CameraMetadata_getNativeMetadata(JNIEnv* env, jobject thiz,
82 /*out*/CameraMetadata* metadata) {
83 if (!thiz) {
84 ALOGE("%s: Invalid java metadata object.", __FUNCTION__);
85 return BAD_VALUE;
86 }
87
88 if (!metadata) {
89 ALOGE("%s: Invalid output metadata object.", __FUNCTION__);
90 return BAD_VALUE;
91 }
92 CameraMetadata* nativePtr = reinterpret_cast<CameraMetadata*>(env->GetLongField(thiz,
93 fields.metadata_ptr));
94 if (nativePtr == NULL) {
95 ALOGE("%s: Invalid native pointer in java metadata object.", __FUNCTION__);
96 return BAD_VALUE;
97 }
98 *metadata = *nativePtr;
99 return OK;
100}
101
102} /*namespace android*/
103
Igor Murashkinb519cc52013-07-02 11:23:44 -0700104namespace {
105struct Helpers {
106 static size_t getTypeSize(uint8_t type) {
107 if (type >= NUM_TYPES) {
108 ALOGE("%s: Invalid type specified (%ud)", __FUNCTION__, type);
109 return static_cast<size_t>(-1);
110 }
111
112 return camera_metadata_type_size[type];
113 }
114
115 static status_t updateAny(CameraMetadata *metadata,
116 uint32_t tag,
117 uint32_t type,
118 const void *data,
119 size_t dataBytes) {
120
121 if (type >= NUM_TYPES) {
122 ALOGE("%s: Invalid type specified (%ud)", __FUNCTION__, type);
123 return INVALID_OPERATION;
124 }
125
126 size_t typeSize = getTypeSize(type);
127
128 if (dataBytes % typeSize != 0) {
Dan Albert46d84442014-11-18 16:07:51 -0800129 ALOGE("%s: Expected dataBytes (%zu) to be divisible by typeSize "
130 "(%zu)", __FUNCTION__, dataBytes, typeSize);
Igor Murashkinb519cc52013-07-02 11:23:44 -0700131 return BAD_VALUE;
132 }
133
134 size_t dataCount = dataBytes / typeSize;
135
136 switch(type) {
137#define METADATA_UPDATE(runtime_type, compile_type) \
138 case runtime_type: { \
139 const compile_type *dataPtr = \
140 static_cast<const compile_type*>(data); \
141 return metadata->update(tag, dataPtr, dataCount); \
142 } \
143
144 METADATA_UPDATE(TYPE_BYTE, uint8_t);
145 METADATA_UPDATE(TYPE_INT32, int32_t);
146 METADATA_UPDATE(TYPE_FLOAT, float);
147 METADATA_UPDATE(TYPE_INT64, int64_t);
148 METADATA_UPDATE(TYPE_DOUBLE, double);
149 METADATA_UPDATE(TYPE_RATIONAL, camera_metadata_rational_t);
150
151 default: {
152 // unreachable
153 ALOGE("%s: Unreachable", __FUNCTION__);
154 return INVALID_OPERATION;
155 }
156 }
157
158#undef METADATA_UPDATE
159 }
160};
161} // namespace {}
162
Igor Murashkin70725502013-06-25 20:27:06 +0000163extern "C" {
164
Ruben Brunkc620eb72015-07-29 18:19:11 -0700165static jobject CameraMetadata_getAllVendorKeys(JNIEnv* env, jobject thiz, jclass keyType);
Emilian Peevde62d842017-03-23 19:20:40 +0000166static jint CameraMetadata_getTagFromKey(JNIEnv *env, jobject thiz, jstring keyName, jlong vendorId);
167static jint CameraMetadata_getTagFromKeyLocal(JNIEnv *env, jobject thiz, jstring keyName);
168static jint CameraMetadata_getTypeFromTag(JNIEnv *env, jobject thiz, jint tag, jlong vendorId);
169static jint CameraMetadata_getTypeFromTagLocal(JNIEnv *env, jobject thiz, jint tag);
Ruben Brunk85c43882014-02-21 17:40:51 -0800170static jint CameraMetadata_setupGlobalVendorTagDescriptor(JNIEnv *env, jobject thiz);
Igor Murashkin70725502013-06-25 20:27:06 +0000171
172// Less safe access to native pointer. Does NOT throw any Java exceptions if NULL.
173static CameraMetadata* CameraMetadata_getPointerNoThrow(JNIEnv *env, jobject thiz) {
174
175 if (thiz == NULL) {
176 return NULL;
177 }
178
179 return reinterpret_cast<CameraMetadata*>(env->GetLongField(thiz, fields.metadata_ptr));
180}
181
182// Safe access to native pointer from object. Throws if not possible to access.
183static CameraMetadata* CameraMetadata_getPointerThrow(JNIEnv *env, jobject thiz,
184 const char* argName = "this") {
185
186 if (thiz == NULL) {
187 ALOGV("%s: Throwing java.lang.NullPointerException for null reference",
188 __FUNCTION__);
189 jniThrowNullPointerException(env, argName);
190 return NULL;
191 }
192
193 CameraMetadata* metadata = CameraMetadata_getPointerNoThrow(env, thiz);
194 if (metadata == NULL) {
195 ALOGV("%s: Throwing java.lang.IllegalStateException for closed object",
196 __FUNCTION__);
197 jniThrowException(env, "java/lang/IllegalStateException",
198 "Metadata object was already closed");
199 return NULL;
200 }
201
202 return metadata;
203}
204
205static jlong CameraMetadata_allocate(JNIEnv *env, jobject thiz) {
206 ALOGV("%s", __FUNCTION__);
207
208 return reinterpret_cast<jlong>(new CameraMetadata());
209}
210
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700211static jlong CameraMetadata_allocateCopy(JNIEnv *env, jobject thiz,
212 jobject other) {
213 ALOGV("%s", __FUNCTION__);
214
215 CameraMetadata* otherMetadata =
216 CameraMetadata_getPointerThrow(env, other, "other");
217
218 // In case of exception, return
219 if (otherMetadata == NULL) return NULL;
220
221 // Clone native metadata and return new pointer
222 return reinterpret_cast<jlong>(new CameraMetadata(*otherMetadata));
223}
224
225
Igor Murashkin70725502013-06-25 20:27:06 +0000226static jboolean CameraMetadata_isEmpty(JNIEnv *env, jobject thiz) {
227 ALOGV("%s", __FUNCTION__);
228
229 CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
230
231 if (metadata == NULL) {
232 ALOGW("%s: Returning early due to exception being thrown",
233 __FUNCTION__);
234 return JNI_TRUE; // actually throws java exc.
235 }
236
237 jboolean empty = metadata->isEmpty();
238
Dan Albert46d84442014-11-18 16:07:51 -0800239 ALOGV("%s: Empty returned %d, entry count was %zu",
Igor Murashkin70725502013-06-25 20:27:06 +0000240 __FUNCTION__, empty, metadata->entryCount());
241
242 return empty;
243}
244
245static jint CameraMetadata_getEntryCount(JNIEnv *env, jobject thiz) {
246 ALOGV("%s", __FUNCTION__);
247
248 CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
249
250 if (metadata == NULL) return 0; // actually throws java exc.
251
252 return metadata->entryCount();
253}
254
255// idempotent. calling more than once has no effect.
256static void CameraMetadata_close(JNIEnv *env, jobject thiz) {
257 ALOGV("%s", __FUNCTION__);
258
259 CameraMetadata* metadata = CameraMetadata_getPointerNoThrow(env, thiz);
260
261 if (metadata != NULL) {
262 delete metadata;
263 env->SetLongField(thiz, fields.metadata_ptr, 0);
264 }
265
266 LOG_ALWAYS_FATAL_IF(CameraMetadata_getPointerNoThrow(env, thiz) != NULL,
267 "Expected the native ptr to be 0 after #close");
268}
269
270static void CameraMetadata_swap(JNIEnv *env, jobject thiz, jobject other) {
271 ALOGV("%s", __FUNCTION__);
272
273 CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
274
275 // order is important: we can't call another JNI method
276 // if there is an exception pending
277 if (metadata == NULL) return;
278
279 CameraMetadata* otherMetadata = CameraMetadata_getPointerThrow(env, other, "other");
280
281 if (otherMetadata == NULL) return;
282
283 metadata->swap(*otherMetadata);
284}
285
Igor Murashkinb519cc52013-07-02 11:23:44 -0700286static jbyteArray CameraMetadata_readValues(JNIEnv *env, jobject thiz, jint tag) {
287 ALOGV("%s (tag = %d)", __FUNCTION__, tag);
288
289 CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
290 if (metadata == NULL) return NULL;
291
Emilian Peevde62d842017-03-23 19:20:40 +0000292 const camera_metadata_t *metaBuffer = metadata->getAndLock();
293 int tagType = get_local_camera_metadata_tag_type(tag, metaBuffer);
294 metadata->unlock(metaBuffer);
Igor Murashkinb519cc52013-07-02 11:23:44 -0700295 if (tagType == -1) {
296 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
297 "Tag (%d) did not have a type", tag);
298 return NULL;
299 }
300 size_t tagSize = Helpers::getTypeSize(tagType);
301
302 camera_metadata_entry entry = metadata->find(tag);
303 if (entry.count == 0) {
304 if (!metadata->exists(tag)) {
305 ALOGV("%s: Tag %d does not have any entries", __FUNCTION__, tag);
306 return NULL;
307 } else {
308 // OK: we will return a 0-sized array.
309 ALOGV("%s: Tag %d had an entry, but it had 0 data", __FUNCTION__,
310 tag);
311 }
312 }
313
314 jsize byteCount = entry.count * tagSize;
315 jbyteArray byteArray = env->NewByteArray(byteCount);
316 if (env->ExceptionCheck()) return NULL;
317
318 // Copy into java array from native array
319 ScopedByteArrayRW arrayWriter(env, byteArray);
320 memcpy(arrayWriter.get(), entry.data.u8, byteCount);
321
322 return byteArray;
323}
324
325static void CameraMetadata_writeValues(JNIEnv *env, jobject thiz, jint tag, jbyteArray src) {
326 ALOGV("%s (tag = %d)", __FUNCTION__, tag);
327
328 CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
329 if (metadata == NULL) return;
330
Emilian Peevde62d842017-03-23 19:20:40 +0000331 const camera_metadata_t *metaBuffer = metadata->getAndLock();
332 int tagType = get_local_camera_metadata_tag_type(tag, metaBuffer);
333 metadata->unlock(metaBuffer);
Igor Murashkinb519cc52013-07-02 11:23:44 -0700334 if (tagType == -1) {
335 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
336 "Tag (%d) did not have a type", tag);
337 return;
338 }
Igor Murashkinb519cc52013-07-02 11:23:44 -0700339
340 status_t res;
341
342 if (src == NULL) {
343 // If array is NULL, delete the entry
Igor Murashkin3710db82013-07-18 20:11:17 -0700344 if (metadata->exists(tag)) {
345 res = metadata->erase(tag);
346 ALOGV("%s: Erase values (res = %d)", __FUNCTION__, res);
347 } else {
348 res = OK;
349 ALOGV("%s: Don't need to erase", __FUNCTION__);
350 }
Igor Murashkinb519cc52013-07-02 11:23:44 -0700351 } else {
352 // Copy from java array into native array
353 ScopedByteArrayRO arrayReader(env, src);
354 if (arrayReader.get() == NULL) return;
355
356 res = Helpers::updateAny(metadata, static_cast<uint32_t>(tag),
357 tagType, arrayReader.get(), arrayReader.size());
Igor Murashkin3710db82013-07-18 20:11:17 -0700358
359 ALOGV("%s: Update values (res = %d)", __FUNCTION__, res);
Igor Murashkinb519cc52013-07-02 11:23:44 -0700360 }
361
362 if (res == OK) {
363 return;
364 } else if (res == BAD_VALUE) {
365 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
366 "Src byte array was poorly formed");
367 } else if (res == INVALID_OPERATION) {
368 jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
369 "Internal error while trying to update metadata");
370 } else {
371 jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
372 "Unknown error (%d) while trying to update "
373 "metadata", res);
374 }
375}
376
Igor Murashkind6d65152014-05-19 16:31:02 -0700377struct DumpMetadataParams {
378 int writeFd;
379 const CameraMetadata* metadata;
380};
381
382static void* CameraMetadata_writeMetadataThread(void* arg) {
383 DumpMetadataParams* p = static_cast<DumpMetadataParams*>(arg);
384
385 /*
386 * Write the dumped data, and close the writing side FD.
387 */
388 p->metadata->dump(p->writeFd, /*verbosity*/2);
389
390 if (close(p->writeFd) < 0) {
391 ALOGE("%s: Failed to close writeFd (errno = %#x, message = '%s')",
392 __FUNCTION__, errno, strerror(errno));
393 }
394
395 return NULL;
396}
397
398static void CameraMetadata_dump(JNIEnv *env, jobject thiz) {
399 ALOGV("%s", __FUNCTION__);
400 CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
401 if (metadata == NULL) {
402 return;
403 }
404
405 /*
406 * Create a socket pair for local streaming read/writes.
407 *
408 * The metadata will be dumped into the write side,
409 * and then read back out (and logged) via the read side.
410 */
411
412 int writeFd, readFd;
413 {
414
415 int sv[2];
416 if (socketpair(AF_LOCAL, SOCK_STREAM, /*protocol*/0, &sv[0]) < 0) {
417 jniThrowExceptionFmt(env, "java/io/IOException",
418 "Failed to create socketpair (errno = %#x, message = '%s')",
419 errno, strerror(errno));
420 return;
421 }
422 writeFd = sv[0];
423 readFd = sv[1];
424 }
425
426 /*
427 * Create a thread for doing the writing.
428 *
429 * The reading and writing must be concurrent, otherwise
430 * the write will block forever once it exhausts the capped
431 * buffer size (from getsockopt).
432 */
433 pthread_t writeThread;
434 DumpMetadataParams params = {
435 writeFd,
436 metadata
437 };
438
439 {
440 int threadRet = pthread_create(&writeThread, /*attr*/NULL,
441 CameraMetadata_writeMetadataThread, (void*)&params);
442
443 if (threadRet != 0) {
444 close(writeFd);
Narayan Kamath7f63b9a2017-04-20 14:32:12 +0100445 close(readFd);
Igor Murashkind6d65152014-05-19 16:31:02 -0700446
447 jniThrowExceptionFmt(env, "java/io/IOException",
448 "Failed to create thread for writing (errno = %#x, message = '%s')",
449 threadRet, strerror(threadRet));
Narayan Kamath7f63b9a2017-04-20 14:32:12 +0100450 return;
Igor Murashkind6d65152014-05-19 16:31:02 -0700451 }
452 }
453
454 /*
455 * Read out a byte until stream is complete. Write completed lines
456 * to ALOG.
457 */
458 {
459 char out[] = {'\0', '\0'}; // large enough to append as a string
460 String8 logLine;
461
462 // Read one byte at a time! Very slow but avoids complicated \n scanning.
463 ssize_t res;
464 while ((res = TEMP_FAILURE_RETRY(read(readFd, &out[0], /*count*/1))) > 0) {
465 if (out[0] == '\n') {
466 ALOGD("%s", logLine.string());
467 logLine.clear();
468 } else {
469 logLine.append(out);
470 }
471 }
472
473 if (res < 0) {
474 jniThrowExceptionFmt(env, "java/io/IOException",
475 "Failed to read from fd (errno = %#x, message = '%s')",
476 errno, strerror(errno));
477 //return;
478 } else if (!logLine.isEmpty()) {
479 ALOGD("%s", logLine.string());
480 }
Narayan Kamath7f63b9a2017-04-20 14:32:12 +0100481
482 close(readFd);
Igor Murashkind6d65152014-05-19 16:31:02 -0700483 }
484
485 int res;
486
487 // Join until thread finishes. Ensures params/metadata is valid until then.
488 if ((res = pthread_join(writeThread, /*retval*/NULL)) != 0) {
489 ALOGE("%s: Failed to join thread (errno = %#x, message = '%s')",
490 __FUNCTION__, res, strerror(res));
491 }
492}
493
Igor Murashkin70725502013-06-25 20:27:06 +0000494static void CameraMetadata_readFromParcel(JNIEnv *env, jobject thiz, jobject parcel) {
495 ALOGV("%s", __FUNCTION__);
496 CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
497 if (metadata == NULL) {
498 return;
499 }
500
501 Parcel* parcelNative = parcelForJavaObject(env, parcel);
502 if (parcelNative == NULL) {
503 jniThrowNullPointerException(env, "parcel");
504 return;
505 }
506
507 status_t err;
508 if ((err = metadata->readFromParcel(parcelNative)) != OK) {
509 jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
510 "Failed to read from parcel (error code %d)", err);
511 return;
512 }
513}
514
515static void CameraMetadata_writeToParcel(JNIEnv *env, jobject thiz, jobject parcel) {
516 ALOGV("%s", __FUNCTION__);
517 CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
518 if (metadata == NULL) {
519 return;
520 }
521
522 Parcel* parcelNative = parcelForJavaObject(env, parcel);
523 if (parcelNative == NULL) {
524 jniThrowNullPointerException(env, "parcel");
525 return;
526 }
527
528 status_t err;
529 if ((err = metadata->writeToParcel(parcelNative)) != OK) {
530 jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
531 "Failed to write to parcel (error code %d)", err);
532 return;
533 }
534}
535
536} // extern "C"
537
538//-------------------------------------------------
539
Daniel Micay76f6a862015-09-19 17:31:01 -0400540static const JNINativeMethod gCameraMetadataMethods[] = {
Igor Murashkinb519cc52013-07-02 11:23:44 -0700541// static methods
Igor Murashkinb519cc52013-07-02 11:23:44 -0700542 { "nativeGetTagFromKey",
Emilian Peevde62d842017-03-23 19:20:40 +0000543 "(Ljava/lang/String;J)I",
Igor Murashkinb519cc52013-07-02 11:23:44 -0700544 (void *)CameraMetadata_getTagFromKey },
545 { "nativeGetTypeFromTag",
Emilian Peevde62d842017-03-23 19:20:40 +0000546 "(IJ)I",
Igor Murashkinb519cc52013-07-02 11:23:44 -0700547 (void *)CameraMetadata_getTypeFromTag },
Ruben Brunk85c43882014-02-21 17:40:51 -0800548 { "nativeSetupGlobalVendorTagDescriptor",
549 "()I",
550 (void*)CameraMetadata_setupGlobalVendorTagDescriptor },
Igor Murashkinb519cc52013-07-02 11:23:44 -0700551// instance methods
Igor Murashkin70725502013-06-25 20:27:06 +0000552 { "nativeAllocate",
553 "()J",
554 (void*)CameraMetadata_allocate },
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700555 { "nativeAllocateCopy",
556 "(L" CAMERA_METADATA_CLASS_NAME ";)J",
557 (void *)CameraMetadata_allocateCopy },
Igor Murashkin70725502013-06-25 20:27:06 +0000558 { "nativeIsEmpty",
559 "()Z",
560 (void*)CameraMetadata_isEmpty },
561 { "nativeGetEntryCount",
562 "()I",
563 (void*)CameraMetadata_getEntryCount },
564 { "nativeClose",
565 "()V",
566 (void*)CameraMetadata_close },
567 { "nativeSwap",
568 "(L" CAMERA_METADATA_CLASS_NAME ";)V",
569 (void *)CameraMetadata_swap },
Emilian Peevde62d842017-03-23 19:20:40 +0000570 { "nativeGetTagFromKeyLocal",
571 "(Ljava/lang/String;)I",
572 (void *)CameraMetadata_getTagFromKeyLocal },
573 { "nativeGetTypeFromTagLocal",
574 "(I)I",
575 (void *)CameraMetadata_getTypeFromTagLocal },
Igor Murashkinb519cc52013-07-02 11:23:44 -0700576 { "nativeReadValues",
577 "(I)[B",
578 (void *)CameraMetadata_readValues },
579 { "nativeWriteValues",
580 "(I[B)V",
581 (void *)CameraMetadata_writeValues },
Igor Murashkind6d65152014-05-19 16:31:02 -0700582 { "nativeDump",
583 "()V",
584 (void *)CameraMetadata_dump },
Emilian Peevde62d842017-03-23 19:20:40 +0000585 { "nativeGetAllVendorKeys",
586 "(Ljava/lang/Class;)Ljava/util/ArrayList;",
587 (void *)CameraMetadata_getAllVendorKeys},
Igor Murashkinb519cc52013-07-02 11:23:44 -0700588// Parcelable interface
Igor Murashkin70725502013-06-25 20:27:06 +0000589 { "nativeReadFromParcel",
590 "(Landroid/os/Parcel;)V",
591 (void *)CameraMetadata_readFromParcel },
592 { "nativeWriteToParcel",
593 "(Landroid/os/Parcel;)V",
594 (void *)CameraMetadata_writeToParcel },
595};
596
Igor Murashkin70725502013-06-25 20:27:06 +0000597// Get all the required offsets in java class and register native functions
Eino-Ville Talvala2f1a2e42013-07-25 17:12:05 -0700598int register_android_hardware_camera2_CameraMetadata(JNIEnv *env)
Igor Murashkin70725502013-06-25 20:27:06 +0000599{
Ruben Brunkc620eb72015-07-29 18:19:11 -0700600
601 // Store global references to Key-related classes and methods used natively
602 jclass characteristicsKeyClazz = FindClassOrDie(env, CHARACTERISTICS_KEY_CLASS_NAME);
603 jclass requestKeyClazz = FindClassOrDie(env, REQUEST_KEY_CLASS_NAME);
604 jclass resultKeyClazz = FindClassOrDie(env, RESULT_KEY_CLASS_NAME);
605 gMetadataOffsets.mCharacteristicsKey = MakeGlobalRefOrDie(env, characteristicsKeyClazz);
606 gMetadataOffsets.mRequestKey = MakeGlobalRefOrDie(env, requestKeyClazz);
607 gMetadataOffsets.mResultKey = MakeGlobalRefOrDie(env, resultKeyClazz);
608 gMetadataOffsets.mCharacteristicsConstr = GetMethodIDOrDie(env,
609 gMetadataOffsets.mCharacteristicsKey, "<init>",
Emilian Peevde62d842017-03-23 19:20:40 +0000610 "(Ljava/lang/String;Ljava/lang/Class;J)V");
Ruben Brunkc620eb72015-07-29 18:19:11 -0700611 gMetadataOffsets.mRequestConstr = GetMethodIDOrDie(env,
Emilian Peevde62d842017-03-23 19:20:40 +0000612 gMetadataOffsets.mRequestKey, "<init>", "(Ljava/lang/String;Ljava/lang/Class;J)V");
Ruben Brunkc620eb72015-07-29 18:19:11 -0700613 gMetadataOffsets.mResultConstr = GetMethodIDOrDie(env,
Emilian Peevde62d842017-03-23 19:20:40 +0000614 gMetadataOffsets.mResultKey, "<init>", "(Ljava/lang/String;Ljava/lang/Class;J)V");
Ruben Brunkc620eb72015-07-29 18:19:11 -0700615
616 // Store global references for primitive array types used by Keys
617 jclass byteClazz = FindClassOrDie(env, "[B");
618 jclass int32Clazz = FindClassOrDie(env, "[I");
619 jclass floatClazz = FindClassOrDie(env, "[F");
620 jclass int64Clazz = FindClassOrDie(env, "[J");
621 jclass doubleClazz = FindClassOrDie(env, "[D");
622 jclass rationalClazz = FindClassOrDie(env, "[Landroid/util/Rational;");
623 gMetadataOffsets.mByteArray = MakeGlobalRefOrDie(env, byteClazz);
624 gMetadataOffsets.mInt32Array = MakeGlobalRefOrDie(env, int32Clazz);
625 gMetadataOffsets.mFloatArray = MakeGlobalRefOrDie(env, floatClazz);
626 gMetadataOffsets.mInt64Array = MakeGlobalRefOrDie(env, int64Clazz);
627 gMetadataOffsets.mDoubleArray = MakeGlobalRefOrDie(env, doubleClazz);
628 gMetadataOffsets.mRationalArray = MakeGlobalRefOrDie(env, rationalClazz);
629
630 // Store global references for ArrayList methods used
631 jclass arrayListClazz = FindClassOrDie(env, "java/util/ArrayList");
632 gMetadataOffsets.mArrayList = MakeGlobalRefOrDie(env, arrayListClazz);
633 gMetadataOffsets.mArrayListConstr = GetMethodIDOrDie(env, gMetadataOffsets.mArrayList,
634 "<init>", "(I)V");
635 gMetadataOffsets.mArrayListAdd = GetMethodIDOrDie(env, gMetadataOffsets.mArrayList,
636 "add", "(Ljava/lang/Object;)Z");
637
Andreas Gampe08e6c342017-02-16 15:10:20 -0800638 jclass cameraMetadataClazz = FindClassOrDie(env, CAMERA_METADATA_CLASS_NAME);
639 fields.metadata_ptr = GetFieldIDOrDie(env, cameraMetadataClazz, "mMetadataPtr", "J");
640
Igor Murashkin70725502013-06-25 20:27:06 +0000641 // Register native functions
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800642 return RegisterMethodsOrDie(env,
Igor Murashkin70725502013-06-25 20:27:06 +0000643 CAMERA_METADATA_CLASS_NAME,
644 gCameraMetadataMethods,
645 NELEM(gCameraMetadataMethods));
646}
647
648extern "C" {
Ruben Brunkc620eb72015-07-29 18:19:11 -0700649
Emilian Peevde62d842017-03-23 19:20:40 +0000650static jint CameraMetadata_getTypeFromTagLocal(JNIEnv *env, jobject thiz, jint tag) {
651 CameraMetadata* metadata = CameraMetadata_getPointerNoThrow(env, thiz);
652 metadata_vendor_id_t vendorId = CAMERA_METADATA_INVALID_VENDOR_ID;
653 if (metadata) {
654 const camera_metadata_t *metaBuffer = metadata->getAndLock();
655 vendorId = get_camera_metadata_vendor_id(metaBuffer);
656 metadata->unlock(metaBuffer);
657 }
Ruben Brunkc620eb72015-07-29 18:19:11 -0700658
Emilian Peevde62d842017-03-23 19:20:40 +0000659 int tagType = get_local_camera_metadata_tag_type_vendor_id(tag, vendorId);
660 if (tagType == -1) {
661 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
662 "Tag (%d) did not have a type", tag);
663 return -1;
664 }
665
666 return tagType;
667}
668
669static jint CameraMetadata_getTagFromKeyLocal(JNIEnv *env, jobject thiz, jstring keyName) {
670 ScopedUtfChars keyScoped(env, keyName);
671 const char *key = keyScoped.c_str();
672 if (key == NULL) {
673 // exception thrown by ScopedUtfChars
674 return 0;
675 }
676 ALOGV("%s (key = '%s')", __FUNCTION__, key);
677
678 uint32_t tag = 0;
679 sp<VendorTagDescriptor> vTags;
680 CameraMetadata* metadata = CameraMetadata_getPointerNoThrow(env, thiz);
681 if (metadata) {
682 sp<VendorTagDescriptorCache> cache = VendorTagDescriptorCache::getGlobalVendorTagCache();
683 if (cache.get()) {
684 const camera_metadata_t *metaBuffer = metadata->getAndLock();
685 metadata_vendor_id_t vendorId = get_camera_metadata_vendor_id(metaBuffer);
686 metadata->unlock(metaBuffer);
687 cache->getVendorTagDescriptor(vendorId, &vTags);
688 }
689 }
690
691 status_t res = CameraMetadata::getTagFromName(key, vTags.get(), &tag);
692 if (res != OK) {
693 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
694 "Could not find tag for key '%s')", key);
695 }
696 return tag;
697}
698
699static jobject CameraMetadata_getAllVendorKeys(JNIEnv* env, jobject thiz, jclass keyType) {
700 metadata_vendor_id_t vendorId = CAMERA_METADATA_INVALID_VENDOR_ID;
Ruben Brunkc620eb72015-07-29 18:19:11 -0700701 // Get all vendor tags
702 sp<VendorTagDescriptor> vTags = VendorTagDescriptor::getGlobalVendorTagDescriptor();
703 if (vTags.get() == nullptr) {
Emilian Peevde62d842017-03-23 19:20:40 +0000704 sp<VendorTagDescriptorCache> cache = VendorTagDescriptorCache::getGlobalVendorTagCache();
705 if (cache.get() == nullptr) {
706 // No vendor tags.
707 return nullptr;
708 }
709
710 CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
711 if (metadata == NULL) return NULL;
712
713 const camera_metadata_t *metaBuffer = metadata->getAndLock();
714 vendorId = get_camera_metadata_vendor_id(metaBuffer);
715 cache->getVendorTagDescriptor(vendorId, &vTags);
716 metadata->unlock(metaBuffer);
717 if (vTags.get() == nullptr) {
718 return nullptr;
719 }
Ruben Brunkc620eb72015-07-29 18:19:11 -0700720 }
721
722 int count = vTags->getTagCount();
723 if (count <= 0) {
724 // No vendor tags.
725 return NULL;
726 }
727
728 std::vector<uint32_t> tagIds(count, /*initializer value*/0);
729 vTags->getTagArray(&tagIds[0]);
730
731 // Which key class/constructor should we use?
732 jclass keyClazz;
733 jmethodID keyConstr;
734 if (env->IsSameObject(keyType, gMetadataOffsets.mCharacteristicsKey)) {
735 keyClazz = gMetadataOffsets.mCharacteristicsKey;
736 keyConstr = gMetadataOffsets.mCharacteristicsConstr;
737 } else if (env->IsSameObject(keyType, gMetadataOffsets.mResultKey)) {
738 keyClazz = gMetadataOffsets.mResultKey;
739 keyConstr = gMetadataOffsets.mResultConstr;
740 } else if (env->IsSameObject(keyType, gMetadataOffsets.mRequestKey)) {
741 keyClazz = gMetadataOffsets.mRequestKey;
742 keyConstr = gMetadataOffsets.mRequestConstr;
743 } else {
744 jniThrowException(env, "java/lang/IllegalArgumentException",
745 "Invalid key class given as argument.");
746 return NULL;
747 }
748
749 // Allocate arrayList to return
750 jobject arrayList = env->NewObject(gMetadataOffsets.mArrayList,
751 gMetadataOffsets.mArrayListConstr, static_cast<jint>(count));
752 if (env->ExceptionCheck()) {
753 return NULL;
754 }
755
756 for (uint32_t id : tagIds) {
757 const char* section = vTags->getSectionName(id);
758 const char* tag = vTags->getTagName(id);
759 int type = vTags->getTagType(id);
760
761 size_t totalLen = strlen(section) + strlen(tag) + 2;
762 std::vector<char> fullName(totalLen, 0);
763 snprintf(&fullName[0], totalLen, "%s.%s", section, tag);
764
765 jstring name = env->NewStringUTF(&fullName[0]);
766
767 if (env->ExceptionCheck()) {
768 return NULL;
769 }
770
771 jclass valueClazz;
772 switch (type) {
773 case TYPE_BYTE:
774 valueClazz = gMetadataOffsets.mByteArray;
775 break;
776 case TYPE_INT32:
777 valueClazz = gMetadataOffsets.mInt32Array;
778 break;
779 case TYPE_FLOAT:
780 valueClazz = gMetadataOffsets.mFloatArray;
781 break;
782 case TYPE_INT64:
783 valueClazz = gMetadataOffsets.mInt64Array;
784 break;
785 case TYPE_DOUBLE:
786 valueClazz = gMetadataOffsets.mDoubleArray;
787 break;
788 case TYPE_RATIONAL:
789 valueClazz = gMetadataOffsets.mRationalArray;
790 break;
791 default:
792 jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
793 "Invalid type %d given for key %s", type, &fullName[0]);
794 return NULL;
795 }
796
Emilian Peevde62d842017-03-23 19:20:40 +0000797 jobject key = env->NewObject(keyClazz, keyConstr, name, valueClazz, vendorId);
Ruben Brunkc620eb72015-07-29 18:19:11 -0700798 if (env->ExceptionCheck()) {
799 return NULL;
800 }
801
802 env->CallBooleanMethod(arrayList, gMetadataOffsets.mArrayListAdd, key);
803 if (env->ExceptionCheck()) {
804 return NULL;
805 }
806
807 env->DeleteLocalRef(name);
808 env->DeleteLocalRef(key);
809 }
810
811 return arrayList;
812}
813
Emilian Peevde62d842017-03-23 19:20:40 +0000814static jint CameraMetadata_getTagFromKey(JNIEnv *env, jobject thiz, jstring keyName,
815 jlong vendorId) {
Igor Murashkinb519cc52013-07-02 11:23:44 -0700816 ScopedUtfChars keyScoped(env, keyName);
817 const char *key = keyScoped.c_str();
818 if (key == NULL) {
819 // exception thrown by ScopedUtfChars
820 return 0;
821 }
Igor Murashkinb519cc52013-07-02 11:23:44 -0700822 ALOGV("%s (key = '%s')", __FUNCTION__, key);
823
Ruben Brunk32ef3ae2014-02-21 17:40:51 -0800824 uint32_t tag = 0;
Eino-Ville Talvala376e24a2016-07-15 11:59:51 -0700825 sp<VendorTagDescriptor> vTags =
826 VendorTagDescriptor::getGlobalVendorTagDescriptor();
Emilian Peevde62d842017-03-23 19:20:40 +0000827 if (vTags.get() == nullptr) {
828 sp<VendorTagDescriptorCache> cache = VendorTagDescriptorCache::getGlobalVendorTagCache();
829 if (cache.get() != nullptr) {
830 cache->getVendorTagDescriptor(vendorId, &vTags);
831 }
832 }
833
Eino-Ville Talvala376e24a2016-07-15 11:59:51 -0700834 status_t res = CameraMetadata::getTagFromName(key, vTags.get(), &tag);
835 if (res != OK) {
836 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
837 "Could not find tag for key '%s')", key);
Igor Murashkinb519cc52013-07-02 11:23:44 -0700838 }
Igor Murashkinb519cc52013-07-02 11:23:44 -0700839 return tag;
840}
841
Emilian Peevde62d842017-03-23 19:20:40 +0000842static jint CameraMetadata_getTypeFromTag(JNIEnv *env, jobject thiz, jint tag, jlong vendorId) {
843 int tagType = get_local_camera_metadata_tag_type_vendor_id(tag, vendorId);
Igor Murashkinb519cc52013-07-02 11:23:44 -0700844 if (tagType == -1) {
845 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
846 "Tag (%d) did not have a type", tag);
847 return -1;
848 }
849
850 return tagType;
851}
852
Ruben Brunk85c43882014-02-21 17:40:51 -0800853static jint CameraMetadata_setupGlobalVendorTagDescriptor(JNIEnv *env, jobject thiz) {
854 const String16 NAME("media.camera");
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800855 sp<hardware::ICameraService> cameraService;
Ruben Brunk85c43882014-02-21 17:40:51 -0800856 status_t err = getService(NAME, /*out*/&cameraService);
857
858 if (err != OK) {
859 ALOGE("%s: Failed to get camera service, received error %s (%d)", __FUNCTION__,
860 strerror(-err), err);
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800861 return hardware::ICameraService::ERROR_DISCONNECTED;
Ruben Brunk85c43882014-02-21 17:40:51 -0800862 }
863
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800864 sp<VendorTagDescriptor> desc = new VendorTagDescriptor();
865 binder::Status res = cameraService->getCameraVendorTagDescriptor(/*out*/desc.get());
Ruben Brunk85c43882014-02-21 17:40:51 -0800866
Eino-Ville Talvala5f2f8042016-03-03 11:50:39 -0800867 if (res.serviceSpecificErrorCode() == hardware::ICameraService::ERROR_DISCONNECTED) {
868 // No camera module available, not an error on devices with no cameras
Igor Murashkin5614cbe2014-03-17 14:00:55 -0700869 VendorTagDescriptor::clearGlobalVendorTagDescriptor();
Igor Murashkin5614cbe2014-03-17 14:00:55 -0700870 return OK;
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800871 } else if (!res.isOk()) {
Eino-Ville Talvala5f2f8042016-03-03 11:50:39 -0800872 VendorTagDescriptor::clearGlobalVendorTagDescriptor();
873 ALOGE("%s: Failed to setup vendor tag descriptors: %s",
874 __FUNCTION__, res.toString8().string());
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800875 return res.serviceSpecificErrorCode();
Ruben Brunk85c43882014-02-21 17:40:51 -0800876 }
Emilian Peevde62d842017-03-23 19:20:40 +0000877 if (0 < desc->getTagCount()) {
878 err = VendorTagDescriptor::setAsGlobalVendorTagDescriptor(desc);
879 } else {
880 sp<VendorTagDescriptorCache> cache = new VendorTagDescriptorCache();
881 binder::Status res = cameraService->getCameraVendorTagCache(/*out*/cache.get());
882 if (res.serviceSpecificErrorCode() == hardware::ICameraService::ERROR_DISCONNECTED) {
883 // No camera module available, not an error on devices with no cameras
884 VendorTagDescriptorCache::clearGlobalVendorTagCache();
885 return OK;
886 } else if (!res.isOk()) {
887 VendorTagDescriptorCache::clearGlobalVendorTagCache();
888 ALOGE("%s: Failed to setup vendor tag cache: %s",
889 __FUNCTION__, res.toString8().string());
890 return res.serviceSpecificErrorCode();
891 }
Ruben Brunk85c43882014-02-21 17:40:51 -0800892
Emilian Peevde62d842017-03-23 19:20:40 +0000893 err = VendorTagDescriptorCache::setAsGlobalVendorTagCache(cache);
894 }
Ruben Brunk85c43882014-02-21 17:40:51 -0800895
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800896 if (err != OK) {
897 return hardware::ICameraService::ERROR_INVALID_OPERATION;
898 }
899 return OK;
Ruben Brunk85c43882014-02-21 17:40:51 -0800900}
901
Igor Murashkin70725502013-06-25 20:27:06 +0000902} // extern "C"