Merge "Setting layer brightness doesn't need nit info for readback tests" 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 3117134..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);
@@ -1277,6 +1303,12 @@
             mmapSources.insert(port.id);
         }
     }
+    if (mmapSources.empty() && mmapSinks.empty()) {
+        AudioMMapPolicyInfo never;
+        never.mmapPolicy = AudioMMapPolicy::NEVER;
+        _aidl_return->push_back(never);
+        return ndk::ScopedAStatus::ok();
+    }
     for (const auto& route : getConfig().routes) {
         if (mmapSinks.count(route.sinkPortId) != 0) {
             // The sink is a mix port, add the sources if they are device ports.
diff --git a/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp b/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp
index ccf7cfc..621d200 100644
--- a/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp
@@ -87,6 +87,7 @@
 using aidl::android::media::audio::common::AudioFormatType;
 using aidl::android::media::audio::common::AudioIoFlags;
 using aidl::android::media::audio::common::AudioLatencyMode;
+using aidl::android::media::audio::common::AudioMMapPolicy;
 using aidl::android::media::audio::common::AudioMMapPolicyInfo;
 using aidl::android::media::audio::common::AudioMMapPolicyType;
 using aidl::android::media::audio::common::AudioMode;
@@ -1237,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) {
@@ -1263,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(); }
@@ -1272,6 +1297,7 @@
     }
 
   private:
+    std::optional<AudioPatch> mInitialPatch;
     WithAudioPortConfig mSrcPortConfig;
     WithAudioPortConfig mSinkPortConfig;
     IModule* mModule = nullptr;
@@ -2133,7 +2159,13 @@
         std::vector<AudioMMapPolicyInfo> policyInfos;
         EXPECT_IS_OK(module->getMmapPolicyInfos(mmapPolicyType, &policyInfos))
                 << toString(mmapPolicyType);
-        EXPECT_EQ(isMmapSupported, !policyInfos.empty());
+        const bool isMMapSupportedByPolicyInfos =
+                std::find_if(policyInfos.begin(), policyInfos.end(), [](const auto& info) {
+                    return info.mmapPolicy == AudioMMapPolicy::AUTO ||
+                           info.mmapPolicy == AudioMMapPolicy::ALWAYS;
+                }) != policyInfos.end();
+        EXPECT_EQ(isMmapSupported, isMMapSupportedByPolicyInfos)
+                << ::android::internal::ToString(policyInfos);
     }
 }
 
@@ -3630,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()));
                 }
             }
         }
@@ -3653,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()) {
@@ -3692,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;
@@ -4172,58 +4231,32 @@
 class WithRemoteSubmix {
   public:
     WithRemoteSubmix() = default;
-    WithRemoteSubmix(AudioDeviceAddress address) : mAddress(address) {}
+    explicit WithRemoteSubmix(AudioDeviceAddress address) : mAddress(address) {}
     WithRemoteSubmix(const WithRemoteSubmix&) = delete;
     WithRemoteSubmix& operator=(const WithRemoteSubmix&) = delete;
-    std::optional<AudioPort> getAudioPort() {
+    static std::optional<AudioPort> getRemoteSubmixAudioPort(
+            ModuleConfig* moduleConfig,
+            const std::optional<AudioDeviceAddress>& address = std::nullopt) {
         AudioDeviceType deviceType = IOTraits<Stream>::is_input ? AudioDeviceType::IN_SUBMIX
                                                                 : AudioDeviceType::OUT_SUBMIX;
-        auto ports = mModuleConfig->getAudioPortsForDeviceTypes(
+        auto ports = moduleConfig->getAudioPortsForDeviceTypes(
                 std::vector<AudioDeviceType>{deviceType},
                 AudioDeviceDescription::CONNECTION_VIRTUAL);
-        if (!ports.empty()) return ports.front();
-        return {};
-    }
-    /* Connect remote submix external device */
-    void SetUpPortConnection() {
-        auto port = getAudioPort();
-        ASSERT_TRUE(port.has_value()) << "Device AudioPort for remote submix not found";
-        if (mAddress.has_value()) {
-            port.value().ext.template get<AudioPortExt::Tag::device>().device.address =
-                    mAddress.value();
+        if (ports.empty()) return {};
+        AudioPort port = ports.front();
+        if (address) {
+            port.ext.template get<AudioPortExt::Tag::device>().device.address = address.value();
         } else {
-            port = GenerateUniqueDeviceAddress(port.value());
+            port = GenerateUniqueDeviceAddress(port);
         }
-        mConnectedPort = std::make_unique<WithDevicePortConnectedState>(port.value());
-        ASSERT_NO_FATAL_FAILURE(mConnectedPort->SetUp(mModule, mModuleConfig));
+        return port;
     }
-    AudioDeviceAddress getAudioDeviceAddress() {
-        if (!mAddress.has_value()) {
-            mAddress = mConnectedPort->get()
-                               .ext.template get<AudioPortExt::Tag::device>()
-                               .device.address;
-        }
-        return mAddress.value();
-    }
-    /* Get mix port config for stream and setup patch for it. */
-    void SetupPatch() {
-        const auto portConfig =
-                mModuleConfig->getSingleConfigForMixPort(IOTraits<Stream>::is_input);
-        if (!portConfig.has_value()) {
-            LOG(DEBUG) << __func__ << ": portConfig not found";
-            mSkipTest = true;
-            return;
-        }
-        auto devicePortConfig = mModuleConfig->getSingleConfigForDevicePort(mConnectedPort->get());
-        mPatch = std::make_unique<WithAudioPatch>(IOTraits<Stream>::is_input, portConfig.value(),
-                                                  devicePortConfig);
-        ASSERT_NO_FATAL_FAILURE(mPatch->SetUp(mModule));
-    }
-    void SetUp(IModule* module, ModuleConfig* moduleConfig) {
+    std::optional<AudioDeviceAddress> getAudioDeviceAddress() const { return mAddress; }
+    void SetUp(IModule* module, ModuleConfig* moduleConfig, const AudioPort& connectedPort) {
         mModule = module;
         mModuleConfig = moduleConfig;
-        ASSERT_NO_FATAL_FAILURE(SetUpPortConnection());
-        ASSERT_NO_FATAL_FAILURE(SetupPatch());
+
+        ASSERT_NO_FATAL_FAILURE(SetupPatch(connectedPort));
         if (!mSkipTest) {
             // open stream
             mStream = std::make_unique<WithStream<Stream>>(
@@ -4231,6 +4264,11 @@
             ASSERT_NO_FATAL_FAILURE(
                     mStream->SetUp(mModule, AudioCoreModuleBase::kDefaultBufferSizeFrames));
         }
+        mAddress = connectedPort.ext.template get<AudioPortExt::Tag::device>().device.address;
+    }
+    void SetUp(IModule* module, ModuleConfig* moduleConfig) {
+        ASSERT_NO_FATAL_FAILURE(SetUpPortConnection(module, moduleConfig));
+        SetUp(module, moduleConfig, mConnectedPort->get());
     }
     void sendBurstCommands() {
         const StreamContext* context = mStream->getContext();
@@ -4248,9 +4286,31 @@
         }
         EXPECT_FALSE(driver.hasRetrogradeObservablePosition());
     }
-    bool skipTest() { return mSkipTest; }
+    bool skipTest() const { return mSkipTest; }
 
   private:
+    /* Connect remote submix external device */
+    void SetUpPortConnection(IModule* module, ModuleConfig* moduleConfig) {
+        auto port = getRemoteSubmixAudioPort(moduleConfig, mAddress);
+        ASSERT_TRUE(port.has_value()) << "Device AudioPort for remote submix not found";
+        mConnectedPort = std::make_unique<WithDevicePortConnectedState>(port.value());
+        ASSERT_NO_FATAL_FAILURE(mConnectedPort->SetUp(module, moduleConfig));
+    }
+    /* Get mix port config for stream and setup patch for it. */
+    void SetupPatch(const AudioPort& connectedPort) {
+        const auto portConfig =
+                mModuleConfig->getSingleConfigForMixPort(IOTraits<Stream>::is_input);
+        if (!portConfig.has_value()) {
+            LOG(DEBUG) << __func__ << ": portConfig not found";
+            mSkipTest = true;
+            return;
+        }
+        auto devicePortConfig = mModuleConfig->getSingleConfigForDevicePort(connectedPort);
+        mPatch = std::make_unique<WithAudioPatch>(IOTraits<Stream>::is_input, portConfig.value(),
+                                                  devicePortConfig);
+        ASSERT_NO_FATAL_FAILURE(mPatch->SetUp(mModule));
+    }
+
     bool mSkipTest = false;
     IModule* mModule = nullptr;
     ModuleConfig* mModuleConfig = nullptr;
@@ -4288,9 +4348,11 @@
     if (streamOut.skipTest()) {
         GTEST_SKIP() << "No mix port for attached devices";
     }
+    auto address = streamOut.getAudioDeviceAddress();
+    ASSERT_TRUE(address.has_value());
 
     // open input stream
-    WithRemoteSubmix<IStreamIn> streamIn(streamOut.getAudioDeviceAddress());
+    WithRemoteSubmix<IStreamIn> streamIn(address.value());
     ASSERT_NO_FATAL_FAILURE(streamIn.SetUp(module.get(), moduleConfig.get()));
     if (streamIn.skipTest()) {
         GTEST_SKIP() << "No mix port for attached devices";
@@ -4307,9 +4369,11 @@
     if (streamOut.skipTest()) {
         GTEST_SKIP() << "No mix port for attached devices";
     }
+    auto address = streamOut.getAudioDeviceAddress();
+    ASSERT_TRUE(address.has_value());
 
     // open input stream
-    WithRemoteSubmix<IStreamIn> streamIn(streamOut.getAudioDeviceAddress());
+    WithRemoteSubmix<IStreamIn> streamIn(address.value());
     ASSERT_NO_FATAL_FAILURE(streamIn.SetUp(module.get(), moduleConfig.get()));
     if (streamIn.skipTest()) {
         GTEST_SKIP() << "No mix port for attached devices";
@@ -4321,6 +4385,43 @@
     ASSERT_NO_FATAL_FAILURE(streamIn.sendBurstCommands());
 }
 
+TEST_P(AudioModuleRemoteSubmix, OpenInputMultipleTimes) {
+    // open output stream
+    WithRemoteSubmix<IStreamOut> streamOut;
+    ASSERT_NO_FATAL_FAILURE(streamOut.SetUp(module.get(), moduleConfig.get()));
+    if (streamOut.skipTest()) {
+        GTEST_SKIP() << "No mix port for attached devices";
+    }
+    auto address = streamOut.getAudioDeviceAddress();
+    ASSERT_TRUE(address.has_value());
+
+    // connect remote submix input device port
+    auto port = WithRemoteSubmix<IStreamIn>::getRemoteSubmixAudioPort(moduleConfig.get(),
+                                                                      address.value());
+    ASSERT_TRUE(port.has_value()) << "Device AudioPort for remote submix not found";
+    WithDevicePortConnectedState connectedInputPort(port.value());
+    ASSERT_NO_FATAL_FAILURE(connectedInputPort.SetUp(module.get(), moduleConfig.get()));
+
+    // open input streams
+    const int streamInCount = 3;
+    std::vector<std::unique_ptr<WithRemoteSubmix<IStreamIn>>> streamIns(streamInCount);
+    for (int i = 0; i < streamInCount; i++) {
+        streamIns[i] = std::make_unique<WithRemoteSubmix<IStreamIn>>();
+        ASSERT_NO_FATAL_FAILURE(
+                streamIns[i]->SetUp(module.get(), moduleConfig.get(), connectedInputPort.get()));
+        if (streamIns[i]->skipTest()) {
+            GTEST_SKIP() << "No mix port for attached devices";
+        }
+    }
+    // write something to output stream
+    ASSERT_NO_FATAL_FAILURE(streamOut.sendBurstCommands());
+
+    // read from input streams
+    for (int i = 0; i < streamInCount; i++) {
+        ASSERT_NO_FATAL_FAILURE(streamIns[i]->sendBurstCommands());
+    }
+}
+
 INSTANTIATE_TEST_SUITE_P(AudioModuleRemoteSubmixTest, AudioModuleRemoteSubmix,
                          ::testing::ValuesIn(getRemoteSubmixModuleInstance()));
 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioModuleRemoteSubmix);
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/sv/1.0/default/tests/fuzzer/AutomotiveSvV1_0Fuzzer.cpp b/automotive/sv/1.0/default/tests/fuzzer/AutomotiveSvV1_0Fuzzer.cpp
index 98834f5..4c4cc70 100644
--- a/automotive/sv/1.0/default/tests/fuzzer/AutomotiveSvV1_0Fuzzer.cpp
+++ b/automotive/sv/1.0/default/tests/fuzzer/AutomotiveSvV1_0Fuzzer.cpp
@@ -41,35 +41,32 @@
 
 void SurroundViewFuzzer::invoke2dSessionAPI() {
     sp<ISurroundView2dSession> surroundView2dSession;
+    sp<SurroundViewStream> handler;
+    mSurroundViewService->start2dSession(
+            [&surroundView2dSession](const sp<ISurroundView2dSession>& session, SvResult result) {
+                if (result == SvResult::OK) {
+                    surroundView2dSession = session;
+                }
+            });
+
+    if (surroundView2dSession && !mIs2dStreamStarted) {
+        handler = sp<SurroundViewStream>::make(surroundView2dSession);
+        if (surroundView2dSession->startStream(handler) == SvResult::OK) {
+            mIs2dStreamStarted = true;
+        }
+    }
 
     while (mFuzzedDataProvider.remaining_bytes() > 0) {
         auto surroundView2dFunc = mFuzzedDataProvider.PickValueInArray<
                 const std::function<void()>>({
                 [&]() {
-                    mSurroundViewService->start2dSession(
-                            [&surroundView2dSession](const sp<ISurroundView2dSession>& session,
-                                                     SvResult result) {
-                                if (result == SvResult::OK) {
-                                    surroundView2dSession = session;
-                                }
-                            });
-                },
-                [&]() {
-                    if (surroundView2dSession) {
-                        sp<SurroundViewStream> handler =
-                                sp<SurroundViewStream>::make(surroundView2dSession);
-                        surroundView2dSession->startStream(handler);
-                        mIs2dStreamStarted = true;
-                    }
-                },
-                [&]() {
                     if (surroundView2dSession) {
                         surroundView2dSession->get2dMappingInfo(
                                 []([[maybe_unused]] Sv2dMappingInfo info) {});
                     }
                 },
                 [&]() {
-                    if (surroundView2dSession) {
+                    if (surroundView2dSession && mIs2dStreamStarted) {
                         Sv2dConfig config;
                         config.width = mFuzzedDataProvider.ConsumeIntegralInRange<uint32_t>(
                                 kMinConfigDimension, kMaxConfigDimension);
@@ -149,8 +146,11 @@
                     }
                 },
                 [&]() {
-                    mSurroundViewService->stop2dSession(
+                    SvResult result = mSurroundViewService->stop2dSession(
                             mFuzzedDataProvider.ConsumeBool() ? surroundView2dSession : nullptr);
+                    if (result == SvResult::OK) {
+                        mIs2dStreamStarted = false;
+                    }
                 },
         });
         surroundView2dFunc();
@@ -159,31 +159,40 @@
     if (surroundView2dSession && mIs2dStreamStarted) {
         surroundView2dSession->stopStream();
     }
+
+    if (surroundView2dSession) {
+        mSurroundViewService->stop2dSession(surroundView2dSession);
+    }
 }
 
 void SurroundViewFuzzer::invoke3dSessionAPI() {
     sp<ISurroundView3dSession> surroundView3dSession;
+    sp<SurroundViewStream> handler;
+    mSurroundViewService->start3dSession(
+            [&surroundView3dSession](const sp<ISurroundView3dSession>& session, SvResult result) {
+                if (result == SvResult::OK) {
+                    surroundView3dSession = session;
+                }
+            });
+
+    const size_t numViews = mFuzzedDataProvider.ConsumeIntegralInRange<size_t>(1, kMaxViews);
+    std::vector<View3d> views(numViews);
+    for (size_t i = 0; i < numViews; ++i) {
+        views[i].viewId = mFuzzedDataProvider.ConsumeIntegral<uint32_t>();
+    }
+    surroundView3dSession->setViews(views);
+
+    if (surroundView3dSession) {
+        handler = sp<SurroundViewStream>::make(surroundView3dSession);
+
+        if (surroundView3dSession->startStream(handler) == SvResult::OK) {
+            mIs3dStreamStarted = true;
+        }
+    }
     while (mFuzzedDataProvider.remaining_bytes() > 0) {
         auto surroundView3dFunc = mFuzzedDataProvider.PickValueInArray<
                 const std::function<void()>>({
                 [&]() {
-                    mSurroundViewService->start3dSession(
-                            [&surroundView3dSession](const sp<ISurroundView3dSession>& session,
-                                                     SvResult result) {
-                                if (result == SvResult::OK) {
-                                    surroundView3dSession = session;
-                                }
-                            });
-                },
-                [&]() {
-                    if (surroundView3dSession) {
-                        sp<SurroundViewStream> handler =
-                                sp<SurroundViewStream>::make(surroundView3dSession);
-                        surroundView3dSession->startStream(handler);
-                        mIs3dStreamStarted = true;
-                    }
-                },
-                [&]() {
                     if (surroundView3dSession) {
                         const size_t numViews =
                                 mFuzzedDataProvider.ConsumeIntegralInRange<size_t>(1, kMaxViews);
@@ -195,7 +204,7 @@
                     }
                 },
                 [&]() {
-                    if (surroundView3dSession) {
+                    if (surroundView3dSession && mIs3dStreamStarted) {
                         Sv3dConfig config;
                         config.width = mFuzzedDataProvider.ConsumeIntegralInRange<uint32_t>(
                                 kMinConfigDimension, kMaxConfigDimension);
@@ -306,8 +315,11 @@
                     }
                 },
                 [&]() {
-                    mSurroundViewService->stop3dSession(
+                    SvResult result = mSurroundViewService->stop3dSession(
                             mFuzzedDataProvider.ConsumeBool() ? surroundView3dSession : nullptr);
+                    if (result == SvResult::OK) {
+                        mIs3dStreamStarted = false;
+                    }
                 },
         });
         surroundView3dFunc();
@@ -315,6 +327,10 @@
     if (surroundView3dSession && mIs3dStreamStarted) {
         surroundView3dSession->stopStream();
     }
+
+    if (surroundView3dSession) {
+        mSurroundViewService->stop3dSession(surroundView3dSession);
+    }
 }
 
 void SurroundViewFuzzer::process() {
diff --git a/automotive/vehicle/OWNERS b/automotive/vehicle/OWNERS
index 429ec39..d6969e5 100644
--- a/automotive/vehicle/OWNERS
+++ b/automotive/vehicle/OWNERS
@@ -1,3 +1,2 @@
 ericjeong@google.com
-keunyoung@google.com
 shanyu@google.com
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/proto/Android.bp b/automotive/vehicle/proto/Android.bp
index 7b98540..e7dabcf 100644
--- a/automotive/vehicle/proto/Android.bp
+++ b/automotive/vehicle/proto/Android.bp
@@ -27,7 +27,7 @@
     visibility: [
         "//hardware/interfaces/automotive/vehicle:__subpackages__",
         "//device/generic/car/emulator:__subpackages__",
-        "//device/google/sdv/sdv_ivi_cf:__subpackages__",
+        "//system/software_defined_vehicle/core_services:__subpackages__",
     ],
     vendor: true,
     host_supported: true,
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/biometrics/common/util/include/util/Util.h b/biometrics/common/util/include/util/Util.h
index da19dc6..efd66bc 100644
--- a/biometrics/common/util/include/util/Util.h
+++ b/biometrics/common/util/include/util/Util.h
@@ -23,6 +23,9 @@
 #include <thread>
 #include <vector>
 
+#include <android-base/parseint.h>
+using ::android::base::ParseInt;
+
 namespace aidl::android::hardware::biometrics {
 
 #define SLEEP_MS(x) \
@@ -64,6 +67,87 @@
                 std::sregex_token_iterator());
         return parts;
     }
+
+    // Returns a vector of integers for the string separated by comma,
+    // Empty vector is returned if there is any parsing error
+    static std::vector<int32_t> parseIntSequence(const std::string& str,
+                                                 const std::string& sep = ",") {
+        std::vector<std::string> seqs = Util::split(str, sep);
+        std::vector<int32_t> res;
+
+        for (const auto& seq : seqs) {
+            int32_t val;
+            if (ParseInt(seq, &val)) {
+                res.push_back(val);
+            } else {
+                LOG(WARNING) << "Invalid int sequence:" + str + " seq:" + seq;
+                res.clear();
+                break;
+            }
+        }
+
+        return res;
+    }
+
+    // Parses a single enrollment stage string in the format of
+    //     enroll_stage_spec: <duration>[-acquiredInfos]
+    //                                      duration: integerInMs
+    //                                      acquiredInfos: [info1,info2,...]
+    //
+    // Returns false if there is parsing error
+    //
+    static bool parseEnrollmentCaptureSingle(const std::string& str,
+                                             std::vector<std::vector<int32_t>>& res) {
+        std::vector<int32_t> defaultAcquiredInfo = {1};
+        bool aborted = true;
+
+        do {
+            std::smatch sms;
+            // Parses strings like "1000-[5,1]" or "500"
+            std::regex ex("((\\d+)(-\\[([\\d|,]+)\\])?)");
+            if (!regex_match(str.cbegin(), str.cend(), sms, ex)) break;
+            int32_t duration;
+            if (!ParseInt(sms.str(2), &duration)) break;
+            res.push_back({duration});
+            if (!sms.str(4).empty()) {
+                auto acqv = parseIntSequence(sms.str(4));
+                if (acqv.empty()) break;
+                res.push_back(acqv);
+            } else
+                res.push_back(defaultAcquiredInfo);
+            aborted = false;
+        } while (0);
+
+        return !aborted;
+    }
+
+    // Parses enrollment string consisting of one or more stages in the formst of
+    //  <enroll_stage_spec>[,enroll_stage_spec,...]
+    // Empty vector is returned in case of parsing error
+    static std::vector<std::vector<int32_t>> parseEnrollmentCapture(const std::string& str) {
+        std::vector<std::vector<int32_t>> res;
+
+        std::string s(str);
+        s.erase(std::remove_if(s.begin(), s.end(), ::isspace), s.end());
+        bool aborted = false;
+        std::smatch sms;
+        // Parses strings like "1000-[5,1],500,800-[6,5,1]"
+        //                               -------------- ----- ---------------
+        //  into parts:                       A       B       C
+        while (regex_search(s, sms, std::regex("^(,)?(\\d+(-\\[[\\d|,]+\\])?)"))) {
+            if (!parseEnrollmentCaptureSingle(sms.str(2), res)) {
+                aborted = true;
+                break;
+            }
+            s = sms.suffix();
+        }
+        if (aborted || s.length() != 0) {
+            res.clear();
+            LOG(ERROR) << "Failed to parse enrollment captures:" + str;
+        }
+
+        return res;
+    }
 };
 
 }  // namespace aidl::android::hardware::biometrics
diff --git a/biometrics/face/aidl/default/FakeFaceEngine.cpp b/biometrics/face/aidl/default/FakeFaceEngine.cpp
index 0f088f4..578231d 100644
--- a/biometrics/face/aidl/default/FakeFaceEngine.cpp
+++ b/biometrics/face/aidl/default/FakeFaceEngine.cpp
@@ -136,56 +136,127 @@
                                       const std::future<void>& cancel) {
     BEGIN_OP(FaceHalProperties::operation_authenticate_latency().value_or(0));
 
-    // Signal to the framework that we have begun authenticating.
-    AuthenticationFrame frame;
-    frame.data.acquiredInfo = AcquiredInfo::START;
-    frame.data.vendorCode = 0;
-    cb->onAuthenticationFrame(frame);
-
-    // Also signal that we have opened the camera.
-    frame = {};
-    frame.data.acquiredInfo = AcquiredInfo::FIRST_FRAME_RECEIVED;
-    frame.data.vendorCode = 0;
-    cb->onAuthenticationFrame(frame);
-
-    auto now = Util::getSystemNanoTime();
-    int64_t duration = FaceHalProperties::operation_authenticate_duration().value_or(0);
-    if (duration > 0) {
-        do {
-            SLEEP_MS(5);
-        } while (!Util::hasElapsed(now, duration));
-    }
-
-    if (FaceHalProperties::operation_authenticate_fails().value_or(false)) {
-        LOG(ERROR) << "Fail: operation_authenticate_fails";
-        cb->onError(Error::VENDOR, 0 /* vendorError */);
-        return;
-    }
-
-    if (FaceHalProperties::lockout().value_or(false)) {
-        LOG(ERROR) << "Fail: lockout";
-        cb->onLockoutPermanent();
-        cb->onError(Error::HW_UNAVAILABLE, 0 /* vendorError */);
-        return;
-    }
-
-    if (shouldCancel(cancel)) {
-        LOG(ERROR) << "Fail: cancel";
-        cb->onError(Error::CANCELED, 0 /* vendorCode */);
-        return;
-    }
-
     auto id = FaceHalProperties::enrollment_hit().value_or(0);
     auto enrolls = FaceHalProperties::enrollments();
     auto isEnrolled = std::find(enrolls.begin(), enrolls.end(), id) != enrolls.end();
-    if (id < 0 || !isEnrolled) {
-        LOG(ERROR) << (isEnrolled ? "invalid enrollment hit" : "Fail: not enrolled");
-        cb->onAuthenticationFailed();
+
+    auto vec2str = [](std::vector<AcquiredInfo> va) {
+        std::stringstream ss;
+        bool isFirst = true;
+        for (auto ac : va) {
+            if (!isFirst) ss << ",";
+            ss << std::to_string((int8_t)ac);
+            isFirst = false;
+        }
+        return ss.str();
+    };
+
+    // default behavior mimic face sensor in U
+    int64_t defaultAuthDuration = 500;
+    std::string defaultAcquiredInfo =
+            vec2str({AcquiredInfo::START, AcquiredInfo::FIRST_FRAME_RECEIVED});
+    if (!isEnrolled) {
+        std::vector<AcquiredInfo> v;
+        for (int i = 0; i < 56; i++) v.push_back(AcquiredInfo::NOT_DETECTED);
+        defaultAcquiredInfo += "," + vec2str(v);
+        defaultAuthDuration = 2100;
+    } else {
+        defaultAcquiredInfo += "," + vec2str({AcquiredInfo::TOO_BRIGHT, AcquiredInfo::TOO_BRIGHT,
+                                              AcquiredInfo::TOO_BRIGHT, AcquiredInfo::TOO_BRIGHT,
+                                              AcquiredInfo::GOOD, AcquiredInfo::GOOD});
+    }
+
+    int64_t now = Util::getSystemNanoTime();
+    int64_t duration =
+            FaceHalProperties::operation_authenticate_duration().value_or(defaultAuthDuration);
+    auto acquired =
+            FaceHalProperties::operation_authenticate_acquired().value_or(defaultAcquiredInfo);
+    auto acquiredInfos = Util::parseIntSequence(acquired);
+    int N = acquiredInfos.size();
+
+    if (N == 0) {
+        LOG(ERROR) << "Fail to parse authentiate acquired info: " + acquired;
         cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorError */);
         return;
     }
 
-    cb->onAuthenticationSucceeded(id, {} /* hat */);
+    int i = 0;
+    do {
+        if (FaceHalProperties::lockout().value_or(false)) {
+            LOG(ERROR) << "Fail: lockout";
+            cb->onLockoutPermanent();
+            cb->onError(Error::HW_UNAVAILABLE, 0 /* vendorError */);
+            return;
+        }
+
+        if (FaceHalProperties::operation_authenticate_fails().value_or(false)) {
+            LOG(ERROR) << "Fail: operation_authenticate_fails";
+            cb->onAuthenticationFailed();
+            return;
+        }
+
+        auto err = FaceHalProperties::operation_authenticate_error().value_or(0);
+        if (err != 0) {
+            LOG(ERROR) << "Fail: operation_authenticate_error";
+            auto ec = convertError(err);
+            cb->onError(ec.first, ec.second);
+            return; /* simply terminating current operation for any user inserted error,
+                            revisit if tests need*/
+        }
+
+        if (shouldCancel(cancel)) {
+            LOG(ERROR) << "Fail: cancel";
+            cb->onError(Error::CANCELED, 0 /* vendorCode */);
+            return;
+        }
+
+        if (i < N) {
+            auto ac = convertAcquiredInfo(acquiredInfos[i]);
+            AuthenticationFrame frame;
+            frame.data.acquiredInfo = ac.first;
+            frame.data.vendorCode = ac.second;
+            cb->onAuthenticationFrame(frame);
+            LOG(INFO) << "AcquiredInfo:" << i << ": (" << (int)ac.first << "," << (int)ac.second
+                      << ")";
+            i++;
+        }
+
+        SLEEP_MS(duration / N);
+    } while (!Util::hasElapsed(now, duration));
+
+    if (id > 0 && isEnrolled) {
+        cb->onAuthenticationSucceeded(id, {} /* hat */);
+        return;
+    } else {
+        LOG(ERROR) << "Fail: face not enrolled";
+        cb->onAuthenticationFailed();
+        cb->onError(Error::TIMEOUT, 0 /* vendorError*/);
+        return;
+    }
+}
+
+std::pair<AcquiredInfo, int32_t> FakeFaceEngine::convertAcquiredInfo(int32_t code) {
+    std::pair<AcquiredInfo, int32_t> res;
+    if (code > FACE_ACQUIRED_VENDOR_BASE) {
+        res.first = AcquiredInfo::VENDOR;
+        res.second = code - FACE_ACQUIRED_VENDOR_BASE;
+    } else {
+        res.first = (AcquiredInfo)code;
+        res.second = 0;
+    }
+    return res;
+}
+
+std::pair<Error, int32_t> FakeFaceEngine::convertError(int32_t code) {
+    std::pair<Error, int32_t> res;
+    if (code > FACE_ERROR_VENDOR_BASE) {
+        res.first = Error::VENDOR;
+        res.second = code - FACE_ERROR_VENDOR_BASE;
+    } else {
+        res.first = (Error)code;
+        res.second = 0;
+    }
+    return res;
 }
 
 void FakeFaceEngine::detectInteractionImpl(ISessionCallback* cb, const std::future<void>& cancel) {
@@ -315,4 +386,4 @@
     cb->onLockoutCleared();
 }
 
-}  // namespace aidl::android::hardware::biometrics::face
\ No newline at end of file
+}  // namespace aidl::android::hardware::biometrics::face
diff --git a/biometrics/face/aidl/default/FakeFaceEngine.h b/biometrics/face/aidl/default/FakeFaceEngine.h
index eb99441..06dd396 100644
--- a/biometrics/face/aidl/default/FakeFaceEngine.h
+++ b/biometrics/face/aidl/default/FakeFaceEngine.h
@@ -62,6 +62,12 @@
     void resetLockoutImpl(ISessionCallback* cb, const keymaster::HardwareAuthToken& /*hat*/);
 
     std::mt19937 mRandom;
+
+  private:
+    static constexpr int32_t FACE_ACQUIRED_VENDOR_BASE = 1000;
+    static constexpr int32_t FACE_ERROR_VENDOR_BASE = 1000;
+    std::pair<AcquiredInfo, int32_t> convertAcquiredInfo(int32_t code);
+    std::pair<Error, int32_t> convertError(int32_t code);
 };
 
 }  // namespace aidl::android::hardware::biometrics::face
diff --git a/biometrics/face/aidl/default/README.md b/biometrics/face/aidl/default/README.md
index 77bfe57..516a7aa 100644
--- a/biometrics/face/aidl/default/README.md
+++ b/biometrics/face/aidl/default/README.md
@@ -18,6 +18,7 @@
 Face VHAL enabling is gated by the following two AND conditions:
 1. The Face VHAL feature flag (as part of Trunk-development strategy) must be tured until the flags life-cycle ends.
 2. The Face VHAL must be enabled via sysprop
+See adb commands below
 
 ##Getting Stared
 
@@ -47,8 +48,7 @@
 $ adb shell setprop vendor.face.virtual.operation_authenticate_duration 800
 $ adb shell setprop vendor.face.virtual.enrollment_hit 1
 ```
-Note: At the initial phase of the Face VHAL development, Face-on-camera simulation is not supported, hence
-the authentication immediately occurrs  as soon as the authentication request arriving at VHAL.
+Refer to face.sysprop for full supported features of authentication, such as error and acquiredInfo insertion
 
 
 ## Enrollment via Setup
diff --git a/biometrics/face/aidl/default/face.sysprop b/biometrics/face/aidl/default/face.sysprop
index 6b0f37f..be32015 100644
--- a/biometrics/face/aidl/default/face.sysprop
+++ b/biometrics/face/aidl/default/face.sysprop
@@ -157,3 +157,22 @@
     access: ReadWrite
     api_name: "operation_authenticate_duration"
 }
+
+# insert error for authenticate operations
+prop {
+    prop_name: "vendor.face.virtual.operation_authenticate_error"
+    type: Integer
+    scope: Internal
+    access: ReadWrite
+    api_name: "operation_authenticate_error"
+}
+
+# acquired info during authentication in format of sequence
+prop {
+    prop_name: "vendor.face.virtual.operation_authenticate_acquired"
+    type: String
+    scope: Internal
+    access: ReadWrite
+    api_name: "operation_authenticate_acquired"
+}
+
diff --git a/biometrics/face/aidl/default/tests/FakeFaceEngineTest.cpp b/biometrics/face/aidl/default/tests/FakeFaceEngineTest.cpp
index c8ad6b7..6897dc4 100644
--- a/biometrics/face/aidl/default/tests/FakeFaceEngineTest.cpp
+++ b/biometrics/face/aidl/default/tests/FakeFaceEngineTest.cpp
@@ -245,7 +245,7 @@
     FaceHalProperties::enrollments({3});
     FaceHalProperties::enrollment_hit(100);
     mEngine.authenticateImpl(mCallback.get(), 0 /* operationId*/, mCancel.get_future());
-    ASSERT_EQ(Error::UNABLE_TO_PROCESS, mCallback->mError);
+    ASSERT_EQ(Error::TIMEOUT, mCallback->mError);
     ASSERT_TRUE(mCallback->mAuthenticateFailed);
 }
 
@@ -380,4 +380,4 @@
     ASSERT_FALSE(mCallback->mAuthenticateFailed);
 }
 
-}  // namespace aidl::android::hardware::biometrics::face
\ No newline at end of file
+}  // namespace aidl::android::hardware::biometrics::face
diff --git a/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp b/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp
index 54076c8..574570e 100644
--- a/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp
+++ b/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp
@@ -142,7 +142,7 @@
         return true;
     }
     auto enrollmentId = std::stoi(parts[0]);
-    auto progress = parseEnrollmentCapture(parts[1]);
+    auto progress = Util::parseEnrollmentCapture(parts[1]);
     for (size_t i = 0; i < progress.size(); i += 2) {
         auto left = (progress.size() - i) / 2 - 1;
         auto duration = progress[i][0];
@@ -193,7 +193,7 @@
     int64_t now = Util::getSystemNanoTime();
     int64_t duration = FingerprintHalProperties::operation_authenticate_duration().value_or(10);
     auto acquired = FingerprintHalProperties::operation_authenticate_acquired().value_or("1");
-    auto acquiredInfos = parseIntSequence(acquired);
+    auto acquiredInfos = Util::parseIntSequence(acquired);
     int N = acquiredInfos.size();
 
     if (N == 0) {
@@ -271,7 +271,7 @@
             FingerprintHalProperties::operation_detect_interaction_duration().value_or(10);
 
     auto acquired = FingerprintHalProperties::operation_detect_interaction_acquired().value_or("1");
-    auto acquiredInfos = parseIntSequence(acquired);
+    auto acquiredInfos = Util::parseIntSequence(acquired);
     int N = acquiredInfos.size();
     int64_t now = Util::getSystemNanoTime();
 
@@ -450,76 +450,6 @@
     return SensorLocation();
 }
 
-std::vector<int32_t> FakeFingerprintEngine::parseIntSequence(const std::string& str,
-                                                             const std::string& sep) {
-    std::vector<std::string> seqs = Util::split(str, sep);
-    std::vector<int32_t> res;
-
-    for (const auto& seq : seqs) {
-        int32_t val;
-        if (ParseInt(seq, &val)) {
-            res.push_back(val);
-        } else {
-            LOG(WARNING) << "Invalid int sequence:" + str;
-            res.clear();
-            break;
-        }
-    }
-
-    return res;
-}
-
-bool FakeFingerprintEngine::parseEnrollmentCaptureSingle(const std::string& str,
-                                                         std::vector<std::vector<int32_t>>& res) {
-    std::vector<int32_t> defaultAcquiredInfo = {(int32_t)AcquiredInfo::GOOD};
-    bool aborted = true;
-
-    do {
-        std::smatch sms;
-        // Parses strings like "1000-[5,1]" or "500"
-        std::regex ex("((\\d+)(-\\[([\\d|,]+)\\])?)");
-        if (!regex_match(str.cbegin(), str.cend(), sms, ex)) break;
-        int32_t duration;
-        if (!ParseInt(sms.str(2), &duration)) break;
-        res.push_back({duration});
-        if (!sms.str(4).empty()) {
-            auto acqv = parseIntSequence(sms.str(4));
-            if (acqv.empty()) break;
-            res.push_back(acqv);
-        } else
-            res.push_back(defaultAcquiredInfo);
-        aborted = false;
-    } while (0);
-
-    return !aborted;
-}
-
-std::vector<std::vector<int32_t>> FakeFingerprintEngine::parseEnrollmentCapture(
-        const std::string& str) {
-    std::vector<std::vector<int32_t>> res;
-
-    std::string s(str);
-    s.erase(std::remove_if(s.begin(), s.end(), ::isspace), s.end());
-    bool aborted = false;
-    std::smatch sms;
-    // Parses strings like "1000-[5,1],500,800-[6,5,1]"
-    //                      ---------- --- -----------
-    //  into parts:             A       B       C
-    while (regex_search(s, sms, std::regex("^(,)?(\\d+(-\\[[\\d|,]+\\])?)"))) {
-        if (!parseEnrollmentCaptureSingle(sms.str(2), res)) {
-            aborted = true;
-            break;
-        }
-        s = sms.suffix();
-    }
-    if (aborted || s.length() != 0) {
-        res.clear();
-        LOG(ERROR) << "Failed to parse enrollment captures:" + str;
-    }
-
-    return res;
-}
-
 std::pair<AcquiredInfo, int32_t> FakeFingerprintEngine::convertAcquiredInfo(int32_t code) {
     std::pair<AcquiredInfo, int32_t> res;
     if (code > FINGERPRINT_ACQUIRED_VENDOR_BASE) {
diff --git a/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h b/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h
index 2450115..15d8360 100644
--- a/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h
+++ b/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h
@@ -68,10 +68,6 @@
 
     virtual void fingerDownAction();
 
-    std::vector<int32_t> parseIntSequence(const std::string& str, const std::string& sep = ",");
-
-    std::vector<std::vector<int32_t>> parseEnrollmentCapture(const std::string& str);
-
     int32_t getLatency(const std::vector<std::optional<std::int32_t>>& latencyVec);
 
     std::mt19937 mRandom;
@@ -110,8 +106,6 @@
     static constexpr int32_t FINGERPRINT_ERROR_VENDOR_BASE = 1000;
     std::pair<AcquiredInfo, int32_t> convertAcquiredInfo(int32_t code);
     std::pair<Error, int32_t> convertError(int32_t code);
-    bool parseEnrollmentCaptureSingle(const std::string& str,
-                                      std::vector<std::vector<int32_t>>& res);
     int32_t getRandomInRange(int32_t bound1, int32_t bound2);
     bool checkSensorLockout(ISessionCallback*);
     void clearLockout(ISessionCallback* cb);
diff --git a/biometrics/fingerprint/aidl/default/tests/FakeFingerprintEngineTest.cpp b/biometrics/fingerprint/aidl/default/tests/FakeFingerprintEngineTest.cpp
index fe405f4..45b5be8 100644
--- a/biometrics/fingerprint/aidl/default/tests/FakeFingerprintEngineTest.cpp
+++ b/biometrics/fingerprint/aidl/default/tests/FakeFingerprintEngineTest.cpp
@@ -421,29 +421,29 @@
 
 TEST_F(FakeFingerprintEngineTest, parseIntSequence) {
     std::vector<int32_t> seqV;
-    seqV = mEngine.parseIntSequence("");
+    seqV = Util::parseIntSequence("");
     ASSERT_EQ(0, seqV.size());
-    seqV = mEngine.parseIntSequence("2");
+    seqV = Util::parseIntSequence("2");
     ASSERT_EQ(1, seqV.size());
     ASSERT_EQ(2, seqV[0]);
-    seqV = mEngine.parseIntSequence("2,3,4");
+    seqV = Util::parseIntSequence("2,3,4");
     std::vector<int32_t> expV{2, 3, 4};
     ASSERT_EQ(expV, seqV);
-    seqV = mEngine.parseIntSequence("2,3,a");
+    seqV = Util::parseIntSequence("2,3,a");
     ASSERT_EQ(0, seqV.size());
-    seqV = mEngine.parseIntSequence("2, 3, 4");
+    seqV = Util::parseIntSequence("2, 3, 4");
     ASSERT_EQ(expV, seqV);
-    seqV = mEngine.parseIntSequence("123,456");
+    seqV = Util::parseIntSequence("123,456");
     ASSERT_EQ(2, seqV.size());
     std::vector<int32_t> expV1{123, 456};
     ASSERT_EQ(expV1, seqV);
-    seqV = mEngine.parseIntSequence("12f3,456");
+    seqV = Util::parseIntSequence("12f3,456");
     ASSERT_EQ(0, seqV.size());
 }
 
 TEST_F(FakeFingerprintEngineTest, parseEnrollmentCaptureOk) {
     std::vector<std::vector<int32_t>> ecV;
-    ecV = mEngine.parseEnrollmentCapture("100,200,300");
+    ecV = Util::parseEnrollmentCapture("100,200,300");
     ASSERT_EQ(6, ecV.size());
     std::vector<std::vector<int32_t>> expE{{100}, {200}, {300}};
     std::vector<int32_t> defC{1};
@@ -451,26 +451,26 @@
         ASSERT_EQ(expE[i / 2], ecV[i]);
         ASSERT_EQ(defC, ecV[i + 1]);
     }
-    ecV = mEngine.parseEnrollmentCapture("100");
+    ecV = Util::parseEnrollmentCapture("100");
     ASSERT_EQ(2, ecV.size());
     ASSERT_EQ(expE[0], ecV[0]);
     ASSERT_EQ(defC, ecV[1]);
 
-    ecV = mEngine.parseEnrollmentCapture("100-[5,6,7]");
+    ecV = Util::parseEnrollmentCapture("100-[5,6,7]");
     std::vector<int32_t> expC{5, 6, 7};
     ASSERT_EQ(2, ecV.size());
     for (int i = 0; i < ecV.size(); i += 2) {
         ASSERT_EQ(expE[i / 2], ecV[i]);
         ASSERT_EQ(expC, ecV[i + 1]);
     }
-    ecV = mEngine.parseEnrollmentCapture("100-[5,6,7], 200, 300-[9,10]");
+    ecV = Util::parseEnrollmentCapture("100-[5,6,7], 200, 300-[9,10]");
     std::vector<std::vector<int32_t>> expC1{{5, 6, 7}, {1}, {9, 10}};
     ASSERT_EQ(6, ecV.size());
     for (int i = 0; i < ecV.size(); i += 2) {
         ASSERT_EQ(expE[i / 2], ecV[i]);
         ASSERT_EQ(expC1[i / 2], ecV[i + 1]);
     }
-    ecV = mEngine.parseEnrollmentCapture("100-[5,6,7], 200-[2,1], 300-[9]");
+    ecV = Util::parseEnrollmentCapture("100-[5,6,7], 200-[2,1], 300-[9]");
     std::vector<std::vector<int32_t>> expC2{{5, 6, 7}, {2, 1}, {9}};
     ASSERT_EQ(ecV.size(), 6);
     for (int i = 0; i < ecV.size(); i += 2) {
@@ -484,7 +484,7 @@
                                     "100,2x0,300", "200-[f]", "a,b"};
     std::vector<std::vector<int32_t>> ecV;
     for (const auto& s : badStr) {
-        ecV = mEngine.parseEnrollmentCapture(s);
+        ecV = Util::parseEnrollmentCapture(s);
         ASSERT_EQ(ecV.size(), 0);
     }
 }
@@ -508,7 +508,7 @@
 TEST_F(FakeFingerprintEngineTest, lockoutTimer) {
     mEngine.startLockoutTimer(200, mCallback.get());
     ASSERT_TRUE(mEngine.getLockoutTimerStarted());
-    std::this_thread::sleep_for(std::chrono::milliseconds(210));
+    std::this_thread::sleep_for(std::chrono::milliseconds(230));
     ASSERT_FALSE(mEngine.getLockoutTimerStarted());
     ASSERT_TRUE(mCallback->mLockoutCleared);
 }
diff --git a/boot/1.1/default/Android.bp b/boot/1.1/default/Android.bp
index e7a8d6e..0b0a5b7 100644
--- a/boot/1.1/default/Android.bp
+++ b/boot/1.1/default/Android.bp
@@ -20,7 +20,6 @@
     srcs: ["BootControl.cpp"],
 
     shared_libs: [
-        "libbase",
         "liblog",
         "libhidlbase",
         "libhardware",
diff --git a/boot/1.1/default/boot_control/Android.bp b/boot/1.1/default/boot_control/Android.bp
index d0dcb59..6aa30c2 100644
--- a/boot/1.1/default/boot_control/Android.bp
+++ b/boot/1.1/default/boot_control/Android.bp
@@ -35,13 +35,14 @@
     ],
 
     shared_libs: [
+        "android.hardware.boot@1.1",
+        "libbase",
         "liblog",
     ],
     static_libs: [
         "libbootloader_message",
         "libfstab",
     ],
-
 }
 
 cc_library_static {
@@ -51,13 +52,7 @@
     recovery_available: true,
     vendor_available: true,
 
-    srcs: [
-        "libboot_control.cpp",
-    ],
-    static_libs: [
-        "android.hardware.boot@1.1",
-        "libbase",
-    ],
+    srcs: ["libboot_control.cpp"],
 }
 
 cc_library_shared {
@@ -72,8 +67,6 @@
         "libboot_control",
     ],
     shared_libs: [
-        "android.hardware.boot@1.1",
-        "libbase",
         "libhardware",
     ],
 }
diff --git a/boot/1.2/default/Android.bp b/boot/1.2/default/Android.bp
index f1e9c34..4e1c35e 100644
--- a/boot/1.2/default/Android.bp
+++ b/boot/1.2/default/Android.bp
@@ -20,7 +20,6 @@
     srcs: ["BootControl.cpp"],
 
     shared_libs: [
-        "libbase",
         "liblog",
         "libhidlbase",
         "libhardware",
diff --git a/boot/aidl/default/Android.bp b/boot/aidl/default/Android.bp
index c1d3c57..dcb40db 100644
--- a/boot/aidl/default/Android.bp
+++ b/boot/aidl/default/Android.bp
@@ -27,77 +27,29 @@
     name: "android.hardware.boot-service_common",
     relative_install_path: "hw",
     defaults: ["libboot_control_defaults"],
-    srcs: [
-        "main.cpp",
-        "BootControl.cpp",
+    vintf_fragments: ["android.hardware.boot-service.default.xml"],
+    shared_libs: [
+        "libbase",
+        "libbinder_ndk",
+        "android.hardware.boot@1.1",
+        "android.hardware.boot-V1-ndk",
     ],
+    static_libs: [
+        "libboot_control",
+    ],
+    srcs: ["main.cpp", "BootControl.cpp"],
 }
 
 cc_binary {
     name: "android.hardware.boot-service.default",
     defaults: ["android.hardware.boot-service_common"],
+    init_rc: ["android.hardware.boot-service.default.rc"],
     vendor: true,
-
-    stl: "c++_static",
-    shared_libs: [
-        "libbinder_ndk",
-        "liblog",
-    ],
-    static_libs: [
-        "android.hardware.boot@1.1",
-        "android.hardware.boot-V1-ndk",
-        "libbase",
-        "libboot_control",
-    ],
-
-    installable: false, // installed in APEX
 }
 
 cc_binary {
     name: "android.hardware.boot-service.default_recovery",
     defaults: ["android.hardware.boot-service_common"],
     init_rc: ["android.hardware.boot-service.default_recovery.rc"],
-    vintf_fragments: ["android.hardware.boot-service.default.xml"],
     recovery: true,
-
-    shared_libs: [
-        "libbase",
-        "libbinder_ndk",
-        "android.hardware.boot@1.1",
-        "android.hardware.boot-V1-ndk",
-    ],
-    static_libs: [
-        "libboot_control",
-    ],
-}
-
-prebuilt_etc {
-    name: "android.hardware.boot-service.default.rc",
-    src: "android.hardware.boot-service.default.rc",
-    installable: false,
-}
-
-prebuilt_etc {
-    name: "android.hardware.boot-service.default.xml",
-    src: "android.hardware.boot-service.default.xml",
-    sub_dir: "vintf",
-    installable: false,
-}
-
-apex {
-    name: "com.android.hardware.boot",
-    vendor: true,
-    manifest: "apex_manifest.json",
-    file_contexts: "apex_file_contexts",
-    key: "com.android.hardware.key",
-    certificate: ":com.android.hardware.certificate",
-    updatable: false,
-
-    binaries: [
-        "android.hardware.boot-service.default",
-    ],
-    prebuilts: [
-        "android.hardware.boot-service.default.rc",
-        "android.hardware.boot-service.default.xml",
-    ],
 }
diff --git a/boot/aidl/default/android.hardware.boot-service.default.rc b/boot/aidl/default/android.hardware.boot-service.default.rc
index 5090e2c..589f803 100644
--- a/boot/aidl/default/android.hardware.boot-service.default.rc
+++ b/boot/aidl/default/android.hardware.boot-service.default.rc
@@ -1,4 +1,4 @@
-service vendor.boot-default /apex/com.android.hardware.boot/bin/hw/android.hardware.boot-service.default
+service vendor.boot-default /vendor/bin/hw/android.hardware.boot-service.default
     class early_hal
     user root
     group root
diff --git a/boot/aidl/default/apex_file_contexts b/boot/aidl/default/apex_file_contexts
deleted file mode 100644
index bf03585..0000000
--- a/boot/aidl/default/apex_file_contexts
+++ /dev/null
@@ -1,3 +0,0 @@
-(/.*)?                                                          u:object_r:vendor_file:s0
-/etc(/.*)?                                                      u:object_r:vendor_configs_file:s0
-/bin/hw/android\.hardware\.boot-service\.default                u:object_r:hal_bootctl_default_exec:s0
diff --git a/boot/aidl/default/apex_manifest.json b/boot/aidl/default/apex_manifest.json
deleted file mode 100644
index 92661c9..0000000
--- a/boot/aidl/default/apex_manifest.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
-    "name": "com.android.hardware.boot",
-    "version": 1,
-    "vendorBootstrap": true
-}
\ No newline at end of file
diff --git a/camera/provider/2.4/default/ExternalCameraProviderImpl_2_4.cpp b/camera/provider/2.4/default/ExternalCameraProviderImpl_2_4.cpp
index 04db7f3..2d919cc 100644
--- a/camera/provider/2.4/default/ExternalCameraProviderImpl_2_4.cpp
+++ b/camera/provider/2.4/default/ExternalCameraProviderImpl_2_4.cpp
@@ -95,13 +95,14 @@
 
 Return<Status> ExternalCameraProviderImpl_2_4::setCallback(
         const sp<ICameraProviderCallback>& callback) {
+    if (callback == nullptr) {
+        return Status::ILLEGAL_ARGUMENT;
+    }
+
     {
         Mutex::Autolock _l(mLock);
         mCallbacks = callback;
     }
-    if (mCallbacks == nullptr) {
-        return Status::OK;
-    }
     // Send a callback for all devices to initialize
     {
         for (const auto& pair : mCameraStatusMap) {
diff --git a/camera/provider/2.4/default/LegacyCameraProviderImpl_2_4.cpp b/camera/provider/2.4/default/LegacyCameraProviderImpl_2_4.cpp
index 69318c7..07ed689 100644
--- a/camera/provider/2.4/default/LegacyCameraProviderImpl_2_4.cpp
+++ b/camera/provider/2.4/default/LegacyCameraProviderImpl_2_4.cpp
@@ -448,11 +448,11 @@
 // Methods from ::android::hardware::camera::provider::V2_4::ICameraProvider follow.
 Return<Status> LegacyCameraProviderImpl_2_4::setCallback(
         const sp<ICameraProviderCallback>& callback) {
+    if (callback == nullptr) {
+        return Status::ILLEGAL_ARGUMENT;
+    }
     Mutex::Autolock _l(mCbLock);
     mCallbacks = callback;
-    if (mCallbacks == nullptr) {
-        return Status::OK;
-    }
     // Add and report all presenting external cameras.
     for (auto const& statusPair : mCameraStatusMap) {
         int id = std::stoi(statusPair.first);
diff --git a/camera/provider/2.7/default/ExternalCameraProviderImpl_2_7.cpp b/camera/provider/2.7/default/ExternalCameraProviderImpl_2_7.cpp
index 62ce074..eba49a5 100644
--- a/camera/provider/2.7/default/ExternalCameraProviderImpl_2_7.cpp
+++ b/camera/provider/2.7/default/ExternalCameraProviderImpl_2_7.cpp
@@ -91,11 +91,11 @@
 
 Return<Status> ExternalCameraProviderImpl_2_7::setCallback(
         const sp<ICameraProviderCallback>& callback) {
+    if (callback == nullptr) {
+        return Status::ILLEGAL_ARGUMENT;
+    }
     Mutex::Autolock _l(mLock);
     mCallbacks = callback;
-    if (mCallbacks == nullptr) {
-        return Status::OK;
-    }
     // Send a callback for all devices to initialize
     {
         for (const auto& pair : mCameraStatusMap) {
diff --git a/camera/provider/default/ExternalCameraProvider.cpp b/camera/provider/default/ExternalCameraProvider.cpp
index 4d2c847..54875ab 100644
--- a/camera/provider/default/ExternalCameraProvider.cpp
+++ b/camera/provider/default/ExternalCameraProvider.cpp
@@ -75,15 +75,15 @@
 
 ndk::ScopedAStatus ExternalCameraProvider::setCallback(
         const std::shared_ptr<ICameraProviderCallback>& in_callback) {
+    if (in_callback == nullptr) {
+        return fromStatus(Status::ILLEGAL_ARGUMENT);
+    }
+
     {
         Mutex::Autolock _l(mLock);
         mCallback = in_callback;
     }
 
-    if (mCallback == nullptr) {
-        return fromStatus(Status::OK);
-    }
-
     for (const auto& pair : mCameraStatusMap) {
         mCallback->cameraDeviceStatusChange(pair.first, pair.second);
     }
diff --git a/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/IGraphicBufferAllocator.aidl b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/IGraphicBufferAllocator.aidl
index da3d5ff..3e460dd 100644
--- a/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/IGraphicBufferAllocator.aidl
+++ b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/IGraphicBufferAllocator.aidl
@@ -36,7 +36,7 @@
 interface IGraphicBufferAllocator {
   android.hardware.media.c2.IGraphicBufferAllocator.Allocation allocate(in android.hardware.media.c2.IGraphicBufferAllocator.Description desc);
   boolean deallocate(in long id);
-  android.hardware.media.c2.IGraphicBufferAllocator.WaitableFds getWaitableFds();
+  ParcelFileDescriptor getWaitableFd();
   parcelable Allocation {
     android.hardware.HardwareBuffer buffer;
     ParcelFileDescriptor fence;
@@ -47,8 +47,4 @@
     int format;
     long usage;
   }
-  parcelable WaitableFds {
-    ParcelFileDescriptor allocEvent;
-    ParcelFileDescriptor statusEvent;
-  }
 }
diff --git a/media/c2/aidl/android/hardware/media/c2/IGraphicBufferAllocator.aidl b/media/c2/aidl/android/hardware/media/c2/IGraphicBufferAllocator.aidl
index 1c97214..49c4ea4 100644
--- a/media/c2/aidl/android/hardware/media/c2/IGraphicBufferAllocator.aidl
+++ b/media/c2/aidl/android/hardware/media/c2/IGraphicBufferAllocator.aidl
@@ -75,31 +75,22 @@
     boolean deallocate(in long id);
 
     /**
-     * Fds for waitable object events.
-     *
-     * Fds are created by eventfd() with semaphore mode.
-     * For allocEvent, An integer counter regarding dequeuable buffer count is maintained
-     * by client using read()/write() to the fd. The fd can be checked whether it is
-     * readable via poll(). When in readable status, the specified counter is positive
-     * so allocate/dequeue can happen.
-     *
-     * For statusEvent, the client can notify further allocation is not feasible.
-     * e.g.) life-cycle of the underlying allocator is ended.
-     *
-     * C2Fence object should be implemented based on this Fds. Thus, C2Fence can return
-     * either by allocation being ready or allocation being infeasible by the client status
-     * change.
-     */
-    parcelable WaitableFds {
-        ParcelFileDescriptor allocEvent;
-        ParcelFileDescriptor statusEvent;
-    }
-
-    /**
-     * Gets waiable file descriptors.
+     * Gets a waitable file descriptor.
      *
      * Use this method once and cache it in order not to create unnecessary duplicated fds.
-     * The returned array will have two fds.
+     *
+     * Two file descriptors are created by pipe2(), and the reading end will be returned
+     * and shared by this method. Whenever a dequeuable buffer is ready a byte will be
+     * written to the writing end. Whenever a buffer is allocated(or dequeued) a byte will
+     * be read from the reading end.
+     *
+     * The returned file descriptor(the reading end) can be polled whether the read is ready
+     * via ::poll(). If no more allocate() can be fulfilled(by status change or etc.), the
+     * writing end will be closed. In the case, POLLHUP event can be retrieved via ::poll().
+     *
+     * C2Fence object should be implemented based on this Fd. Thus, C2Fence can return
+     * either by allocation being ready or allocation being infeasible by the client status
+     * change.
      *
      * If many waitable objects based on the same fd are competing, all watiable objects will be
      * notified. After being notified, they should invoke allocate(). At least one of them can
@@ -110,5 +101,5 @@
      * @return an fd array which will be wrapped to C2Fence and will be waited for
      *     until allocating is unblocked.
      */
-    WaitableFds getWaitableFds();
+    ParcelFileDescriptor getWaitableFd();
 }
diff --git a/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/Mode.aidl b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/Mode.aidl
index efbb300..b8a0710 100644
--- a/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/Mode.aidl
+++ b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/Mode.aidl
@@ -51,4 +51,5 @@
   CAMERA_STREAMING_HIGH,
   GAME,
   GAME_LOADING,
+  DISPLAY_CHANGE,
 }
diff --git a/power/aidl/android/hardware/power/Mode.aidl b/power/aidl/android/hardware/power/Mode.aidl
index cc4b130..78f0363 100644
--- a/power/aidl/android/hardware/power/Mode.aidl
+++ b/power/aidl/android/hardware/power/Mode.aidl
@@ -134,11 +134,6 @@
     DISPLAY_INACTIVE,
 
     /**
-     * Below hints are currently not sent in Android framework but OEM might choose to
-     * implement for power/perf optimizations.
-     */
-
-    /**
      * This mode indicates that low latency audio is active.
      */
     AUDIO_STREAMING_LOW_LATENCY,
@@ -172,4 +167,10 @@
      * This mode indicates that the user is waiting for loading in a game.
      */
     GAME_LOADING,
+
+    /**
+     * This mode indicates that the display layout is changing due to rotation
+     * or switching between inner and outer panels.
+     */
+    DISPLAY_CHANGE,
 }