• 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 
18 // #define LOG_NDEBUG 0
19 #define LOG_TAG "CameraMetadata-JNI"
20 #include <utils/Errors.h>
21 #include <utils/Log.h>
22 #include <utils/RefBase.h>
23 #include <utils/Vector.h>
24 #include <utils/SortedVector.h>
25 #include <utils/KeyedVector.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <vector>
29 
30 #include "jni.h"
31 #include "JNIHelp.h"
32 #include "android_os_Parcel.h"
33 #include "core_jni_helpers.h"
34 #include "android_runtime/android_hardware_camera2_CameraMetadata.h"
35 
36 #include <android/hardware/ICameraService.h>
37 #include <binder/IServiceManager.h>
38 #include <camera/CameraMetadata.h>
39 #include <camera_metadata_hidden.h>
40 #include <camera/VendorTagDescriptor.h>
41 #include <nativehelper/ScopedUtfChars.h>
42 #include <nativehelper/ScopedPrimitiveArray.h>
43 
44 #include <sys/types.h> // for socketpair
45 #include <sys/socket.h> // for socketpair
46 
47 // fully-qualified class name
48 #define CAMERA_METADATA_CLASS_NAME "android/hardware/camera2/impl/CameraMetadataNative"
49 #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"
52 
53 using namespace android;
54 
55 static 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 
73 struct fields_t {
74     jfieldID    metadata_ptr;
75 };
76 
77 static fields_t fields;
78 
79 namespace android {
80 
CameraMetadata_getNativeMetadata(JNIEnv * env,jobject thiz,CameraMetadata * metadata)81 status_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 
104 namespace {
105 struct Helpers {
getTypeSize__anon4d58fb420111::Helpers106     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 
updateAny__anon4d58fb420111::Helpers115     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) {
129             ALOGE("%s: Expected dataBytes (%zu) to be divisible by typeSize "
130                   "(%zu)", __FUNCTION__, dataBytes, typeSize);
131             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 
163 extern "C" {
164 
165 static jobject CameraMetadata_getAllVendorKeys(JNIEnv* env, jobject thiz, jclass keyType);
166 static jint CameraMetadata_getTagFromKey(JNIEnv *env, jobject thiz, jstring keyName, jlong vendorId);
167 static jint CameraMetadata_getTagFromKeyLocal(JNIEnv *env, jobject thiz, jstring keyName);
168 static jint CameraMetadata_getTypeFromTag(JNIEnv *env, jobject thiz, jint tag, jlong vendorId);
169 static jint CameraMetadata_getTypeFromTagLocal(JNIEnv *env, jobject thiz, jint tag);
170 static jint CameraMetadata_setupGlobalVendorTagDescriptor(JNIEnv *env, jobject thiz);
171 
172 // Less safe access to native pointer. Does NOT throw any Java exceptions if NULL.
CameraMetadata_getPointerNoThrow(JNIEnv * env,jobject thiz)173 static 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.
CameraMetadata_getPointerThrow(JNIEnv * env,jobject thiz,const char * argName="this")183 static 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 
CameraMetadata_allocate(JNIEnv * env,jobject thiz)205 static jlong CameraMetadata_allocate(JNIEnv *env, jobject thiz) {
206     ALOGV("%s", __FUNCTION__);
207 
208     return reinterpret_cast<jlong>(new CameraMetadata());
209 }
210 
CameraMetadata_allocateCopy(JNIEnv * env,jobject thiz,jobject other)211 static 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 
CameraMetadata_isEmpty(JNIEnv * env,jobject thiz)226 static 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 
239     ALOGV("%s: Empty returned %d, entry count was %zu",
240           __FUNCTION__, empty, metadata->entryCount());
241 
242     return empty;
243 }
244 
CameraMetadata_getEntryCount(JNIEnv * env,jobject thiz)245 static 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.
CameraMetadata_close(JNIEnv * env,jobject thiz)256 static 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 
CameraMetadata_swap(JNIEnv * env,jobject thiz,jobject other)270 static 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 
CameraMetadata_readValues(JNIEnv * env,jobject thiz,jint tag)286 static 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     const camera_metadata_t *metaBuffer = metadata->getAndLock();
293     int tagType = get_local_camera_metadata_tag_type(tag, metaBuffer);
294     metadata->unlock(metaBuffer);
295     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 
CameraMetadata_writeValues(JNIEnv * env,jobject thiz,jint tag,jbyteArray src)325 static 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 
331     const camera_metadata_t *metaBuffer = metadata->getAndLock();
332     int tagType = get_local_camera_metadata_tag_type(tag, metaBuffer);
333     metadata->unlock(metaBuffer);
334     if (tagType == -1) {
335         jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
336                              "Tag (%d) did not have a type", tag);
337         return;
338     }
339 
340     status_t res;
341 
342     if (src == NULL) {
343         // If array is NULL, delete the entry
344         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         }
351     } 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());
358 
359         ALOGV("%s: Update values (res = %d)", __FUNCTION__, res);
360     }
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 
377 struct DumpMetadataParams {
378     int writeFd;
379     const CameraMetadata* metadata;
380 };
381 
CameraMetadata_writeMetadataThread(void * arg)382 static 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 
CameraMetadata_dump(JNIEnv * env,jobject thiz)398 static 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);
445 
446             jniThrowExceptionFmt(env, "java/io/IOException",
447                     "Failed to create thread for writing (errno = %#x, message = '%s')",
448                     threadRet, strerror(threadRet));
449         }
450     }
451 
452     /*
453      * Read out a byte until stream is complete. Write completed lines
454      * to ALOG.
455      */
456     {
457         char out[] = {'\0', '\0'}; // large enough to append as a string
458         String8 logLine;
459 
460         // Read one byte at a time! Very slow but avoids complicated \n scanning.
461         ssize_t res;
462         while ((res = TEMP_FAILURE_RETRY(read(readFd, &out[0], /*count*/1))) > 0) {
463             if (out[0] == '\n') {
464                 ALOGD("%s", logLine.string());
465                 logLine.clear();
466             } else {
467                 logLine.append(out);
468             }
469         }
470 
471         if (res < 0) {
472             jniThrowExceptionFmt(env, "java/io/IOException",
473                     "Failed to read from fd (errno = %#x, message = '%s')",
474                     errno, strerror(errno));
475             //return;
476         } else if (!logLine.isEmpty()) {
477             ALOGD("%s", logLine.string());
478         }
479     }
480 
481     int res;
482 
483     // Join until thread finishes. Ensures params/metadata is valid until then.
484     if ((res = pthread_join(writeThread, /*retval*/NULL)) != 0) {
485         ALOGE("%s: Failed to join thread (errno = %#x, message = '%s')",
486                 __FUNCTION__, res, strerror(res));
487     }
488 }
489 
CameraMetadata_readFromParcel(JNIEnv * env,jobject thiz,jobject parcel)490 static void CameraMetadata_readFromParcel(JNIEnv *env, jobject thiz, jobject parcel) {
491     ALOGV("%s", __FUNCTION__);
492     CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
493     if (metadata == NULL) {
494         return;
495     }
496 
497     Parcel* parcelNative = parcelForJavaObject(env, parcel);
498     if (parcelNative == NULL) {
499         jniThrowNullPointerException(env, "parcel");
500         return;
501     }
502 
503     status_t err;
504     if ((err = metadata->readFromParcel(parcelNative)) != OK) {
505         jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
506                              "Failed to read from parcel (error code %d)", err);
507         return;
508     }
509 }
510 
CameraMetadata_writeToParcel(JNIEnv * env,jobject thiz,jobject parcel)511 static void CameraMetadata_writeToParcel(JNIEnv *env, jobject thiz, jobject parcel) {
512     ALOGV("%s", __FUNCTION__);
513     CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
514     if (metadata == NULL) {
515         return;
516     }
517 
518     Parcel* parcelNative = parcelForJavaObject(env, parcel);
519     if (parcelNative == NULL) {
520         jniThrowNullPointerException(env, "parcel");
521         return;
522     }
523 
524     status_t err;
525     if ((err = metadata->writeToParcel(parcelNative)) != OK) {
526         jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
527                                   "Failed to write to parcel (error code %d)", err);
528         return;
529     }
530 }
531 
532 } // extern "C"
533 
534 //-------------------------------------------------
535 
536 static const JNINativeMethod gCameraMetadataMethods[] = {
537 // static methods
538   { "nativeGetTagFromKey",
539     "(Ljava/lang/String;J)I",
540     (void *)CameraMetadata_getTagFromKey },
541   { "nativeGetTypeFromTag",
542     "(IJ)I",
543     (void *)CameraMetadata_getTypeFromTag },
544   { "nativeSetupGlobalVendorTagDescriptor",
545     "()I",
546     (void*)CameraMetadata_setupGlobalVendorTagDescriptor },
547 // instance methods
548   { "nativeAllocate",
549     "()J",
550     (void*)CameraMetadata_allocate },
551   { "nativeAllocateCopy",
552     "(L" CAMERA_METADATA_CLASS_NAME ";)J",
553     (void *)CameraMetadata_allocateCopy },
554   { "nativeIsEmpty",
555     "()Z",
556     (void*)CameraMetadata_isEmpty },
557   { "nativeGetEntryCount",
558     "()I",
559     (void*)CameraMetadata_getEntryCount },
560   { "nativeClose",
561     "()V",
562     (void*)CameraMetadata_close },
563   { "nativeSwap",
564     "(L" CAMERA_METADATA_CLASS_NAME ";)V",
565     (void *)CameraMetadata_swap },
566   { "nativeGetTagFromKeyLocal",
567     "(Ljava/lang/String;)I",
568     (void *)CameraMetadata_getTagFromKeyLocal },
569   { "nativeGetTypeFromTagLocal",
570     "(I)I",
571     (void *)CameraMetadata_getTypeFromTagLocal },
572   { "nativeReadValues",
573     "(I)[B",
574     (void *)CameraMetadata_readValues },
575   { "nativeWriteValues",
576     "(I[B)V",
577     (void *)CameraMetadata_writeValues },
578   { "nativeDump",
579     "()V",
580     (void *)CameraMetadata_dump },
581   { "nativeGetAllVendorKeys",
582     "(Ljava/lang/Class;)Ljava/util/ArrayList;",
583     (void *)CameraMetadata_getAllVendorKeys},
584 // Parcelable interface
585   { "nativeReadFromParcel",
586     "(Landroid/os/Parcel;)V",
587     (void *)CameraMetadata_readFromParcel },
588   { "nativeWriteToParcel",
589     "(Landroid/os/Parcel;)V",
590     (void *)CameraMetadata_writeToParcel },
591 };
592 
593 // Get all the required offsets in java class and register native functions
register_android_hardware_camera2_CameraMetadata(JNIEnv * env)594 int register_android_hardware_camera2_CameraMetadata(JNIEnv *env)
595 {
596 
597     // Store global references to Key-related classes and methods used natively
598     jclass characteristicsKeyClazz = FindClassOrDie(env, CHARACTERISTICS_KEY_CLASS_NAME);
599     jclass requestKeyClazz = FindClassOrDie(env, REQUEST_KEY_CLASS_NAME);
600     jclass resultKeyClazz = FindClassOrDie(env, RESULT_KEY_CLASS_NAME);
601     gMetadataOffsets.mCharacteristicsKey = MakeGlobalRefOrDie(env, characteristicsKeyClazz);
602     gMetadataOffsets.mRequestKey = MakeGlobalRefOrDie(env, requestKeyClazz);
603     gMetadataOffsets.mResultKey = MakeGlobalRefOrDie(env, resultKeyClazz);
604     gMetadataOffsets.mCharacteristicsConstr = GetMethodIDOrDie(env,
605             gMetadataOffsets.mCharacteristicsKey, "<init>",
606             "(Ljava/lang/String;Ljava/lang/Class;J)V");
607     gMetadataOffsets.mRequestConstr = GetMethodIDOrDie(env,
608             gMetadataOffsets.mRequestKey, "<init>", "(Ljava/lang/String;Ljava/lang/Class;J)V");
609     gMetadataOffsets.mResultConstr = GetMethodIDOrDie(env,
610             gMetadataOffsets.mResultKey, "<init>", "(Ljava/lang/String;Ljava/lang/Class;J)V");
611 
612     // Store global references for primitive array types used by Keys
613     jclass byteClazz = FindClassOrDie(env, "[B");
614     jclass int32Clazz = FindClassOrDie(env, "[I");
615     jclass floatClazz = FindClassOrDie(env, "[F");
616     jclass int64Clazz = FindClassOrDie(env, "[J");
617     jclass doubleClazz = FindClassOrDie(env, "[D");
618     jclass rationalClazz = FindClassOrDie(env, "[Landroid/util/Rational;");
619     gMetadataOffsets.mByteArray = MakeGlobalRefOrDie(env, byteClazz);
620     gMetadataOffsets.mInt32Array = MakeGlobalRefOrDie(env, int32Clazz);
621     gMetadataOffsets.mFloatArray = MakeGlobalRefOrDie(env, floatClazz);
622     gMetadataOffsets.mInt64Array = MakeGlobalRefOrDie(env, int64Clazz);
623     gMetadataOffsets.mDoubleArray = MakeGlobalRefOrDie(env, doubleClazz);
624     gMetadataOffsets.mRationalArray = MakeGlobalRefOrDie(env, rationalClazz);
625 
626     // Store global references for ArrayList methods used
627     jclass arrayListClazz = FindClassOrDie(env, "java/util/ArrayList");
628     gMetadataOffsets.mArrayList = MakeGlobalRefOrDie(env, arrayListClazz);
629     gMetadataOffsets.mArrayListConstr = GetMethodIDOrDie(env, gMetadataOffsets.mArrayList,
630             "<init>", "(I)V");
631     gMetadataOffsets.mArrayListAdd = GetMethodIDOrDie(env, gMetadataOffsets.mArrayList,
632             "add", "(Ljava/lang/Object;)Z");
633 
634     jclass cameraMetadataClazz = FindClassOrDie(env, CAMERA_METADATA_CLASS_NAME);
635     fields.metadata_ptr = GetFieldIDOrDie(env, cameraMetadataClazz, "mMetadataPtr", "J");
636 
637     // Register native functions
638     return RegisterMethodsOrDie(env,
639             CAMERA_METADATA_CLASS_NAME,
640             gCameraMetadataMethods,
641             NELEM(gCameraMetadataMethods));
642 }
643 
644 extern "C" {
645 
CameraMetadata_getTypeFromTagLocal(JNIEnv * env,jobject thiz,jint tag)646 static jint CameraMetadata_getTypeFromTagLocal(JNIEnv *env, jobject thiz, jint tag) {
647     CameraMetadata* metadata = CameraMetadata_getPointerNoThrow(env, thiz);
648     metadata_vendor_id_t vendorId = CAMERA_METADATA_INVALID_VENDOR_ID;
649     if (metadata) {
650         const camera_metadata_t *metaBuffer = metadata->getAndLock();
651         vendorId = get_camera_metadata_vendor_id(metaBuffer);
652         metadata->unlock(metaBuffer);
653     }
654 
655     int tagType = get_local_camera_metadata_tag_type_vendor_id(tag, vendorId);
656     if (tagType == -1) {
657         jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
658                              "Tag (%d) did not have a type", tag);
659         return -1;
660     }
661 
662     return tagType;
663 }
664 
CameraMetadata_getTagFromKeyLocal(JNIEnv * env,jobject thiz,jstring keyName)665 static jint CameraMetadata_getTagFromKeyLocal(JNIEnv *env, jobject thiz, jstring keyName) {
666     ScopedUtfChars keyScoped(env, keyName);
667     const char *key = keyScoped.c_str();
668     if (key == NULL) {
669         // exception thrown by ScopedUtfChars
670         return 0;
671     }
672     ALOGV("%s (key = '%s')", __FUNCTION__, key);
673 
674     uint32_t tag = 0;
675     sp<VendorTagDescriptor> vTags;
676     CameraMetadata* metadata = CameraMetadata_getPointerNoThrow(env, thiz);
677     if (metadata) {
678         sp<VendorTagDescriptorCache> cache = VendorTagDescriptorCache::getGlobalVendorTagCache();
679         if (cache.get()) {
680             const camera_metadata_t *metaBuffer = metadata->getAndLock();
681             metadata_vendor_id_t vendorId = get_camera_metadata_vendor_id(metaBuffer);
682             metadata->unlock(metaBuffer);
683             cache->getVendorTagDescriptor(vendorId, &vTags);
684         }
685     }
686 
687     status_t res = CameraMetadata::getTagFromName(key, vTags.get(), &tag);
688     if (res != OK) {
689         jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
690                              "Could not find tag for key '%s')", key);
691     }
692     return tag;
693 }
694 
CameraMetadata_getAllVendorKeys(JNIEnv * env,jobject thiz,jclass keyType)695 static jobject CameraMetadata_getAllVendorKeys(JNIEnv* env, jobject thiz, jclass keyType) {
696     metadata_vendor_id_t vendorId = CAMERA_METADATA_INVALID_VENDOR_ID;
697     // Get all vendor tags
698     sp<VendorTagDescriptor> vTags = VendorTagDescriptor::getGlobalVendorTagDescriptor();
699     if (vTags.get() == nullptr) {
700         sp<VendorTagDescriptorCache> cache = VendorTagDescriptorCache::getGlobalVendorTagCache();
701         if (cache.get() == nullptr) {
702             // No vendor tags.
703             return nullptr;
704         }
705 
706         CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
707         if (metadata == NULL) return NULL;
708 
709         const camera_metadata_t *metaBuffer = metadata->getAndLock();
710         vendorId = get_camera_metadata_vendor_id(metaBuffer);
711         cache->getVendorTagDescriptor(vendorId, &vTags);
712         metadata->unlock(metaBuffer);
713         if (vTags.get() == nullptr) {
714             return nullptr;
715         }
716     }
717 
718     int count = vTags->getTagCount();
719     if (count <= 0) {
720         // No vendor tags.
721         return NULL;
722     }
723 
724     std::vector<uint32_t> tagIds(count, /*initializer value*/0);
725     vTags->getTagArray(&tagIds[0]);
726 
727     // Which key class/constructor should we use?
728     jclass keyClazz;
729     jmethodID keyConstr;
730     if (env->IsSameObject(keyType, gMetadataOffsets.mCharacteristicsKey)) {
731         keyClazz = gMetadataOffsets.mCharacteristicsKey;
732         keyConstr = gMetadataOffsets.mCharacteristicsConstr;
733     } else if (env->IsSameObject(keyType, gMetadataOffsets.mResultKey)) {
734         keyClazz = gMetadataOffsets.mResultKey;
735         keyConstr = gMetadataOffsets.mResultConstr;
736     } else if (env->IsSameObject(keyType, gMetadataOffsets.mRequestKey)) {
737         keyClazz = gMetadataOffsets.mRequestKey;
738         keyConstr = gMetadataOffsets.mRequestConstr;
739     } else {
740         jniThrowException(env, "java/lang/IllegalArgumentException",
741                 "Invalid key class given as argument.");
742         return NULL;
743     }
744 
745     // Allocate arrayList to return
746     jobject arrayList = env->NewObject(gMetadataOffsets.mArrayList,
747             gMetadataOffsets.mArrayListConstr, static_cast<jint>(count));
748     if (env->ExceptionCheck()) {
749         return NULL;
750     }
751 
752     for (uint32_t id : tagIds) {
753         const char* section = vTags->getSectionName(id);
754         const char* tag = vTags->getTagName(id);
755         int type = vTags->getTagType(id);
756 
757         size_t totalLen = strlen(section) + strlen(tag) + 2;
758         std::vector<char> fullName(totalLen, 0);
759         snprintf(&fullName[0], totalLen, "%s.%s", section, tag);
760 
761         jstring name = env->NewStringUTF(&fullName[0]);
762 
763         if (env->ExceptionCheck()) {
764             return NULL;
765         }
766 
767         jclass valueClazz;
768         switch (type) {
769             case TYPE_BYTE:
770                 valueClazz = gMetadataOffsets.mByteArray;
771                 break;
772             case TYPE_INT32:
773                 valueClazz = gMetadataOffsets.mInt32Array;
774                 break;
775             case TYPE_FLOAT:
776                 valueClazz = gMetadataOffsets.mFloatArray;
777                 break;
778             case TYPE_INT64:
779                 valueClazz = gMetadataOffsets.mInt64Array;
780                 break;
781             case TYPE_DOUBLE:
782                 valueClazz = gMetadataOffsets.mDoubleArray;
783                 break;
784             case TYPE_RATIONAL:
785                 valueClazz = gMetadataOffsets.mRationalArray;
786                 break;
787             default:
788                 jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
789                         "Invalid type %d given for key %s", type, &fullName[0]);
790                 return NULL;
791         }
792 
793         jobject key = env->NewObject(keyClazz, keyConstr, name, valueClazz, vendorId);
794         if (env->ExceptionCheck()) {
795             return NULL;
796         }
797 
798         env->CallBooleanMethod(arrayList, gMetadataOffsets.mArrayListAdd, key);
799         if (env->ExceptionCheck()) {
800             return NULL;
801         }
802 
803         env->DeleteLocalRef(name);
804         env->DeleteLocalRef(key);
805     }
806 
807     return arrayList;
808 }
809 
CameraMetadata_getTagFromKey(JNIEnv * env,jobject thiz,jstring keyName,jlong vendorId)810 static jint CameraMetadata_getTagFromKey(JNIEnv *env, jobject thiz, jstring keyName,
811         jlong vendorId) {
812     ScopedUtfChars keyScoped(env, keyName);
813     const char *key = keyScoped.c_str();
814     if (key == NULL) {
815         // exception thrown by ScopedUtfChars
816         return 0;
817     }
818     ALOGV("%s (key = '%s')", __FUNCTION__, key);
819 
820     uint32_t tag = 0;
821     sp<VendorTagDescriptor> vTags =
822             VendorTagDescriptor::getGlobalVendorTagDescriptor();
823     if (vTags.get() == nullptr) {
824         sp<VendorTagDescriptorCache> cache = VendorTagDescriptorCache::getGlobalVendorTagCache();
825         if (cache.get() != nullptr) {
826             cache->getVendorTagDescriptor(vendorId, &vTags);
827         }
828     }
829 
830     status_t res = CameraMetadata::getTagFromName(key, vTags.get(), &tag);
831     if (res != OK) {
832         jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
833                              "Could not find tag for key '%s')", key);
834     }
835     return tag;
836 }
837 
CameraMetadata_getTypeFromTag(JNIEnv * env,jobject thiz,jint tag,jlong vendorId)838 static jint CameraMetadata_getTypeFromTag(JNIEnv *env, jobject thiz, jint tag, jlong vendorId) {
839     int tagType = get_local_camera_metadata_tag_type_vendor_id(tag, vendorId);
840     if (tagType == -1) {
841         jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
842                              "Tag (%d) did not have a type", tag);
843         return -1;
844     }
845 
846     return tagType;
847 }
848 
CameraMetadata_setupGlobalVendorTagDescriptor(JNIEnv * env,jobject thiz)849 static jint CameraMetadata_setupGlobalVendorTagDescriptor(JNIEnv *env, jobject thiz) {
850     const String16 NAME("media.camera");
851     sp<hardware::ICameraService> cameraService;
852     status_t err = getService(NAME, /*out*/&cameraService);
853 
854     if (err != OK) {
855         ALOGE("%s: Failed to get camera service, received error %s (%d)", __FUNCTION__,
856                 strerror(-err), err);
857         return hardware::ICameraService::ERROR_DISCONNECTED;
858     }
859 
860     sp<VendorTagDescriptor> desc = new VendorTagDescriptor();
861     binder::Status res = cameraService->getCameraVendorTagDescriptor(/*out*/desc.get());
862 
863     if (res.serviceSpecificErrorCode() == hardware::ICameraService::ERROR_DISCONNECTED) {
864         // No camera module available, not an error on devices with no cameras
865         VendorTagDescriptor::clearGlobalVendorTagDescriptor();
866         return OK;
867     } else if (!res.isOk()) {
868         VendorTagDescriptor::clearGlobalVendorTagDescriptor();
869         ALOGE("%s: Failed to setup vendor tag descriptors: %s",
870                 __FUNCTION__, res.toString8().string());
871         return res.serviceSpecificErrorCode();
872     }
873     if (0 < desc->getTagCount()) {
874         err = VendorTagDescriptor::setAsGlobalVendorTagDescriptor(desc);
875     } else {
876         sp<VendorTagDescriptorCache> cache = new VendorTagDescriptorCache();
877         binder::Status res = cameraService->getCameraVendorTagCache(/*out*/cache.get());
878         if (res.serviceSpecificErrorCode() == hardware::ICameraService::ERROR_DISCONNECTED) {
879             // No camera module available, not an error on devices with no cameras
880             VendorTagDescriptorCache::clearGlobalVendorTagCache();
881             return OK;
882         } else if (!res.isOk()) {
883             VendorTagDescriptorCache::clearGlobalVendorTagCache();
884             ALOGE("%s: Failed to setup vendor tag cache: %s",
885                     __FUNCTION__, res.toString8().string());
886             return res.serviceSpecificErrorCode();
887         }
888 
889         err = VendorTagDescriptorCache::setAsGlobalVendorTagCache(cache);
890     }
891 
892     if (err != OK) {
893         return hardware::ICameraService::ERROR_INVALID_OPERATION;
894     }
895     return OK;
896 }
897 
898 } // extern "C"
899