Camera: Initial support for vendor tag caches

Vendor tag cache will be used alternatively to the regular
Vendor tag descriptor. The caches can support multiple vendor
tag providers at the same time. The native metadata along with
the requests/results/characteristics will store vendor specific
information that will be used to indentify the respective
descriptor.

Bug: 34275821
Test: Complete Camera/Camera2 CTS tests
Change-Id: I50b7cf9aa5575944fde7673a1728869690b2ce0d
diff --git a/core/jni/android_hardware_camera2_CameraMetadata.cpp b/core/jni/android_hardware_camera2_CameraMetadata.cpp
index 78a5735..c11ce0f 100644
--- a/core/jni/android_hardware_camera2_CameraMetadata.cpp
+++ b/core/jni/android_hardware_camera2_CameraMetadata.cpp
@@ -36,6 +36,7 @@
 #include <android/hardware/ICameraService.h>
 #include <binder/IServiceManager.h>
 #include <camera/CameraMetadata.h>
+#include <camera_metadata_hidden.h>
 #include <camera/VendorTagDescriptor.h>
 #include <nativehelper/ScopedUtfChars.h>
 #include <nativehelper/ScopedPrimitiveArray.h>
@@ -162,8 +163,10 @@
 extern "C" {
 
 static jobject CameraMetadata_getAllVendorKeys(JNIEnv* env, jobject thiz, jclass keyType);
-static jint CameraMetadata_getTagFromKey(JNIEnv *env, jobject thiz, jstring keyName);
-static jint CameraMetadata_getTypeFromTag(JNIEnv *env, jobject thiz, jint tag);
+static jint CameraMetadata_getTagFromKey(JNIEnv *env, jobject thiz, jstring keyName, jlong vendorId);
+static jint CameraMetadata_getTagFromKeyLocal(JNIEnv *env, jobject thiz, jstring keyName);
+static jint CameraMetadata_getTypeFromTag(JNIEnv *env, jobject thiz, jint tag, jlong vendorId);
+static jint CameraMetadata_getTypeFromTagLocal(JNIEnv *env, jobject thiz, jint tag);
 static jint CameraMetadata_setupGlobalVendorTagDescriptor(JNIEnv *env, jobject thiz);
 
 // Less safe access to native pointer. Does NOT throw any Java exceptions if NULL.
@@ -286,7 +289,9 @@
     CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
     if (metadata == NULL) return NULL;
 
-    int tagType = get_camera_metadata_tag_type(tag);
+    const camera_metadata_t *metaBuffer = metadata->getAndLock();
+    int tagType = get_local_camera_metadata_tag_type(tag, metaBuffer);
+    metadata->unlock(metaBuffer);
     if (tagType == -1) {
         jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
                              "Tag (%d) did not have a type", tag);
@@ -323,7 +328,9 @@
     CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
     if (metadata == NULL) return;
 
-    int tagType = get_camera_metadata_tag_type(tag);
+    const camera_metadata_t *metaBuffer = metadata->getAndLock();
+    int tagType = get_local_camera_metadata_tag_type(tag, metaBuffer);
+    metadata->unlock(metaBuffer);
     if (tagType == -1) {
         jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
                              "Tag (%d) did not have a type", tag);
@@ -528,14 +535,11 @@
 
 static const JNINativeMethod gCameraMetadataMethods[] = {
 // static methods
-  { "nativeGetAllVendorKeys",
-    "(Ljava/lang/Class;)Ljava/util/ArrayList;",
-    (void *)CameraMetadata_getAllVendorKeys},
   { "nativeGetTagFromKey",
-    "(Ljava/lang/String;)I",
+    "(Ljava/lang/String;J)I",
     (void *)CameraMetadata_getTagFromKey },
   { "nativeGetTypeFromTag",
-    "(I)I",
+    "(IJ)I",
     (void *)CameraMetadata_getTypeFromTag },
   { "nativeSetupGlobalVendorTagDescriptor",
     "()I",
@@ -559,6 +563,12 @@
   { "nativeSwap",
     "(L" CAMERA_METADATA_CLASS_NAME ";)V",
     (void *)CameraMetadata_swap },
+  { "nativeGetTagFromKeyLocal",
+    "(Ljava/lang/String;)I",
+    (void *)CameraMetadata_getTagFromKeyLocal },
+  { "nativeGetTypeFromTagLocal",
+    "(I)I",
+    (void *)CameraMetadata_getTypeFromTagLocal },
   { "nativeReadValues",
     "(I)[B",
     (void *)CameraMetadata_readValues },
@@ -568,6 +578,9 @@
   { "nativeDump",
     "()V",
     (void *)CameraMetadata_dump },
+  { "nativeGetAllVendorKeys",
+    "(Ljava/lang/Class;)Ljava/util/ArrayList;",
+    (void *)CameraMetadata_getAllVendorKeys},
 // Parcelable interface
   { "nativeReadFromParcel",
     "(Landroid/os/Parcel;)V",
@@ -590,11 +603,11 @@
     gMetadataOffsets.mResultKey = MakeGlobalRefOrDie(env, resultKeyClazz);
     gMetadataOffsets.mCharacteristicsConstr = GetMethodIDOrDie(env,
             gMetadataOffsets.mCharacteristicsKey, "<init>",
-            "(Ljava/lang/String;Ljava/lang/Class;)V");
+            "(Ljava/lang/String;Ljava/lang/Class;J)V");
     gMetadataOffsets.mRequestConstr = GetMethodIDOrDie(env,
-            gMetadataOffsets.mRequestKey, "<init>", "(Ljava/lang/String;Ljava/lang/Class;)V");
+            gMetadataOffsets.mRequestKey, "<init>", "(Ljava/lang/String;Ljava/lang/Class;J)V");
     gMetadataOffsets.mResultConstr = GetMethodIDOrDie(env,
-            gMetadataOffsets.mResultKey, "<init>", "(Ljava/lang/String;Ljava/lang/Class;)V");
+            gMetadataOffsets.mResultKey, "<init>", "(Ljava/lang/String;Ljava/lang/Class;J)V");
 
     // Store global references for primitive array types used by Keys
     jclass byteClazz = FindClassOrDie(env, "[B");
@@ -630,13 +643,76 @@
 
 extern "C" {
 
-static jobject CameraMetadata_getAllVendorKeys(JNIEnv* env, jobject thiz, jclass keyType) {
+static jint CameraMetadata_getTypeFromTagLocal(JNIEnv *env, jobject thiz, jint tag) {
+    CameraMetadata* metadata = CameraMetadata_getPointerNoThrow(env, thiz);
+    metadata_vendor_id_t vendorId = CAMERA_METADATA_INVALID_VENDOR_ID;
+    if (metadata) {
+        const camera_metadata_t *metaBuffer = metadata->getAndLock();
+        vendorId = get_camera_metadata_vendor_id(metaBuffer);
+        metadata->unlock(metaBuffer);
+    }
 
+    int tagType = get_local_camera_metadata_tag_type_vendor_id(tag, vendorId);
+    if (tagType == -1) {
+        jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
+                             "Tag (%d) did not have a type", tag);
+        return -1;
+    }
+
+    return tagType;
+}
+
+static jint CameraMetadata_getTagFromKeyLocal(JNIEnv *env, jobject thiz, jstring keyName) {
+    ScopedUtfChars keyScoped(env, keyName);
+    const char *key = keyScoped.c_str();
+    if (key == NULL) {
+        // exception thrown by ScopedUtfChars
+        return 0;
+    }
+    ALOGV("%s (key = '%s')", __FUNCTION__, key);
+
+    uint32_t tag = 0;
+    sp<VendorTagDescriptor> vTags;
+    CameraMetadata* metadata = CameraMetadata_getPointerNoThrow(env, thiz);
+    if (metadata) {
+        sp<VendorTagDescriptorCache> cache = VendorTagDescriptorCache::getGlobalVendorTagCache();
+        if (cache.get()) {
+            const camera_metadata_t *metaBuffer = metadata->getAndLock();
+            metadata_vendor_id_t vendorId = get_camera_metadata_vendor_id(metaBuffer);
+            metadata->unlock(metaBuffer);
+            cache->getVendorTagDescriptor(vendorId, &vTags);
+        }
+    }
+
+    status_t res = CameraMetadata::getTagFromName(key, vTags.get(), &tag);
+    if (res != OK) {
+        jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
+                             "Could not find tag for key '%s')", key);
+    }
+    return tag;
+}
+
+static jobject CameraMetadata_getAllVendorKeys(JNIEnv* env, jobject thiz, jclass keyType) {
+    metadata_vendor_id_t vendorId = CAMERA_METADATA_INVALID_VENDOR_ID;
     // Get all vendor tags
     sp<VendorTagDescriptor> vTags = VendorTagDescriptor::getGlobalVendorTagDescriptor();
     if (vTags.get() == nullptr) {
-        // No vendor tags.
-        return NULL;
+        sp<VendorTagDescriptorCache> cache = VendorTagDescriptorCache::getGlobalVendorTagCache();
+        if (cache.get() == nullptr) {
+            // No vendor tags.
+            return nullptr;
+        }
+
+        CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, thiz);
+        if (metadata == NULL) return NULL;
+
+        const camera_metadata_t *metaBuffer = metadata->getAndLock();
+        vendorId = get_camera_metadata_vendor_id(metaBuffer);
+        cache->getVendorTagDescriptor(vendorId, &vTags);
+        metadata->unlock(metaBuffer);
+        if (vTags.get() == nullptr) {
+            return nullptr;
+        }
     }
 
     int count = vTags->getTagCount();
@@ -714,7 +790,7 @@
                 return NULL;
         }
 
-        jobject key = env->NewObject(keyClazz, keyConstr, name, valueClazz);
+        jobject key = env->NewObject(keyClazz, keyConstr, name, valueClazz, vendorId);
         if (env->ExceptionCheck()) {
             return NULL;
         }
@@ -731,8 +807,8 @@
     return arrayList;
 }
 
-static jint CameraMetadata_getTagFromKey(JNIEnv *env, jobject thiz, jstring keyName) {
-
+static jint CameraMetadata_getTagFromKey(JNIEnv *env, jobject thiz, jstring keyName,
+        jlong vendorId) {
     ScopedUtfChars keyScoped(env, keyName);
     const char *key = keyScoped.c_str();
     if (key == NULL) {
@@ -744,6 +820,13 @@
     uint32_t tag = 0;
     sp<VendorTagDescriptor> vTags =
             VendorTagDescriptor::getGlobalVendorTagDescriptor();
+    if (vTags.get() == nullptr) {
+        sp<VendorTagDescriptorCache> cache = VendorTagDescriptorCache::getGlobalVendorTagCache();
+        if (cache.get() != nullptr) {
+            cache->getVendorTagDescriptor(vendorId, &vTags);
+        }
+    }
+
     status_t res = CameraMetadata::getTagFromName(key, vTags.get(), &tag);
     if (res != OK) {
         jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
@@ -752,8 +835,8 @@
     return tag;
 }
 
-static jint CameraMetadata_getTypeFromTag(JNIEnv *env, jobject thiz, jint tag) {
-    int tagType = get_camera_metadata_tag_type(tag);
+static jint CameraMetadata_getTypeFromTag(JNIEnv *env, jobject thiz, jint tag, jlong vendorId) {
+    int tagType = get_local_camera_metadata_tag_type_vendor_id(tag, vendorId);
     if (tagType == -1) {
         jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
                              "Tag (%d) did not have a type", tag);
@@ -787,8 +870,24 @@
                 __FUNCTION__, res.toString8().string());
         return res.serviceSpecificErrorCode();
     }
+    if (0 < desc->getTagCount()) {
+        err = VendorTagDescriptor::setAsGlobalVendorTagDescriptor(desc);
+    } else {
+        sp<VendorTagDescriptorCache> cache = new VendorTagDescriptorCache();
+        binder::Status res = cameraService->getCameraVendorTagCache(/*out*/cache.get());
+        if (res.serviceSpecificErrorCode() == hardware::ICameraService::ERROR_DISCONNECTED) {
+            // No camera module available, not an error on devices with no cameras
+            VendorTagDescriptorCache::clearGlobalVendorTagCache();
+            return OK;
+        } else if (!res.isOk()) {
+            VendorTagDescriptorCache::clearGlobalVendorTagCache();
+            ALOGE("%s: Failed to setup vendor tag cache: %s",
+                    __FUNCTION__, res.toString8().string());
+            return res.serviceSpecificErrorCode();
+        }
 
-    err = VendorTagDescriptor::setAsGlobalVendorTagDescriptor(desc);
+        err = VendorTagDescriptorCache::setAsGlobalVendorTagCache(cache);
+    }
 
     if (err != OK) {
         return hardware::ICameraService::ERROR_INVALID_OPERATION;