Open and close v4l2 devices.

BUG: 29191881
Change-Id: Id740ab30fd8f79b4a2cb99d1e5bef2be7472c992
diff --git a/modules/camera/3_4/Android.mk b/modules/camera/3_4/Android.mk
index b3b921f..074f9c2 100644
--- a/modules/camera/3_4/Android.mk
+++ b/modules/camera/3_4/Android.mk
@@ -26,10 +26,12 @@
 #   some various unexpected variables had to be set.
 
 LOCAL_SHARED_LIBRARIES := \
+    libbase \
     libcamera_client \
     libcamera_metadata \
     libcutils \
     liblog \
+    libnativehelper \
     libsync \
     libutils \
 
diff --git a/modules/camera/3_4/Camera.cpp b/modules/camera/3_4/Camera.cpp
index b18f0c3..6e9e12a 100644
--- a/modules/camera/3_4/Camera.cpp
+++ b/modules/camera/3_4/Camera.cpp
@@ -81,7 +81,7 @@
     }
 }
 
-int Camera::open(const hw_module_t *module, hw_device_t **device)
+int Camera::openDevice(const hw_module_t *module, hw_device_t **device)
 {
     ALOGI("%s:%d: Opening camera device", __func__, mId);
     ATRACE_CALL();
@@ -92,7 +92,10 @@
         return -EBUSY;
     }
 
-    // TODO: open camera dev nodes, etc
+    int connectResult = connect();
+    if (connectResult != 0) {
+      return connectResult;
+    }
     mBusy = true;
     mDevice.common.module = const_cast<hw_module_t*>(module);
     *device = &mDevice.common;
@@ -124,7 +127,7 @@
         return -EINVAL;
     }
 
-    // TODO: close camera dev nodes, etc
+    disconnect();
     mBusy = false;
     return 0;
 }
diff --git a/modules/camera/3_4/Camera.h b/modules/camera/3_4/Camera.h
index ab8f221..3ecd0a8 100644
--- a/modules/camera/3_4/Camera.h
+++ b/modules/camera/3_4/Camera.h
@@ -40,7 +40,7 @@
         virtual ~Camera();
 
         // Common Camera Device Operations (see <hardware/camera_common.h>)
-        int open(const hw_module_t *module, hw_device_t **device);
+        int openDevice(const hw_module_t *module, hw_device_t **device);
         int getInfo(struct camera_info *info);
         int close();
 
@@ -54,6 +54,10 @@
 
 
     protected:
+        // Connect to the device: open dev nodes, etc.
+        virtual int connect() = 0;
+        // Disconnect from the device: close dev nodes, etc.
+        virtual void disconnect() = 0;
         // Initialize static camera characteristics for individual device
         virtual camera_metadata_t *initStaticInfo() = 0;
         // Initialize device info: facing, orientation, resource cost,
diff --git a/modules/camera/3_4/V4L2Camera.cpp b/modules/camera/3_4/V4L2Camera.cpp
index aa65cdf..5e5c0c4 100644
--- a/modules/camera/3_4/V4L2Camera.cpp
+++ b/modules/camera/3_4/V4L2Camera.cpp
@@ -16,8 +16,13 @@
 
 #include "V4L2Camera.h"
 
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
 #include <camera/CameraMetadata.h>
 #include <hardware/camera3.h>
+#include <nativehelper/ScopedFd.h>
 
 #include "Common.h"
 
@@ -32,6 +37,35 @@
   HAL_LOG_ENTER();
 }
 
+int V4L2Camera::connect() {
+  HAL_LOG_ENTER();
+
+  if (mDeviceFd.get() >= 0) {
+    HAL_LOGE("Camera device %s is opened. Close it first", mDevicePath.c_str());
+    return -EIO;
+  }
+
+  int fd = TEMP_FAILURE_RETRY(open(mDevicePath.c_str(), O_RDWR));
+  if (fd < 0) {
+    HAL_LOGE("failed to open %s (%s)", mDevicePath.c_str(), strerror(errno));
+    return -errno;
+  }
+  mDeviceFd.reset(fd);
+
+  // TODO(b/29185945): confirm this is a supported device.
+  //   This is checked by the HAL, but the device at mDevicePath may
+  //   not be the same one that was there when the HAL was loaded.
+  //   (Alternatively, better hotplugging support may make this unecessary
+  //   by disabling cameras that get disconnected and checking newly connected
+  //   cameras, so connect() is never called on an unsupported camera)
+  return 0;
+}
+
+void V4L2Camera::disconnect() {
+  HAL_LOG_ENTER();
+  mDeviceFd.reset();
+}
+
 camera_metadata_t* V4L2Camera::initStaticInfo() {
   HAL_LOG_ENTER();
 
diff --git a/modules/camera/3_4/V4L2Camera.h b/modules/camera/3_4/V4L2Camera.h
index 4ac9cc4..4cc0103 100644
--- a/modules/camera/3_4/V4L2Camera.h
+++ b/modules/camera/3_4/V4L2Camera.h
@@ -21,7 +21,9 @@
 
 #include <string>
 
+#include <nativehelper/ScopedFd.h>
 #include <system/camera_metadata.h>
+
 #include "Camera.h"
 #include "Common.h"
 
@@ -37,6 +39,10 @@
 
 private:
   // default_camera_hal::Camera virtual methods.
+  // Connect to the device: open dev nodes, etc.
+  int connect();
+  // Disconnect from the device: close dev nodes, etc.
+  void disconnect();
   // Initialize static camera characteristics for individual device.
   camera_metadata_t *initStaticInfo();
   // Initialize device info: facing, orientation, resource cost,
@@ -49,6 +55,8 @@
 
   // The camera device path. For example, /dev/video0.
   const std::string mDevicePath;
+  // The opened device fd.
+  ScopedFd mDeviceFd;
 
   DISALLOW_COPY_AND_ASSIGN(V4L2Camera);
 };
diff --git a/modules/camera/3_4/V4L2CameraHAL.cpp b/modules/camera/3_4/V4L2CameraHAL.cpp
index ec99a4c..6696ba5 100644
--- a/modules/camera/3_4/V4L2CameraHAL.cpp
+++ b/modules/camera/3_4/V4L2CameraHAL.cpp
@@ -30,6 +30,8 @@
 #include <cstdlib>
 #include <unordered_set>
 
+#include <android-base/parseint.h>
+
 #include "Common.h"
 #include "V4L2Camera.h"
 
@@ -46,22 +48,6 @@
 // Default global camera hal.
 static V4L2CameraHAL gCameraHAL;
 
-// Helper function for converting and validating string name to int id.
-// Returns either a non-negative camera id, or a negative error code.
-static int id_from_name(const char* name) {
-  if (name == NULL || *name == '\0') {
-    HAL_LOGE("Invalid camera id name is NULL");
-    return -EINVAL;
-  }
-  char* nameEnd;
-  int id = strtol(name, &nameEnd, 10);
-  if (*nameEnd != '\0' || id < 0) {
-    HAL_LOGE("Invalid camera id name %s", name);
-    return -EINVAL;
-  }
-  return id;
-}
-
 V4L2CameraHAL::V4L2CameraHAL() : mCameras(), mCallbacks(NULL) {
   HAL_LOG_ENTER();
   // Adds all available V4L2 devices.
@@ -171,14 +157,12 @@
     return -EINVAL;
   }
 
-  int id = id_from_name(name);
-  if (id < 0) {
-    return id;
-  } else if (id < 0 || id >= mCameras.size()) {
+  int id;
+  if (!android::base::ParseInt(name, &id, 0, getNumberOfCameras() - 1)) {
     return -EINVAL;
   }
   // TODO(b/29185945): Hotplugging: return -EINVAL if unplugged.
-  return mCameras[id]->open(module, device);
+  return mCameras[id]->openDevice(module, device);
 }
 
 /*