camera3: Pass vendor tags through binder.

Bug: 12134423

Change-Id: Icef3fe9e67160767bdb8244ac49c85b68b497123
diff --git a/core/java/android/hardware/ICameraService.aidl b/core/java/android/hardware/ICameraService.aidl
index 542af6a..4c50dda 100644
--- a/core/java/android/hardware/ICameraService.aidl
+++ b/core/java/android/hardware/ICameraService.aidl
@@ -61,4 +61,12 @@
     int removeListener(ICameraServiceListener listener);
 
     int getCameraCharacteristics(int cameraId, out CameraMetadataNative info);
+
+    /**
+     * The java stubs for this method are not intended to be used.  Please use
+     * the native stub in frameworks/av/include/camera/ICameraService.h instead.
+     * The BinderHolder output is being used as a placeholder, and will not be
+     * well-formatted in the generated java method.
+     */
+    int getCameraVendorTagDescriptor(out BinderHolder desc);
 }
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index 2ac50e4..78e7037 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -48,6 +48,8 @@
  */
 public final class CameraManager {
 
+    private static final String TAG = "CameraManager";
+
     /**
      * This should match the ICameraService definition
      */
@@ -79,6 +81,19 @@
         mCameraService = CameraBinderDecorator.newInstance(cameraServiceRaw);
 
         try {
+            int err = CameraMetadataNative.nativeSetupGlobalVendorTagDescriptor();
+            if (err == CameraBinderDecorator.EOPNOTSUPP) {
+                Log.w(TAG, "HAL version doesn't vendor tags.");
+            } else {
+                CameraBinderDecorator.throwOnError(CameraMetadataNative.
+                        nativeSetupGlobalVendorTagDescriptor());
+            }
+        } catch(CameraRuntimeException e) {
+            throw new IllegalStateException("Failed to setup camera vendor tags",
+                    e.asChecked());
+        }
+
+        try {
             mCameraService.addListener(new CameraServiceListener());
         } catch(CameraRuntimeException e) {
             throw new IllegalStateException("Failed to register a camera service listener",
diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
index 2ddcb14..0d4a4cb 100644
--- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
+++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
@@ -105,6 +105,18 @@
     }
 
     /**
+     * Set the global client-side vendor tag descriptor to allow use of vendor
+     * tags in camera applications.
+     *
+     * @return int A native status_t value corresponding to one of the
+     * {@link CameraBinderDecorator} integer constants.
+     * @see CameraBinderDecorator#throwOnError
+     *
+     * @hide
+     */
+    public static native int nativeSetupGlobalVendorTagDescriptor();
+
+    /**
      * Set a camera metadata field to a value. The field definitions can be
      * found in {@link CameraCharacteristics}, {@link CaptureResult}, and
      * {@link CaptureRequest}.
diff --git a/core/java/android/hardware/camera2/utils/CameraBinderDecorator.java b/core/java/android/hardware/camera2/utils/CameraBinderDecorator.java
index e535e00..328ccbe 100644
--- a/core/java/android/hardware/camera2/utils/CameraBinderDecorator.java
+++ b/core/java/android/hardware/camera2/utils/CameraBinderDecorator.java
@@ -64,47 +64,7 @@
             // int return type => status_t => convert to exception
             if (m.getReturnType() == Integer.TYPE) {
                 int returnValue = (Integer) result;
-
-                switch (returnValue) {
-                    case NO_ERROR:
-                        return;
-                    case PERMISSION_DENIED:
-                        throw new SecurityException("Lacking privileges to access camera service");
-                    case ALREADY_EXISTS:
-                        // This should be handled at the call site. Typically this isn't bad,
-                        // just means we tried to do an operation that already completed.
-                        return;
-                    case BAD_VALUE:
-                        throw new IllegalArgumentException("Bad argument passed to camera service");
-                    case DEAD_OBJECT:
-                        UncheckedThrow.throwAnyException(new CameraRuntimeException(
-                                CAMERA_DISCONNECTED));
-                    case EACCES:
-                        UncheckedThrow.throwAnyException(new CameraRuntimeException(
-                                CAMERA_DISABLED));
-                    case EBUSY:
-                        UncheckedThrow.throwAnyException(new CameraRuntimeException(
-                                CAMERA_IN_USE));
-                    case EUSERS:
-                        UncheckedThrow.throwAnyException(new CameraRuntimeException(
-                                MAX_CAMERAS_IN_USE));
-                    case ENODEV:
-                        UncheckedThrow.throwAnyException(new CameraRuntimeException(
-                                CAMERA_DISCONNECTED));
-                    case EOPNOTSUPP:
-                        UncheckedThrow.throwAnyException(new CameraRuntimeException(
-                                CAMERA_DEPRECATED_HAL));
-                }
-
-                /**
-                 * Trap the rest of the negative return values. If we have known
-                 * error codes i.e. ALREADY_EXISTS that aren't really runtime
-                 * errors, then add them to the top switch statement
-                 */
-                if (returnValue < 0) {
-                    throw new UnsupportedOperationException(String.format("Unknown error %d",
-                            returnValue));
-                }
+                throwOnError(returnValue);
             }
         }
 
@@ -131,6 +91,54 @@
     }
 
     /**
+     * Throw error codes returned by the camera service as exceptions.
+     *
+     * @param errorFlag error to throw as an exception.
+     */
+    public static void throwOnError(int errorFlag) {
+        switch (errorFlag) {
+            case NO_ERROR:
+                return;
+            case PERMISSION_DENIED:
+                throw new SecurityException("Lacking privileges to access camera service");
+            case ALREADY_EXISTS:
+                // This should be handled at the call site. Typically this isn't bad,
+                // just means we tried to do an operation that already completed.
+                return;
+            case BAD_VALUE:
+                throw new IllegalArgumentException("Bad argument passed to camera service");
+            case DEAD_OBJECT:
+                UncheckedThrow.throwAnyException(new CameraRuntimeException(
+                        CAMERA_DISCONNECTED));
+            case EACCES:
+                UncheckedThrow.throwAnyException(new CameraRuntimeException(
+                        CAMERA_DISABLED));
+            case EBUSY:
+                UncheckedThrow.throwAnyException(new CameraRuntimeException(
+                        CAMERA_IN_USE));
+            case EUSERS:
+                UncheckedThrow.throwAnyException(new CameraRuntimeException(
+                        MAX_CAMERAS_IN_USE));
+            case ENODEV:
+                UncheckedThrow.throwAnyException(new CameraRuntimeException(
+                        CAMERA_DISCONNECTED));
+            case EOPNOTSUPP:
+                UncheckedThrow.throwAnyException(new CameraRuntimeException(
+                        CAMERA_DEPRECATED_HAL));
+        }
+
+        /**
+         * Trap the rest of the negative return values. If we have known
+         * error codes i.e. ALREADY_EXISTS that aren't really runtime
+         * errors, then add them to the top switch statement
+         */
+        if (errorFlag < 0) {
+            throw new UnsupportedOperationException(String.format("Unknown error %d",
+                    errorFlag));
+        }
+    }
+
+    /**
      * <p>
      * Wraps the type T with a proxy that will check 'status_t' return codes
      * from the native side of the camera service, and throw Java exceptions
diff --git a/core/jni/android_hardware_camera2_CameraMetadata.cpp b/core/jni/android_hardware_camera2_CameraMetadata.cpp
index 3c7da1e..8c15ac25 100644
--- a/core/jni/android_hardware_camera2_CameraMetadata.cpp
+++ b/core/jni/android_hardware_camera2_CameraMetadata.cpp
@@ -19,13 +19,18 @@
 // #define LOG_NNDEBUG 0
 #define LOG_TAG "CameraMetadata-JNI"
 #include <utils/Log.h>
+#include <utils/RefBase.h>
+#include <string.h>
 
 #include "jni.h"
 #include "JNIHelp.h"
 #include "android_os_Parcel.h"
 #include "android_runtime/AndroidRuntime.h"
 
+#include <binder/IServiceManager.h>
 #include <camera/CameraMetadata.h>
+#include <camera/ICameraService.h>
+#include <camera/VendorTagDescriptor.h>
 #include <nativehelper/ScopedUtfChars.h>
 #include <nativehelper/ScopedPrimitiveArray.h>
 
@@ -112,6 +117,7 @@
 static void CameraMetadata_classInit(JNIEnv *env, jobject thiz);
 static jint CameraMetadata_getTagFromKey(JNIEnv *env, jobject thiz, jstring keyName);
 static jint CameraMetadata_getTypeFromTag(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.
 static CameraMetadata* CameraMetadata_getPointerNoThrow(JNIEnv *env, jobject thiz) {
@@ -372,6 +378,9 @@
   { "nativeGetTypeFromTag",
     "(I)I",
     (void *)CameraMetadata_getTypeFromTag },
+  { "nativeSetupGlobalVendorTagDescriptor",
+    "()I",
+    (void*)CameraMetadata_setupGlobalVendorTagDescriptor },
 // instance methods
   { "nativeAllocate",
     "()J",
@@ -556,4 +565,29 @@
     return tagType;
 }
 
+static jint CameraMetadata_setupGlobalVendorTagDescriptor(JNIEnv *env, jobject thiz) {
+    const String16 NAME("media.camera");
+    sp<ICameraService> cameraService;
+    status_t err = getService(NAME, /*out*/&cameraService);
+
+    if (err != OK) {
+        ALOGE("%s: Failed to get camera service, received error %s (%d)", __FUNCTION__,
+                strerror(-err), err);
+        return err;
+    }
+
+    sp<VendorTagDescriptor> desc;
+    err = cameraService->getCameraVendorTagDescriptor(/*out*/desc);
+
+    if (err != OK) {
+        ALOGE("%s: Failed to setup vendor tag descriptors, received error %s (%d)", __FUNCTION__,
+                strerror(-err), err);
+        return err;
+    }
+
+    err = VendorTagDescriptor::setAsGlobalVendorTagDescriptor(desc);
+
+    return err;
+}
+
 } // extern "C"