camera: Support multiple physical camera requests

Capture requests could include settings for different physical
cameras. Camera service should always check whether such
extended requests refer to valid physical devices and process
them accordingly.
Fix some stability issues in the camera native tests.

Test: Basic camera sanity using camera application,
camera_client_test, Camera CTS
Bug: 64691172

Change-Id: I68b81e983dd0b7caebfa03e4f0cf283f2a91dc7a
diff --git a/camera/camera2/CaptureRequest.cpp b/camera/camera2/CaptureRequest.cpp
index 983d29b..1843ec4 100644
--- a/camera/camera2/CaptureRequest.cpp
+++ b/camera/camera2/CaptureRequest.cpp
@@ -18,6 +18,7 @@
 // #define LOG_NDEBUG 0
 #define LOG_TAG "CameraRequest"
 #include <utils/Log.h>
+#include <utils/String16.h>
 
 #include <camera/camera2/CaptureRequest.h>
 
@@ -42,18 +43,39 @@
         return BAD_VALUE;
     }
 
-    mMetadata.clear();
     mSurfaceList.clear();
     mStreamIdxList.clear();
     mSurfaceIdxList.clear();
+    mPhysicalCameraSettings.clear();
 
     status_t err = OK;
 
-    if ((err = mMetadata.readFromParcel(parcel)) != OK) {
-        ALOGE("%s: Failed to read metadata from parcel", __FUNCTION__);
+    int32_t settingsCount;
+    if ((err = parcel->readInt32(&settingsCount)) != OK) {
+        ALOGE("%s: Failed to read the settings count from parcel: %d", __FUNCTION__, err);
         return err;
     }
-    ALOGV("%s: Read metadata from parcel", __FUNCTION__);
+
+    if (settingsCount <= 0) {
+        ALOGE("%s: Settings count %d should always be positive!", __FUNCTION__, settingsCount);
+        return BAD_VALUE;
+    }
+
+    for (int32_t i = 0; i < settingsCount; i++) {
+        String16 id;
+        if ((err = parcel->readString16(&id)) != OK) {
+            ALOGE("%s: Failed to read camera id!", __FUNCTION__);
+            return BAD_VALUE;
+        }
+
+        CameraMetadata settings;
+        if ((err = settings.readFromParcel(parcel)) != OK) {
+            ALOGE("%s: Failed to read metadata from parcel", __FUNCTION__);
+            return err;
+        }
+        ALOGV("%s: Read metadata from parcel", __FUNCTION__);
+        mPhysicalCameraSettings.push_back({std::string(String8(id).string()), settings});
+    }
 
     int isReprocess = 0;
     if ((err = parcel->readInt32(&isReprocess)) != OK) {
@@ -135,10 +157,25 @@
 
     status_t err = OK;
 
-    if ((err = mMetadata.writeToParcel(parcel)) != OK) {
+    int32_t settingsCount = static_cast<int32_t>(mPhysicalCameraSettings.size());
+
+    if ((err = parcel->writeInt32(settingsCount)) != OK) {
+        ALOGE("%s: Failed to write settings count!", __FUNCTION__);
         return err;
     }
 
+    for (const auto &it : mPhysicalCameraSettings) {
+        if ((err = parcel->writeString16(String16(it.id.c_str()))) != OK) {
+            ALOGE("%s: Failed to camera id!", __FUNCTION__);
+            return err;
+        }
+
+        if ((err = it.settings.writeToParcel(parcel)) != OK) {
+            ALOGE("%s: Failed to write settings!", __FUNCTION__);
+            return err;
+        }
+    }
+
     parcel->writeInt32(mIsReprocess ? 1 : 0);
 
     if (mSurfaceConverted) {
diff --git a/camera/include/camera/camera2/CaptureRequest.h b/camera/include/camera/camera2/CaptureRequest.h
index c53799f..506abab 100644
--- a/camera/include/camera/camera2/CaptureRequest.h
+++ b/camera/include/camera/camera2/CaptureRequest.h
@@ -40,7 +40,11 @@
     CaptureRequest(CaptureRequest&& rhs) noexcept;
     virtual ~CaptureRequest();
 
-    CameraMetadata          mMetadata;
+    struct PhysicalCameraSettings {
+        std::string id;
+        CameraMetadata settings;
+    };
+    std::vector<PhysicalCameraSettings> mPhysicalCameraSettings;
 
     // Used by NDK client to pass surfaces by stream/surface index.
     bool                    mSurfaceConverted = false;
diff --git a/camera/ndk/impl/ACameraDevice.cpp b/camera/ndk/impl/ACameraDevice.cpp
index f7cea4f..ef1c61f 100644
--- a/camera/ndk/impl/ACameraDevice.cpp
+++ b/camera/ndk/impl/ACameraDevice.cpp
@@ -372,7 +372,8 @@
         const ACaptureRequest* request, /*out*/sp<CaptureRequest>& outReq) {
     camera_status_t ret;
     sp<CaptureRequest> req(new CaptureRequest());
-    req->mMetadata = request->settings->getInternalData();
+    req->mPhysicalCameraSettings.push_back({std::string(mCameraId.string()),
+            request->settings->getInternalData()});
     req->mIsReprocess = false; // NDK does not support reprocessing yet
     req->mContext = request->context;
     req->mSurfaceConverted = true; // set to true, and fill in stream/surface idx to speed up IPC
@@ -418,7 +419,7 @@
 ACaptureRequest*
 CameraDevice::allocateACaptureRequest(sp<CaptureRequest>& req) {
     ACaptureRequest* pRequest = new ACaptureRequest();
-    CameraMetadata clone = req->mMetadata;
+    CameraMetadata clone = req->mPhysicalCameraSettings.begin()->settings;
     pRequest->settings = new ACameraMetadata(clone.release(), ACameraMetadata::ACM_REQUEST);
     pRequest->targets  = new ACameraOutputTargets();
     for (size_t i = 0; i < req->mSurfaceList.size(); i++) {
diff --git a/camera/tests/CameraBinderTests.cpp b/camera/tests/CameraBinderTests.cpp
index 8fe9a86..24c0c51 100644
--- a/camera/tests/CameraBinderTests.cpp
+++ b/camera/tests/CameraBinderTests.cpp
@@ -317,6 +317,9 @@
     EXPECT_TRUE(res.isOk()) << res;
 
     EXPECT_EQ(numCameras, static_cast<const int>(statuses.size()));
+    for (const auto &it : statuses) {
+        listener->onStatusChanged(it.status, String16(it.cameraId));
+    }
 
     for (int32_t i = 0; i < numCameras; i++) {
         String16 cameraId = String16(String8::format("%d", i));
@@ -421,6 +424,9 @@
         serviceListener = new TestCameraServiceListener();
         std::vector<hardware::CameraStatus> statuses;
         service->addListener(serviceListener, &statuses);
+        for (const auto &it : statuses) {
+            serviceListener->onStatusChanged(it.status, String16(it.cameraId));
+        }
         service->getNumberOfCameras(hardware::ICameraService::CAMERA_TYPE_BACKWARD_COMPATIBLE,
                 &numCameras);
     }
@@ -439,8 +445,9 @@
     ASSERT_NOT_NULL(service);
     EXPECT_TRUE(serviceListener->waitForNumCameras(numCameras));
     for (int32_t i = 0; i < numCameras; i++) {
+        String8 cameraId8 = String8::format("%d", i);
         // Make sure we're available, or skip device tests otherwise
-        String16 cameraId(String8::format("%d",i));
+        String16 cameraId(cameraId8);
         int32_t s = serviceListener->getStatus(cameraId);
         EXPECT_EQ(hardware::ICameraServiceListener::STATUS_PRESENT, s);
         if (s != hardware::ICameraServiceListener::STATUS_PRESENT) {
@@ -488,7 +495,7 @@
         EXPECT_TRUE(res.isOk()) << res;
 
         hardware::camera2::CaptureRequest request;
-        request.mMetadata = requestTemplate;
+        request.mPhysicalCameraSettings.push_back({cameraId8.string(), requestTemplate});
         request.mSurfaceList.add(surface);
         request.mIsReprocess = false;
         int64_t lastFrameNumber = 0;
@@ -515,7 +522,7 @@
                 /*out*/&requestTemplate);
         EXPECT_TRUE(res.isOk()) << res;
         hardware::camera2::CaptureRequest request2;
-        request2.mMetadata = requestTemplate;
+        request2.mPhysicalCameraSettings.push_back({cameraId8.string(), requestTemplate});
         request2.mSurfaceList.add(surface);
         request2.mIsReprocess = false;
         callbacks->clearStatus();
@@ -548,10 +555,10 @@
         EXPECT_TRUE(res.isOk()) << res;
         android::hardware::camera2::CaptureRequest request3;
         android::hardware::camera2::CaptureRequest request4;
-        request3.mMetadata = requestTemplate;
+        request3.mPhysicalCameraSettings.push_back({cameraId8.string(), requestTemplate});
         request3.mSurfaceList.add(surface);
         request3.mIsReprocess = false;
-        request4.mMetadata = requestTemplate2;
+        request4.mPhysicalCameraSettings.push_back({cameraId8.string(), requestTemplate2});
         request4.mSurfaceList.add(surface);
         request4.mIsReprocess = false;
         std::vector<hardware::camera2::CaptureRequest> requestList;
@@ -585,3 +592,62 @@
     }
 
 };
+
+TEST_F(CameraClientBinderTest, CheckBinderCaptureRequest) {
+    sp<CaptureRequest> requestOriginal, requestParceled;
+    sp<IGraphicBufferProducer> gbProducer;
+    sp<IGraphicBufferConsumer> gbConsumer;
+    BufferQueue::createBufferQueue(&gbProducer, &gbConsumer);
+    sp<Surface> surface(new Surface(gbProducer, /*controlledByApp*/false));
+    Vector<sp<Surface>> surfaceList;
+    surfaceList.push_back(surface);
+    std::string physicalDeviceId1 = "0";
+    std::string physicalDeviceId2 = "1";
+    CameraMetadata physicalDeviceSettings1, physicalDeviceSettings2;
+    uint8_t intent1 = ANDROID_CONTROL_CAPTURE_INTENT_PREVIEW;
+    uint8_t intent2 = ANDROID_CONTROL_CAPTURE_INTENT_VIDEO_RECORD;
+    EXPECT_EQ(OK, physicalDeviceSettings1.update(ANDROID_CONTROL_CAPTURE_INTENT, &intent1, 1));
+    EXPECT_EQ(OK, physicalDeviceSettings2.update(ANDROID_CONTROL_CAPTURE_INTENT, &intent2, 1));
+
+    requestParceled = new CaptureRequest();
+    Parcel p;
+    EXPECT_TRUE(requestParceled->readFromParcel(&p) != OK);
+    p.writeInt32(0);
+    p.setDataPosition(0);
+    EXPECT_TRUE(requestParceled->readFromParcel(&p) != OK);
+    p.freeData();
+    p.writeInt32(-1);
+    p.setDataPosition(0);
+    EXPECT_TRUE(requestParceled->readFromParcel(&p) != OK);
+    p.freeData();
+    p.writeInt32(1);
+    p.setDataPosition(0);
+    EXPECT_TRUE(requestParceled->readFromParcel(&p) != OK);
+
+    requestOriginal = new CaptureRequest();
+    requestOriginal->mPhysicalCameraSettings.push_back({physicalDeviceId1,
+            physicalDeviceSettings1});
+    requestOriginal->mPhysicalCameraSettings.push_back({physicalDeviceId2,
+            physicalDeviceSettings2});
+    requestOriginal->mSurfaceList.push_back(surface);
+    requestOriginal->mIsReprocess = false;
+    requestOriginal->mSurfaceConverted = false;
+
+    p.freeData();
+    EXPECT_TRUE(requestOriginal->writeToParcel(&p) == OK);
+    p.setDataPosition(0);
+    EXPECT_TRUE(requestParceled->readFromParcel(&p) == OK);
+    EXPECT_EQ(requestParceled->mIsReprocess, false);
+    EXPECT_FALSE(requestParceled->mSurfaceList.empty());
+    EXPECT_EQ(2u, requestParceled->mPhysicalCameraSettings.size());
+    auto it = requestParceled->mPhysicalCameraSettings.begin();
+    EXPECT_EQ(physicalDeviceId1, it->id);
+    EXPECT_TRUE(it->settings.exists(ANDROID_CONTROL_CAPTURE_INTENT));
+    auto entry = it->settings.find(ANDROID_CONTROL_CAPTURE_INTENT);
+    EXPECT_EQ(entry.data.u8[0], intent1);
+    it++;
+    EXPECT_EQ(physicalDeviceId2, it->id);
+    EXPECT_TRUE(it->settings.exists(ANDROID_CONTROL_CAPTURE_INTENT));
+    entry = it->settings.find(ANDROID_CONTROL_CAPTURE_INTENT);
+    EXPECT_EQ(entry.data.u8[0], intent2);
+};
diff --git a/camera/tests/VendorTagDescriptorTests.cpp b/camera/tests/VendorTagDescriptorTests.cpp
index 75cfb73..0ee358d 100644
--- a/camera/tests/VendorTagDescriptorTests.cpp
+++ b/camera/tests/VendorTagDescriptorTests.cpp
@@ -142,6 +142,7 @@
     EXPECT_EQ(OK, vDescOriginal->writeToParcel(&p));
     p.setDataPosition(0);
 
+    vDescParceled = new VendorTagDescriptor();
     ASSERT_EQ(OK, vDescParceled->readFromParcel(&p));
 
     // Ensure consistent tag count