Camera: Handle binder call failure due to static metadata size

For physical camera static metadata, we should reduce its size before
passing it across binder if possible.

Test: Camera CTS
Bug: 124129552
Change-Id: I0d9129642ddcbb4c1a1c7fcf7a88bac734be4f5a
diff --git a/camera/common/1.0/default/CameraModule.cpp b/camera/common/1.0/default/CameraModule.cpp
index 3e3ef43..467c121 100644
--- a/camera/common/1.0/default/CameraModule.cpp
+++ b/camera/common/1.0/default/CameraModule.cpp
@@ -253,6 +253,14 @@
         }
         mCameraInfoMap.removeItemsAt(0);
     }
+
+    while (mPhysicalCameraInfoMap.size() > 0) {
+        camera_metadata_t* metadata = mPhysicalCameraInfoMap.editValueAt(0);
+        if (metadata != NULL) {
+            free_camera_metadata(metadata);
+        }
+        mPhysicalCameraInfoMap.removeItemsAt(0);
+    }
 }
 
 int CameraModule::init() {
@@ -351,7 +359,14 @@
             return ret;
         }
 
-        index = mPhysicalCameraInfoMap.add(physicalCameraId, info);
+        // The camera_metadata_t returned by get_physical_camera_info could be using
+        // more memory than necessary due to unused reserved space. Reduce the
+        // size by appending it to a new CameraMetadata object, which internally
+        // calls resizeIfNeeded.
+        CameraMetadata m;
+        m.append(info);
+        camera_metadata_t* derivedMetadata = m.release();
+        index = mPhysicalCameraInfoMap.add(physicalCameraId, derivedMetadata);
     }
 
     assert(index != NAME_NOT_FOUND);
@@ -473,6 +488,43 @@
    }
 }
 
+bool CameraModule::isLogicalMultiCamera(
+        const common::V1_0::helper::CameraMetadata& metadata,
+        std::unordered_set<std::string>* physicalCameraIds) {
+    if (physicalCameraIds == nullptr) {
+        ALOGE("%s: physicalCameraIds must not be null", __FUNCTION__);
+        return false;
+    }
+
+    bool isLogicalMultiCamera = false;
+    camera_metadata_ro_entry_t capabilities =
+            metadata.find(ANDROID_REQUEST_AVAILABLE_CAPABILITIES);
+    for (size_t i = 0; i < capabilities.count; i++) {
+        if (capabilities.data.u8[i] ==
+                ANDROID_REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA) {
+            isLogicalMultiCamera = true;
+            break;
+        }
+    }
+
+    if (isLogicalMultiCamera) {
+        camera_metadata_ro_entry_t entry =
+                metadata.find(ANDROID_LOGICAL_MULTI_CAMERA_PHYSICAL_IDS);
+        const uint8_t* ids = entry.data.u8;
+        size_t start = 0;
+        for (size_t i = 0; i < entry.count; ++i) {
+            if (ids[i] == '\0') {
+                if (start != i) {
+                    const char* physicalId = reinterpret_cast<const char*>(ids+start);
+                    physicalCameraIds->emplace(physicalId);
+                }
+                start = i + 1;
+            }
+        }
+    }
+    return isLogicalMultiCamera;
+}
+
 status_t CameraModule::filterOpenErrorCode(status_t err) {
     switch(err) {
         case NO_ERROR:
@@ -487,8 +539,24 @@
 }
 
 void CameraModule::removeCamera(int cameraId) {
-    free_camera_metadata(const_cast<camera_metadata_t*>(
-        mCameraInfoMap.valueFor(cameraId).static_camera_characteristics));
+    std::unordered_set<std::string> physicalIds;
+    camera_metadata_t *metadata = const_cast<camera_metadata_t*>(
+            mCameraInfoMap.valueFor(cameraId).static_camera_characteristics);
+    common::V1_0::helper::CameraMetadata hidlMetadata(metadata);
+
+    if (isLogicalMultiCamera(hidlMetadata, &physicalIds)) {
+        for (const auto& id : physicalIds) {
+            int idInt = std::stoi(id);
+            if (mPhysicalCameraInfoMap.indexOfKey(idInt) >= 0) {
+                free_camera_metadata(mPhysicalCameraInfoMap[idInt]);
+                mPhysicalCameraInfoMap.removeItem(idInt);
+            } else {
+                ALOGE("%s: Cannot find corresponding static metadata for physical id %s",
+                        __FUNCTION__, id.c_str());
+            }
+        }
+    }
+    free_camera_metadata(metadata);
     mCameraInfoMap.removeItem(cameraId);
     mDeviceVersionMap.removeItem(cameraId);
 }
diff --git a/camera/common/1.0/default/include/CameraModule.h b/camera/common/1.0/default/include/CameraModule.h
index 32c387f..c89e934 100644
--- a/camera/common/1.0/default/include/CameraModule.h
+++ b/camera/common/1.0/default/include/CameraModule.h
@@ -17,6 +17,9 @@
 #ifndef CAMERA_COMMON_1_0_CAMERAMODULE_H
 #define CAMERA_COMMON_1_0_CAMERAMODULE_H
 
+#include <string>
+#include <unordered_set>
+
 #include <hardware/camera.h>
 #include <utils/Mutex.h>
 #include <utils/KeyedVector.h>
@@ -69,6 +72,10 @@
     int isStreamCombinationSupported(int cameraId, camera_stream_combination_t *streams);
     void notifyDeviceStateChange(uint64_t deviceState);
 
+    static bool isLogicalMultiCamera(
+            const common::V1_0::helper::CameraMetadata& metadata,
+            std::unordered_set<std::string>* physicalCameraIds);
+
 private:
     // Derive camera characteristics keys defined after HAL device version
     static void deriveCameraCharacteristicsKeys(uint32_t deviceVersion, CameraMetadata &chars);
diff --git a/camera/device/3.4/default/CameraDeviceSession.cpp b/camera/device/3.4/default/CameraDeviceSession.cpp
index e52577c..c937834 100644
--- a/camera/device/3.4/default/CameraDeviceSession.cpp
+++ b/camera/device/3.4/default/CameraDeviceSession.cpp
@@ -22,6 +22,7 @@
 #include <hardware/gralloc.h>
 #include <hardware/gralloc1.h>
 #include "CameraDeviceSession.h"
+#include "CameraModule.h"
 
 namespace android {
 namespace hardware {
@@ -30,6 +31,8 @@
 namespace V3_4 {
 namespace implementation {
 
+using ::android::hardware::camera::common::V1_0::helper::CameraModule;
+
 CameraDeviceSession::CameraDeviceSession(
     camera3_device_t* device,
     const camera_metadata_t* deviceInfo,
@@ -54,31 +57,9 @@
 
     mResultBatcher_3_4.setNumPartialResults(mNumPartialResults);
 
-    camera_metadata_entry_t capabilities =
-            mDeviceInfo.find(ANDROID_REQUEST_AVAILABLE_CAPABILITIES);
-    bool isLogicalMultiCamera = false;
-    for (size_t i = 0; i < capabilities.count; i++) {
-        if (capabilities.data.u8[i] ==
-                ANDROID_REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA) {
-            isLogicalMultiCamera = true;
-            break;
-        }
-    }
-    if (isLogicalMultiCamera) {
-        camera_metadata_entry entry =
-                mDeviceInfo.find(ANDROID_LOGICAL_MULTI_CAMERA_PHYSICAL_IDS);
-        const uint8_t* ids = entry.data.u8;
-        size_t start = 0;
-        for (size_t i = 0; i < entry.count; ++i) {
-            if (ids[i] == '\0') {
-                if (start != i) {
-                    const char* physicalId = reinterpret_cast<const char*>(ids+start);
-                    mPhysicalCameraIds.emplace(physicalId);
-                }
-                start = i + 1;
-            }
-        }
-    }
+    // Parse and store current logical camera's physical ids.
+    (void)CameraModule::isLogicalMultiCamera(mDeviceInfo, &mPhysicalCameraIds);
+
 }
 
 CameraDeviceSession::~CameraDeviceSession() {