blob: f37fd78f6bdd55eca59887daa064b87cad31e16d [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
Andreas Gampeed6b9df2014-11-20 22:02:20 -080046static const bool kIsDebug = false;
Igor Murashkin70725502013-06-25 20:27:06 +000047
48// fully-qualified class name
Eino-Ville Talvala70c22072013-08-27 12:09:04 -070049#define CAMERA_METADATA_CLASS_NAME "android/hardware/camera2/impl/CameraMetadataNative"
Ruben Brunkc620eb72015-07-29 18:19:11 -070050#define CHARACTERISTICS_KEY_CLASS_NAME "android/hardware/camera2/CameraCharacteristics$Key"
51#define REQUEST_KEY_CLASS_NAME "android/hardware/camera2/CaptureRequest$Key"
52#define RESULT_KEY_CLASS_NAME "android/hardware/camera2/CaptureResult$Key"
Igor Murashkin70725502013-06-25 20:27:06 +000053
54using namespace android;
55
Ruben Brunkc620eb72015-07-29 18:19:11 -070056static struct metadata_java_key_offsets_t {
57 jclass mCharacteristicsKey;
58 jclass mResultKey;
59 jclass mRequestKey;
60 jmethodID mCharacteristicsConstr;
61 jmethodID mResultConstr;
62 jmethodID mRequestConstr;
63 jclass mByteArray;
64 jclass mInt32Array;
65 jclass mFloatArray;
66 jclass mInt64Array;
67 jclass mDoubleArray;
68 jclass mRationalArray;
69 jclass mArrayList;
70 jmethodID mArrayListConstr;
71 jmethodID mArrayListAdd;
72} gMetadataOffsets;
73
Igor Murashkin70725502013-06-25 20:27:06 +000074struct fields_t {
75 jfieldID metadata_ptr;
76};
77
78static fields_t fields;
79
Ruben Brunkf967a542014-04-28 16:31:11 -070080namespace android {
81
82status_t CameraMetadata_getNativeMetadata(JNIEnv* env, jobject thiz,
83 /*out*/CameraMetadata* metadata) {
84 if (!thiz) {
85 ALOGE("%s: Invalid java metadata object.", __FUNCTION__);
86 return BAD_VALUE;
87 }
88
89 if (!metadata) {
90 ALOGE("%s: Invalid output metadata object.", __FUNCTION__);
91 return BAD_VALUE;
92 }
93 CameraMetadata* nativePtr = reinterpret_cast<CameraMetadata*>(env->GetLongField(thiz,
94 fields.metadata_ptr));
95 if (nativePtr == NULL) {
96 ALOGE("%s: Invalid native pointer in java metadata object.", __FUNCTION__);
97 return BAD_VALUE;
98 }
99 *metadata = *nativePtr;
100 return OK;
101}
102
103} /*namespace android*/
104
Igor Murashkinb519cc52013-07-02 11:23:44 -0700105namespace {
106struct Helpers {
107 static size_t getTypeSize(uint8_t type) {
108 if (type >= NUM_TYPES) {
109 ALOGE("%s: Invalid type specified (%ud)", __FUNCTION__, type);
110 return static_cast<size_t>(-1);
111 }
112
113 return camera_metadata_type_size[type];
114 }
115
116 static status_t updateAny(CameraMetadata *metadata,
117 uint32_t tag,
118 uint32_t type,
119 const void *data,
120 size_t dataBytes) {
121
122 if (type >= NUM_TYPES) {
123 ALOGE("%s: Invalid type specified (%ud)", __FUNCTION__, type);
124 return INVALID_OPERATION;
125 }
126
127 size_t typeSize = getTypeSize(type);
128
129 if (dataBytes % typeSize != 0) {
Dan Albert46d84442014-11-18 16:07:51 -0800130 ALOGE("%s: Expected dataBytes (%zu) to be divisible by typeSize "
131 "(%zu)", __FUNCTION__, dataBytes, typeSize);
Igor Murashkinb519cc52013-07-02 11:23:44 -0700132 return BAD_VALUE;
133 }
134
135 size_t dataCount = dataBytes / typeSize;
136
137 switch(type) {
138#define METADATA_UPDATE(runtime_type, compile_type) \
139 case runtime_type: { \
140 const compile_type *dataPtr = \
141 static_cast<const compile_type*>(data); \
142 return metadata->update(tag, dataPtr, dataCount); \
143 } \
144
145 METADATA_UPDATE(TYPE_BYTE, uint8_t);
146 METADATA_UPDATE(TYPE_INT32, int32_t);
147 METADATA_UPDATE(TYPE_FLOAT, float);
148 METADATA_UPDATE(TYPE_INT64, int64_t);
149 METADATA_UPDATE(TYPE_DOUBLE, double);
150 METADATA_UPDATE(TYPE_RATIONAL, camera_metadata_rational_t);
151
152 default: {
153 // unreachable
154 ALOGE("%s: Unreachable", __FUNCTION__);
155 return INVALID_OPERATION;
156 }
157 }
158
159#undef METADATA_UPDATE
160 }
161};
162} // namespace {}
163
Igor Murashkin70725502013-06-25 20:27:06 +0000164extern "C" {
165
166static void CameraMetadata_classInit(JNIEnv *env, jobject thiz);
Ruben Brunkc620eb72015-07-29 18:19:11 -0700167static jobject CameraMetadata_getAllVendorKeys(JNIEnv* env, jobject thiz, jclass keyType);
Igor Murashkinb519cc52013-07-02 11:23:44 -0700168static jint CameraMetadata_getTagFromKey(JNIEnv *env, jobject thiz, jstring keyName);
169static jint CameraMetadata_getTypeFromTag(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
292 int tagType = get_camera_metadata_tag_type(tag);
293 if (tagType == -1) {
294 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
295 "Tag (%d) did not have a type", tag);
296 return NULL;
297 }
298 size_t tagSize = Helpers::getTypeSize(tagType);
299
300 camera_metadata_entry entry = metadata->find(tag);
301 if (entry.count == 0) {
302 if (!metadata->exists(tag)) {
303 ALOGV("%s: Tag %d does not have any entries", __FUNCTION__, tag);
304 return NULL;
305 } else {
306 // OK: we will return a 0-sized array.
307 ALOGV("%s: Tag %d had an entry, but it had 0 data", __FUNCTION__,
308 tag);
309 }
310 }
311
312 jsize byteCount = entry.count * tagSize;
313 jbyteArray byteArray = env->NewByteArray(byteCount);
314 if (env->ExceptionCheck()) return NULL;
315
316 // Copy into java array from native array
317 ScopedByteArrayRW arrayWriter(env, byteArray);
318 memcpy(arrayWriter.get(), entry.data.u8, byteCount);
319
320 return byteArray;
321}
322
323static void CameraMetadata_writeValues(JNIEnv *env, jobject thiz, jint tag, jbyteArray src) {
324 ALOGV("%s (tag = %d)", __FUNCTION__, tag);
325
326 CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
327 if (metadata == NULL) return;
328
329 int tagType = get_camera_metadata_tag_type(tag);
330 if (tagType == -1) {
331 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
332 "Tag (%d) did not have a type", tag);
333 return;
334 }
Igor Murashkinb519cc52013-07-02 11:23:44 -0700335
336 status_t res;
337
338 if (src == NULL) {
339 // If array is NULL, delete the entry
Igor Murashkin3710db82013-07-18 20:11:17 -0700340 if (metadata->exists(tag)) {
341 res = metadata->erase(tag);
342 ALOGV("%s: Erase values (res = %d)", __FUNCTION__, res);
343 } else {
344 res = OK;
345 ALOGV("%s: Don't need to erase", __FUNCTION__);
346 }
Igor Murashkinb519cc52013-07-02 11:23:44 -0700347 } else {
348 // Copy from java array into native array
349 ScopedByteArrayRO arrayReader(env, src);
350 if (arrayReader.get() == NULL) return;
351
352 res = Helpers::updateAny(metadata, static_cast<uint32_t>(tag),
353 tagType, arrayReader.get(), arrayReader.size());
Igor Murashkin3710db82013-07-18 20:11:17 -0700354
355 ALOGV("%s: Update values (res = %d)", __FUNCTION__, res);
Igor Murashkinb519cc52013-07-02 11:23:44 -0700356 }
357
358 if (res == OK) {
359 return;
360 } else if (res == BAD_VALUE) {
361 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
362 "Src byte array was poorly formed");
363 } else if (res == INVALID_OPERATION) {
364 jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
365 "Internal error while trying to update metadata");
366 } else {
367 jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
368 "Unknown error (%d) while trying to update "
369 "metadata", res);
370 }
371}
372
Igor Murashkind6d65152014-05-19 16:31:02 -0700373struct DumpMetadataParams {
374 int writeFd;
375 const CameraMetadata* metadata;
376};
377
378static void* CameraMetadata_writeMetadataThread(void* arg) {
379 DumpMetadataParams* p = static_cast<DumpMetadataParams*>(arg);
380
381 /*
382 * Write the dumped data, and close the writing side FD.
383 */
384 p->metadata->dump(p->writeFd, /*verbosity*/2);
385
386 if (close(p->writeFd) < 0) {
387 ALOGE("%s: Failed to close writeFd (errno = %#x, message = '%s')",
388 __FUNCTION__, errno, strerror(errno));
389 }
390
391 return NULL;
392}
393
394static void CameraMetadata_dump(JNIEnv *env, jobject thiz) {
395 ALOGV("%s", __FUNCTION__);
396 CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
397 if (metadata == NULL) {
398 return;
399 }
400
401 /*
402 * Create a socket pair for local streaming read/writes.
403 *
404 * The metadata will be dumped into the write side,
405 * and then read back out (and logged) via the read side.
406 */
407
408 int writeFd, readFd;
409 {
410
411 int sv[2];
412 if (socketpair(AF_LOCAL, SOCK_STREAM, /*protocol*/0, &sv[0]) < 0) {
413 jniThrowExceptionFmt(env, "java/io/IOException",
414 "Failed to create socketpair (errno = %#x, message = '%s')",
415 errno, strerror(errno));
416 return;
417 }
418 writeFd = sv[0];
419 readFd = sv[1];
420 }
421
422 /*
423 * Create a thread for doing the writing.
424 *
425 * The reading and writing must be concurrent, otherwise
426 * the write will block forever once it exhausts the capped
427 * buffer size (from getsockopt).
428 */
429 pthread_t writeThread;
430 DumpMetadataParams params = {
431 writeFd,
432 metadata
433 };
434
435 {
436 int threadRet = pthread_create(&writeThread, /*attr*/NULL,
437 CameraMetadata_writeMetadataThread, (void*)&params);
438
439 if (threadRet != 0) {
440 close(writeFd);
441
442 jniThrowExceptionFmt(env, "java/io/IOException",
443 "Failed to create thread for writing (errno = %#x, message = '%s')",
444 threadRet, strerror(threadRet));
445 }
446 }
447
448 /*
449 * Read out a byte until stream is complete. Write completed lines
450 * to ALOG.
451 */
452 {
453 char out[] = {'\0', '\0'}; // large enough to append as a string
454 String8 logLine;
455
456 // Read one byte at a time! Very slow but avoids complicated \n scanning.
457 ssize_t res;
458 while ((res = TEMP_FAILURE_RETRY(read(readFd, &out[0], /*count*/1))) > 0) {
459 if (out[0] == '\n') {
460 ALOGD("%s", logLine.string());
461 logLine.clear();
462 } else {
463 logLine.append(out);
464 }
465 }
466
467 if (res < 0) {
468 jniThrowExceptionFmt(env, "java/io/IOException",
469 "Failed to read from fd (errno = %#x, message = '%s')",
470 errno, strerror(errno));
471 //return;
472 } else if (!logLine.isEmpty()) {
473 ALOGD("%s", logLine.string());
474 }
475 }
476
477 int res;
478
479 // Join until thread finishes. Ensures params/metadata is valid until then.
480 if ((res = pthread_join(writeThread, /*retval*/NULL)) != 0) {
481 ALOGE("%s: Failed to join thread (errno = %#x, message = '%s')",
482 __FUNCTION__, res, strerror(res));
483 }
484}
485
Igor Murashkin70725502013-06-25 20:27:06 +0000486static void CameraMetadata_readFromParcel(JNIEnv *env, jobject thiz, jobject parcel) {
487 ALOGV("%s", __FUNCTION__);
488 CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
489 if (metadata == NULL) {
490 return;
491 }
492
493 Parcel* parcelNative = parcelForJavaObject(env, parcel);
494 if (parcelNative == NULL) {
495 jniThrowNullPointerException(env, "parcel");
496 return;
497 }
498
499 status_t err;
500 if ((err = metadata->readFromParcel(parcelNative)) != OK) {
501 jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
502 "Failed to read from parcel (error code %d)", err);
503 return;
504 }
505}
506
507static void CameraMetadata_writeToParcel(JNIEnv *env, jobject thiz, jobject parcel) {
508 ALOGV("%s", __FUNCTION__);
509 CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
510 if (metadata == NULL) {
511 return;
512 }
513
514 Parcel* parcelNative = parcelForJavaObject(env, parcel);
515 if (parcelNative == NULL) {
516 jniThrowNullPointerException(env, "parcel");
517 return;
518 }
519
520 status_t err;
521 if ((err = metadata->writeToParcel(parcelNative)) != OK) {
522 jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
523 "Failed to write to parcel (error code %d)", err);
524 return;
525 }
526}
527
528} // extern "C"
529
530//-------------------------------------------------
531
Daniel Micay76f6a862015-09-19 17:31:01 -0400532static const JNINativeMethod gCameraMetadataMethods[] = {
Igor Murashkinb519cc52013-07-02 11:23:44 -0700533// static methods
Igor Murashkin70725502013-06-25 20:27:06 +0000534 { "nativeClassInit",
535 "()V",
536 (void *)CameraMetadata_classInit },
Ruben Brunkc620eb72015-07-29 18:19:11 -0700537 { "nativeGetAllVendorKeys",
538 "(Ljava/lang/Class;)Ljava/util/ArrayList;",
539 (void *)CameraMetadata_getAllVendorKeys},
Igor Murashkinb519cc52013-07-02 11:23:44 -0700540 { "nativeGetTagFromKey",
541 "(Ljava/lang/String;)I",
542 (void *)CameraMetadata_getTagFromKey },
543 { "nativeGetTypeFromTag",
544 "(I)I",
545 (void *)CameraMetadata_getTypeFromTag },
Ruben Brunk85c43882014-02-21 17:40:51 -0800546 { "nativeSetupGlobalVendorTagDescriptor",
547 "()I",
548 (void*)CameraMetadata_setupGlobalVendorTagDescriptor },
Igor Murashkinb519cc52013-07-02 11:23:44 -0700549// instance methods
Igor Murashkin70725502013-06-25 20:27:06 +0000550 { "nativeAllocate",
551 "()J",
552 (void*)CameraMetadata_allocate },
Eino-Ville Talvala70c22072013-08-27 12:09:04 -0700553 { "nativeAllocateCopy",
554 "(L" CAMERA_METADATA_CLASS_NAME ";)J",
555 (void *)CameraMetadata_allocateCopy },
Igor Murashkin70725502013-06-25 20:27:06 +0000556 { "nativeIsEmpty",
557 "()Z",
558 (void*)CameraMetadata_isEmpty },
559 { "nativeGetEntryCount",
560 "()I",
561 (void*)CameraMetadata_getEntryCount },
562 { "nativeClose",
563 "()V",
564 (void*)CameraMetadata_close },
565 { "nativeSwap",
566 "(L" CAMERA_METADATA_CLASS_NAME ";)V",
567 (void *)CameraMetadata_swap },
Igor Murashkinb519cc52013-07-02 11:23:44 -0700568 { "nativeReadValues",
569 "(I)[B",
570 (void *)CameraMetadata_readValues },
571 { "nativeWriteValues",
572 "(I[B)V",
573 (void *)CameraMetadata_writeValues },
Igor Murashkind6d65152014-05-19 16:31:02 -0700574 { "nativeDump",
575 "()V",
576 (void *)CameraMetadata_dump },
Igor Murashkinb519cc52013-07-02 11:23:44 -0700577// Parcelable interface
Igor Murashkin70725502013-06-25 20:27:06 +0000578 { "nativeReadFromParcel",
579 "(Landroid/os/Parcel;)V",
580 (void *)CameraMetadata_readFromParcel },
581 { "nativeWriteToParcel",
582 "(Landroid/os/Parcel;)V",
583 (void *)CameraMetadata_writeToParcel },
584};
585
586struct field {
587 const char *class_name;
588 const char *field_name;
589 const char *field_type;
590 jfieldID *jfield;
591};
592
593static int find_fields(JNIEnv *env, field *fields, int count)
594{
595 for (int i = 0; i < count; i++) {
596 field *f = &fields[i];
597 jclass clazz = env->FindClass(f->class_name);
598 if (clazz == NULL) {
599 ALOGE("Can't find %s", f->class_name);
600 return -1;
601 }
602
603 jfieldID field = env->GetFieldID(clazz, f->field_name, f->field_type);
604 if (field == NULL) {
605 ALOGE("Can't find %s.%s", f->class_name, f->field_name);
606 return -1;
607 }
608
609 *(f->jfield) = field;
610 }
611
612 return 0;
613}
614
615// Get all the required offsets in java class and register native functions
Eino-Ville Talvala2f1a2e42013-07-25 17:12:05 -0700616int register_android_hardware_camera2_CameraMetadata(JNIEnv *env)
Igor Murashkin70725502013-06-25 20:27:06 +0000617{
Ruben Brunkc620eb72015-07-29 18:19:11 -0700618
619 // Store global references to Key-related classes and methods used natively
620 jclass characteristicsKeyClazz = FindClassOrDie(env, CHARACTERISTICS_KEY_CLASS_NAME);
621 jclass requestKeyClazz = FindClassOrDie(env, REQUEST_KEY_CLASS_NAME);
622 jclass resultKeyClazz = FindClassOrDie(env, RESULT_KEY_CLASS_NAME);
623 gMetadataOffsets.mCharacteristicsKey = MakeGlobalRefOrDie(env, characteristicsKeyClazz);
624 gMetadataOffsets.mRequestKey = MakeGlobalRefOrDie(env, requestKeyClazz);
625 gMetadataOffsets.mResultKey = MakeGlobalRefOrDie(env, resultKeyClazz);
626 gMetadataOffsets.mCharacteristicsConstr = GetMethodIDOrDie(env,
627 gMetadataOffsets.mCharacteristicsKey, "<init>",
628 "(Ljava/lang/String;Ljava/lang/Class;)V");
629 gMetadataOffsets.mRequestConstr = GetMethodIDOrDie(env,
630 gMetadataOffsets.mRequestKey, "<init>", "(Ljava/lang/String;Ljava/lang/Class;)V");
631 gMetadataOffsets.mResultConstr = GetMethodIDOrDie(env,
632 gMetadataOffsets.mResultKey, "<init>", "(Ljava/lang/String;Ljava/lang/Class;)V");
633
634 // Store global references for primitive array types used by Keys
635 jclass byteClazz = FindClassOrDie(env, "[B");
636 jclass int32Clazz = FindClassOrDie(env, "[I");
637 jclass floatClazz = FindClassOrDie(env, "[F");
638 jclass int64Clazz = FindClassOrDie(env, "[J");
639 jclass doubleClazz = FindClassOrDie(env, "[D");
640 jclass rationalClazz = FindClassOrDie(env, "[Landroid/util/Rational;");
641 gMetadataOffsets.mByteArray = MakeGlobalRefOrDie(env, byteClazz);
642 gMetadataOffsets.mInt32Array = MakeGlobalRefOrDie(env, int32Clazz);
643 gMetadataOffsets.mFloatArray = MakeGlobalRefOrDie(env, floatClazz);
644 gMetadataOffsets.mInt64Array = MakeGlobalRefOrDie(env, int64Clazz);
645 gMetadataOffsets.mDoubleArray = MakeGlobalRefOrDie(env, doubleClazz);
646 gMetadataOffsets.mRationalArray = MakeGlobalRefOrDie(env, rationalClazz);
647
648 // Store global references for ArrayList methods used
649 jclass arrayListClazz = FindClassOrDie(env, "java/util/ArrayList");
650 gMetadataOffsets.mArrayList = MakeGlobalRefOrDie(env, arrayListClazz);
651 gMetadataOffsets.mArrayListConstr = GetMethodIDOrDie(env, gMetadataOffsets.mArrayList,
652 "<init>", "(I)V");
653 gMetadataOffsets.mArrayListAdd = GetMethodIDOrDie(env, gMetadataOffsets.mArrayList,
654 "add", "(Ljava/lang/Object;)Z");
655
Igor Murashkin70725502013-06-25 20:27:06 +0000656 // Register native functions
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800657 return RegisterMethodsOrDie(env,
Igor Murashkin70725502013-06-25 20:27:06 +0000658 CAMERA_METADATA_CLASS_NAME,
659 gCameraMetadataMethods,
660 NELEM(gCameraMetadataMethods));
661}
662
663extern "C" {
Ruben Brunkc620eb72015-07-29 18:19:11 -0700664
Igor Murashkin70725502013-06-25 20:27:06 +0000665static void CameraMetadata_classInit(JNIEnv *env, jobject thiz) {
666 // XX: Why do this separately instead of doing it in the register function?
667 ALOGV("%s", __FUNCTION__);
668
669 field fields_to_find[] = {
670 { CAMERA_METADATA_CLASS_NAME, "mMetadataPtr", "J", &fields.metadata_ptr },
671 };
672
673 // Do this here instead of in register_native_methods,
674 // since otherwise it will fail to find the fields.
675 if (find_fields(env, fields_to_find, NELEM(fields_to_find)) < 0)
676 return;
677
Andreas Gampe0f0b4912014-11-12 08:03:48 -0800678 env->FindClass(CAMERA_METADATA_CLASS_NAME);
Igor Murashkin70725502013-06-25 20:27:06 +0000679}
Igor Murashkinb519cc52013-07-02 11:23:44 -0700680
Ruben Brunkc620eb72015-07-29 18:19:11 -0700681static jobject CameraMetadata_getAllVendorKeys(JNIEnv* env, jobject thiz, jclass keyType) {
682
683 // Get all vendor tags
684 sp<VendorTagDescriptor> vTags = VendorTagDescriptor::getGlobalVendorTagDescriptor();
685 if (vTags.get() == nullptr) {
686 // No vendor tags.
687 return NULL;
688 }
689
690 int count = vTags->getTagCount();
691 if (count <= 0) {
692 // No vendor tags.
693 return NULL;
694 }
695
696 std::vector<uint32_t> tagIds(count, /*initializer value*/0);
697 vTags->getTagArray(&tagIds[0]);
698
699 // Which key class/constructor should we use?
700 jclass keyClazz;
701 jmethodID keyConstr;
702 if (env->IsSameObject(keyType, gMetadataOffsets.mCharacteristicsKey)) {
703 keyClazz = gMetadataOffsets.mCharacteristicsKey;
704 keyConstr = gMetadataOffsets.mCharacteristicsConstr;
705 } else if (env->IsSameObject(keyType, gMetadataOffsets.mResultKey)) {
706 keyClazz = gMetadataOffsets.mResultKey;
707 keyConstr = gMetadataOffsets.mResultConstr;
708 } else if (env->IsSameObject(keyType, gMetadataOffsets.mRequestKey)) {
709 keyClazz = gMetadataOffsets.mRequestKey;
710 keyConstr = gMetadataOffsets.mRequestConstr;
711 } else {
712 jniThrowException(env, "java/lang/IllegalArgumentException",
713 "Invalid key class given as argument.");
714 return NULL;
715 }
716
717 // Allocate arrayList to return
718 jobject arrayList = env->NewObject(gMetadataOffsets.mArrayList,
719 gMetadataOffsets.mArrayListConstr, static_cast<jint>(count));
720 if (env->ExceptionCheck()) {
721 return NULL;
722 }
723
724 for (uint32_t id : tagIds) {
725 const char* section = vTags->getSectionName(id);
726 const char* tag = vTags->getTagName(id);
727 int type = vTags->getTagType(id);
728
729 size_t totalLen = strlen(section) + strlen(tag) + 2;
730 std::vector<char> fullName(totalLen, 0);
731 snprintf(&fullName[0], totalLen, "%s.%s", section, tag);
732
733 jstring name = env->NewStringUTF(&fullName[0]);
734
735 if (env->ExceptionCheck()) {
736 return NULL;
737 }
738
739 jclass valueClazz;
740 switch (type) {
741 case TYPE_BYTE:
742 valueClazz = gMetadataOffsets.mByteArray;
743 break;
744 case TYPE_INT32:
745 valueClazz = gMetadataOffsets.mInt32Array;
746 break;
747 case TYPE_FLOAT:
748 valueClazz = gMetadataOffsets.mFloatArray;
749 break;
750 case TYPE_INT64:
751 valueClazz = gMetadataOffsets.mInt64Array;
752 break;
753 case TYPE_DOUBLE:
754 valueClazz = gMetadataOffsets.mDoubleArray;
755 break;
756 case TYPE_RATIONAL:
757 valueClazz = gMetadataOffsets.mRationalArray;
758 break;
759 default:
760 jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
761 "Invalid type %d given for key %s", type, &fullName[0]);
762 return NULL;
763 }
764
765 jobject key = env->NewObject(keyClazz, keyConstr, name, valueClazz);
766 if (env->ExceptionCheck()) {
767 return NULL;
768 }
769
770 env->CallBooleanMethod(arrayList, gMetadataOffsets.mArrayListAdd, key);
771 if (env->ExceptionCheck()) {
772 return NULL;
773 }
774
775 env->DeleteLocalRef(name);
776 env->DeleteLocalRef(key);
777 }
778
779 return arrayList;
780}
781
Igor Murashkinb519cc52013-07-02 11:23:44 -0700782static jint CameraMetadata_getTagFromKey(JNIEnv *env, jobject thiz, jstring keyName) {
783
784 ScopedUtfChars keyScoped(env, keyName);
785 const char *key = keyScoped.c_str();
786 if (key == NULL) {
787 // exception thrown by ScopedUtfChars
788 return 0;
789 }
790 size_t keyLength = strlen(key);
791
792 ALOGV("%s (key = '%s')", __FUNCTION__, key);
793
Ruben Brunk32ef3ae2014-02-21 17:40:51 -0800794 sp<VendorTagDescriptor> vTags = VendorTagDescriptor::getGlobalVendorTagDescriptor();
795
Igor Murashkin3c40a042014-04-22 15:05:50 -0700796 SortedVector<String8> vendorSections;
797 size_t vendorSectionCount = 0;
798
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700799 if (vTags != NULL) {
Igor Murashkin3c40a042014-04-22 15:05:50 -0700800 vendorSections = vTags->getAllSectionNames();
801 vendorSectionCount = vendorSections.size();
802 }
Ruben Brunk32ef3ae2014-02-21 17:40:51 -0800803
Igor Murashkinb519cc52013-07-02 11:23:44 -0700804 // First, find the section by the longest string match
805 const char *section = NULL;
806 size_t sectionIndex = 0;
807 size_t sectionLength = 0;
Ruben Brunk32ef3ae2014-02-21 17:40:51 -0800808 size_t totalSectionCount = ANDROID_SECTION_COUNT + vendorSectionCount;
809 for (size_t i = 0; i < totalSectionCount; ++i) {
810
811 const char *str = (i < ANDROID_SECTION_COUNT) ? camera_metadata_section_names[i] :
812 vendorSections[i - ANDROID_SECTION_COUNT].string();
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800813 if (kIsDebug) {
814 ALOGV("%s: Trying to match against section '%s'", __FUNCTION__, str);
815 }
Igor Murashkinb519cc52013-07-02 11:23:44 -0700816 if (strstr(key, str) == key) { // key begins with the section name
817 size_t strLength = strlen(str);
818
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800819 if (kIsDebug) {
820 ALOGV("%s: Key begins with section name", __FUNCTION__);
821 }
Igor Murashkinb519cc52013-07-02 11:23:44 -0700822
823 // section name is the longest we've found so far
824 if (section == NULL || sectionLength < strLength) {
825 section = str;
826 sectionIndex = i;
827 sectionLength = strLength;
828
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800829 if (kIsDebug) {
830 ALOGV("%s: Found new best section (%s)", __FUNCTION__, section);
831 }
Igor Murashkinb519cc52013-07-02 11:23:44 -0700832 }
833 }
834 }
835
Igor Murashkinb519cc52013-07-02 11:23:44 -0700836 // TODO: Make above get_camera_metadata_section_from_name ?
837
838 if (section == NULL) {
839 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
840 "Could not find section name for key '%s')", key);
841 return 0;
842 } else {
Dan Albert46d84442014-11-18 16:07:51 -0800843 ALOGV("%s: Found matched section '%s' (%zu)",
Igor Murashkinb519cc52013-07-02 11:23:44 -0700844 __FUNCTION__, section, sectionIndex);
845 }
846
847 // Get the tag name component of the key
848 const char *keyTagName = key + sectionLength + 1; // x.y.z -> z
849 if (sectionLength + 1 >= keyLength) {
850 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
851 "Key length too short for key '%s')", key);
Ruben Brunk32ef3ae2014-02-21 17:40:51 -0800852 return 0;
Igor Murashkinb519cc52013-07-02 11:23:44 -0700853 }
854
855 // Match rest of name against the tag names in that section only
Ruben Brunk32ef3ae2014-02-21 17:40:51 -0800856 uint32_t tag = 0;
857 if (sectionIndex < ANDROID_SECTION_COUNT) {
858 // Match built-in tags (typically android.*)
859 uint32_t tagBegin, tagEnd; // [tagBegin, tagEnd)
860 tagBegin = camera_metadata_section_bounds[sectionIndex][0];
861 tagEnd = camera_metadata_section_bounds[sectionIndex][1];
Igor Murashkinb519cc52013-07-02 11:23:44 -0700862
Ruben Brunk32ef3ae2014-02-21 17:40:51 -0800863 for (tag = tagBegin; tag < tagEnd; ++tag) {
864 const char *tagName = get_camera_metadata_tag_name(tag);
Igor Murashkinb519cc52013-07-02 11:23:44 -0700865
Ruben Brunk32ef3ae2014-02-21 17:40:51 -0800866 if (strcmp(keyTagName, tagName) == 0) {
867 ALOGV("%s: Found matched tag '%s' (%d)",
868 __FUNCTION__, tagName, tag);
869 break;
870 }
871 }
872
873 if (tag == tagEnd) {
874 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
875 "Could not find tag name for key '%s')", key);
876 return 0;
877 }
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700878 } else if (vTags != NULL) {
Ruben Brunk32ef3ae2014-02-21 17:40:51 -0800879 // Match vendor tags (typically com.*)
880 const String8 sectionName(section);
881 const String8 tagName(keyTagName);
882
883 status_t res = OK;
884 if ((res = vTags->lookupTag(tagName, sectionName, &tag)) != OK) {
885 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
886 "%s: No vendor tag matches key '%s'", __FUNCTION__, key);
887 return 0;
Igor Murashkinb519cc52013-07-02 11:23:44 -0700888 }
889 }
890
Igor Murashkinb519cc52013-07-02 11:23:44 -0700891 // TODO: Make above get_camera_metadata_tag_from_name ?
892
Igor Murashkinb519cc52013-07-02 11:23:44 -0700893 return tag;
894}
895
896static jint CameraMetadata_getTypeFromTag(JNIEnv *env, jobject thiz, jint tag) {
897 int tagType = get_camera_metadata_tag_type(tag);
898 if (tagType == -1) {
899 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
900 "Tag (%d) did not have a type", tag);
901 return -1;
902 }
903
904 return tagType;
905}
906
Ruben Brunk85c43882014-02-21 17:40:51 -0800907static jint CameraMetadata_setupGlobalVendorTagDescriptor(JNIEnv *env, jobject thiz) {
908 const String16 NAME("media.camera");
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800909 sp<hardware::ICameraService> cameraService;
Ruben Brunk85c43882014-02-21 17:40:51 -0800910 status_t err = getService(NAME, /*out*/&cameraService);
911
912 if (err != OK) {
913 ALOGE("%s: Failed to get camera service, received error %s (%d)", __FUNCTION__,
914 strerror(-err), err);
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800915 return hardware::ICameraService::ERROR_DISCONNECTED;
Ruben Brunk85c43882014-02-21 17:40:51 -0800916 }
917
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800918 sp<VendorTagDescriptor> desc = new VendorTagDescriptor();
919 binder::Status res = cameraService->getCameraVendorTagDescriptor(/*out*/desc.get());
Ruben Brunk85c43882014-02-21 17:40:51 -0800920
Eino-Ville Talvala5f2f8042016-03-03 11:50:39 -0800921 if (res.serviceSpecificErrorCode() == hardware::ICameraService::ERROR_DISCONNECTED) {
922 // No camera module available, not an error on devices with no cameras
Igor Murashkin5614cbe2014-03-17 14:00:55 -0700923 VendorTagDescriptor::clearGlobalVendorTagDescriptor();
Igor Murashkin5614cbe2014-03-17 14:00:55 -0700924 return OK;
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800925 } else if (!res.isOk()) {
Eino-Ville Talvala5f2f8042016-03-03 11:50:39 -0800926 VendorTagDescriptor::clearGlobalVendorTagDescriptor();
927 ALOGE("%s: Failed to setup vendor tag descriptors: %s",
928 __FUNCTION__, res.toString8().string());
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800929 return res.serviceSpecificErrorCode();
Ruben Brunk85c43882014-02-21 17:40:51 -0800930 }
931
932 err = VendorTagDescriptor::setAsGlobalVendorTagDescriptor(desc);
933
Eino-Ville Talvala5d2d7782015-12-17 16:50:50 -0800934 if (err != OK) {
935 return hardware::ICameraService::ERROR_INVALID_OPERATION;
936 }
937 return OK;
Ruben Brunk85c43882014-02-21 17:40:51 -0800938}
939
Igor Murashkin70725502013-06-25 20:27:06 +0000940} // extern "C"