Camera: plumb external camera API1 support

And also some refactoring to unify external camera
config file logics.

Bug: 72261912
Change-Id: If83d779c57540809bdaa58a5a32cf4ade734fafe
diff --git a/camera/device/3.4/default/ExternalCameraDevice.cpp b/camera/device/3.4/default/ExternalCameraDevice.cpp
index 569acfd..61b8921 100644
--- a/camera/device/3.4/default/ExternalCameraDevice.cpp
+++ b/camera/device/3.4/default/ExternalCameraDevice.cpp
@@ -44,9 +44,10 @@
 
 } // anonymous namespace
 
-ExternalCameraDevice::ExternalCameraDevice(const std::string& cameraId) :
+ExternalCameraDevice::ExternalCameraDevice(
+            const std::string& cameraId, const ExternalCameraConfig& cfg) :
         mCameraId(cameraId),
-        mCfg(ExternalCameraDeviceConfig::loadFromCfg()) {
+        mCfg(cfg) {
 
     status_t ret = initCameraCharacteristics();
     if (ret != OK) {
diff --git a/camera/device/3.4/default/ExternalCameraDeviceSession.cpp b/camera/device/3.4/default/ExternalCameraDeviceSession.cpp
index 51bfe36..74fd7f4 100644
--- a/camera/device/3.4/default/ExternalCameraDeviceSession.cpp
+++ b/camera/device/3.4/default/ExternalCameraDeviceSession.cpp
@@ -55,7 +55,7 @@
 
 ExternalCameraDeviceSession::ExternalCameraDeviceSession(
         const sp<ICameraDeviceCallback>& callback,
-        const ExternalCameraDeviceConfig& cfg,
+        const ExternalCameraConfig& cfg,
         const std::vector<SupportedV4L2Format>& sortedFormats,
         const CroppingType& croppingType,
         const common::V1_0::helper::CameraMetadata& chars,
diff --git a/camera/device/3.4/default/ExternalCameraUtils.cpp b/camera/device/3.4/default/ExternalCameraUtils.cpp
index 212573a..80f296c 100644
--- a/camera/device/3.4/default/ExternalCameraUtils.cpp
+++ b/camera/device/3.4/default/ExternalCameraUtils.cpp
@@ -30,14 +30,6 @@
 namespace V3_4 {
 namespace implementation {
 
-namespace {
-    const int  kDefaultJpegBufSize = 5 << 20; // 5MB
-    const int  kDefaultNumVideoBuffer = 4;
-    const int  kDefaultNumStillBuffer = 2;
-} // anonymous namespace
-
-const char* ExternalCameraDeviceConfig::kDefaultCfgPath = "/vendor/etc/external_camera_config.xml";
-
 V4L2Frame::V4L2Frame(
         uint32_t w, uint32_t h, uint32_t fourcc,
         int bufIdx, int fd, uint32_t dataSize, uint64_t offset) :
@@ -148,10 +140,32 @@
     return 0;
 }
 
+bool isAspectRatioClose(float ar1, float ar2) {
+    const float kAspectRatioMatchThres = 0.025f; // This threshold is good enough to distinguish
+                                                // 4:3/16:9/20:9
+                                                // 1.33 / 1.78 / 2
+    return (std::abs(ar1 - ar2) < kAspectRatioMatchThres);
+}
 
-ExternalCameraDeviceConfig ExternalCameraDeviceConfig::loadFromCfg(const char* cfgPath) {
+}  // namespace implementation
+}  // namespace V3_4
+}  // namespace device
+
+
+namespace external {
+namespace common {
+
+namespace {
+    const int  kDefaultJpegBufSize = 5 << 20; // 5MB
+    const int  kDefaultNumVideoBuffer = 4;
+    const int  kDefaultNumStillBuffer = 2;
+} // anonymous namespace
+
+const char* ExternalCameraConfig::kDefaultCfgPath = "/vendor/etc/external_camera_config.xml";
+
+ExternalCameraConfig ExternalCameraConfig::loadFromCfg(const char* cfgPath) {
     using namespace tinyxml2;
-    ExternalCameraDeviceConfig ret;
+    ExternalCameraConfig ret;
 
     XMLDocument configXml;
     XMLError err = configXml.LoadFile(cfgPath);
@@ -169,6 +183,29 @@
         return ret;
     }
 
+    XMLElement *providerCfg = extCam->FirstChildElement("Provider");
+    if (providerCfg == nullptr) {
+        ALOGI("%s: no external camera provider config specified", __FUNCTION__);
+        return ret;
+    }
+
+    XMLElement *ignore = providerCfg->FirstChildElement("ignore");
+    if (ignore == nullptr) {
+        ALOGI("%s: no internal ignored device specified", __FUNCTION__);
+        return ret;
+    }
+
+    XMLElement *id = ignore->FirstChildElement("id");
+    while (id != nullptr) {
+        const char* text = id->GetText();
+        if (text != nullptr) {
+            ret.mInternalDevices.insert(text);
+            ALOGI("%s: device %s will be ignored by external camera provider",
+                    __FUNCTION__, text);
+        }
+        id = id->NextSiblingElement("id");
+    }
+
     XMLElement *deviceCfg = extCam->FirstChildElement("Device");
     if (deviceCfg == nullptr) {
         ALOGI("%s: no external camera device config specified", __FUNCTION__);
@@ -226,7 +263,7 @@
         ret.fpsLimits = limits;
     }
 
-    ALOGI("%s: external camera cfd loaded: maxJpgBufSize %d,"
+    ALOGI("%s: external camera cfg loaded: maxJpgBufSize %d,"
             " num video buffers %d, num still buffers %d",
             __FUNCTION__, ret.maxJpegBufSize,
             ret.numVideoBuffers, ret.numStillBuffers);
@@ -237,7 +274,7 @@
     return ret;
 }
 
-ExternalCameraDeviceConfig::ExternalCameraDeviceConfig() :
+ExternalCameraConfig::ExternalCameraConfig() :
         maxJpegBufSize(kDefaultJpegBufSize),
         numVideoBuffers(kDefaultNumVideoBuffer),
         numStillBuffers(kDefaultNumStillBuffer) {
@@ -247,16 +284,9 @@
     fpsLimits.push_back({/*Size*/{4096, 3072}, /*FPS upper bound*/5.0});
 }
 
-bool isAspectRatioClose(float ar1, float ar2) {
-    const float kAspectRatioMatchThres = 0.025f; // This threshold is good enough to distinguish
-                                                // 4:3/16:9/20:9
-                                                // 1.33 / 1.78 / 2
-    return (std::abs(ar1 - ar2) < kAspectRatioMatchThres);
-}
 
-}  // namespace implementation
-}  // namespace V3_4
-}  // namespace device
+}  // namespace common
+}  // namespace external
 }  // namespace camera
 }  // namespace hardware
 }  // namespace android
diff --git a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h
index fabf26a..cced3f7 100644
--- a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h
+++ b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h
@@ -67,6 +67,9 @@
 using ::android::hardware::camera::common::V1_0::Status;
 using ::android::hardware::camera::common::V1_0::helper::HandleImporter;
 using ::android::hardware::camera::common::V1_0::helper::ExifUtils;
+using ::android::hardware::camera::external::common::ExternalCameraConfig;
+using ::android::hardware::camera::external::common::Size;
+using ::android::hardware::camera::external::common::SizeHasher;
 using ::android::hardware::graphics::common::V1_0::BufferUsage;
 using ::android::hardware::graphics::common::V1_0::Dataspace;
 using ::android::hardware::graphics::common::V1_0::PixelFormat;
@@ -84,7 +87,7 @@
 struct ExternalCameraDeviceSession : public virtual RefBase {
 
     ExternalCameraDeviceSession(const sp<ICameraDeviceCallback>&,
-            const ExternalCameraDeviceConfig& cfg,
+            const ExternalCameraConfig& cfg,
             const std::vector<SupportedV4L2Format>& sortedFormats,
             const CroppingType& croppingType,
             const common::V1_0::helper::CameraMetadata& chars,
@@ -277,7 +280,7 @@
 
     mutable Mutex mLock; // Protect all private members except otherwise noted
     const sp<ICameraDeviceCallback> mCallback;
-    const ExternalCameraDeviceConfig mCfg;
+    const ExternalCameraConfig& mCfg;
     const common::V1_0::helper::CameraMetadata mCameraCharacteristics;
     const std::vector<SupportedV4L2Format> mSupportedFormats;
     const CroppingType mCroppingType;
@@ -293,7 +296,7 @@
 
     bool mV4l2Streaming = false;
     SupportedV4L2Format mV4l2StreamingFmt;
-    size_t mV4L2BufferCount;
+    size_t mV4L2BufferCount = 0;
 
     static const int kBufferWaitTimeoutSec = 3; // TODO: handle long exposure (or not allowing)
     std::mutex mV4l2BufferLock; // protect the buffer count and condition below
diff --git a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDevice_3_4.h b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDevice_3_4.h
index ef4b41c..5880469 100644
--- a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDevice_3_4.h
+++ b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDevice_3_4.h
@@ -38,6 +38,8 @@
 using ::android::hardware::camera::common::V1_0::CameraResourceCost;
 using ::android::hardware::camera::common::V1_0::TorchMode;
 using ::android::hardware::camera::common::V1_0::Status;
+using ::android::hardware::camera::external::common::ExternalCameraConfig;
+using ::android::hardware::camera::external::common::Size;
 using ::android::hardware::Return;
 using ::android::hardware::Void;
 using ::android::hardware::hidl_vec;
@@ -54,7 +56,7 @@
     // be multiple CameraDevice trying to access the same physical camera.  Also, provider will have
     // to keep track of all CameraDevice objects in order to notify CameraDevice when the underlying
     // camera is detached.
-    ExternalCameraDevice(const std::string& cameraId);
+    ExternalCameraDevice(const std::string& cameraId, const ExternalCameraConfig& cfg);
     ~ExternalCameraDevice();
 
     // Caller must use this method to check if CameraDevice ctor failed
@@ -95,7 +97,7 @@
     Mutex mLock;
     bool mInitFailed = false;
     std::string mCameraId;
-    const ExternalCameraDeviceConfig mCfg;
+    const ExternalCameraConfig& mCfg;
     std::vector<SupportedV4L2Format> mSupportedFormats;
     CroppingType mCroppingType;
 
diff --git a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h
index 849f947..e56160a 100644
--- a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h
+++ b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h
@@ -21,6 +21,7 @@
 #include "utils/LightRefBase.h"
 #include <mutex>
 #include <vector>
+#include <unordered_set>
 #include <android/hardware/graphics/mapper/2.0/IMapper.h>
 
 using android::hardware::graphics::mapper::V2_0::IMapper;
@@ -29,6 +30,60 @@
 namespace android {
 namespace hardware {
 namespace camera {
+
+namespace external {
+namespace common {
+
+struct Size {
+    uint32_t width;
+    uint32_t height;
+
+    bool operator==(const Size& other) const {
+        return (width == other.width && height == other.height);
+    }
+};
+
+struct SizeHasher {
+    size_t operator()(const Size& sz) const {
+        size_t result = 1;
+        result = 31 * result + sz.width;
+        result = 31 * result + sz.height;
+        return result;
+    }
+};
+
+struct ExternalCameraConfig {
+    static const char* kDefaultCfgPath;
+    static ExternalCameraConfig loadFromCfg(const char* cfgPath = kDefaultCfgPath);
+
+    // List of internal V4L2 video nodes external camera HAL must ignore.
+    std::unordered_set<std::string> mInternalDevices;
+
+    // Maximal size of a JPEG buffer, in bytes
+    uint32_t maxJpegBufSize;
+
+    // Maximum Size that can sustain 30fps streaming
+    Size maxVideoSize;
+
+    // Size of v4l2 buffer queue when streaming <= kMaxVideoSize
+    uint32_t numVideoBuffers;
+
+    // Size of v4l2 buffer queue when streaming > kMaxVideoSize
+    uint32_t numStillBuffers;
+
+    struct FpsLimitation {
+        Size size;
+        float fpsUpperBound;
+    };
+    std::vector<FpsLimitation> fpsLimits;
+
+private:
+    ExternalCameraConfig();
+};
+
+} // common
+} // external
+
 namespace device {
 namespace V3_4 {
 namespace implementation {
@@ -85,50 +140,6 @@
     VERTICAL = 1
 };
 
-struct Size {
-    uint32_t width;
-    uint32_t height;
-
-    bool operator==(const Size& other) const {
-        return (width == other.width && height == other.height);
-    }
-};
-
-struct SizeHasher {
-    size_t operator()(const Size& sz) const {
-        size_t result = 1;
-        result = 31 * result + sz.width;
-        result = 31 * result + sz.height;
-        return result;
-    }
-};
-
-struct ExternalCameraDeviceConfig {
-    static const char* kDefaultCfgPath;
-    static ExternalCameraDeviceConfig loadFromCfg(const char* cfgPath = kDefaultCfgPath);
-
-    // Maximal size of a JPEG buffer, in bytes
-    uint32_t maxJpegBufSize;
-
-    // Maximum Size that can sustain 30fps streaming
-    Size maxVideoSize;
-
-    // Size of v4l2 buffer queue when streaming <= kMaxVideoSize
-    uint32_t numVideoBuffers;
-
-    // Size of v4l2 buffer queue when streaming > kMaxVideoSize
-    uint32_t numStillBuffers;
-
-    struct FpsLimitation {
-        Size size;
-        float fpsUpperBound;
-    };
-    std::vector<FpsLimitation> fpsLimits;
-
-private:
-    ExternalCameraDeviceConfig();
-};
-
 // Aspect ratio is defined as width/height here and ExternalCameraDevice
 // will guarantee all supported sizes has width >= height (so aspect ratio >= 1.0)
 #define ASPECT_RATIO(sz) (static_cast<float>((sz).width) / (sz).height)
diff --git a/camera/provider/2.4/default/ExternalCameraProvider.cpp b/camera/provider/2.4/default/ExternalCameraProvider.cpp
index 7657fa3..faa4e3a 100644
--- a/camera/provider/2.4/default/ExternalCameraProvider.cpp
+++ b/camera/provider/2.4/default/ExternalCameraProvider.cpp
@@ -24,7 +24,6 @@
 #include <linux/videodev2.h>
 #include "ExternalCameraProvider.h"
 #include "ExternalCameraDevice_3_4.h"
-#include "tinyxml2.h" // XML parsing
 
 namespace android {
 namespace hardware {
@@ -38,6 +37,8 @@
 const std::regex kDeviceNameRE("device@([0-9]+\\.[0-9]+)/external/(.+)");
 const int kMaxDevicePathLen = 256;
 const char* kDevicePath = "/dev/";
+constexpr char kPrefix[] = "video";
+constexpr int kPrefixLen = sizeof(kPrefix) - 1;
 
 bool matchDeviceName(const hidl_string& deviceName, std::string* deviceVersion,
                      std::string* cameraId) {
@@ -58,6 +59,7 @@
 } // anonymous namespace
 
 ExternalCameraProvider::ExternalCameraProvider() :
+        mCfg(ExternalCameraConfig::loadFromCfg()),
         mHotPlugThread(this) {
     mHotPlugThread.run("ExtCamHotPlug", PRIORITY_BACKGROUND);
 }
@@ -69,8 +71,17 @@
 
 Return<Status> ExternalCameraProvider::setCallback(
         const sp<ICameraProviderCallback>& callback) {
-    Mutex::Autolock _l(mLock);
-    mCallbacks = callback;
+    {
+        Mutex::Autolock _l(mLock);
+        mCallbacks = callback;
+    }
+    // Send a callback for all devices to initialize
+    {
+        for (const auto& pair : mCameraStatusMap) {
+            mCallbacks->cameraDeviceStatusChange(pair.first, pair.second);
+        }
+    }
+
     return Status::OK;
 }
 
@@ -82,14 +93,9 @@
 }
 
 Return<void> ExternalCameraProvider::getCameraIdList(getCameraIdList_cb _hidl_cb) {
-    std::vector<hidl_string> deviceNameList;
-    for (auto const& kvPair : mCameraStatusMap) {
-        if (kvPair.second == CameraDeviceStatus::PRESENT) {
-            deviceNameList.push_back(kvPair.first);
-        }
-    }
-    hidl_vec<hidl_string> hidlDeviceNameList(deviceNameList);
-    ALOGV("ExtCam: number of cameras is %zu", deviceNameList.size());
+    // External camera HAL always report 0 camera, and extra cameras
+    // are just reported via cameraDeviceStatusChange callbacks
+    hidl_vec<hidl_string> hidlDeviceNameList;
     _hidl_cb(Status::OK, hidlDeviceNameList);
     return Void();
 }
@@ -130,7 +136,7 @@
     sp<device::V3_2::ICameraDevice> device;
     sp<device::V3_4::implementation::ExternalCameraDevice> deviceImpl =
             new device::V3_4::implementation::ExternalCameraDevice(
-                    cameraId);
+                    cameraId, mCfg);
     if (deviceImpl == nullptr || deviceImpl->isInitFailed()) {
         ALOGE("%s: camera device %s init failed!", __FUNCTION__, cameraId.c_str());
         device = nullptr;
@@ -194,59 +200,10 @@
     }
 }
 
-std::unordered_set<std::string>
-ExternalCameraProvider::HotplugThread::initInternalDevices() {
-    std::unordered_set<std::string> ret;
-    using device::V3_4::implementation::ExternalCameraDeviceConfig;
-    const char* configPath = ExternalCameraDeviceConfig::kDefaultCfgPath;
-
-    using namespace tinyxml2;
-
-    XMLDocument configXml;
-    XMLError err = configXml.LoadFile(configPath);
-    if (err != XML_SUCCESS) {
-        ALOGE("%s: Unable to load external camera config file '%s'. Error: %s",
-                __FUNCTION__, configPath, XMLDocument::ErrorIDToName(err));
-    } else {
-        ALOGI("%s: load external camera config succeed!", __FUNCTION__);
-    }
-
-    XMLElement *extCam = configXml.FirstChildElement("ExternalCamera");
-    if (extCam == nullptr) {
-        ALOGI("%s: no external camera config specified", __FUNCTION__);
-        return ret;
-    }
-
-    XMLElement *providerCfg = extCam->FirstChildElement("Provider");
-    if (providerCfg == nullptr) {
-        ALOGI("%s: no external camera provider config specified", __FUNCTION__);
-        return ret;
-    }
-
-    XMLElement *ignore = providerCfg->FirstChildElement("ignore");
-    if (ignore == nullptr) {
-        ALOGI("%s: no internal ignored device specified", __FUNCTION__);
-        return ret;
-    }
-
-    XMLElement *id = ignore->FirstChildElement("id");
-    while (id != nullptr) {
-        const char* text = id->GetText();
-        if (text != nullptr) {
-            ret.insert(text);
-            ALOGI("%s: device %s will be ignored by external camera provider",
-                    __FUNCTION__, text);
-        }
-        id = id->NextSiblingElement("id");
-    }
-
-    return ret;
-}
-
 ExternalCameraProvider::HotplugThread::HotplugThread(ExternalCameraProvider* parent) :
         Thread(/*canCallJava*/false),
         mParent(parent),
-        mInternalDevices(initInternalDevices()) {}
+        mInternalDevices(parent->mCfg.mInternalDevices) {}
 
 ExternalCameraProvider::HotplugThread::~HotplugThread() {}
 
@@ -261,10 +218,10 @@
     struct dirent* de;
     while ((de = readdir(devdir)) != 0) {
         // Find external v4l devices that's existing before we start watching and add them
-        if (!strncmp("video", de->d_name, 5)) {
+        if (!strncmp(kPrefix, de->d_name, kPrefixLen)) {
             // TODO: This might reject some valid devices. Ex: internal is 33 and a device named 3
             //       is added.
-            std::string deviceId(de->d_name + 5);
+            std::string deviceId(de->d_name + kPrefixLen);
             if (mInternalDevices.count(deviceId) == 0) {
                 ALOGV("Non-internal v4l device %s found", de->d_name);
                 char v4l2DevicePath[kMaxDevicePathLen];
@@ -300,8 +257,8 @@
             while (offset < ret) {
                 struct inotify_event* event = (struct inotify_event*)&eventBuf[offset];
                 if (event->wd == mWd) {
-                    if (!strncmp("video", event->name, 5)) {
-                        std::string deviceId(event->name + 5);
+                    if (!strncmp(kPrefix, event->name, kPrefixLen)) {
+                        std::string deviceId(event->name + kPrefixLen);
                         if (mInternalDevices.count(deviceId) == 0) {
                             char v4l2DevicePath[kMaxDevicePathLen];
                             snprintf(v4l2DevicePath, kMaxDevicePathLen,
diff --git a/camera/provider/2.4/default/ExternalCameraProvider.h b/camera/provider/2.4/default/ExternalCameraProvider.h
index 64a8878..c83cc70 100644
--- a/camera/provider/2.4/default/ExternalCameraProvider.h
+++ b/camera/provider/2.4/default/ExternalCameraProvider.h
@@ -25,6 +25,7 @@
 #include <android/hardware/camera/provider/2.4/ICameraProvider.h>
 #include <hidl/Status.h>
 #include <hidl/MQDescriptor.h>
+#include "ExternalCameraUtils.h"
 
 namespace android {
 namespace hardware {
@@ -36,6 +37,7 @@
 using ::android::hardware::camera::common::V1_0::CameraDeviceStatus;
 using ::android::hardware::camera::common::V1_0::Status;
 using ::android::hardware::camera::common::V1_0::VendorTagSection;
+using ::android::hardware::camera::external::common::ExternalCameraConfig;
 using ::android::hardware::camera::provider::V2_4::ICameraProvider;
 using ::android::hardware::camera::provider::V2_4::ICameraProviderCallback;
 using ::android::hardware::Return;
@@ -81,8 +83,6 @@
         virtual bool threadLoop() override;
 
     private:
-        static std::unordered_set<std::string> initInternalDevices();
-
         ExternalCameraProvider* mParent = nullptr;
         const std::unordered_set<std::string> mInternalDevices;
 
@@ -93,6 +93,7 @@
     Mutex mLock;
     sp<ICameraProviderCallback> mCallbacks = nullptr;
     std::unordered_map<std::string, CameraDeviceStatus> mCameraStatusMap; // camera id -> status
+    const ExternalCameraConfig mCfg;
     HotplugThread mHotPlugThread;
 };