Implement support for device-aware RECORD_AUDIO permission
Add a device ID as part of each AudioMix which can be used for (virtual)
device specific routing decisions and policy applications.
When constructing AudioRecordClients and when checking for the
RECORD_AUDIO permission held by the caller - intersect the deviceID of
the AudioMix as this is the place the microphone sensor is located in.
Bug: 291737188
Test: atest VirtualAudioPermissionTest
Change-Id: I792bd91c3b817557c1b4cf0a0f54248a0677b4b0
diff --git a/media/libaudioclient/Android.bp b/media/libaudioclient/Android.bp
index 90910a1..c23d7d3 100644
--- a/media/libaudioclient/Android.bp
+++ b/media/libaudioclient/Android.bp
@@ -64,6 +64,7 @@
"audiopolicy-aidl-cpp",
"audiopolicy-types-aidl-cpp",
"capture_state_listener-aidl-cpp",
+ "framework-permission-aidl-cpp",
"libaudiofoundation",
"libaudioclient_aidl_conversion",
"libaudioutils",
@@ -367,6 +368,7 @@
],
imports: [
"audioclient-types-aidl",
+ "framework-permission-aidl",
],
backend: {
cpp: {
diff --git a/media/libaudioclient/PolicyAidlConversion.cpp b/media/libaudioclient/PolicyAidlConversion.cpp
index a71bb18..441e329 100644
--- a/media/libaudioclient/PolicyAidlConversion.cpp
+++ b/media/libaudioclient/PolicyAidlConversion.cpp
@@ -243,6 +243,7 @@
legacy.mAllowPrivilegedMediaPlaybackCapture = aidl.allowPrivilegedMediaPlaybackCapture;
legacy.mVoiceCommunicationCaptureAllowed = aidl.voiceCommunicationCaptureAllowed;
legacy.mToken = aidl.mToken;
+ legacy.mVirtualDeviceId = aidl.mVirtualDeviceId;
return legacy;
}
@@ -267,6 +268,7 @@
aidl.allowPrivilegedMediaPlaybackCapture = legacy.mAllowPrivilegedMediaPlaybackCapture;
aidl.voiceCommunicationCaptureAllowed = legacy.mVoiceCommunicationCaptureAllowed;
aidl.mToken = legacy.mToken;
+ aidl.mVirtualDeviceId = legacy.mVirtualDeviceId;
return aidl;
}
diff --git a/media/libaudioclient/aidl/android/media/AudioMix.aidl b/media/libaudioclient/aidl/android/media/AudioMix.aidl
index f0c561c..bb8537d 100644
--- a/media/libaudioclient/aidl/android/media/AudioMix.aidl
+++ b/media/libaudioclient/aidl/android/media/AudioMix.aidl
@@ -41,4 +41,6 @@
boolean voiceCommunicationCaptureAllowed;
/** Identifies the owner of the AudioPolicy that this AudioMix belongs to */
IBinder mToken;
+ /** Indicates the Id of the VirtualDevice this AudioMix was registered for */
+ int mVirtualDeviceId;
}
diff --git a/media/libaudioclient/include/media/AudioPolicy.h b/media/libaudioclient/include/media/AudioPolicy.h
index 9e4ae54..b190fba 100644
--- a/media/libaudioclient/include/media/AudioPolicy.h
+++ b/media/libaudioclient/include/media/AudioPolicy.h
@@ -129,6 +129,7 @@
String8 mDeviceAddress;
uint32_t mCbFlags; // flags indicating which callbacks to use, see kCbFlag*
sp<IBinder> mToken;
+ uint32_t mVirtualDeviceId;
/** Ignore the AUDIO_FLAG_NO_MEDIA_PROJECTION */
bool mAllowPrivilegedMediaPlaybackCapture = false;
/** Indicates if the caller can capture voice communication output */
diff --git a/media/utils/ServiceUtilities.cpp b/media/utils/ServiceUtilities.cpp
index c4f2808..2d963d9 100644
--- a/media/utils/ServiceUtilities.cpp
+++ b/media/utils/ServiceUtilities.cpp
@@ -113,8 +113,9 @@
return std::optional<AttributionSourceState>{myAttributionSource};
}
-static bool checkRecordingInternal(const AttributionSourceState& attributionSource,
- const String16& msg, bool start, audio_source_t source) {
+ static bool checkRecordingInternal(const AttributionSourceState &attributionSource,
+ const uint32_t virtualDeviceId,
+ const String16 &msg, bool start, audio_source_t source) {
// Okay to not track in app ops as audio server or media server is us and if
// device is rooted security model is considered compromised.
// system_server loses its RECORD_AUDIO permission when a secondary
@@ -126,7 +127,7 @@
// We specify a pid and uid here as mediaserver (aka MediaRecorder or StageFrightRecorder)
// may open a record track on behalf of a client. Note that pid may be a tid.
// IMPORTANT: DON'T USE PermissionCache - RUNTIME PERMISSIONS CHANGE.
- const std::optional<AttributionSourceState> resolvedAttributionSource =
+ std::optional<AttributionSourceState> resolvedAttributionSource =
resolveAttributionSource(attributionSource);
if (!resolvedAttributionSource.has_value()) {
return false;
@@ -135,6 +136,7 @@
const int32_t attributedOpCode = getOpForSource(source);
permission::PermissionChecker permissionChecker;
+ resolvedAttributionSource.value().deviceId = virtualDeviceId;
bool permitted = false;
if (start) {
permitted = (permissionChecker.checkPermissionForStartDataDeliveryFromDatasource(
@@ -149,13 +151,24 @@
return permitted;
}
-bool recordingAllowed(const AttributionSourceState& attributionSource, audio_source_t source) {
- return checkRecordingInternal(attributionSource, String16(), /*start*/ false, source);
+static constexpr int DEVICE_ID_DEFAULT = 0;
+
+bool recordingAllowed(const AttributionSourceState &attributionSource, audio_source_t source) {
+ return checkRecordingInternal(attributionSource, DEVICE_ID_DEFAULT, String16(), /*start*/ false,
+ source);
+}
+
+bool recordingAllowed(const AttributionSourceState &attributionSource,
+ const uint32_t virtualDeviceId,
+ audio_source_t source) {
+ return checkRecordingInternal(attributionSource, virtualDeviceId,
+ String16(), /*start*/ false, source);
}
bool startRecording(const AttributionSourceState& attributionSource, const String16& msg,
audio_source_t source) {
- return checkRecordingInternal(attributionSource, msg, /*start*/ true, source);
+ return checkRecordingInternal(attributionSource, DEVICE_ID_DEFAULT, msg, /*start*/ true,
+ source);
}
void finishRecording(const AttributionSourceState& attributionSource, audio_source_t source) {
diff --git a/media/utils/include/mediautils/ServiceUtilities.h b/media/utils/include/mediautils/ServiceUtilities.h
index 0b3a3f9..aa9e120 100644
--- a/media/utils/include/mediautils/ServiceUtilities.h
+++ b/media/utils/include/mediautils/ServiceUtilities.h
@@ -87,6 +87,10 @@
bool recordingAllowed(const AttributionSourceState& attributionSource,
audio_source_t source = AUDIO_SOURCE_DEFAULT);
+
+bool recordingAllowed(const AttributionSourceState &attributionSource,
+ uint32_t virtualDeviceId,
+ audio_source_t source);
bool startRecording(const AttributionSourceState& attributionSource,
const String16& msg, audio_source_t source);
void finishRecording(const AttributionSourceState& attributionSource, audio_source_t source);
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index bfc3132..8f17ffc 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -166,7 +166,8 @@
audio_input_flags_t flags,
audio_port_handle_t *selectedDeviceId,
input_type_t *inputType,
- audio_port_handle_t *portId) = 0;
+ audio_port_handle_t *portId,
+ uint32_t *virtualDeviceId) = 0;
// indicates to the audio policy manager that the input starts being used.
virtual status_t startInput(audio_port_handle_t portId) = 0;
// indicates to the audio policy manager that the input stops being used.
diff --git a/services/audiopolicy/fuzzer/audiopolicy_fuzzer.cpp b/services/audiopolicy/fuzzer/audiopolicy_fuzzer.cpp
index 58fcb5c..6416a47 100644
--- a/services/audiopolicy/fuzzer/audiopolicy_fuzzer.cpp
+++ b/services/audiopolicy/fuzzer/audiopolicy_fuzzer.cpp
@@ -207,7 +207,8 @@
audio_port_handle_t *selectedDeviceId, audio_format_t format,
audio_channel_mask_t channelMask, int sampleRate,
audio_input_flags_t flags = AUDIO_INPUT_FLAG_NONE,
- audio_port_handle_t *portId = nullptr);
+ audio_port_handle_t *portId = nullptr,
+ uint32_t *virtualDeviceId = nullptr);
bool findDevicePort(audio_port_role_t role, audio_devices_t deviceType,
const std::string &address, audio_port_v7 *foundPort);
static audio_port_handle_t getDeviceIdFromPatch(const struct audio_patch *patch);
@@ -283,7 +284,7 @@
bool AudioPolicyManagerFuzzer::getInputForAttr(
const audio_attributes_t &attr, audio_unique_id_t riid, audio_port_handle_t *selectedDeviceId,
audio_format_t format, audio_channel_mask_t channelMask, int sampleRate,
- audio_input_flags_t flags, audio_port_handle_t *portId) {
+ audio_input_flags_t flags, audio_port_handle_t *portId, uint32_t *virtualDeviceId) {
audio_io_handle_t input = AUDIO_IO_HANDLE_NONE;
audio_config_base_t config = AUDIO_CONFIG_BASE_INITIALIZER;
config.sample_rate = sampleRate;
@@ -298,7 +299,7 @@
attributionSource.uid = 0;
attributionSource.token = sp<BBinder>::make();
if (mManager->getInputForAttr(&attr, &input, riid, AUDIO_SESSION_NONE, attributionSource,
- &config, flags, selectedDeviceId, &inputType, portId) != OK) {
+ &config, flags, selectedDeviceId, &inputType, portId, virtualDeviceId) != OK) {
return false;
}
if (*portId == AUDIO_PORT_HANDLE_NONE || input == AUDIO_IO_HANDLE_NONE) {
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 449f1bd..6818413 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -2697,7 +2697,8 @@
audio_input_flags_t flags,
audio_port_handle_t *selectedDeviceId,
input_type_t *inputType,
- audio_port_handle_t *portId)
+ audio_port_handle_t *portId,
+ uint32_t *virtualDeviceId)
{
ALOGV("%s() source %d, sampling rate %d, format %#x, channel mask %#x, session %d, "
"flags %#x attributes=%s requested device ID %d",
@@ -2799,6 +2800,9 @@
} else {
*inputType = API_INPUT_MIX_EXT_POLICY_REROUTE;
}
+ if (virtualDeviceId) {
+ *virtualDeviceId = policyMix->mVirtualDeviceId;
+ }
} else {
if (explicitRoutingDevice != nullptr) {
device = explicitRoutingDevice;
@@ -2822,6 +2826,10 @@
// meaning it receives audio injected into the framework, so the recorder doesn't
// know about it and is therefore considered "legacy"
*inputType = API_INPUT_LEGACY;
+
+ if (virtualDeviceId) {
+ *virtualDeviceId = policyMix->mVirtualDeviceId;
+ }
} else if (audio_is_remote_submix_device(device->type())) {
*inputType = API_INPUT_MIX_CAPTURE;
} else if (device->type() == AUDIO_DEVICE_IN_TELEPHONY_RX) {
@@ -2853,6 +2861,11 @@
goto error;
}
+
+ if (policyMix != nullptr && virtualDeviceId != nullptr) {
+ *virtualDeviceId = policyMix->mVirtualDeviceId;
+ }
+
exit:
*selectedDeviceId = mAvailableInputDevices.contains(device) ?
@@ -3905,6 +3918,7 @@
policyMix->mCbFlags);
_aidl_return.back().mDeviceType = policyMix->mDeviceType;
_aidl_return.back().mToken = policyMix->mToken;
+ _aidl_return.back().mVirtualDeviceId = policyMix->mVirtualDeviceId;
}
ALOGVV("%s() returning %zu registered mixes", __func__, _aidl_return->size());
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index a3232a2..0454e6e 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -141,7 +141,8 @@
audio_input_flags_t flags,
audio_port_handle_t *selectedDeviceId,
input_type_t *inputType,
- audio_port_handle_t *portId);
+ audio_port_handle_t *portId,
+ uint32_t *virtualDeviceId);
// indicates to the audio policy manager that the input starts being used.
virtual status_t startInput(audio_port_handle_t portId);
diff --git a/services/audiopolicy/service/Android.bp b/services/audiopolicy/service/Android.bp
index cddbf39..c4408f9 100644
--- a/services/audiopolicy/service/Android.bp
+++ b/services/audiopolicy/service/Android.bp
@@ -39,6 +39,7 @@
"libstagefright_foundation",
"libutils",
"libxml2",
+ "android.media.audiopolicy-aconfig-cc",
"audioclient-types-aidl-cpp",
"audioflinger-aidl-cpp",
"audiopolicy-aidl-cpp",
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index 2a4c069..203c15e 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -20,6 +20,7 @@
#include "AudioPolicyService.h"
#include "AudioRecordClient.h"
#include "TypeConverter.h"
+#include <android_media_audiopolicy.h>
#include <media/AidlConversion.h>
#include <media/AudioPolicy.h>
#include <media/AudioValidator.h>
@@ -45,6 +46,7 @@
#define MAX_ITEMS_PER_LIST 1024
namespace android {
+namespace audiopolicy_flags = android::media::audiopolicy;
using binder::Status;
using aidl_utils::binderStatusFromStatusT;
using content::AttributionSourceState;
@@ -62,6 +64,8 @@
using media::audio::common::AudioUuid;
using media::audio::common::Int;
+constexpr int kDefaultVirtualDeviceId = 0;
+
const std::vector<audio_usage_t>& SYSTEM_USAGES = {
AUDIO_USAGE_CALL_ASSISTANT,
AUDIO_USAGE_EMERGENCY,
@@ -627,6 +631,8 @@
RETURN_IF_BINDER_ERROR(binderStatusFromStatusT(validateUsage(attr,
attributionSource)));
+ uint32_t virtualDeviceId = kDefaultVirtualDeviceId;
+
// check calling permissions.
// Capturing from the following sources does not require permission RECORD_AUDIO
// as the captured audio does not come from a microphone:
@@ -698,7 +704,8 @@
status = mAudioPolicyManager->getInputForAttr(&attr, &input, riid, session,
attributionSource, &config,
flags, &selectedDeviceId,
- &inputType, &portId);
+ &inputType, &portId,
+ &virtualDeviceId);
}
audioPolicyEffects = mAudioPolicyEffects;
@@ -737,6 +744,14 @@
LOG_ALWAYS_FATAL("%s encountered an invalid input type %d",
__func__, (int)inputType);
}
+
+ if (audiopolicy_flags::record_audio_device_aware_permission()) {
+ // enforce device-aware RECORD_AUDIO permission
+ if (virtualDeviceId != kDefaultVirtualDeviceId &&
+ !recordingAllowed(attributionSource, virtualDeviceId, inputSource)) {
+ status = PERMISSION_DENIED;
+ }
+ }
}
if (status != NO_ERROR) {
@@ -752,6 +767,7 @@
sp<AudioRecordClient> client = new AudioRecordClient(attr, input, session, portId,
selectedDeviceId, attributionSource,
+ virtualDeviceId,
canCaptureOutput, canCaptureHotword,
mOutputCommandThread);
mAudioRecordClients.add(portId, client);
diff --git a/services/audiopolicy/service/AudioRecordClient.cpp b/services/audiopolicy/service/AudioRecordClient.cpp
index a89a84d..6d8b3cf 100644
--- a/services/audiopolicy/service/AudioRecordClient.cpp
+++ b/services/audiopolicy/service/AudioRecordClient.cpp
@@ -18,9 +18,10 @@
#include "AudioRecordClient.h"
#include "AudioPolicyService.h"
+#include <android_media_audiopolicy.h>
namespace android::media::audiopolicy {
-
+namespace audiopolicy_flags = android::media::audiopolicy;
using android::AudioPolicyService;
namespace {
@@ -59,8 +60,10 @@
// static
sp<OpRecordAudioMonitor>
OpRecordAudioMonitor::createIfNeeded(
- const AttributionSourceState& attributionSource, const audio_attributes_t& attr,
- wp<AudioPolicyService::AudioCommandThread> commandThread)
+ const AttributionSourceState &attributionSource,
+ const uint32_t virtualDeviceId,
+ const audio_attributes_t &attr,
+ wp<AudioPolicyService::AudioCommandThread> commandThread)
{
if (isAudioServerOrRootUid(attributionSource.uid)) {
ALOGV("not silencing record for audio or root source %s",
@@ -78,15 +81,19 @@
|| attributionSource.packageName.value().size() == 0) {
return nullptr;
}
- return new OpRecordAudioMonitor(attributionSource, getOpForSource(attr.source), commandThread);
+
+ return new OpRecordAudioMonitor(attributionSource, virtualDeviceId, attr,
+ getOpForSource(attr.source), commandThread);
}
OpRecordAudioMonitor::OpRecordAudioMonitor(
- const AttributionSourceState& attributionSource, int32_t appOp,
+ const AttributionSourceState &attributionSource,
+ const uint32_t virtualDeviceId, const audio_attributes_t &attr,
+ int32_t appOp,
wp<AudioPolicyService::AudioCommandThread> commandThread) :
- mHasOp(true), mAttributionSource(attributionSource), mAppOp(appOp),
- mCommandThread(commandThread)
-{
+ mHasOp(true), mAttributionSource(attributionSource),
+ mVirtualDeviceId(virtualDeviceId), mAttr(attr), mAppOp(appOp),
+ mCommandThread(commandThread) {
}
OpRecordAudioMonitor::~OpRecordAudioMonitor()
@@ -131,7 +138,12 @@
const int32_t mode = mAppOpsManager.checkOp(mAppOp,
mAttributionSource.uid, VALUE_OR_FATAL(aidl2legacy_string_view_String16(
mAttributionSource.packageName.value_or(""))));
- const bool hasIt = (mode == AppOpsManager::MODE_ALLOWED);
+ bool hasIt = (mode == AppOpsManager::MODE_ALLOWED);
+
+ if (audiopolicy_flags::record_audio_device_aware_permission()) {
+ const bool canRecord = recordingAllowed(mAttributionSource, mVirtualDeviceId, mAttr.source);
+ hasIt = hasIt && canRecord;
+ }
// verbose logging only log when appOp changed
ALOGI_IF(hasIt != mHasOp.load(),
"App op %d missing, %ssilencing record %s",
diff --git a/services/audiopolicy/service/AudioRecordClient.h b/services/audiopolicy/service/AudioRecordClient.h
index d3be316..76aff41 100644
--- a/services/audiopolicy/service/AudioRecordClient.h
+++ b/services/audiopolicy/service/AudioRecordClient.h
@@ -38,12 +38,16 @@
static sp<OpRecordAudioMonitor> createIfNeeded(
const AttributionSourceState& attributionSource,
+ uint32_t virtualDeviceId,
const audio_attributes_t& attr,
wp<AudioPolicyService::AudioCommandThread> commandThread);
private:
- OpRecordAudioMonitor(const AttributionSourceState& attributionSource, int32_t appOp,
- wp<AudioPolicyService::AudioCommandThread> commandThread);
+ OpRecordAudioMonitor(const AttributionSourceState &attributionSource,
+ uint32_t virtualDeviceId,
+ const audio_attributes_t &attr,
+ int32_t appOp,
+ wp<AudioPolicyService::AudioCommandThread> commandThread);
void onFirstRef() override;
@@ -67,6 +71,8 @@
std::atomic_bool mHasOp;
const AttributionSourceState mAttributionSource;
+ const uint32_t mVirtualDeviceId;
+ const audio_attributes_t mAttr;
const int32_t mAppOp;
wp<AudioPolicyService::AudioCommandThread> mCommandThread;
};
@@ -81,15 +87,20 @@
const audio_session_t session, audio_port_handle_t portId,
const audio_port_handle_t deviceId,
const AttributionSourceState& attributionSource,
+ const uint32_t virtualDeviceId,
bool canCaptureOutput, bool canCaptureHotword,
wp<AudioPolicyService::AudioCommandThread> commandThread) :
AudioClient(attributes, io, attributionSource,
session, portId, deviceId), attributionSource(attributionSource),
+ virtualDeviceId(virtualDeviceId),
startTimeNs(0), canCaptureOutput(canCaptureOutput),
canCaptureHotword(canCaptureHotword), silenced(false),
mOpRecordAudioMonitor(
OpRecordAudioMonitor::createIfNeeded(attributionSource,
- attributes, commandThread)) {}
+ virtualDeviceId,
+ attributes, commandThread)) {
+
+ }
~AudioRecordClient() override = default;
bool hasOp() const {
@@ -97,6 +108,7 @@
}
const AttributionSourceState attributionSource; // attribution source of client
+ const uint32_t virtualDeviceId; // id of the virtual device associated with the audio device
nsecs_t startTimeNs;
const bool canCaptureOutput;
const bool canCaptureHotword;
diff --git a/services/audiopolicy/tests/audiopolicymanager_tests.cpp b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
index e02c93a..bb9aecb 100644
--- a/services/audiopolicy/tests/audiopolicymanager_tests.cpp
+++ b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
@@ -204,7 +204,8 @@
audio_channel_mask_t channelMask,
int sampleRate,
audio_input_flags_t flags = AUDIO_INPUT_FLAG_NONE,
- audio_port_handle_t *portId = nullptr);
+ audio_port_handle_t *portId = nullptr,
+ uint32_t *virtualDeviceId = nullptr);
PatchCountCheck snapshotPatchCount() { return PatchCountCheck(mClient.get()); }
void getAudioPorts(audio_port_type_t type, audio_port_role_t role,
@@ -316,7 +317,8 @@
audio_channel_mask_t channelMask,
int sampleRate,
audio_input_flags_t flags,
- audio_port_handle_t *portId) {
+ audio_port_handle_t *portId,
+ uint32_t *virtualDeviceId) {
audio_config_base_t config = AUDIO_CONFIG_BASE_INITIALIZER;
config.sample_rate = sampleRate;
config.channel_mask = channelMask;
@@ -324,11 +326,12 @@
audio_port_handle_t localPortId;
if (!portId) portId = &localPortId;
*portId = AUDIO_PORT_HANDLE_NONE;
+ if (!virtualDeviceId) virtualDeviceId = 0;
AudioPolicyInterface::input_type_t inputType;
AttributionSourceState attributionSource = createAttributionSourceState(/*uid=*/ 0);
ASSERT_EQ(OK, mManager->getInputForAttr(
&attr, input, riid, session, attributionSource, &config, flags,
- selectedDeviceId, &inputType, portId));
+ selectedDeviceId, &inputType, portId, virtualDeviceId));
ASSERT_NE(AUDIO_PORT_HANDLE_NONE, *portId);
}
@@ -1296,10 +1299,11 @@
};
audio_config_base_t config = requestedConfig;
audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE;
+ uint32_t *virtualDeviceId = 0;
ASSERT_EQ(OK, mManager->getInputForAttr(
&attr, &input, 1 /*riid*/, AUDIO_SESSION_NONE, attributionSource, &config,
AUDIO_INPUT_FLAG_NONE,
- &selectedDeviceId, &inputType, &portId));
+ &selectedDeviceId, &inputType, &portId, virtualDeviceId));
ASSERT_NE(AUDIO_PORT_HANDLE_NONE, portId);
ASSERT_TRUE(equals(requestedConfig, config));
@@ -1313,7 +1317,7 @@
ASSERT_EQ(OK, mManager->getInputForAttr(
&attr, &input, 1 /*riid*/, AUDIO_SESSION_NONE, attributionSource, &config,
AUDIO_INPUT_FLAG_NONE,
- &selectedDeviceId, &inputType, &portId));
+ &selectedDeviceId, &inputType, &portId, virtualDeviceId));
ASSERT_NE(AUDIO_PORT_HANDLE_NONE, portId);
ASSERT_TRUE(equals(requestedConfig, config));