• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 #undef ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION // TODO:remove this and fix code
18 
19 // #define LOG_NDEBUG 0
20 #include <memory>
21 #define LOG_TAG "CameraMetadata-JNI"
22 #include <utils/Errors.h>
23 #include <utils/Log.h>
24 #include <utils/RefBase.h>
25 #include <utils/Vector.h>
26 #include <utils/SortedVector.h>
27 #include <utils/KeyedVector.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include <vector>
31 
32 #include "jni.h"
33 #include <nativehelper/JNIHelp.h>
34 #include "android_os_Parcel.h"
35 #include "core_jni_helpers.h"
36 #include "android_runtime/android_hardware_camera2_CameraMetadata.h"
37 
38 #include <android/hardware/ICameraService.h>
39 #include <binder/IServiceManager.h>
40 #include <camera/CameraMetadata.h>
41 #include <camera_metadata_hidden.h>
42 #include <camera/VendorTagDescriptor.h>
43 #include <nativehelper/ScopedUtfChars.h>
44 #include <nativehelper/ScopedPrimitiveArray.h>
45 
46 #include <sys/types.h> // for socketpair
47 #include <sys/socket.h> // for socketpair
48 
49 // fully-qualified class name
50 #define CAMERA_METADATA_CLASS_NAME "android/hardware/camera2/impl/CameraMetadataNative"
51 #define CHARACTERISTICS_KEY_CLASS_NAME "android/hardware/camera2/CameraCharacteristics$Key"
52 #define REQUEST_KEY_CLASS_NAME "android/hardware/camera2/CaptureRequest$Key"
53 #define RESULT_KEY_CLASS_NAME "android/hardware/camera2/CaptureResult$Key"
54 
55 using namespace android;
56 
57 static struct metadata_java_key_offsets_t {
58     jclass mCharacteristicsKey;
59     jclass mResultKey;
60     jclass mRequestKey;
61     jmethodID mCharacteristicsConstr;
62     jmethodID mResultConstr;
63     jmethodID mRequestConstr;
64     jclass mByteArray;
65     jclass mInt32Array;
66     jclass mFloatArray;
67     jclass mInt64Array;
68     jclass mDoubleArray;
69     jclass mRationalArray;
70     jclass mArrayList;
71     jmethodID mArrayListConstr;
72     jmethodID mArrayListAdd;
73 } gMetadataOffsets;
74 
75 struct fields_t {
76     jfieldID    metadata_ptr;
77 };
78 
79 static fields_t fields;
80 
81 namespace android {
82 
CameraMetadata_getNativeMetadata(JNIEnv * env,jobject thiz,CameraMetadata * metadata)83 status_t CameraMetadata_getNativeMetadata(JNIEnv* env, jobject thiz,
84         /*out*/CameraMetadata* metadata) {
85     if (!thiz) {
86         ALOGE("%s: Invalid java metadata object.", __FUNCTION__);
87         return BAD_VALUE;
88     }
89 
90     if (!metadata) {
91         ALOGE("%s: Invalid output metadata object.", __FUNCTION__);
92         return BAD_VALUE;
93     }
94     auto nativePtr = reinterpret_cast<std::shared_ptr<CameraMetadata> *>(
95             env->GetLongField(thiz, fields.metadata_ptr));
96     if (nativePtr == NULL) {
97         ALOGE("%s: Invalid native pointer in java metadata object.", __FUNCTION__);
98         return BAD_VALUE;
99     }
100     *metadata = *(nativePtr->get());
101     return OK;
102 }
103 
104 } /*namespace android*/
105 
106 namespace {
107 struct Helpers {
getTypeSize__anonc6fc29f90111::Helpers108     static size_t getTypeSize(uint8_t type) {
109         if (type >= NUM_TYPES) {
110             ALOGE("%s: Invalid type specified (%ud)", __FUNCTION__, type);
111             return static_cast<size_t>(-1);
112         }
113 
114         return camera_metadata_type_size[type];
115     }
116 
updateAny__anonc6fc29f90111::Helpers117     static status_t updateAny(CameraMetadata *metadata,
118                           uint32_t tag,
119                           uint32_t type,
120                           const void *data,
121                           size_t dataBytes) {
122 
123         if (type >= NUM_TYPES) {
124             ALOGE("%s: Invalid type specified (%ud)", __FUNCTION__, type);
125             return INVALID_OPERATION;
126         }
127 
128         size_t typeSize = getTypeSize(type);
129 
130         if (dataBytes % typeSize != 0) {
131             ALOGE("%s: Expected dataBytes (%zu) to be divisible by typeSize "
132                   "(%zu)", __FUNCTION__, dataBytes, typeSize);
133             return BAD_VALUE;
134         }
135 
136         size_t dataCount = dataBytes / typeSize;
137 
138         switch(type) {
139 #define METADATA_UPDATE(runtime_type, compile_type)                            \
140             case runtime_type: {                                               \
141                 const compile_type *dataPtr =                                  \
142                         static_cast<const compile_type*>(data);                \
143                 return metadata->update(tag, dataPtr, dataCount);              \
144             }                                                                  \
145 
146             METADATA_UPDATE(TYPE_BYTE,     uint8_t);
147             METADATA_UPDATE(TYPE_INT32,    int32_t);
148             METADATA_UPDATE(TYPE_FLOAT,    float);
149             METADATA_UPDATE(TYPE_INT64,    int64_t);
150             METADATA_UPDATE(TYPE_DOUBLE,   double);
151             METADATA_UPDATE(TYPE_RATIONAL, camera_metadata_rational_t);
152 
153             default: {
154                 // unreachable
155                 ALOGE("%s: Unreachable", __FUNCTION__);
156                 return INVALID_OPERATION;
157             }
158         }
159 
160 #undef METADATA_UPDATE
161     }
162 };
163 } // namespace {}
164 
165 extern "C" {
166 
167 static void CameraMetadata_setVendorId(JNIEnv* env, jclass thiz, jlong ptr,
168         jlong vendorId);
169 static jobject CameraMetadata_getAllVendorKeys(JNIEnv* env, jclass thiz, jlong ptr,
170         jclass keyType);
171 static jint CameraMetadata_getTagFromKey(JNIEnv *env, jclass thiz, jstring keyName,
172         jlong vendorId);
173 static jint CameraMetadata_getTagFromKeyLocal(JNIEnv *env, jclass thiz, jlong ptr,
174         jstring keyName);
175 static jint CameraMetadata_getTypeFromTag(JNIEnv *env, jclass thiz, jint tag, jlong vendorId);
176 static jint CameraMetadata_getTypeFromTagLocal(JNIEnv *env, jclass thiz, jlong ptr, jint tag);
177 static jint CameraMetadata_setupGlobalVendorTagDescriptor(JNIEnv *env, jclass thiz);
178 
CameraMetadata_getSharedPtr(jlong metadataLongPtr)179 static std::shared_ptr<CameraMetadata>* CameraMetadata_getSharedPtr(jlong metadataLongPtr) {
180     return reinterpret_cast<std::shared_ptr<CameraMetadata>* >(metadataLongPtr);
181 }
182 
183 // Less safe access to native pointer. Does NOT throw any Java exceptions if NULL.
CameraMetadata_getPointerNoThrow(jlong ptr)184 static CameraMetadata* CameraMetadata_getPointerNoThrow(jlong ptr) {
185     auto metadata = CameraMetadata_getSharedPtr(ptr);
186     if (metadata == nullptr) {
187         return nullptr;
188     }
189     return metadata->get();
190 }
191 
192 // Safe access to native pointer from object. Throws if not possible to access.
CameraMetadata_getPointerThrow(JNIEnv * env,jlong ptr,const char * argName="this")193 static CameraMetadata* CameraMetadata_getPointerThrow(JNIEnv *env, jlong ptr,
194                                                  const char* argName = "this") {
195     CameraMetadata* metadata = CameraMetadata_getPointerNoThrow(ptr);
196     if (metadata == nullptr) {
197         ALOGV("%s: Throwing java.lang.IllegalStateException for closed object",
198               __FUNCTION__);
199         jniThrowException(env, "java/lang/IllegalStateException",
200                             "Metadata object was already closed");
201         return nullptr;
202     }
203 
204     return metadata;
205 }
206 
CameraMetadata_allocate(JNIEnv * env,jclass thiz)207 static jlong CameraMetadata_allocate(JNIEnv *env, jclass thiz) {
208     ALOGV("%s", __FUNCTION__);
209 
210     return reinterpret_cast<jlong>(new std::shared_ptr<CameraMetadata>(new CameraMetadata()));
211 }
212 
CameraMetadata_allocateCopy(JNIEnv * env,jclass thiz,jlong other)213 static jlong CameraMetadata_allocateCopy(JNIEnv *env, jclass thiz, jlong other) {
214     ALOGV("%s", __FUNCTION__);
215 
216     CameraMetadata* otherMetadata =
217             CameraMetadata_getPointerThrow(env, other);
218     // In case of exception, return
219     if (otherMetadata == NULL) return NULL;
220 
221     // Clone native metadata and return new pointer.
222     auto clonedMetadata = new CameraMetadata(*otherMetadata);
223     return reinterpret_cast<jlong>(new std::shared_ptr<CameraMetadata>(clonedMetadata));
224 }
225 
226 
CameraMetadata_isEmpty(JNIEnv * env,jclass thiz,jlong ptr)227 static jboolean CameraMetadata_isEmpty(JNIEnv *env, jclass thiz, jlong ptr) {
228     ALOGV("%s", __FUNCTION__);
229 
230     CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, ptr);
231 
232     if (metadata == NULL) {
233         ALOGW("%s: Returning early due to exception being thrown",
234                __FUNCTION__);
235         return JNI_TRUE; // actually throws java exc.
236     }
237 
238     jboolean empty = metadata->isEmpty();
239 
240     ALOGV("%s: Empty returned %d, entry count was %zu",
241           __FUNCTION__, empty, metadata->entryCount());
242 
243     return empty;
244 }
245 
CameraMetadata_getEntryCount(JNIEnv * env,jclass thiz,jlong ptr)246 static jint CameraMetadata_getEntryCount(JNIEnv *env, jclass thiz, jlong ptr) {
247     ALOGV("%s", __FUNCTION__);
248 
249     CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, ptr);
250 
251     if (metadata == NULL) return 0; // actually throws java exc.
252 
253     return metadata->entryCount();
254 }
255 
CameraMetadata_update(JNIEnv * env,jclass thiz,jlong dst,jlong src)256 static void CameraMetadata_update(JNIEnv *env, jclass thiz, jlong dst, jlong src) {
257     ALOGV("%s", __FUNCTION__);
258 
259     CameraMetadata* metadataDst = CameraMetadata_getPointerThrow(env, dst);
260     CameraMetadata* metadataSrc = CameraMetadata_getPointerThrow(env, src);
261 
262     if (((metadataDst == NULL) || (metadataDst->isEmpty())) ||
263             ((metadataSrc == NULL) || metadataSrc->isEmpty())) {
264         return;
265     }
266 
267     auto metaBuffer = metadataSrc->getAndLock();
268     camera_metadata_ro_entry_t entry;
269     auto entryCount = get_camera_metadata_entry_count(metaBuffer);
270     for (size_t i = 0; i < entryCount; i++) {
271         auto stat = get_camera_metadata_ro_entry(metaBuffer, i, &entry);
272         if (stat != NO_ERROR) {
273             ALOGE("%s: Failed to retrieve source metadata!", __func__);
274             metadataSrc->unlock(metaBuffer);
275             return;
276         }
277         switch (entry.type) {
278             case TYPE_BYTE:
279                 metadataDst->update(entry.tag, entry.data.u8, entry.count);
280                 break;
281             case TYPE_INT32:
282                 metadataDst->update(entry.tag, entry.data.i32, entry.count);
283                 break;
284             case TYPE_FLOAT:
285                 metadataDst->update(entry.tag, entry.data.f, entry.count);
286                 break;
287             case TYPE_INT64:
288                 metadataDst->update(entry.tag, entry.data.i64, entry.count);
289                 break;
290             case TYPE_DOUBLE:
291                 metadataDst->update(entry.tag, entry.data.d, entry.count);
292                 break;
293             case TYPE_RATIONAL:
294                 metadataDst->update(entry.tag, entry.data.r, entry.count);
295                 break;
296             default:
297                 ALOGE("%s: Unsupported tag type: %d!", __func__, entry.type);
298         }
299     }
300     metadataSrc->unlock(metaBuffer);
301 }
302 
CameraMetadata_getBufferSize(JNIEnv * env,jclass thiz,jlong ptr)303 static jlong CameraMetadata_getBufferSize(JNIEnv *env, jclass thiz, jlong ptr) {
304     ALOGV("%s", __FUNCTION__);
305 
306     CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, ptr);
307 
308     if (metadata == NULL) return 0;
309 
310     return metadata->bufferSize();
311 }
312 
313 // idempotent. calling more than once has no effect.
CameraMetadata_close(JNIEnv * env,jclass thiz,jlong ptr)314 static void CameraMetadata_close(JNIEnv *env, jclass thiz, jlong ptr) {
315     ALOGV("%s", __FUNCTION__);
316 
317     auto metadata = CameraMetadata_getSharedPtr(ptr);
318     if (metadata != nullptr) {
319         delete metadata;
320     }
321 }
322 
CameraMetadata_swap(JNIEnv * env,jclass thiz,jlong ptr,jlong other)323 static void CameraMetadata_swap(JNIEnv *env, jclass thiz, jlong ptr, jlong other) {
324     ALOGV("%s", __FUNCTION__);
325 
326     auto metadata = CameraMetadata_getSharedPtr(ptr);
327     auto otherMetadata = CameraMetadata_getSharedPtr(other);
328 
329     if (metadata == NULL) return;
330     if (otherMetadata == NULL) return;
331 
332     // Need to swap shared pointers, not CameraMetadata, since the latter may be in use
333     // by an NDK client, and we don't want to swap their data out from under them.
334     metadata->swap(*otherMetadata);
335 }
336 
CameraMetadata_readValues(JNIEnv * env,jclass thiz,jint tag,jlong ptr)337 static jbyteArray CameraMetadata_readValues(JNIEnv *env, jclass thiz, jint tag, jlong ptr) {
338     ALOGV("%s (tag = %d)", __FUNCTION__, tag);
339 
340     const CameraMetadata *metadata = CameraMetadata_getPointerThrow(env, ptr);
341     if (metadata == NULL) return NULL;
342 
343     const camera_metadata_t *metaBuffer = metadata->getAndLock();
344     int tagType = get_local_camera_metadata_tag_type(tag, metaBuffer);
345     metadata->unlock(metaBuffer);
346     if (tagType == -1) {
347         jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
348                              "Tag (%d) did not have a type", tag);
349         return NULL;
350     }
351     size_t tagSize = Helpers::getTypeSize(tagType);
352 
353     camera_metadata_ro_entry entry = metadata->find(tag);
354     if (entry.count == 0) {
355         if (!metadata->exists(tag)) {
356             ALOGV("%s: Tag %d does not have any entries", __FUNCTION__, tag);
357             return NULL;
358         } else {
359             // OK: we will return a 0-sized array.
360             ALOGV("%s: Tag %d had an entry, but it had 0 data", __FUNCTION__, tag);
361         }
362     }
363 
364     jsize byteCount = entry.count * tagSize;
365     jbyteArray byteArray = env->NewByteArray(byteCount);
366     if (env->ExceptionCheck()) return NULL;
367 
368     // Copy into java array from native array
369     ScopedByteArrayRW arrayWriter(env, byteArray);
370     memcpy(arrayWriter.get(), entry.data.u8, byteCount);
371 
372     return byteArray;
373 }
374 
CameraMetadata_writeValues(JNIEnv * env,jclass thiz,jint tag,jbyteArray src,jlong ptr)375 static void CameraMetadata_writeValues(JNIEnv *env, jclass thiz, jint tag, jbyteArray src,
376         jlong ptr) {
377     ALOGV("%s (tag = %d)", __FUNCTION__, tag);
378 
379     CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, ptr);
380     if (metadata == NULL) return;
381 
382     const camera_metadata_t *metaBuffer = metadata->getAndLock();
383     int tagType = get_local_camera_metadata_tag_type(tag, metaBuffer);
384     metadata->unlock(metaBuffer);
385     if (tagType == -1) {
386         jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
387                              "Tag (%d) did not have a type", tag);
388         return;
389     }
390 
391     status_t res;
392 
393     if (src == NULL) {
394         // If array is NULL, delete the entry
395         if (metadata->exists(tag)) {
396             res = metadata->erase(tag);
397             ALOGV("%s: Erase values (res = %d)", __FUNCTION__, res);
398         } else {
399             res = OK;
400             ALOGV("%s: Don't need to erase", __FUNCTION__);
401         }
402     } else {
403         // Copy from java array into native array
404         ScopedByteArrayRO arrayReader(env, src);
405         if (arrayReader.get() == NULL) return;
406 
407         res = Helpers::updateAny(metadata, static_cast<uint32_t>(tag),
408                                  tagType, arrayReader.get(), arrayReader.size());
409 
410         ALOGV("%s: Update values (res = %d)", __FUNCTION__, res);
411     }
412 
413     if (res == OK) {
414         return;
415     } else if (res == BAD_VALUE) {
416         jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
417                              "Src byte array was poorly formed");
418     } else if (res == INVALID_OPERATION) {
419         jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
420                              "Internal error while trying to update metadata");
421     } else {
422         jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
423                              "Unknown error (%d) while trying to update "
424                             "metadata", res);
425     }
426 }
427 
428 struct DumpMetadataParams {
429     int writeFd;
430     const CameraMetadata* metadata;
431 };
432 
CameraMetadata_writeMetadataThread(void * arg)433 static void* CameraMetadata_writeMetadataThread(void* arg) {
434     DumpMetadataParams* p = static_cast<DumpMetadataParams*>(arg);
435 
436     /*
437      * Write the dumped data, and close the writing side FD.
438      */
439     p->metadata->dump(p->writeFd, /*verbosity*/2);
440 
441     if (close(p->writeFd) < 0) {
442         ALOGE("%s: Failed to close writeFd (errno = %#x, message = '%s')",
443                 __FUNCTION__, errno, strerror(errno));
444     }
445 
446     return NULL;
447 }
448 
CameraMetadata_dump(JNIEnv * env,jclass thiz,jlong ptr)449 static void CameraMetadata_dump(JNIEnv *env, jclass thiz, jlong ptr) {
450     ALOGV("%s", __FUNCTION__);
451     CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, ptr);
452     if (metadata == NULL) {
453         return;
454     }
455 
456     /*
457      * Create a socket pair for local streaming read/writes.
458      *
459      * The metadata will be dumped into the write side,
460      * and then read back out (and logged) via the read side.
461      */
462 
463     int writeFd, readFd;
464     {
465 
466         int sv[2];
467         if (socketpair(AF_LOCAL, SOCK_STREAM, /*protocol*/0, &sv[0]) < 0) {
468             jniThrowExceptionFmt(env, "java/io/IOException",
469                     "Failed to create socketpair (errno = %#x, message = '%s')",
470                     errno, strerror(errno));
471             return;
472         }
473         writeFd = sv[0];
474         readFd = sv[1];
475     }
476 
477     /*
478      * Create a thread for doing the writing.
479      *
480      * The reading and writing must be concurrent, otherwise
481      * the write will block forever once it exhausts the capped
482      * buffer size (from getsockopt).
483      */
484     pthread_t writeThread;
485     DumpMetadataParams params = {
486         writeFd,
487         metadata
488     };
489 
490     {
491         int threadRet = pthread_create(&writeThread, /*attr*/NULL,
492                 CameraMetadata_writeMetadataThread, (void*)&params);
493 
494         if (threadRet != 0) {
495             close(writeFd);
496             close(readFd);
497 
498             jniThrowExceptionFmt(env, "java/io/IOException",
499                     "Failed to create thread for writing (errno = %#x, message = '%s')",
500                     threadRet, strerror(threadRet));
501             return;
502         }
503     }
504 
505     /*
506      * Read out a byte until stream is complete. Write completed lines
507      * to ALOG.
508      */
509     {
510         char out[] = {'\0', '\0'}; // large enough to append as a string
511         String8 logLine;
512 
513         // Read one byte at a time! Very slow but avoids complicated \n scanning.
514         ssize_t res;
515         while ((res = TEMP_FAILURE_RETRY(read(readFd, &out[0], /*count*/1))) > 0) {
516             if (out[0] == '\n') {
517                 ALOGD("%s", logLine.c_str());
518                 logLine.clear();
519             } else {
520                 logLine.append(out);
521             }
522         }
523 
524         if (res < 0) {
525             jniThrowExceptionFmt(env, "java/io/IOException",
526                     "Failed to read from fd (errno = %#x, message = '%s')",
527                     errno, strerror(errno));
528             //return;
529         } else if (!logLine.empty()) {
530             ALOGD("%s", logLine.c_str());
531         }
532 
533         close(readFd);
534     }
535 
536     int res;
537 
538     // Join until thread finishes. Ensures params/metadata is valid until then.
539     if ((res = pthread_join(writeThread, /*retval*/NULL)) != 0) {
540         ALOGE("%s: Failed to join thread (errno = %#x, message = '%s')",
541                 __FUNCTION__, res, strerror(res));
542     }
543 }
544 
CameraMetadata_readFromParcel(JNIEnv * env,jclass thiz,jobject parcel,jlong ptr)545 static void CameraMetadata_readFromParcel(JNIEnv *env, jclass thiz, jobject parcel, jlong ptr) {
546     ALOGV("%s", __FUNCTION__);
547     CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, ptr);
548     if (metadata == NULL) {
549         return;
550     }
551 
552     Parcel* parcelNative = parcelForJavaObject(env, parcel);
553     if (parcelNative == NULL) {
554         jniThrowNullPointerException(env, "parcel");
555         return;
556     }
557 
558     status_t err;
559     if ((err = metadata->readFromParcel(parcelNative)) != OK) {
560         jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
561                              "Failed to read from parcel (error code %d)", err);
562         return;
563     }
564 
565     // Update vendor descriptor cache if necessary
566     auto vendorId = metadata->getVendorId();
567     if ((vendorId != CAMERA_METADATA_INVALID_VENDOR_ID) &&
568             !VendorTagDescriptorCache::isVendorCachePresent(vendorId)) {
569         ALOGW("%s: Tag vendor id missing or cache not initialized, trying to update!",
570                 __FUNCTION__);
571         CameraMetadata_setupGlobalVendorTagDescriptor(env, thiz);
572     }
573 }
574 
CameraMetadata_writeToParcel(JNIEnv * env,jclass thiz,jobject parcel,jlong ptr)575 static void CameraMetadata_writeToParcel(JNIEnv *env, jclass thiz, jobject parcel, jlong ptr) {
576     ALOGV("%s", __FUNCTION__);
577     CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, ptr);
578     if (metadata == NULL) {
579         return;
580     }
581 
582     Parcel* parcelNative = parcelForJavaObject(env, parcel);
583     if (parcelNative == NULL) {
584         jniThrowNullPointerException(env, "parcel");
585         return;
586     }
587 
588     status_t err;
589     if ((err = metadata->writeToParcel(parcelNative)) != OK) {
590         jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
591                                   "Failed to write to parcel (error code %d)", err);
592         return;
593     }
594 }
595 
596 } // extern "C"
597 
598 //-------------------------------------------------
599 
600 static const JNINativeMethod gCameraMetadataMethods[] = {
601 // static methods
nativeSetVendorId(JJ)602   { "nativeSetVendorId",
603     "(JJ)V",
604     (void *)CameraMetadata_setVendorId },
nativeGetTagFromKey(Ljava/lang/String;J)605   { "nativeGetTagFromKey",
606     "(Ljava/lang/String;J)I",
607     (void *)CameraMetadata_getTagFromKey },
nativeGetTypeFromTag(IJ)608   { "nativeGetTypeFromTag",
609     "(IJ)I",
610     (void *)CameraMetadata_getTypeFromTag },
nativeSetupGlobalVendorTagDescriptor()611   { "nativeSetupGlobalVendorTagDescriptor",
612     "()I",
613     (void*)CameraMetadata_setupGlobalVendorTagDescriptor },
614 // instance methods
nativeAllocate()615   { "nativeAllocate",
616     "()J",
617     (void*)CameraMetadata_allocate },
nativeAllocateCopy(J)618   { "nativeAllocateCopy",
619     "(J)J",
620     (void *)CameraMetadata_allocateCopy },
nativeUpdate(JJ)621   { "nativeUpdate",
622     "(JJ)V",
623     (void*)CameraMetadata_update },
nativeIsEmpty(J)624   { "nativeIsEmpty",
625     "(J)Z",
626     (void*)CameraMetadata_isEmpty },
nativeGetEntryCount(J)627   { "nativeGetEntryCount",
628     "(J)I",
629     (void*)CameraMetadata_getEntryCount },
nativeGetBufferSize(J)630   { "nativeGetBufferSize",
631     "(J)J",
632     (void*)CameraMetadata_getBufferSize },
nativeClose(J)633   { "nativeClose",
634     "(J)V",
635     (void*)CameraMetadata_close },
nativeSwap(JJ)636   { "nativeSwap",
637     "(JJ)V",
638     (void *)CameraMetadata_swap },
nativeGetTagFromKeyLocal(JLjava/lang/String;)639   { "nativeGetTagFromKeyLocal",
640     "(JLjava/lang/String;)I",
641     (void *)CameraMetadata_getTagFromKeyLocal },
nativeGetTypeFromTagLocal(JI)642   { "nativeGetTypeFromTagLocal",
643     "(JI)I",
644     (void *)CameraMetadata_getTypeFromTagLocal },
nativeReadValues(IJ)645   { "nativeReadValues",
646     "(IJ)[B",
647     (void *)CameraMetadata_readValues },
nativeWriteValues(I[BJ)648   { "nativeWriteValues",
649     "(I[BJ)V",
650     (void *)CameraMetadata_writeValues },
nativeDump(J)651   { "nativeDump",
652     "(J)V",
653     (void *)CameraMetadata_dump },
nativeGetAllVendorKeys(JLjava/lang/Class;)654   { "nativeGetAllVendorKeys",
655     "(JLjava/lang/Class;)Ljava/util/ArrayList;",
656     (void *)CameraMetadata_getAllVendorKeys},
657 // Parcelable interface
nativeReadFromParcel(Landroid/os/Parcel;J)658   { "nativeReadFromParcel",
659     "(Landroid/os/Parcel;J)V",
660     (void *)CameraMetadata_readFromParcel },
nativeWriteToParcel(Landroid/os/Parcel;J)661   { "nativeWriteToParcel",
662     "(Landroid/os/Parcel;J)V",
663     (void *)CameraMetadata_writeToParcel },
664 };
665 
666 // Get all the required offsets in java class and register native functions
register_android_hardware_camera2_CameraMetadata(JNIEnv * env)667 int register_android_hardware_camera2_CameraMetadata(JNIEnv *env)
668 {
669 
670     // Store global references to Key-related classes and methods used natively
671     jclass characteristicsKeyClazz = FindClassOrDie(env, CHARACTERISTICS_KEY_CLASS_NAME);
672     jclass requestKeyClazz = FindClassOrDie(env, REQUEST_KEY_CLASS_NAME);
673     jclass resultKeyClazz = FindClassOrDie(env, RESULT_KEY_CLASS_NAME);
674     gMetadataOffsets.mCharacteristicsKey = MakeGlobalRefOrDie(env, characteristicsKeyClazz);
675     gMetadataOffsets.mRequestKey = MakeGlobalRefOrDie(env, requestKeyClazz);
676     gMetadataOffsets.mResultKey = MakeGlobalRefOrDie(env, resultKeyClazz);
677     gMetadataOffsets.mCharacteristicsConstr = GetMethodIDOrDie(env,
678             gMetadataOffsets.mCharacteristicsKey, "<init>",
679             "(Ljava/lang/String;Ljava/lang/Class;J)V");
680     gMetadataOffsets.mRequestConstr = GetMethodIDOrDie(env,
681             gMetadataOffsets.mRequestKey, "<init>", "(Ljava/lang/String;Ljava/lang/Class;J)V");
682     gMetadataOffsets.mResultConstr = GetMethodIDOrDie(env,
683             gMetadataOffsets.mResultKey, "<init>", "(Ljava/lang/String;Ljava/lang/Class;J)V");
684 
685     // Store global references for primitive array types used by Keys
686     jclass byteClazz = FindClassOrDie(env, "[B");
687     jclass int32Clazz = FindClassOrDie(env, "[I");
688     jclass floatClazz = FindClassOrDie(env, "[F");
689     jclass int64Clazz = FindClassOrDie(env, "[J");
690     jclass doubleClazz = FindClassOrDie(env, "[D");
691     jclass rationalClazz = FindClassOrDie(env, "[Landroid/util/Rational;");
692     gMetadataOffsets.mByteArray = MakeGlobalRefOrDie(env, byteClazz);
693     gMetadataOffsets.mInt32Array = MakeGlobalRefOrDie(env, int32Clazz);
694     gMetadataOffsets.mFloatArray = MakeGlobalRefOrDie(env, floatClazz);
695     gMetadataOffsets.mInt64Array = MakeGlobalRefOrDie(env, int64Clazz);
696     gMetadataOffsets.mDoubleArray = MakeGlobalRefOrDie(env, doubleClazz);
697     gMetadataOffsets.mRationalArray = MakeGlobalRefOrDie(env, rationalClazz);
698 
699     // Store global references for ArrayList methods used
700     jclass arrayListClazz = FindClassOrDie(env, "java/util/ArrayList");
701     gMetadataOffsets.mArrayList = MakeGlobalRefOrDie(env, arrayListClazz);
702     gMetadataOffsets.mArrayListConstr = GetMethodIDOrDie(env, gMetadataOffsets.mArrayList,
703             "<init>", "(I)V");
704     gMetadataOffsets.mArrayListAdd = GetMethodIDOrDie(env, gMetadataOffsets.mArrayList,
705             "add", "(Ljava/lang/Object;)Z");
706 
707     jclass cameraMetadataClazz = FindClassOrDie(env, CAMERA_METADATA_CLASS_NAME);
708     fields.metadata_ptr = GetFieldIDOrDie(env, cameraMetadataClazz, "mMetadataPtr", "J");
709 
710     // Register native functions
711     return RegisterMethodsOrDie(env,
712             CAMERA_METADATA_CLASS_NAME,
713             gCameraMetadataMethods,
714             NELEM(gCameraMetadataMethods));
715 }
716 
717 extern "C" {
718 
CameraMetadata_getTypeFromTagLocal(JNIEnv * env,jclass thiz,jlong ptr,jint tag)719 static jint CameraMetadata_getTypeFromTagLocal(JNIEnv *env, jclass thiz, jlong ptr, jint tag) {
720     CameraMetadata* metadata = CameraMetadata_getPointerNoThrow(ptr);
721     metadata_vendor_id_t vendorId = CAMERA_METADATA_INVALID_VENDOR_ID;
722     if (metadata) {
723         vendorId = metadata->getVendorId();
724     }
725 
726     int tagType = get_local_camera_metadata_tag_type_vendor_id(tag, vendorId);
727     if (tagType == -1) {
728         jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
729                              "Tag (%d) did not have a type", tag);
730         return -1;
731     }
732 
733     return tagType;
734 }
735 
CameraMetadata_getTagFromKeyLocal(JNIEnv * env,jclass thiz,jlong ptr,jstring keyName)736 static jint CameraMetadata_getTagFromKeyLocal(JNIEnv *env, jclass thiz, jlong ptr,
737         jstring keyName) {
738     ScopedUtfChars keyScoped(env, keyName);
739     const char *key = keyScoped.c_str();
740     if (key == NULL) {
741         // exception thrown by ScopedUtfChars
742         return 0;
743     }
744     ALOGV("%s (key = '%s')", __FUNCTION__, key);
745 
746     uint32_t tag = 0;
747     sp<VendorTagDescriptor> vTags;
748     CameraMetadata* metadata = CameraMetadata_getPointerNoThrow(ptr);
749     if (metadata) {
750         sp<VendorTagDescriptorCache> cache = VendorTagDescriptorCache::getGlobalVendorTagCache();
751         if (cache.get()) {
752             auto vendorId = metadata->getVendorId();
753             cache->getVendorTagDescriptor(vendorId, &vTags);
754         }
755     }
756 
757     status_t res = CameraMetadata::getTagFromName(key, vTags.get(), &tag);
758     if (res != OK) {
759         jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
760                              "Could not find tag for key '%s')", key);
761     }
762     return tag;
763 }
764 
CameraMetadata_getAllVendorKeys(JNIEnv * env,jclass thiz,jlong ptr,jclass keyType)765 static jobject CameraMetadata_getAllVendorKeys(JNIEnv* env, jclass thiz, jlong ptr,
766         jclass keyType) {
767     metadata_vendor_id_t vendorId = CAMERA_METADATA_INVALID_VENDOR_ID;
768     // Get all vendor tags
769     sp<VendorTagDescriptor> vTags = VendorTagDescriptor::getGlobalVendorTagDescriptor();
770     if (vTags.get() == nullptr) {
771         sp<VendorTagDescriptorCache> cache = VendorTagDescriptorCache::getGlobalVendorTagCache();
772         if (cache.get() == nullptr) {
773             // No vendor tags.
774             return nullptr;
775         }
776 
777         CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, ptr);
778         if (metadata == NULL) return NULL;
779 
780         vendorId = metadata->getVendorId();
781         cache->getVendorTagDescriptor(vendorId, &vTags);
782         if (vTags.get() == nullptr) {
783             return nullptr;
784         }
785     }
786 
787     int count = vTags->getTagCount();
788     if (count <= 0) {
789         // No vendor tags.
790         return NULL;
791     }
792 
793     std::vector<uint32_t> tagIds(count, /*initializer value*/0);
794     vTags->getTagArray(&tagIds[0]);
795 
796     // Which key class/constructor should we use?
797     jclass keyClazz;
798     jmethodID keyConstr;
799     if (env->IsSameObject(keyType, gMetadataOffsets.mCharacteristicsKey)) {
800         keyClazz = gMetadataOffsets.mCharacteristicsKey;
801         keyConstr = gMetadataOffsets.mCharacteristicsConstr;
802     } else if (env->IsSameObject(keyType, gMetadataOffsets.mResultKey)) {
803         keyClazz = gMetadataOffsets.mResultKey;
804         keyConstr = gMetadataOffsets.mResultConstr;
805     } else if (env->IsSameObject(keyType, gMetadataOffsets.mRequestKey)) {
806         keyClazz = gMetadataOffsets.mRequestKey;
807         keyConstr = gMetadataOffsets.mRequestConstr;
808     } else {
809         jniThrowException(env, "java/lang/IllegalArgumentException",
810                 "Invalid key class given as argument.");
811         return NULL;
812     }
813 
814     // Allocate arrayList to return
815     jobject arrayList = env->NewObject(gMetadataOffsets.mArrayList,
816             gMetadataOffsets.mArrayListConstr, static_cast<jint>(count));
817     if (env->ExceptionCheck()) {
818         return NULL;
819     }
820 
821     for (uint32_t id : tagIds) {
822         const char* section = vTags->getSectionName(id);
823         const char* tag = vTags->getTagName(id);
824         int type = vTags->getTagType(id);
825 
826         size_t totalLen = strlen(section) + strlen(tag) + 2;
827         std::vector<char> fullName(totalLen, 0);
828         snprintf(&fullName[0], totalLen, "%s.%s", section, tag);
829 
830         jstring name = env->NewStringUTF(&fullName[0]);
831 
832         if (env->ExceptionCheck()) {
833             return NULL;
834         }
835 
836         jclass valueClazz;
837         switch (type) {
838             case TYPE_BYTE:
839                 valueClazz = gMetadataOffsets.mByteArray;
840                 break;
841             case TYPE_INT32:
842                 valueClazz = gMetadataOffsets.mInt32Array;
843                 break;
844             case TYPE_FLOAT:
845                 valueClazz = gMetadataOffsets.mFloatArray;
846                 break;
847             case TYPE_INT64:
848                 valueClazz = gMetadataOffsets.mInt64Array;
849                 break;
850             case TYPE_DOUBLE:
851                 valueClazz = gMetadataOffsets.mDoubleArray;
852                 break;
853             case TYPE_RATIONAL:
854                 valueClazz = gMetadataOffsets.mRationalArray;
855                 break;
856             default:
857                 jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
858                         "Invalid type %d given for key %s", type, &fullName[0]);
859                 return NULL;
860         }
861 
862         jobject key = env->NewObject(keyClazz, keyConstr, name, valueClazz, vendorId);
863         if (env->ExceptionCheck()) {
864             return NULL;
865         }
866 
867         env->CallBooleanMethod(arrayList, gMetadataOffsets.mArrayListAdd, key);
868         if (env->ExceptionCheck()) {
869             return NULL;
870         }
871 
872         env->DeleteLocalRef(name);
873         env->DeleteLocalRef(key);
874     }
875 
876     return arrayList;
877 }
878 
CameraMetadata_setVendorId(JNIEnv * env,jclass thiz,jlong ptr,jlong vendorId)879 static void CameraMetadata_setVendorId(JNIEnv *env, jclass thiz, jlong ptr,
880         jlong vendorId) {
881     ALOGV("%s", __FUNCTION__);
882 
883     CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, ptr);
884 
885     if (metadata == NULL) {
886         ALOGW("%s: Returning early due to exception being thrown",
887                __FUNCTION__);
888         return;
889     }
890     if (metadata->isEmpty()) {
891         std::unique_ptr<CameraMetadata> emptyBuffer = std::make_unique<CameraMetadata>(10);
892         metadata->swap(*emptyBuffer);
893     }
894 
895     camera_metadata_t *meta = const_cast<camera_metadata_t *>(metadata->getAndLock());
896     set_camera_metadata_vendor_id(meta, vendorId);
897     metadata->unlock(meta);
898 }
899 
CameraMetadata_getTagFromKey(JNIEnv * env,jclass thiz,jstring keyName,jlong vendorId)900 static jint CameraMetadata_getTagFromKey(JNIEnv *env, jclass thiz, jstring keyName,
901         jlong vendorId) {
902     ScopedUtfChars keyScoped(env, keyName);
903     const char *key = keyScoped.c_str();
904     if (key == NULL) {
905         // exception thrown by ScopedUtfChars
906         return 0;
907     }
908     ALOGV("%s (key = '%s')", __FUNCTION__, key);
909 
910     uint32_t tag = 0;
911     sp<VendorTagDescriptor> vTags =
912             VendorTagDescriptor::getGlobalVendorTagDescriptor();
913     if (vTags.get() == nullptr) {
914         sp<VendorTagDescriptorCache> cache = VendorTagDescriptorCache::getGlobalVendorTagCache();
915         if (cache.get() != nullptr) {
916             cache->getVendorTagDescriptor(vendorId, &vTags);
917         }
918     }
919 
920     status_t res = CameraMetadata::getTagFromName(key, vTags.get(), &tag);
921     if (res != OK) {
922         jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
923                              "Could not find tag for key '%s')", key);
924     }
925     return tag;
926 }
927 
CameraMetadata_getTypeFromTag(JNIEnv * env,jclass thiz,jint tag,jlong vendorId)928 static jint CameraMetadata_getTypeFromTag(JNIEnv *env, jclass thiz, jint tag, jlong vendorId) {
929     int tagType = get_local_camera_metadata_tag_type_vendor_id(tag, vendorId);
930     if (tagType == -1) {
931         jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
932                              "Tag (%d) did not have a type", tag);
933         return -1;
934     }
935 
936     return tagType;
937 }
938 
CameraMetadata_setupGlobalVendorTagDescriptor(JNIEnv * env,jclass thiz)939 static jint CameraMetadata_setupGlobalVendorTagDescriptor(JNIEnv *env, jclass thiz) {
940     const String16 NAME("media.camera");
941     sp<hardware::ICameraService> cameraService;
942     status_t err = getService(NAME, /*out*/&cameraService);
943 
944     if (err != OK) {
945         ALOGE("%s: Failed to get camera service, received error %s (%d)", __FUNCTION__,
946                 strerror(-err), err);
947         return hardware::ICameraService::ERROR_DISCONNECTED;
948     }
949 
950     sp<VendorTagDescriptor> desc = new VendorTagDescriptor();
951     binder::Status res = cameraService->getCameraVendorTagDescriptor(/*out*/desc.get());
952 
953     if (res.serviceSpecificErrorCode() == hardware::ICameraService::ERROR_DISCONNECTED) {
954         // No camera module available, not an error on devices with no cameras
955         VendorTagDescriptor::clearGlobalVendorTagDescriptor();
956         return OK;
957     } else if (!res.isOk()) {
958         VendorTagDescriptor::clearGlobalVendorTagDescriptor();
959         ALOGE("%s: Failed to setup vendor tag descriptors: %s", __FUNCTION__,
960               res.toString8().c_str());
961         return res.serviceSpecificErrorCode();
962     }
963     if (0 < desc->getTagCount()) {
964         err = VendorTagDescriptor::setAsGlobalVendorTagDescriptor(desc);
965     } else {
966         sp<VendorTagDescriptorCache> cache = new VendorTagDescriptorCache();
967         binder::Status res = cameraService->getCameraVendorTagCache(/*out*/cache.get());
968         if (res.serviceSpecificErrorCode() == hardware::ICameraService::ERROR_DISCONNECTED) {
969             // No camera module available, not an error on devices with no cameras
970             VendorTagDescriptorCache::clearGlobalVendorTagCache();
971             return OK;
972         } else if (!res.isOk()) {
973             VendorTagDescriptorCache::clearGlobalVendorTagCache();
974             ALOGE("%s: Failed to setup vendor tag cache: %s", __FUNCTION__,
975                   res.toString8().c_str());
976             return res.serviceSpecificErrorCode();
977         }
978 
979         err = VendorTagDescriptorCache::setAsGlobalVendorTagCache(cache);
980     }
981 
982     if (err != OK) {
983         return hardware::ICameraService::ERROR_INVALID_OPERATION;
984     }
985     return OK;
986 }
987 
988 } // extern "C"
989