Merge "APM: Notify the client about new audio ports" into rvc-dev
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index ffc3a0f..738b52e 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -133,12 +133,14 @@
     sp<DeviceDescriptor> device =
             mHwModules.getDeviceDescriptor(deviceType, device_address, device_name, encodedFormat,
                                            state == AUDIO_POLICY_DEVICE_STATE_AVAILABLE);
-    if (device == 0) {
-        return INVALID_OPERATION;
-    }
+    return device ? setDeviceConnectionStateInt(device, state) : INVALID_OPERATION;
+}
 
+status_t AudioPolicyManager::setDeviceConnectionStateInt(const sp<DeviceDescriptor> &device,
+                                                         audio_policy_dev_state_t state)
+{
     // handle output devices
-    if (audio_is_output_device(deviceType)) {
+    if (audio_is_output_device(device->type())) {
         SortedVector <audio_io_handle_t> outputs;
 
         ssize_t index = mAvailableOutputDevices.indexOf(device);
@@ -155,7 +157,7 @@
                 return INVALID_OPERATION;
             }
             ALOGV("%s() connecting device %s format %x",
-                    __func__, device->toString().c_str(), encodedFormat);
+                    __func__, device->toString().c_str(), device->getEncodedFormat());
 
             // register new device as available
             if (mAvailableOutputDevices.add(device) < 0) {
@@ -217,16 +219,13 @@
         // output device used by a dynamic policy of type recorder as no
         // playback use case is affected.
         bool doCheckForDeviceAndOutputChanges = true;
-        if (device->type() == AUDIO_DEVICE_OUT_REMOTE_SUBMIX
-                && strncmp(device_address, "0", AUDIO_DEVICE_MAX_ADDRESS_LEN) != 0) {
+        if (device->type() == AUDIO_DEVICE_OUT_REMOTE_SUBMIX && device->address() != "0") {
             for (audio_io_handle_t output : outputs) {
                 sp<SwAudioOutputDescriptor> desc = mOutputs.valueFor(output);
                 sp<AudioPolicyMix> policyMix = desc->mPolicyMix.promote();
                 if (policyMix != nullptr
                         && policyMix->mMixType == MIX_TYPE_RECORDERS
-                        && strncmp(device_address,
-                                   policyMix->mDeviceAddress.string(),
-                                   AUDIO_DEVICE_MAX_ADDRESS_LEN) == 0) {
+                        && device->address() == policyMix->mDeviceAddress.string()) {
                     doCheckForDeviceAndOutputChanges = false;
                     break;
                 }
@@ -272,7 +271,7 @@
                 // a valid device selection on those outputs.
                 bool force = (msdOutDevices.isEmpty() || msdOutDevices != desc->devices())
                         && !desc->isDuplicated()
-                        && (!device_distinguishes_on_address(deviceType)
+                        && (!device_distinguishes_on_address(device->type())
                                 // always force when disconnecting (a non-duplicated device)
                                 || (state == AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE));
                 setOutputDevices(desc, newDevices, force, 0);
@@ -288,7 +287,7 @@
     }  // end if is output device
 
     // handle input devices
-    if (audio_is_input_device(deviceType)) {
+    if (audio_is_input_device(device->type())) {
         ssize_t index = mAvailableInputDevices.indexOf(device);
         switch (state)
         {
@@ -4444,7 +4443,7 @@
 
     // after parsing the config, mOutputDevicesAll and mInputDevicesAll contain all known devices;
     // open all output streams needed to access attached devices
-    onNewAudioModulesAvailable();
+    onNewAudioModulesAvailableInt(nullptr /*newDevices*/);
 
     // make sure default device is reachable
     if (mDefaultOutputDevice == 0 || !mAvailableOutputDevices.contains(mDefaultOutputDevice)) {
@@ -4501,6 +4500,16 @@
 
 void AudioPolicyManager::onNewAudioModulesAvailable()
 {
+    DeviceVector newDevices;
+    onNewAudioModulesAvailableInt(&newDevices);
+    if (!newDevices.empty()) {
+        nextAudioPortGeneration();
+        mpClientInterface->onAudioPortListUpdate();
+    }
+}
+
+void AudioPolicyManager::onNewAudioModulesAvailableInt(DeviceVector *newDevices)
+{
     for (const auto& hwModule : mHwModulesAll) {
         if (std::find(mHwModules.begin(), mHwModules.end(), hwModule) != mHwModules.end()) {
             continue;
@@ -4564,6 +4573,7 @@
                 if (!device->isAttached()) {
                     device->attach(hwModule);
                     mAvailableOutputDevices.add(device);
+                    if (newDevices) newDevices->add(device);
                     setEngineDeviceConnectionState(device, AUDIO_POLICY_DEVICE_STATE_AVAILABLE);
                 }
             }
@@ -4619,6 +4629,7 @@
                     device->attach(hwModule);
                     device->importAudioPortAndPickAudioProfile(inProfile, true);
                     mAvailableInputDevices.add(device);
+                    if (newDevices) newDevices->add(device);
                     setEngineDeviceConnectionState(device, AUDIO_POLICY_DEVICE_STATE_AVAILABLE);
                 }
             }
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index 8121f86..c142880 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -788,6 +788,8 @@
 
         std::unordered_map<uid_t, audio_flags_mask_t> mAllowedCapturePolicies;
 private:
+        void onNewAudioModulesAvailableInt(DeviceVector *newDevices);
+
         // Add or remove AC3 DTS encodings based on user preferences.
         void modifySurroundFormats(const sp<DeviceDescriptor>& devDesc, FormatVector *formatsPtr);
         void modifySurroundChannelMasks(ChannelMaskSet *channelMasksPtr);
@@ -878,6 +880,8 @@
                                              const char *device_address,
                                              const char *device_name,
                                              audio_format_t encodedFormat);
+        status_t setDeviceConnectionStateInt(const sp<DeviceDescriptor> &device,
+                                             audio_policy_dev_state_t state);
 
         void setEngineDeviceConnectionState(const sp<DeviceDescriptor> device,
                                       audio_policy_dev_state_t state);
diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp
index dc51cff..dd46ffb 100644
--- a/services/audiopolicy/service/AudioPolicyService.cpp
+++ b/services/audiopolicy/service/AudioPolicyService.cpp
@@ -1876,7 +1876,7 @@
 
 void AudioPolicyService::onNewAudioModulesAvailable()
 {
-    mAudioCommandThread->audioModulesUpdateCommand();
+    mOutputCommandThread->audioModulesUpdateCommand();
 }
 
 
diff --git a/services/audiopolicy/tests/AudioPolicyManagerTestClient.h b/services/audiopolicy/tests/AudioPolicyManagerTestClient.h
index af69466..e1721ea 100644
--- a/services/audiopolicy/tests/AudioPolicyManagerTestClient.h
+++ b/services/audiopolicy/tests/AudioPolicyManagerTestClient.h
@@ -94,6 +94,10 @@
         return NO_ERROR;
     }
 
+    void onAudioPortListUpdate() override {
+        ++mAudioPortListUpdateCount;
+    }
+
     // Helper methods for tests
     size_t getActivePatchesCount() const { return mActivePatches.size(); }
 
@@ -111,12 +115,15 @@
         mAllowedModuleNames.swap(names);
     }
 
+    size_t getAudioPortListUpdateCount() const { return mAudioPortListUpdateCount; }
+
 private:
     audio_module_handle_t mNextModuleHandle = AUDIO_MODULE_HANDLE_NONE + 1;
     audio_io_handle_t mNextIoHandle = AUDIO_IO_HANDLE_NONE + 1;
     audio_patch_handle_t mNextPatchHandle = AUDIO_PATCH_HANDLE_NONE + 1;
     std::map<audio_patch_handle_t, struct audio_patch> mActivePatches;
     std::set<std::string> mAllowedModuleNames;
+    size_t mAudioPortListUpdateCount = 0;
 };
 
 } // namespace android
diff --git a/services/audiopolicy/tests/AudioPolicyTestManager.h b/services/audiopolicy/tests/AudioPolicyTestManager.h
index 922a538..8bab020 100644
--- a/services/audiopolicy/tests/AudioPolicyTestManager.h
+++ b/services/audiopolicy/tests/AudioPolicyTestManager.h
@@ -29,6 +29,7 @@
     using AudioPolicyManager::getOutputs;
     using AudioPolicyManager::getAvailableOutputDevices;
     using AudioPolicyManager::getAvailableInputDevices;
+    uint32_t getAudioPortGeneration() const { return mAudioPortGeneration; }
 };
 
 }  // namespace android
diff --git a/services/audiopolicy/tests/audiopolicymanager_tests.cpp b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
index 7d92f34..a0074bc 100644
--- a/services/audiopolicy/tests/audiopolicymanager_tests.cpp
+++ b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
@@ -104,8 +104,10 @@
             audio_port_handle_t *portId = nullptr);
     PatchCountCheck snapshotPatchCount() { return PatchCountCheck(mClient.get()); }
 
-    void findDevicePort(audio_port_role_t role, audio_devices_t deviceType,
-            const std::string &address, audio_port &foundPort);
+    // Tries to find a device port. If 'foundPort' isn't nullptr,
+    // will generate a failure if the port hasn't been found.
+    bool findDevicePort(audio_port_role_t role, audio_devices_t deviceType,
+            const std::string &address, audio_port *foundPort);
     static audio_port_handle_t getDeviceIdFromPatch(const struct audio_patch* patch);
 
     std::unique_ptr<AudioPolicyManagerTestClient> mClient;
@@ -211,30 +213,36 @@
     ASSERT_NE(AUDIO_PORT_HANDLE_NONE, *portId);
 }
 
-void AudioPolicyManagerTest::findDevicePort(audio_port_role_t role,
-        audio_devices_t deviceType, const std::string &address, audio_port &foundPort) {
+bool AudioPolicyManagerTest::findDevicePort(audio_port_role_t role,
+        audio_devices_t deviceType, const std::string &address, audio_port *foundPort) {
     uint32_t numPorts = 0;
     uint32_t generation1;
     status_t ret;
 
     ret = mManager->listAudioPorts(role, AUDIO_PORT_TYPE_DEVICE, &numPorts, nullptr, &generation1);
-    ASSERT_EQ(NO_ERROR, ret);
+    EXPECT_EQ(NO_ERROR, ret) << "mManager->listAudioPorts returned error";
+    if (HasFailure()) return false;
 
     uint32_t generation2;
     struct audio_port ports[numPorts];
     ret = mManager->listAudioPorts(role, AUDIO_PORT_TYPE_DEVICE, &numPorts, ports, &generation2);
-    ASSERT_EQ(NO_ERROR, ret);
-    ASSERT_EQ(generation1, generation2);
+    EXPECT_EQ(NO_ERROR, ret) << "mManager->listAudioPorts returned error";
+    EXPECT_EQ(generation1, generation2) << "Generations changed during ports retrieval";
+    if (HasFailure()) return false;
 
     for (const auto &port : ports) {
         if (port.role == role && port.ext.device.type == deviceType &&
                 (strncmp(port.ext.device.address, address.c_str(),
                          AUDIO_DEVICE_MAX_ADDRESS_LEN) == 0)) {
-            foundPort = port;
-            return;
+            if (foundPort) *foundPort = port;
+            return true;
         }
     }
-    GTEST_FAIL() << "Device port with role " << role << " and address " << address << "not found";
+    if (foundPort) {
+        ADD_FAILURE() << "Device port with role " << role << " and address "
+                      << address << " not found";
+    }
+    return false;
 }
 
 audio_port_handle_t AudioPolicyManagerTest::getDeviceIdFromPatch(
@@ -694,8 +702,8 @@
     ASSERT_EQ(NO_ERROR, ret);
 
     struct audio_port extractionPort;
-    findDevicePort(AUDIO_PORT_ROLE_SOURCE, AUDIO_DEVICE_IN_REMOTE_SUBMIX,
-            mMixAddress, extractionPort);
+    ASSERT_TRUE(findDevicePort(AUDIO_PORT_ROLE_SOURCE, AUDIO_DEVICE_IN_REMOTE_SUBMIX,
+                    mMixAddress, &extractionPort));
 
     audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
     audio_source_t source = AUDIO_SOURCE_REMOTE_SUBMIX;
@@ -707,8 +715,8 @@
     ASSERT_EQ(NO_ERROR, mManager->startInput(mPortId));
     ASSERT_EQ(extractionPort.id, selectedDeviceId);
 
-    findDevicePort(AUDIO_PORT_ROLE_SINK, AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
-            mMixAddress, mInjectionPort);
+    ASSERT_TRUE(findDevicePort(AUDIO_PORT_ROLE_SINK, AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
+                    mMixAddress, &mInjectionPort));
 }
 
 void AudioPolicyManagerTestDPPlaybackReRouting::TearDown() {
@@ -879,8 +887,8 @@
     ASSERT_EQ(NO_ERROR, ret);
 
     struct audio_port injectionPort;
-    findDevicePort(AUDIO_PORT_ROLE_SINK, AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
-            mMixAddress, injectionPort);
+    ASSERT_TRUE(findDevicePort(AUDIO_PORT_ROLE_SINK, AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
+                    mMixAddress, &injectionPort));
 
     audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
     audio_usage_t usage = AUDIO_USAGE_VIRTUAL_SOURCE;
@@ -892,8 +900,8 @@
     ASSERT_EQ(NO_ERROR, mManager->startOutput(mPortId));
     ASSERT_EQ(injectionPort.id, getDeviceIdFromPatch(mClient->getLastAddedPatch()));
 
-    findDevicePort(AUDIO_PORT_ROLE_SOURCE, AUDIO_DEVICE_IN_REMOTE_SUBMIX,
-            mMixAddress, mExtractionPort);
+    ASSERT_TRUE(findDevicePort(AUDIO_PORT_ROLE_SOURCE, AUDIO_DEVICE_IN_REMOTE_SUBMIX,
+                    mMixAddress, &mExtractionPort));
 }
 
 void AudioPolicyManagerTestDPMixRecordInjection::TearDown() {
@@ -1028,7 +1036,7 @@
     audio_port devicePort;
     const audio_port_role_t role = audio_is_output_device(type)
             ? AUDIO_PORT_ROLE_SINK : AUDIO_PORT_ROLE_SOURCE;
-    findDevicePort(role, type, address, devicePort);
+    ASSERT_TRUE(findDevicePort(role, type, address, &devicePort));
 
     audio_port_handle_t routedPortId = devicePort.id;
     // Try start input or output according to the device type
@@ -1162,3 +1170,21 @@
     ASSERT_EQ(AUDIO_POLICY_DEVICE_STATE_AVAILABLE, mManager->getDeviceConnectionState(
                     AUDIO_DEVICE_IN_REMOTE_SUBMIX, "0"));
 }
+
+TEST_F(AudioPolicyManagerDynamicHwModulesTest, ListAddedAudioPorts) {
+    ASSERT_FALSE(
+            findDevicePort(AUDIO_PORT_ROLE_SOURCE, AUDIO_DEVICE_IN_REMOTE_SUBMIX, "0", nullptr));
+    mClient->swapAllowedModuleNames({"primary", "r_submix"});
+    mManager->onNewAudioModulesAvailable();
+    struct audio_port port;
+    ASSERT_TRUE(findDevicePort(AUDIO_PORT_ROLE_SOURCE, AUDIO_DEVICE_IN_REMOTE_SUBMIX, "0", &port));
+}
+
+TEST_F(AudioPolicyManagerDynamicHwModulesTest, ClientIsUpdated) {
+    const size_t prevAudioPortListUpdateCount = mClient->getAudioPortListUpdateCount();
+    const uint32_t prevAudioPortGeneration = mManager->getAudioPortGeneration();
+    mClient->swapAllowedModuleNames({"primary", "r_submix"});
+    mManager->onNewAudioModulesAvailable();
+    EXPECT_GT(mClient->getAudioPortListUpdateCount(), prevAudioPortListUpdateCount);
+    EXPECT_GT(mManager->getAudioPortGeneration(), prevAudioPortGeneration);
+}