Merge "Return ILLEGAL_ARGUMENT for setting null callback" into main
diff --git a/audio/aidl/default/Configuration.cpp b/audio/aidl/default/Configuration.cpp
index 85e4e24..635a25b 100644
--- a/audio/aidl/default/Configuration.cpp
+++ b/audio/aidl/default/Configuration.cpp
@@ -237,7 +237,7 @@
         c.ports.push_back(primaryOutMix);
 
         AudioPort primaryInMix =
-                createPort(c.nextPortId++, "primary input", 0, true, createPortMixExt(0, 0));
+                createPort(c.nextPortId++, "primary input", 0, true, createPortMixExt(0, 1));
         primaryInMix.profiles.push_back(
                 createProfile(PcmType::INT_16_BIT,
                               {AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO},
@@ -252,14 +252,14 @@
         c.ports.push_back(telephonyTxOutMix);
 
         AudioPort telephonyRxInMix =
-                createPort(c.nextPortId++, "telephony_rx", 0, true, createPortMixExt(1, 1));
+                createPort(c.nextPortId++, "telephony_rx", 0, true, createPortMixExt(0, 1));
         telephonyRxInMix.profiles.insert(telephonyRxInMix.profiles.begin(),
                                          standardPcmAudioProfiles.begin(),
                                          standardPcmAudioProfiles.end());
         c.ports.push_back(telephonyRxInMix);
 
         AudioPort fmTunerInMix =
-                createPort(c.nextPortId++, "fm_tuner", 0, true, createPortMixExt(1, 1));
+                createPort(c.nextPortId++, "fm_tuner", 0, true, createPortMixExt(0, 1));
         fmTunerInMix.profiles.insert(fmTunerInMix.profiles.begin(),
                                      standardPcmAudioProfiles.begin(),
                                      standardPcmAudioProfiles.end());
@@ -441,7 +441,7 @@
         c.ports.push_back(usbDeviceOutMix);
 
         AudioPort usbDeviceInMix =
-                createPort(c.nextPortId++, "usb_device input", 0, true, createPortMixExt(1, 1));
+                createPort(c.nextPortId++, "usb_device input", 0, true, createPortMixExt(0, 1));
         c.ports.push_back(usbDeviceInMix);
 
         c.routes.push_back(createRoute({usbDeviceOutMix}, usbOutDevice));
diff --git a/audio/aidl/default/Module.cpp b/audio/aidl/default/Module.cpp
index 819b3c5..76132b3 100644
--- a/audio/aidl/default/Module.cpp
+++ b/audio/aidl/default/Module.cpp
@@ -340,21 +340,43 @@
 
 ndk::ScopedAStatus Module::updateStreamsConnectedState(const AudioPatch& oldPatch,
                                                        const AudioPatch& newPatch) {
-    // Streams from the old patch need to be disconnected, streams from the new
-    // patch need to be connected. If the stream belongs to both patches, no need
-    // to update it.
+    // Notify streams about the new set of devices they are connected to.
     auto maybeFailure = ndk::ScopedAStatus::ok();
-    std::set<int32_t> idsToDisconnect, idsToConnect, idsToDisconnectOnFailure;
-    idsToDisconnect.insert(oldPatch.sourcePortConfigIds.begin(),
-                           oldPatch.sourcePortConfigIds.end());
-    idsToDisconnect.insert(oldPatch.sinkPortConfigIds.begin(), oldPatch.sinkPortConfigIds.end());
-    idsToConnect.insert(newPatch.sourcePortConfigIds.begin(), newPatch.sourcePortConfigIds.end());
-    idsToConnect.insert(newPatch.sinkPortConfigIds.begin(), newPatch.sinkPortConfigIds.end());
-    std::for_each(idsToDisconnect.begin(), idsToDisconnect.end(), [&](const auto& portConfigId) {
-        if (idsToConnect.count(portConfigId) == 0 && mStreams.count(portConfigId) != 0) {
-            if (auto status = mStreams.setStreamConnectedDevices(portConfigId, {}); status.isOk()) {
+    using Connections =
+            std::map<int32_t /*mixPortConfigId*/, std::set<int32_t /*devicePortConfigId*/>>;
+    Connections oldConnections, newConnections;
+    auto fillConnectionsHelper = [&](Connections& connections,
+                                     const std::vector<int32_t>& mixPortCfgIds,
+                                     const std::vector<int32_t>& devicePortCfgIds) {
+        for (int32_t mixPortCfgId : mixPortCfgIds) {
+            connections[mixPortCfgId].insert(devicePortCfgIds.begin(), devicePortCfgIds.end());
+        }
+    };
+    auto fillConnections = [&](Connections& connections, const AudioPatch& patch) {
+        if (std::find_if(patch.sourcePortConfigIds.begin(), patch.sourcePortConfigIds.end(),
+                         [&](int32_t portConfigId) { return mStreams.count(portConfigId) > 0; }) !=
+            patch.sourcePortConfigIds.end()) {
+            // Sources are mix ports.
+            fillConnectionsHelper(connections, patch.sourcePortConfigIds, patch.sinkPortConfigIds);
+        } else if (std::find_if(patch.sinkPortConfigIds.begin(), patch.sinkPortConfigIds.end(),
+                                [&](int32_t portConfigId) {
+                                    return mStreams.count(portConfigId) > 0;
+                                }) != patch.sinkPortConfigIds.end()) {
+            // Sources are device ports.
+            fillConnectionsHelper(connections, patch.sinkPortConfigIds, patch.sourcePortConfigIds);
+        }  // Otherwise, there are no streams to notify.
+    };
+    fillConnections(oldConnections, oldPatch);
+    fillConnections(newConnections, newPatch);
+
+    std::for_each(oldConnections.begin(), oldConnections.end(), [&](const auto& connectionPair) {
+        const int32_t mixPortConfigId = connectionPair.first;
+        if (auto it = newConnections.find(mixPortConfigId);
+            it == newConnections.end() || it->second != connectionPair.second) {
+            if (auto status = mStreams.setStreamConnectedDevices(mixPortConfigId, {});
+                status.isOk()) {
                 LOG(DEBUG) << "updateStreamsConnectedState: The stream on port config id "
-                           << portConfigId << " has been disconnected";
+                           << mixPortConfigId << " has been disconnected";
             } else {
                 // Disconnection is tricky to roll back, just register a failure.
                 maybeFailure = std::move(status);
@@ -362,23 +384,26 @@
         }
     });
     if (!maybeFailure.isOk()) return maybeFailure;
-    std::for_each(idsToConnect.begin(), idsToConnect.end(), [&](const auto& portConfigId) {
-        if (idsToDisconnect.count(portConfigId) == 0 && mStreams.count(portConfigId) != 0) {
-            const auto connectedDevices = findConnectedDevices(portConfigId);
+    std::set<int32_t> idsToDisconnectOnFailure;
+    std::for_each(newConnections.begin(), newConnections.end(), [&](const auto& connectionPair) {
+        const int32_t mixPortConfigId = connectionPair.first;
+        if (auto it = oldConnections.find(mixPortConfigId);
+            it == oldConnections.end() || it->second != connectionPair.second) {
+            const auto connectedDevices = findConnectedDevices(mixPortConfigId);
             if (connectedDevices.empty()) {
                 // This is important as workers use the vector size to derive the connection status.
                 LOG(FATAL) << "updateStreamsConnectedState: No connected devices found for port "
                               "config id "
-                           << portConfigId;
+                           << mixPortConfigId;
             }
-            if (auto status = mStreams.setStreamConnectedDevices(portConfigId, connectedDevices);
+            if (auto status = mStreams.setStreamConnectedDevices(mixPortConfigId, connectedDevices);
                 status.isOk()) {
                 LOG(DEBUG) << "updateStreamsConnectedState: The stream on port config id "
-                           << portConfigId << " has been connected to: "
+                           << mixPortConfigId << " has been connected to: "
                            << ::android::internal::ToString(connectedDevices);
             } else {
                 maybeFailure = std::move(status);
-                idsToDisconnectOnFailure.insert(portConfigId);
+                idsToDisconnectOnFailure.insert(mixPortConfigId);
             }
         }
     });
@@ -515,7 +540,7 @@
         }
     }
 
-    connectedPort.id = ++getConfig().nextPortId;
+    connectedPort.id = getConfig().nextPortId++;
     auto [connectedPortsIt, _] =
             mConnectedDevicePorts.insert(std::pair(connectedPort.id, std::set<int32_t>()));
     LOG(DEBUG) << __func__ << ": template port " << templateId << " external device connected, "
@@ -865,6 +890,7 @@
         patches.push_back(*_aidl_return);
     } else {
         oldPatch = *existing;
+        *existing = *_aidl_return;
     }
     patchesBackup = mPatches;
     registerPatch(*_aidl_return);
diff --git a/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp b/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp
index a4670db..621d200 100644
--- a/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp
@@ -1238,11 +1238,25 @@
                    const AudioPortConfig& portConfig2)
         : mSrcPortConfig(sinkIsCfg1 ? portConfig2 : portConfig1),
           mSinkPortConfig(sinkIsCfg1 ? portConfig1 : portConfig2) {}
+    WithAudioPatch(const WithAudioPatch& patch, const AudioPortConfig& srcPortConfig,
+                   const AudioPortConfig& sinkPortConfig)
+        : mInitialPatch(patch.mPatch),
+          mSrcPortConfig(srcPortConfig),
+          mSinkPortConfig(sinkPortConfig),
+          mModule(patch.mModule),
+          mPatch(patch.mPatch) {}
     WithAudioPatch(const WithAudioPatch&) = delete;
     WithAudioPatch& operator=(const WithAudioPatch&) = delete;
     ~WithAudioPatch() {
         if (mModule != nullptr && mPatch.id != 0) {
-            EXPECT_IS_OK(mModule->resetAudioPatch(mPatch.id)) << "patch id " << getId();
+            if (mInitialPatch.has_value()) {
+                AudioPatch ignored;
+                // This releases our port configs so that they can be reset.
+                EXPECT_IS_OK(mModule->setAudioPatch(*mInitialPatch, &ignored))
+                        << "patch id " << mInitialPatch->id;
+            } else {
+                EXPECT_IS_OK(mModule->resetAudioPatch(mPatch.id)) << "patch id " << getId();
+            }
         }
     }
     void SetUpPortConfigs(IModule* module) {
@@ -1264,6 +1278,16 @@
             EXPECT_GT(latencyMs, 0) << "patch id " << getId();
         }
     }
+    void VerifyAgainstAllPatches(IModule* module) {
+        std::vector<AudioPatch> allPatches;
+        ASSERT_IS_OK(module->getAudioPatches(&allPatches));
+        const auto& patchIt = findById(allPatches, getId());
+        ASSERT_NE(patchIt, allPatches.end()) << "patch id " << getId();
+        if (get() != *patchIt) {
+            FAIL() << "Stored patch: " << get().toString() << " is not the same as returned "
+                   << "by the HAL module: " << patchIt->toString();
+        }
+    }
     int32_t getId() const { return mPatch.id; }
     const AudioPatch& get() const { return mPatch; }
     const AudioPortConfig& getSinkPortConfig() const { return mSinkPortConfig.get(); }
@@ -1273,6 +1297,7 @@
     }
 
   private:
+    std::optional<AudioPatch> mInitialPatch;
     WithAudioPortConfig mSrcPortConfig;
     WithAudioPortConfig mSinkPortConfig;
     IModule* mModule = nullptr;
@@ -3637,9 +3662,12 @@
                     patches.push_back(
                             std::make_unique<WithAudioPatch>(srcSink.first, srcSink.second));
                     EXPECT_NO_FATAL_FAILURE(patches[patches.size() - 1]->SetUp(module.get()));
+                    EXPECT_NO_FATAL_FAILURE(
+                            patches[patches.size() - 1]->VerifyAgainstAllPatches(module.get()));
                 } else {
                     WithAudioPatch patch(srcSink.first, srcSink.second);
                     EXPECT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
+                    EXPECT_NO_FATAL_FAILURE(patch.VerifyAgainstAllPatches(module.get()));
                 }
             }
         }
@@ -3660,6 +3688,29 @@
         }
     }
 
+    void UpdatePatchPorts(bool isInput) {
+        auto srcSinkGroups = moduleConfig->getRoutableSrcSinkGroups(isInput);
+        if (srcSinkGroups.empty()) {
+            GTEST_SKIP() << "No routes to any attached " << direction(isInput, false) << " devices";
+        }
+        bool hasAtLeastOnePair = false;
+        for (const auto& srcSinkGroup : srcSinkGroups) {
+            const auto& srcSinks = srcSinkGroup.second;
+            if (srcSinks.size() < 2) continue;
+            hasAtLeastOnePair = true;
+            const auto& pair1 = srcSinks[0];
+            const auto& pair2 = srcSinks[1];
+            WithAudioPatch patch(pair1.first, pair1.second);
+            ASSERT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
+            WithAudioPatch update(patch, pair2.first, pair2.second);
+            EXPECT_NO_FATAL_FAILURE(update.SetUp(module.get()));
+            EXPECT_NO_FATAL_FAILURE(update.VerifyAgainstAllPatches(module.get()));
+        }
+        if (!hasAtLeastOnePair) {
+            GTEST_SKIP() << "No routes with multiple sources";
+        }
+    }
+
     void UpdateInvalidPatchId(bool isInput) {
         auto srcSinkGroups = moduleConfig->getRoutableSrcSinkGroups(isInput);
         if (srcSinkGroups.empty()) {
@@ -3699,6 +3750,7 @@
 TEST_PATCH_BOTH_DIRECTIONS(SetPatch);
 TEST_PATCH_BOTH_DIRECTIONS(UpdateInvalidPatchId);
 TEST_PATCH_BOTH_DIRECTIONS(UpdatePatch);
+TEST_PATCH_BOTH_DIRECTIONS(UpdatePatchPorts);
 
 TEST_P(AudioModulePatch, ResetInvalidPatchId) {
     std::set<int32_t> patchIds;
diff --git a/automotive/remoteaccess/hal/default/Android.bp b/automotive/remoteaccess/hal/default/Android.bp
index 70dba30..97ed2c1 100644
--- a/automotive/remoteaccess/hal/default/Android.bp
+++ b/automotive/remoteaccess/hal/default/Android.bp
@@ -47,17 +47,6 @@
     ],
 }
 
-// TODO(b/295393732): remove this once we finish the migration from V1 to V2.
-cc_binary {
-    name: "android.hardware.automotive.remoteaccess@V1-default-service",
-    defaults: ["remote-access-hal-defaults"],
-    vintf_fragments: ["remoteaccess-default-service-v1.xml"],
-    init_rc: ["remoteaccess-default-service-v1.rc"],
-    cflags: [
-        "-DGRPC_SERVICE_ADDRESS=\"10.0.2.2:50051\"",
-    ],
-}
-
 cc_binary {
     name: "android.hardware.automotive.remoteaccess@V2-default-service",
     defaults: ["remote-access-hal-defaults"],
@@ -68,18 +57,6 @@
     ],
 }
 
-// TODO(b/295393732): remove this once we finish the migration from V1 to V2.
-cc_binary {
-    name: "android.hardware.automotive.remoteaccess@V1-tcu-test-service",
-    defaults: ["remote-access-hal-defaults"],
-    vintf_fragments: ["remoteaccess-default-service-v1.xml"],
-    init_rc: ["remoteaccess-tcu-test-service-v1.rc"],
-    cflags: [
-        "-DGRPC_SERVICE_ADDRESS=\"10.10.10.1:50051\"",
-        "-DGRPC_SERVICE_IFNAME=\"eth1\"",
-    ],
-}
-
 cc_binary {
     name: "android.hardware.automotive.remoteaccess@V2-tcu-test-service",
     defaults: ["remote-access-hal-defaults"],
diff --git a/automotive/remoteaccess/hal/default/remoteaccess-default-service-v1.rc b/automotive/remoteaccess/hal/default/remoteaccess-default-service-v1.rc
deleted file mode 100644
index b7a9cdc..0000000
--- a/automotive/remoteaccess/hal/default/remoteaccess-default-service-v1.rc
+++ /dev/null
@@ -1,4 +0,0 @@
-service vendor.remoteaccess-default /vendor/bin/hw/android.hardware.automotive.remoteaccess@V1-default-service
-    class hal
-    user vehicle_network
-    group system inet
diff --git a/automotive/remoteaccess/hal/default/remoteaccess-default-service-v1.xml b/automotive/remoteaccess/hal/default/remoteaccess-default-service-v1.xml
deleted file mode 100644
index d050a1b..0000000
--- a/automotive/remoteaccess/hal/default/remoteaccess-default-service-v1.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<manifest version="1.0" type="device">
-    <hal format="aidl">
-        <name>android.hardware.automotive.remoteaccess</name>
-        <version>1</version>
-        <fqname>IRemoteAccess/default</fqname>
-    </hal>
-</manifest>
diff --git a/automotive/remoteaccess/hal/default/remoteaccess-tcu-test-service-v1.rc b/automotive/remoteaccess/hal/default/remoteaccess-tcu-test-service-v1.rc
deleted file mode 100644
index 59315eb..0000000
--- a/automotive/remoteaccess/hal/default/remoteaccess-tcu-test-service-v1.rc
+++ /dev/null
@@ -1,5 +0,0 @@
-service vendor.remoteaccess-default /vendor/bin/hw/android.hardware.automotive.remoteaccess@V1-tcu-test-service
-    class hal
-    user vehicle_network
-    group system inet
-    capabilities NET_RAW
diff --git a/automotive/vehicle/aidl/generated_lib/cpp/AccessForVehicleProperty.h b/automotive/vehicle/aidl/generated_lib/cpp/AccessForVehicleProperty.h
index d0c6e83..92c2707 100644
--- a/automotive/vehicle/aidl/generated_lib/cpp/AccessForVehicleProperty.h
+++ b/automotive/vehicle/aidl/generated_lib/cpp/AccessForVehicleProperty.h
@@ -247,6 +247,7 @@
         {VehicleProperty::SUPPORTED_PROPERTY_IDS, VehiclePropertyAccess::READ},
         {VehicleProperty::SHUTDOWN_REQUEST, VehiclePropertyAccess::WRITE},
         {VehicleProperty::VEHICLE_IN_USE, VehiclePropertyAccess::READ_WRITE},
+        {VehicleProperty::CLUSTER_HEARTBEAT, VehiclePropertyAccess::WRITE},
         {VehicleProperty::AUTOMATIC_EMERGENCY_BRAKING_ENABLED, VehiclePropertyAccess::READ_WRITE},
         {VehicleProperty::AUTOMATIC_EMERGENCY_BRAKING_STATE, VehiclePropertyAccess::READ},
         {VehicleProperty::FORWARD_COLLISION_WARNING_ENABLED, VehiclePropertyAccess::READ_WRITE},
diff --git a/automotive/vehicle/aidl/generated_lib/cpp/ChangeModeForVehicleProperty.h b/automotive/vehicle/aidl/generated_lib/cpp/ChangeModeForVehicleProperty.h
index 48532c9..e1bdf7d 100644
--- a/automotive/vehicle/aidl/generated_lib/cpp/ChangeModeForVehicleProperty.h
+++ b/automotive/vehicle/aidl/generated_lib/cpp/ChangeModeForVehicleProperty.h
@@ -247,6 +247,7 @@
         {VehicleProperty::SUPPORTED_PROPERTY_IDS, VehiclePropertyChangeMode::STATIC},
         {VehicleProperty::SHUTDOWN_REQUEST, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::VEHICLE_IN_USE, VehiclePropertyChangeMode::ON_CHANGE},
+        {VehicleProperty::CLUSTER_HEARTBEAT, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::AUTOMATIC_EMERGENCY_BRAKING_ENABLED, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::AUTOMATIC_EMERGENCY_BRAKING_STATE, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::FORWARD_COLLISION_WARNING_ENABLED, VehiclePropertyChangeMode::ON_CHANGE},
diff --git a/automotive/vehicle/aidl/generated_lib/java/AccessForVehicleProperty.java b/automotive/vehicle/aidl/generated_lib/java/AccessForVehicleProperty.java
index 758670d..b5c3de9 100644
--- a/automotive/vehicle/aidl/generated_lib/java/AccessForVehicleProperty.java
+++ b/automotive/vehicle/aidl/generated_lib/java/AccessForVehicleProperty.java
@@ -239,6 +239,7 @@
         Map.entry(VehicleProperty.SUPPORTED_PROPERTY_IDS, VehiclePropertyAccess.READ),
         Map.entry(VehicleProperty.SHUTDOWN_REQUEST, VehiclePropertyAccess.WRITE),
         Map.entry(VehicleProperty.VEHICLE_IN_USE, VehiclePropertyAccess.READ_WRITE),
+        Map.entry(VehicleProperty.CLUSTER_HEARTBEAT, VehiclePropertyAccess.WRITE),
         Map.entry(VehicleProperty.AUTOMATIC_EMERGENCY_BRAKING_ENABLED, VehiclePropertyAccess.READ_WRITE),
         Map.entry(VehicleProperty.AUTOMATIC_EMERGENCY_BRAKING_STATE, VehiclePropertyAccess.READ),
         Map.entry(VehicleProperty.FORWARD_COLLISION_WARNING_ENABLED, VehiclePropertyAccess.READ_WRITE),
diff --git a/automotive/vehicle/aidl/generated_lib/java/ChangeModeForVehicleProperty.java b/automotive/vehicle/aidl/generated_lib/java/ChangeModeForVehicleProperty.java
index 29069f8..0f126e7 100644
--- a/automotive/vehicle/aidl/generated_lib/java/ChangeModeForVehicleProperty.java
+++ b/automotive/vehicle/aidl/generated_lib/java/ChangeModeForVehicleProperty.java
@@ -239,6 +239,7 @@
         Map.entry(VehicleProperty.SUPPORTED_PROPERTY_IDS, VehiclePropertyChangeMode.STATIC),
         Map.entry(VehicleProperty.SHUTDOWN_REQUEST, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.VEHICLE_IN_USE, VehiclePropertyChangeMode.ON_CHANGE),
+        Map.entry(VehicleProperty.CLUSTER_HEARTBEAT, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.AUTOMATIC_EMERGENCY_BRAKING_ENABLED, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.AUTOMATIC_EMERGENCY_BRAKING_STATE, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.FORWARD_COLLISION_WARNING_ENABLED, VehiclePropertyChangeMode.ON_CHANGE),
diff --git a/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json b/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json
index b9f784b..4a16bf7 100644
--- a/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json
+++ b/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json
@@ -3621,6 +3621,21 @@
             "property": "VehicleProperty::CLUSTER_NAVIGATION_STATE"
         },
         {
+            "property": "VehicleProperty::CLUSTER_HEARTBEAT",
+            "configArray": [
+                0,
+                0,
+                0,
+                0,
+                0,
+                2,
+                0,
+                0,
+                16
+            ],
+            "comment": "configArray specifies it consists of int64[2] and byte[16]."
+        },
+        {
             "property": "VehicleProperty::GENERAL_SAFETY_REGULATION_COMPLIANCE_REQUIREMENT",
             "defaultValue": {
                 "int32Values": [
diff --git a/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/VehicleProperty.aidl b/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/VehicleProperty.aidl
index ba75e7b..231186f 100644
--- a/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/VehicleProperty.aidl
+++ b/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/VehicleProperty.aidl
@@ -245,6 +245,7 @@
   SUPPORTED_PROPERTY_IDS = (((0x0F48 + 0x10000000) + 0x01000000) + 0x00410000) /* 289476424 */,
   SHUTDOWN_REQUEST = (((0x0F49 + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.GLOBAL) + android.hardware.automotive.vehicle.VehiclePropertyType.INT32) /* 289410889 */,
   VEHICLE_IN_USE = (((0x0F4A + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.GLOBAL) + android.hardware.automotive.vehicle.VehiclePropertyType.BOOLEAN) /* 287313738 */,
+  CLUSTER_HEARTBEAT = (((0x0F4B + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.GLOBAL) + android.hardware.automotive.vehicle.VehiclePropertyType.MIXED) /* 299896651 */,
   AUTOMATIC_EMERGENCY_BRAKING_ENABLED = (((0x1000 + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.GLOBAL) + android.hardware.automotive.vehicle.VehiclePropertyType.BOOLEAN) /* 287313920 */,
   AUTOMATIC_EMERGENCY_BRAKING_STATE = (((0x1001 + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.GLOBAL) + android.hardware.automotive.vehicle.VehiclePropertyType.INT32) /* 289411073 */,
   FORWARD_COLLISION_WARNING_ENABLED = (((0x1002 + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.GLOBAL) + android.hardware.automotive.vehicle.VehiclePropertyType.BOOLEAN) /* 287313922 */,
diff --git a/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleProperty.aidl b/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleProperty.aidl
index 7d88810..545df4b 100644
--- a/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleProperty.aidl
+++ b/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleProperty.aidl
@@ -4487,6 +4487,20 @@
     VEHICLE_IN_USE =
             0x0F4A + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
 
+    /**
+     * Sends the heartbeat signal to ClusterOS.
+     *
+     * int64[0]: epochTimeNs
+     * int64[1]: the visibility of ClusterUI, 0 - invisible, 1 - visible
+     * bytes: the app specific metadata, this can be empty when ClusterHomeService use the heartbeat
+     *     to deliver the change of the visibility.
+     *
+     * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+     * @access VehiclePropertyAccess.WRITE
+     */
+    CLUSTER_HEARTBEAT =
+            0x0F4B + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.MIXED,
+
     /***********************************************************************************************
      * Start of ADAS Properties
      *
diff --git a/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp b/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp
index 8bcad1e..6e6d05c 100644
--- a/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp
+++ b/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp
@@ -865,6 +865,12 @@
                    VehicleArea::GLOBAL, VehiclePropertyType::INT32);
 }
 
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyClusterHeartbeatConfig) {
+    verifyProperty(VehicleProperty::CLUSTER_HEARTBEAT, VehiclePropertyAccess::WRITE,
+                   VehiclePropertyChangeMode::ON_CHANGE, VehiclePropertyGroup::SYSTEM,
+                   VehicleArea::GLOBAL, VehiclePropertyType::MIXED);
+}
+
 std::vector<ServiceDescriptor> getDescriptors() {
     std::vector<ServiceDescriptor> descriptors;
     for (std::string name : getAidlHalInstanceNames(IVehicle::descriptor)) {
diff --git a/camera/common/default/Android.bp b/camera/common/default/Android.bp
index b5d3095..e8c8f9d 100644
--- a/camera/common/default/Android.bp
+++ b/camera/common/default/Android.bp
@@ -30,12 +30,13 @@
         "libgralloctypes",
         "libhardware",
         "libcamera_metadata",
+        "android.hardware.graphics.mapper@2.0",
+        "android.hardware.graphics.mapper@3.0",
+        "android.hardware.graphics.mapper@4.0",
         "libexif",
-        "libui",
     ],
     include_dirs: ["system/media/private/camera/include"],
     export_include_dirs: ["include"],
-    export_shared_lib_headers: ["libui"],
 }
 
 // NOTE: Deprecated module kept for compatibility reasons.
diff --git a/camera/common/default/HandleImporter.cpp b/camera/common/default/HandleImporter.cpp
index 9c579e5..1145baa 100644
--- a/camera/common/default/HandleImporter.cpp
+++ b/camera/common/default/HandleImporter.cpp
@@ -17,10 +17,9 @@
 #define LOG_TAG "HandleImporter"
 #include "HandleImporter.h"
 
-#include <aidl/android/hardware/graphics/common/Smpte2086.h>
 #include <gralloctypes/Gralloc4.h>
 #include <log/log.h>
-#include <ui/GraphicBufferMapper.h>
+#include "aidl/android/hardware/graphics/common/Smpte2086.h"
 
 namespace android {
 namespace hardware {
@@ -32,6 +31,12 @@
 using aidl::android::hardware::graphics::common::PlaneLayoutComponent;
 using aidl::android::hardware::graphics::common::PlaneLayoutComponentType;
 using aidl::android::hardware::graphics::common::Smpte2086;
+using MetadataType = android::hardware::graphics::mapper::V4_0::IMapper::MetadataType;
+using MapperErrorV2 = android::hardware::graphics::mapper::V2_0::Error;
+using MapperErrorV3 = android::hardware::graphics::mapper::V3_0::Error;
+using MapperErrorV4 = android::hardware::graphics::mapper::V4_0::Error;
+using IMapperV3 = android::hardware::graphics::mapper::V3_0::IMapper;
+using IMapperV4 = android::hardware::graphics::mapper::V4_0::IMapper;
 
 HandleImporter::HandleImporter() : mInitialized(false) {}
 
@@ -40,20 +45,51 @@
         return;
     }
 
-    GraphicBufferMapper::preloadHal();
+    mMapperV4 = IMapperV4::getService();
+    if (mMapperV4 != nullptr) {
+        mInitialized = true;
+        return;
+    }
+
+    mMapperV3 = IMapperV3::getService();
+    if (mMapperV3 != nullptr) {
+        mInitialized = true;
+        return;
+    }
+
+    mMapperV2 = IMapper::getService();
+    if (mMapperV2 == nullptr) {
+        ALOGE("%s: cannnot acccess graphics mapper HAL!", __FUNCTION__);
+        return;
+    }
+
     mInitialized = true;
     return;
 }
 
 void HandleImporter::cleanup() {
+    mMapperV4.clear();
+    mMapperV3.clear();
+    mMapperV2.clear();
     mInitialized = false;
 }
 
-bool HandleImporter::importBufferInternal(buffer_handle_t& handle) {
+template <class M, class E>
+bool HandleImporter::importBufferInternal(const sp<M> mapper, buffer_handle_t& handle) {
+    E error;
     buffer_handle_t importedHandle;
-    auto status = GraphicBufferMapper::get().importBufferNoValidate(handle, &importedHandle);
-    if (status != OK) {
-        ALOGE("%s: mapper importBuffer failed: %d", __FUNCTION__, status);
+    auto ret = mapper->importBuffer(
+            hidl_handle(handle), [&](const auto& tmpError, const auto& tmpBufferHandle) {
+                error = tmpError;
+                importedHandle = static_cast<buffer_handle_t>(tmpBufferHandle);
+            });
+
+    if (!ret.isOk()) {
+        ALOGE("%s: mapper importBuffer failed: %s", __FUNCTION__, ret.description().c_str());
+        return false;
+    }
+
+    if (error != E::NONE) {
         return false;
     }
 
@@ -61,32 +97,170 @@
     return true;
 }
 
-android_ycbcr HandleImporter::lockYCbCr(buffer_handle_t& buf, uint64_t cpuUsage,
-                                        const android::Rect& accessRegion) {
-    Mutex::Autolock lock(mLock);
+template <class M, class E>
+YCbCrLayout HandleImporter::lockYCbCrInternal(const sp<M> mapper, buffer_handle_t& buf,
+                                              uint64_t cpuUsage,
+                                              const IMapper::Rect& accessRegion) {
+    hidl_handle acquireFenceHandle;
+    auto buffer = const_cast<native_handle_t*>(buf);
+    YCbCrLayout layout = {};
 
-    if (!mInitialized) {
-        initializeLocked();
+    typename M::Rect accessRegionCopy = {accessRegion.left, accessRegion.top, accessRegion.width,
+                                         accessRegion.height};
+    mapper->lockYCbCr(buffer, cpuUsage, accessRegionCopy, acquireFenceHandle,
+                      [&](const auto& tmpError, const auto& tmpLayout) {
+                          if (tmpError == E::NONE) {
+                              // Member by member copy from different versions of YCbCrLayout.
+                              layout.y = tmpLayout.y;
+                              layout.cb = tmpLayout.cb;
+                              layout.cr = tmpLayout.cr;
+                              layout.yStride = tmpLayout.yStride;
+                              layout.cStride = tmpLayout.cStride;
+                              layout.chromaStep = tmpLayout.chromaStep;
+                          } else {
+                              ALOGE("%s: failed to lockYCbCr error %d!", __FUNCTION__, tmpError);
+                          }
+                      });
+    return layout;
+}
+
+bool isMetadataPesent(const sp<IMapperV4> mapper, const buffer_handle_t& buf,
+                      MetadataType metadataType) {
+    auto buffer = const_cast<native_handle_t*>(buf);
+    bool ret = false;
+    hidl_vec<uint8_t> vec;
+    mapper->get(buffer, metadataType, [&](const auto& tmpError, const auto& tmpMetadata) {
+        if (tmpError == MapperErrorV4::NONE) {
+            vec = tmpMetadata;
+        } else {
+            ALOGE("%s: failed to get metadata %d!", __FUNCTION__, tmpError);
+        }
+    });
+
+    if (vec.size() > 0) {
+        if (metadataType == gralloc4::MetadataType_Smpte2086) {
+            std::optional<Smpte2086> realSmpte2086;
+            gralloc4::decodeSmpte2086(vec, &realSmpte2086);
+            ret = realSmpte2086.has_value();
+        } else if (metadataType == gralloc4::MetadataType_Smpte2094_10) {
+            std::optional<std::vector<uint8_t>> realSmpte2094_10;
+            gralloc4::decodeSmpte2094_10(vec, &realSmpte2094_10);
+            ret = realSmpte2094_10.has_value();
+        } else if (metadataType == gralloc4::MetadataType_Smpte2094_40) {
+            std::optional<std::vector<uint8_t>> realSmpte2094_40;
+            gralloc4::decodeSmpte2094_40(vec, &realSmpte2094_40);
+            ret = realSmpte2094_40.has_value();
+        } else {
+            ALOGE("%s: Unknown metadata type!", __FUNCTION__);
+        }
     }
-    android_ycbcr layout;
 
-    status_t status = GraphicBufferMapper::get().lockYCbCr(buf, cpuUsage, accessRegion, &layout);
+    return ret;
+}
 
-    if (status != OK) {
-        ALOGE("%s: failed to lockYCbCr error %d!", __FUNCTION__, status);
+std::vector<PlaneLayout> getPlaneLayouts(const sp<IMapperV4> mapper, buffer_handle_t& buf) {
+    auto buffer = const_cast<native_handle_t*>(buf);
+    std::vector<PlaneLayout> planeLayouts;
+    hidl_vec<uint8_t> encodedPlaneLayouts;
+    mapper->get(buffer, gralloc4::MetadataType_PlaneLayouts,
+                [&](const auto& tmpError, const auto& tmpEncodedPlaneLayouts) {
+                    if (tmpError == MapperErrorV4::NONE) {
+                        encodedPlaneLayouts = tmpEncodedPlaneLayouts;
+                    } else {
+                        ALOGE("%s: failed to get plane layouts %d!", __FUNCTION__, tmpError);
+                    }
+                });
+
+    gralloc4::decodePlaneLayouts(encodedPlaneLayouts, &planeLayouts);
+
+    return planeLayouts;
+}
+
+template <>
+YCbCrLayout HandleImporter::lockYCbCrInternal<IMapperV4, MapperErrorV4>(
+        const sp<IMapperV4> mapper, buffer_handle_t& buf, uint64_t cpuUsage,
+        const IMapper::Rect& accessRegion) {
+    hidl_handle acquireFenceHandle;
+    auto buffer = const_cast<native_handle_t*>(buf);
+    YCbCrLayout layout = {};
+    void* mapped = nullptr;
+
+    typename IMapperV4::Rect accessRegionV4 = {accessRegion.left, accessRegion.top,
+                                               accessRegion.width, accessRegion.height};
+    mapper->lock(buffer, cpuUsage, accessRegionV4, acquireFenceHandle,
+                 [&](const auto& tmpError, const auto& tmpPtr) {
+                     if (tmpError == MapperErrorV4::NONE) {
+                         mapped = tmpPtr;
+                     } else {
+                         ALOGE("%s: failed to lock error %d!", __FUNCTION__, tmpError);
+                     }
+                 });
+
+    if (mapped == nullptr) {
+        return layout;
+    }
+
+    std::vector<PlaneLayout> planeLayouts = getPlaneLayouts(mapper, buf);
+    for (const auto& planeLayout : planeLayouts) {
+        for (const auto& planeLayoutComponent : planeLayout.components) {
+            const auto& type = planeLayoutComponent.type;
+
+            if (!gralloc4::isStandardPlaneLayoutComponentType(type)) {
+                continue;
+            }
+
+            uint8_t* data = reinterpret_cast<uint8_t*>(mapped);
+            data += planeLayout.offsetInBytes;
+            data += planeLayoutComponent.offsetInBits / 8;
+
+            switch (static_cast<PlaneLayoutComponentType>(type.value)) {
+                case PlaneLayoutComponentType::Y:
+                    layout.y = data;
+                    layout.yStride = planeLayout.strideInBytes;
+                    break;
+                case PlaneLayoutComponentType::CB:
+                    layout.cb = data;
+                    layout.cStride = planeLayout.strideInBytes;
+                    layout.chromaStep = planeLayout.sampleIncrementInBits / 8;
+                    break;
+                case PlaneLayoutComponentType::CR:
+                    layout.cr = data;
+                    layout.cStride = planeLayout.strideInBytes;
+                    layout.chromaStep = planeLayout.sampleIncrementInBits / 8;
+                    break;
+                default:
+                    break;
+            }
+        }
     }
 
     return layout;
 }
 
-std::vector<PlaneLayout> getPlaneLayouts(buffer_handle_t& buf) {
-    std::vector<PlaneLayout> planeLayouts;
-    status_t status = GraphicBufferMapper::get().getPlaneLayouts(buf, &planeLayouts);
-    if (status != OK) {
-        ALOGE("%s: failed to get PlaneLayouts! Status %d", __FUNCTION__, status);
-    }
+template <class M, class E>
+int HandleImporter::unlockInternal(const sp<M> mapper, buffer_handle_t& buf) {
+    int releaseFence = -1;
+    auto buffer = const_cast<native_handle_t*>(buf);
 
-    return planeLayouts;
+    mapper->unlock(buffer, [&](const auto& tmpError, const auto& tmpReleaseFence) {
+        if (tmpError == E::NONE) {
+            auto fenceHandle = tmpReleaseFence.getNativeHandle();
+            if (fenceHandle) {
+                if (fenceHandle->numInts != 0 || fenceHandle->numFds != 1) {
+                    ALOGE("%s: bad release fence numInts %d numFds %d", __FUNCTION__,
+                          fenceHandle->numInts, fenceHandle->numFds);
+                    return;
+                }
+                releaseFence = dup(fenceHandle->data[0]);
+                if (releaseFence < 0) {
+                    ALOGE("%s: bad release fence FD %d", __FUNCTION__, releaseFence);
+                }
+            }
+        } else {
+            ALOGE("%s: failed to unlock error %d!", __FUNCTION__, tmpError);
+        }
+    });
+    return releaseFence;
 }
 
 // In IComposer, any buffer_handle_t is owned by the caller and we need to
@@ -103,7 +277,20 @@
         initializeLocked();
     }
 
-    return importBufferInternal(handle);
+    if (mMapperV4 != nullptr) {
+        return importBufferInternal<IMapperV4, MapperErrorV4>(mMapperV4, handle);
+    }
+
+    if (mMapperV3 != nullptr) {
+        return importBufferInternal<IMapperV3, MapperErrorV3>(mMapperV3, handle);
+    }
+
+    if (mMapperV2 != nullptr) {
+        return importBufferInternal<IMapper, MapperErrorV2>(mMapperV2, handle);
+    }
+
+    ALOGE("%s: mMapperV4, mMapperV3 and mMapperV2 are all null!", __FUNCTION__);
+    return false;
 }
 
 void HandleImporter::freeBuffer(buffer_handle_t handle) {
@@ -116,9 +303,21 @@
         initializeLocked();
     }
 
-    status_t status = GraphicBufferMapper::get().freeBuffer(handle);
-    if (status != OK) {
-        ALOGE("%s: mapper freeBuffer failed. Status %d", __FUNCTION__, status);
+    if (mMapperV4 != nullptr) {
+        auto ret = mMapperV4->freeBuffer(const_cast<native_handle_t*>(handle));
+        if (!ret.isOk()) {
+            ALOGE("%s: mapper freeBuffer failed: %s", __FUNCTION__, ret.description().c_str());
+        }
+    } else if (mMapperV3 != nullptr) {
+        auto ret = mMapperV3->freeBuffer(const_cast<native_handle_t*>(handle));
+        if (!ret.isOk()) {
+            ALOGE("%s: mapper freeBuffer failed: %s", __FUNCTION__, ret.description().c_str());
+        }
+    } else {
+        auto ret = mMapperV2->freeBuffer(const_cast<native_handle_t*>(handle));
+        if (!ret.isOk()) {
+            ALOGE("%s: mapper freeBuffer failed: %s", __FUNCTION__, ret.description().c_str());
+        }
     }
 }
 
@@ -146,12 +345,12 @@
 }
 
 void* HandleImporter::lock(buffer_handle_t& buf, uint64_t cpuUsage, size_t size) {
-    android::Rect accessRegion{0, 0, static_cast<int>(size), 1};
+    IMapper::Rect accessRegion{0, 0, static_cast<int>(size), 1};
     return lock(buf, cpuUsage, accessRegion);
 }
 
 void* HandleImporter::lock(buffer_handle_t& buf, uint64_t cpuUsage,
-                           const android::Rect& accessRegion) {
+                           const IMapper::Rect& accessRegion) {
     Mutex::Autolock lock(mLock);
 
     if (!mInitialized) {
@@ -159,18 +358,81 @@
     }
 
     void* ret = nullptr;
-    status_t status = GraphicBufferMapper::get().lock(buf, cpuUsage, accessRegion, &ret);
-    if (status != OK) {
-        ALOGE("%s: failed to lock error %d!", __FUNCTION__, status);
+
+    if (mMapperV4 == nullptr && mMapperV3 == nullptr && mMapperV2 == nullptr) {
+        ALOGE("%s: mMapperV4, mMapperV3 and mMapperV2 are all null!", __FUNCTION__);
+        return ret;
+    }
+
+    hidl_handle acquireFenceHandle;
+    auto buffer = const_cast<native_handle_t*>(buf);
+    if (mMapperV4 != nullptr) {
+        IMapperV4::Rect accessRegionV4{accessRegion.left, accessRegion.top, accessRegion.width,
+                                       accessRegion.height};
+
+        mMapperV4->lock(buffer, cpuUsage, accessRegionV4, acquireFenceHandle,
+                        [&](const auto& tmpError, const auto& tmpPtr) {
+                            if (tmpError == MapperErrorV4::NONE) {
+                                ret = tmpPtr;
+                            } else {
+                                ALOGE("%s: failed to lock error %d!", __FUNCTION__, tmpError);
+                            }
+                        });
+    } else if (mMapperV3 != nullptr) {
+        IMapperV3::Rect accessRegionV3{accessRegion.left, accessRegion.top, accessRegion.width,
+                                       accessRegion.height};
+
+        mMapperV3->lock(buffer, cpuUsage, accessRegionV3, acquireFenceHandle,
+                        [&](const auto& tmpError, const auto& tmpPtr, const auto& /*bytesPerPixel*/,
+                            const auto& /*bytesPerStride*/) {
+                            if (tmpError == MapperErrorV3::NONE) {
+                                ret = tmpPtr;
+                            } else {
+                                ALOGE("%s: failed to lock error %d!", __FUNCTION__, tmpError);
+                            }
+                        });
+    } else {
+        mMapperV2->lock(buffer, cpuUsage, accessRegion, acquireFenceHandle,
+                        [&](const auto& tmpError, const auto& tmpPtr) {
+                            if (tmpError == MapperErrorV2::NONE) {
+                                ret = tmpPtr;
+                            } else {
+                                ALOGE("%s: failed to lock error %d!", __FUNCTION__, tmpError);
+                            }
+                        });
     }
 
     ALOGV("%s: ptr %p accessRegion.top: %d accessRegion.left: %d accessRegion.width: %d "
           "accessRegion.height: %d",
-          __FUNCTION__, ret, accessRegion.top, accessRegion.left, accessRegion.width(),
-          accessRegion.height());
+          __FUNCTION__, ret, accessRegion.top, accessRegion.left, accessRegion.width,
+          accessRegion.height);
     return ret;
 }
 
+YCbCrLayout HandleImporter::lockYCbCr(buffer_handle_t& buf, uint64_t cpuUsage,
+                                      const IMapper::Rect& accessRegion) {
+    Mutex::Autolock lock(mLock);
+
+    if (!mInitialized) {
+        initializeLocked();
+    }
+
+    if (mMapperV4 != nullptr) {
+        return lockYCbCrInternal<IMapperV4, MapperErrorV4>(mMapperV4, buf, cpuUsage, accessRegion);
+    }
+
+    if (mMapperV3 != nullptr) {
+        return lockYCbCrInternal<IMapperV3, MapperErrorV3>(mMapperV3, buf, cpuUsage, accessRegion);
+    }
+
+    if (mMapperV2 != nullptr) {
+        return lockYCbCrInternal<IMapper, MapperErrorV2>(mMapperV2, buf, cpuUsage, accessRegion);
+    }
+
+    ALOGE("%s: mMapperV4, mMapperV3 and mMapperV2 are all null!", __FUNCTION__);
+    return {};
+}
+
 status_t HandleImporter::getMonoPlanarStrideBytes(buffer_handle_t& buf, uint32_t* stride /*out*/) {
     if (stride == nullptr) {
         return BAD_VALUE;
@@ -182,26 +444,35 @@
         initializeLocked();
     }
 
-    std::vector<PlaneLayout> planeLayouts = getPlaneLayouts(buf);
-    if (planeLayouts.size() != 1) {
-        ALOGE("%s: Unexpected number of planes %zu!", __FUNCTION__, planeLayouts.size());
-        return BAD_VALUE;
-    }
+    if (mMapperV4 != nullptr) {
+        std::vector<PlaneLayout> planeLayouts = getPlaneLayouts(mMapperV4, buf);
+        if (planeLayouts.size() != 1) {
+            ALOGE("%s: Unexpected number of planes %zu!", __FUNCTION__, planeLayouts.size());
+            return BAD_VALUE;
+        }
 
-    *stride = planeLayouts[0].strideInBytes;
+        *stride = planeLayouts[0].strideInBytes;
+    } else {
+        ALOGE("%s: mMapperV4 is null! Query not supported!", __FUNCTION__);
+        return NO_INIT;
+    }
 
     return OK;
 }
 
 int HandleImporter::unlock(buffer_handle_t& buf) {
-    int releaseFence = -1;
-
-    status_t status = GraphicBufferMapper::get().unlockAsync(buf, &releaseFence);
-    if (status != OK) {
-        ALOGE("%s: failed to unlock error %d!", __FUNCTION__, status);
+    if (mMapperV4 != nullptr) {
+        return unlockInternal<IMapperV4, MapperErrorV4>(mMapperV4, buf);
+    }
+    if (mMapperV3 != nullptr) {
+        return unlockInternal<IMapperV3, MapperErrorV3>(mMapperV3, buf);
+    }
+    if (mMapperV2 != nullptr) {
+        return unlockInternal<IMapper, MapperErrorV2>(mMapperV2, buf);
     }
 
-    return releaseFence;
+    ALOGE("%s: mMapperV4, mMapperV3 and mMapperV2 are all null!", __FUNCTION__);
+    return -1;
 }
 
 bool HandleImporter::isSmpte2086Present(const buffer_handle_t& buf) {
@@ -210,14 +481,14 @@
     if (!mInitialized) {
         initializeLocked();
     }
-    std::optional<ui::Smpte2086> metadata;
-    status_t status = GraphicBufferMapper::get().getSmpte2086(buf, &metadata);
-    if (status != OK) {
-        ALOGE("%s: Mapper failed to get Smpte2094_40 metadata! Status: %d", __FUNCTION__, status);
-        return false;
+
+    if (mMapperV4 != nullptr) {
+        return isMetadataPesent(mMapperV4, buf, gralloc4::MetadataType_Smpte2086);
+    } else {
+        ALOGE("%s: mMapperV4 is null! Query not supported!", __FUNCTION__);
     }
 
-    return metadata.has_value();
+    return false;
 }
 
 bool HandleImporter::isSmpte2094_10Present(const buffer_handle_t& buf) {
@@ -227,14 +498,13 @@
         initializeLocked();
     }
 
-    std::optional<std::vector<uint8_t>> metadata;
-    status_t status = GraphicBufferMapper::get().getSmpte2094_10(buf, &metadata);
-    if (status != OK) {
-        ALOGE("%s: Mapper failed to get Smpte2094_40 metadata! Status: %d", __FUNCTION__, status);
-        return false;
+    if (mMapperV4 != nullptr) {
+        return isMetadataPesent(mMapperV4, buf, gralloc4::MetadataType_Smpte2094_10);
+    } else {
+        ALOGE("%s: mMapperV4 is null! Query not supported!", __FUNCTION__);
     }
 
-    return metadata.has_value();
+    return false;
 }
 
 bool HandleImporter::isSmpte2094_40Present(const buffer_handle_t& buf) {
@@ -244,14 +514,13 @@
         initializeLocked();
     }
 
-    std::optional<std::vector<uint8_t>> metadata;
-    status_t status = GraphicBufferMapper::get().getSmpte2094_40(buf, &metadata);
-    if (status != OK) {
-        ALOGE("%s: Mapper failed to get Smpte2094_40 metadata! Status: %d", __FUNCTION__, status);
-        return false;
+    if (mMapperV4 != nullptr) {
+        return isMetadataPesent(mMapperV4, buf, gralloc4::MetadataType_Smpte2094_40);
+    } else {
+        ALOGE("%s: mMapperV4 is null! Query not supported!", __FUNCTION__);
     }
 
-    return metadata.has_value();
+    return false;
 }
 
 }  // namespace helper
diff --git a/camera/common/default/include/HandleImporter.h b/camera/common/default/include/HandleImporter.h
index df01202..5408ba9 100644
--- a/camera/common/default/include/HandleImporter.h
+++ b/camera/common/default/include/HandleImporter.h
@@ -17,11 +17,15 @@
 #ifndef CAMERA_COMMON_1_0_HANDLEIMPORTED_H
 #define CAMERA_COMMON_1_0_HANDLEIMPORTED_H
 
+#include <android/hardware/graphics/mapper/2.0/IMapper.h>
+#include <android/hardware/graphics/mapper/3.0/IMapper.h>
+#include <android/hardware/graphics/mapper/4.0/IMapper.h>
 #include <cutils/native_handle.h>
-#include <system/graphics.h>
-#include <ui/Rect.h>
 #include <utils/Mutex.h>
 
+using android::hardware::graphics::mapper::V2_0::IMapper;
+using android::hardware::graphics::mapper::V2_0::YCbCrLayout;
+
 namespace android {
 namespace hardware {
 namespace camera {
@@ -45,11 +49,11 @@
     void* lock(buffer_handle_t& buf, uint64_t cpuUsage, size_t size);
 
     // Locks 2-D buffer. Assumes caller has waited for acquire fences.
-    void* lock(buffer_handle_t& buf, uint64_t cpuUsage, const android::Rect& accessRegion);
+    void* lock(buffer_handle_t& buf, uint64_t cpuUsage, const IMapper::Rect& accessRegion);
 
     // Assumes caller has waited for acquire fences.
-    android_ycbcr lockYCbCr(buffer_handle_t& buf, uint64_t cpuUsage,
-                            const android::Rect& accessRegion);
+    YCbCrLayout lockYCbCr(buffer_handle_t& buf, uint64_t cpuUsage,
+                          const IMapper::Rect& accessRegion);
 
     // Query the stride of the first plane in bytes.
     status_t getMonoPlanarStrideBytes(buffer_handle_t& buf, uint32_t* stride /*out*/);
@@ -65,11 +69,19 @@
     void initializeLocked();
     void cleanup();
 
-    bool importBufferInternal(buffer_handle_t& handle);
-    int unlockInternal(buffer_handle_t& buf);
+    template <class M, class E>
+    bool importBufferInternal(const sp<M> mapper, buffer_handle_t& handle);
+    template <class M, class E>
+    YCbCrLayout lockYCbCrInternal(const sp<M> mapper, buffer_handle_t& buf, uint64_t cpuUsage,
+                                  const IMapper::Rect& accessRegion);
+    template <class M, class E>
+    int unlockInternal(const sp<M> mapper, buffer_handle_t& buf);
 
     Mutex mLock;
     bool mInitialized;
+    sp<IMapper> mMapperV2;
+    sp<graphics::mapper::V3_0::IMapper> mMapperV3;
+    sp<graphics::mapper::V4_0::IMapper> mMapperV4;
 };
 
 }  // namespace helper
diff --git a/camera/device/1.0/default/Android.bp b/camera/device/1.0/default/Android.bp
index 6992ff0..9ff6480 100644
--- a/camera/device/1.0/default/Android.bp
+++ b/camera/device/1.0/default/Android.bp
@@ -32,7 +32,6 @@
         "libgralloctypes",
         "libhardware",
         "libcamera_metadata",
-        "libui",
     ],
     static_libs: [
         "android.hardware.camera.common@1.0-helper",
diff --git a/camera/device/3.2/default/Android.bp b/camera/device/3.2/default/Android.bp
index adf834a..a196291 100644
--- a/camera/device/3.2/default/Android.bp
+++ b/camera/device/3.2/default/Android.bp
@@ -30,7 +30,6 @@
         "libhardware",
         "libcamera_metadata",
         "libfmq",
-        "libui",
     ],
     static_libs: [
         "android.hardware.camera.common@1.0-helper",
diff --git a/camera/device/3.4/default/Android.bp b/camera/device/3.4/default/Android.bp
index 100106e..9f0c777 100644
--- a/camera/device/3.4/default/Android.bp
+++ b/camera/device/3.4/default/Android.bp
@@ -106,7 +106,6 @@
         "libjpeg",
         "libexif",
         "libtinyxml2",
-        "libui",
     ],
     static_libs: [
         "android.hardware.camera.common@1.0-helper",
diff --git a/camera/device/3.4/default/ExternalCameraDeviceSession.cpp b/camera/device/3.4/default/ExternalCameraDeviceSession.cpp
index 01b3d41..ca7186b 100644
--- a/camera/device/3.4/default/ExternalCameraDeviceSession.cpp
+++ b/camera/device/3.4/default/ExternalCameraDeviceSession.cpp
@@ -1574,23 +1574,14 @@
             } break;
             case PixelFormat::YCBCR_420_888:
             case PixelFormat::YV12: {
-                android::Rect outRect{0, 0, static_cast<int32_t>(halBuf.width),
-                                      static_cast<int32_t>(halBuf.height)};
-                android_ycbcr result =
-                        sHandleImporter.lockYCbCr(*(halBuf.bufPtr), halBuf.usage, outRect);
-                ALOGV("%s: outLayout y %p cb %p cr %p y_str %zu c_str %zu c_step %zu", __FUNCTION__,
-                      result.y, result.cb, result.cr, result.ystride, result.cstride,
-                      result.chroma_step);
-                if (result.ystride > UINT32_MAX || result.cstride > UINT32_MAX ||
-                    result.chroma_step > UINT32_MAX) {
-                    return onDeviceError("%s: lockYCbCr failed. Unexpected values!", __FUNCTION__);
-                }
-                YCbCrLayout outLayout = {.y = result.y,
-                                         .cb = result.cb,
-                                         .cr = result.cr,
-                                         .yStride = static_cast<uint32_t>(result.ystride),
-                                         .cStride = static_cast<uint32_t>(result.cstride),
-                                         .chromaStep = static_cast<uint32_t>(result.chroma_step)};
+                IMapper::Rect outRect {0, 0,
+                        static_cast<int32_t>(halBuf.width),
+                        static_cast<int32_t>(halBuf.height)};
+                YCbCrLayout outLayout = sHandleImporter.lockYCbCr(
+                        *(halBuf.bufPtr), halBuf.usage, outRect);
+                ALOGV("%s: outLayout y %p cb %p cr %p y_str %d c_str %d c_step %d",
+                        __FUNCTION__, outLayout.y, outLayout.cb, outLayout.cr,
+                        outLayout.yStride, outLayout.cStride, outLayout.chromaStep);
 
                 // Convert to output buffer size/format
                 uint32_t outputFourcc = getFourCcFromLayout(outLayout);
diff --git a/camera/device/3.5/default/Android.bp b/camera/device/3.5/default/Android.bp
index bc15629..9d27b32 100644
--- a/camera/device/3.5/default/Android.bp
+++ b/camera/device/3.5/default/Android.bp
@@ -46,7 +46,6 @@
     ],
     shared_libs: [
         "libhidlbase",
-        "libui",
         "libutils",
         "libcutils",
         "camera.device@3.2-impl",
@@ -82,7 +81,6 @@
     ],
     shared_libs: [
         "libhidlbase",
-        "libui",
         "libutils",
         "libcutils",
         "camera.device@3.2-impl",
diff --git a/camera/device/3.6/default/Android.bp b/camera/device/3.6/default/Android.bp
index b4a486f..89ee145 100644
--- a/camera/device/3.6/default/Android.bp
+++ b/camera/device/3.6/default/Android.bp
@@ -41,7 +41,6 @@
     ],
     shared_libs: [
         "libhidlbase",
-        "libui",
         "libutils",
         "libcutils",
         "camera.device@3.2-impl",
diff --git a/camera/device/3.6/default/ExternalCameraOfflineSession.cpp b/camera/device/3.6/default/ExternalCameraOfflineSession.cpp
index 1f1dfee..e606fda 100644
--- a/camera/device/3.6/default/ExternalCameraOfflineSession.cpp
+++ b/camera/device/3.6/default/ExternalCameraOfflineSession.cpp
@@ -222,23 +222,14 @@
             } break;
             case PixelFormat::YCBCR_420_888:
             case PixelFormat::YV12: {
-                android::Rect outRect{0, 0, static_cast<int32_t>(halBuf.width),
-                                      static_cast<int32_t>(halBuf.height)};
-                android_ycbcr result =
-                        sHandleImporter.lockYCbCr(*(halBuf.bufPtr), halBuf.usage, outRect);
-                ALOGV("%s: outLayout y %p cb %p cr %p y_str %zu c_str %zu c_step %zu", __FUNCTION__,
-                      result.y, result.cb, result.cr, result.ystride, result.cstride,
-                      result.chroma_step);
-                if (result.ystride > UINT32_MAX || result.cstride > UINT32_MAX ||
-                    result.chroma_step > UINT32_MAX) {
-                    return onDeviceError("%s: lockYCbCr failed. Unexpected values!", __FUNCTION__);
-                }
-                YCbCrLayout outLayout = {.y = result.y,
-                                         .cb = result.cb,
-                                         .cr = result.cr,
-                                         .yStride = static_cast<uint32_t>(result.ystride),
-                                         .cStride = static_cast<uint32_t>(result.cstride),
-                                         .chromaStep = static_cast<uint32_t>(result.chroma_step)};
+                IMapper::Rect outRect {0, 0,
+                        static_cast<int32_t>(halBuf.width),
+                        static_cast<int32_t>(halBuf.height)};
+                YCbCrLayout outLayout = sHandleImporter.lockYCbCr(
+                        *(halBuf.bufPtr), halBuf.usage, outRect);
+                ALOGV("%s: outLayout y %p cb %p cr %p y_str %d c_str %d c_step %d",
+                        __FUNCTION__, outLayout.y, outLayout.cb, outLayout.cr,
+                        outLayout.yStride, outLayout.cStride, outLayout.chromaStep);
 
                 // Convert to output buffer size/format
                 uint32_t outputFourcc = V3_4::implementation::getFourCcFromLayout(outLayout);
diff --git a/camera/device/default/Android.bp b/camera/device/default/Android.bp
index 5fbcb5d..b9f10d6 100644
--- a/camera/device/default/Android.bp
+++ b/camera/device/default/Android.bp
@@ -40,7 +40,7 @@
     shared_libs: [
         "android.hardware.camera.common-V1-ndk",
         "android.hardware.camera.device-V1-ndk",
-        "android.hardware.graphics.allocator-V2-ndk",
+        "android.hardware.graphics.allocator-V1-ndk",
         "android.hardware.graphics.mapper@2.0",
         "android.hardware.graphics.mapper@3.0",
         "android.hardware.graphics.mapper@4.0",
@@ -60,7 +60,6 @@
         "libsync",
         "libtinyxml2",
         "libutils",
-        "libui",
         "libyuv",
     ],
     static_libs: [
diff --git a/camera/device/default/ExternalCameraDeviceSession.cpp b/camera/device/default/ExternalCameraDeviceSession.cpp
index 896e0da..95a36f0 100644
--- a/camera/device/default/ExternalCameraDeviceSession.cpp
+++ b/camera/device/default/ExternalCameraDeviceSession.cpp
@@ -2882,23 +2882,13 @@
             } break;
             case PixelFormat::YCBCR_420_888:
             case PixelFormat::YV12: {
-                android::Rect outRect{0, 0, static_cast<int32_t>(halBuf.width),
+                IMapper::Rect outRect{0, 0, static_cast<int32_t>(halBuf.width),
                                       static_cast<int32_t>(halBuf.height)};
-                android_ycbcr result = sHandleImporter.lockYCbCr(
+                YCbCrLayout outLayout = sHandleImporter.lockYCbCr(
                         *(halBuf.bufPtr), static_cast<uint64_t>(halBuf.usage), outRect);
-                ALOGV("%s: outLayout y %p cb %p cr %p y_str %zu c_str %zu c_step %zu", __FUNCTION__,
-                      result.y, result.cb, result.cr, result.ystride, result.cstride,
-                      result.chroma_step);
-                if (result.ystride > UINT32_MAX || result.cstride > UINT32_MAX ||
-                    result.chroma_step > UINT32_MAX) {
-                    return onDeviceError("%s: lockYCbCr failed. Unexpected values!", __FUNCTION__);
-                }
-                YCbCrLayout outLayout = {.y = result.y,
-                                         .cb = result.cb,
-                                         .cr = result.cr,
-                                         .yStride = static_cast<uint32_t>(result.ystride),
-                                         .cStride = static_cast<uint32_t>(result.cstride),
-                                         .chromaStep = static_cast<uint32_t>(result.chroma_step)};
+                ALOGV("%s: outLayout y %p cb %p cr %p y_str %d c_str %d c_step %d", __FUNCTION__,
+                      outLayout.y, outLayout.cb, outLayout.cr, outLayout.yStride, outLayout.cStride,
+                      outLayout.chromaStep);
 
                 // Convert to output buffer size/format
                 uint32_t outputFourcc = getFourCcFromLayout(outLayout);
diff --git a/camera/device/default/ExternalCameraDeviceSession.h b/camera/device/default/ExternalCameraDeviceSession.h
index 736bfd1..836266f 100644
--- a/camera/device/default/ExternalCameraDeviceSession.h
+++ b/camera/device/default/ExternalCameraDeviceSession.h
@@ -24,9 +24,6 @@
 #include <aidl/android/hardware/camera/device/BufferRequest.h>
 #include <aidl/android/hardware/camera/device/Stream.h>
 #include <android-base/unique_fd.h>
-#include <android/hardware/graphics/mapper/2.0/IMapper.h>
-#include <android/hardware/graphics/mapper/3.0/IMapper.h>
-#include <android/hardware/graphics/mapper/4.0/IMapper.h>
 #include <fmq/AidlMessageQueue.h>
 #include <utils/Thread.h>
 #include <deque>
@@ -58,7 +55,6 @@
 using ::android::hardware::camera::common::helper::SimpleThread;
 using ::android::hardware::camera::external::common::ExternalCameraConfig;
 using ::android::hardware::camera::external::common::SizeHasher;
-using ::android::hardware::graphics::mapper::V2_0::YCbCrLayout;
 using ::ndk::ScopedAStatus;
 
 class ExternalCameraDeviceSession : public BnCameraDeviceSession, public OutputThreadInterface {
diff --git a/camera/device/default/ExternalCameraOfflineSession.cpp b/camera/device/default/ExternalCameraOfflineSession.cpp
index 53bd44f..4c7f732 100644
--- a/camera/device/default/ExternalCameraOfflineSession.cpp
+++ b/camera/device/default/ExternalCameraOfflineSession.cpp
@@ -486,23 +486,13 @@
             } break;
             case PixelFormat::YCBCR_420_888:
             case PixelFormat::YV12: {
-                android::Rect outRect{0, 0, static_cast<int32_t>(halBuf.width),
+                IMapper::Rect outRect{0, 0, static_cast<int32_t>(halBuf.width),
                                       static_cast<int32_t>(halBuf.height)};
-                android_ycbcr result = sHandleImporter.lockYCbCr(
+                YCbCrLayout outLayout = sHandleImporter.lockYCbCr(
                         *(halBuf.bufPtr), static_cast<uint64_t>(halBuf.usage), outRect);
-                ALOGV("%s: outLayout y %p cb %p cr %p y_str %zu c_str %zu c_step %zu", __FUNCTION__,
-                      result.y, result.cb, result.cr, result.ystride, result.cstride,
-                      result.chroma_step);
-                if (result.ystride > UINT32_MAX || result.cstride > UINT32_MAX ||
-                    result.chroma_step > UINT32_MAX) {
-                    return onDeviceError("%s: lockYCbCr failed. Unexpected values!", __FUNCTION__);
-                }
-                YCbCrLayout outLayout = {.y = result.y,
-                                         .cb = result.cb,
-                                         .cr = result.cr,
-                                         .yStride = static_cast<uint32_t>(result.ystride),
-                                         .cStride = static_cast<uint32_t>(result.cstride),
-                                         .chromaStep = static_cast<uint32_t>(result.chroma_step)};
+                ALOGV("%s: outLayout y %p cb %p cr %p y_str %d c_str %d c_step %d", __FUNCTION__,
+                      outLayout.y, outLayout.cb, outLayout.cr, outLayout.yStride, outLayout.cStride,
+                      outLayout.chromaStep);
 
                 // Convert to output buffer size/format
                 uint32_t outputFourcc = getFourCcFromLayout(outLayout);
@@ -554,4 +544,4 @@
 }  // namespace device
 }  // namespace camera
 }  // namespace hardware
-}  // namespace android
+}  // namespace android
\ No newline at end of file
diff --git a/camera/device/default/ExternalCameraUtils.h b/camera/device/default/ExternalCameraUtils.h
index d434905..b37933c 100644
--- a/camera/device/default/ExternalCameraUtils.h
+++ b/camera/device/default/ExternalCameraUtils.h
@@ -25,11 +25,7 @@
 #include <aidl/android/hardware/camera/device/NotifyMsg.h>
 #include <aidl/android/hardware/graphics/common/BufferUsage.h>
 #include <aidl/android/hardware/graphics/common/PixelFormat.h>
-#include <android/hardware/graphics/mapper/2.0/IMapper.h>
-#include <android/hardware/graphics/mapper/3.0/IMapper.h>
-#include <android/hardware/graphics/mapper/4.0/IMapper.h>
 #include <tinyxml2.h>
-#include <map>
 #include <unordered_map>
 #include <unordered_set>
 
@@ -41,8 +37,6 @@
 using ::aidl::android::hardware::graphics::common::PixelFormat;
 using ::android::hardware::camera::common::V1_0::helper::CameraMetadata;
 using ::android::hardware::camera::common::V1_0::helper::HandleImporter;
-using ::android::hardware::graphics::mapper::V2_0::IMapper;
-using ::android::hardware::graphics::mapper::V2_0::YCbCrLayout;
 
 namespace android {
 namespace hardware {