getInputForAttr perm check cleanup pt2

Update param types for AudioPolicyManager::getInputForAttr to avoid
ptrs/inout for clarity.

No behavior changes for now.

Test: CtsMediaAudioTestCases
Bug: 374870131
Bug: 343523722
Flag: EXEMPT mechanical refactoring

Change-Id: Ic179b09159b47b5af5a56811af9ef759e47eea0c
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 0ebf8d1..88bced6 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-#include "utils/Errors.h"
 #define LOG_TAG "APM_AudioPolicyManager"
 
 // Need to keep the log statements even in production builds
@@ -46,6 +45,7 @@
 #include <android_media_audiopolicy.h>
 #include <com_android_media_audioserver.h>
 #include <cutils/bitops.h>
+#include <error/expected_utils.h>
 #include <media/AudioParameter.h>
 #include <policy.h>
 #include <private/android_filesystem_config.h>
@@ -71,6 +71,8 @@
 using android::media::audio::common::AudioMMapPolicyType;
 using android::media::audio::common::AudioPortDeviceExt;
 using android::media::audio::common::AudioPortExt;
+using android::media::audio::common::AudioConfigBase;
+using binder::Status;
 using com::android::media::audioserver::fix_call_audio_patch;
 using content::AttributionSourceState;
 
@@ -2925,63 +2927,57 @@
     return false;
 }
 
-status_t AudioPolicyManager::getInputForAttr(const audio_attributes_t *attr,
-                                             audio_io_handle_t *input,
-                                             audio_unique_id_t riid,
-                                             audio_session_t session,
-                                             const AttributionSourceState& attributionSource,
-                                             audio_config_base_t *config,
-                                             audio_input_flags_t flags,
-                                             audio_port_handle_t *selectedDeviceId,
-                                             input_type_t *inputType,
-                                             audio_port_handle_t *portId,
-                                             uint32_t *virtualDeviceId)
+base::expected<media::GetInputForAttrResponse, std::variant<binder::Status, AudioConfigBase>>
+AudioPolicyManager::getInputForAttr(audio_attributes_t attributes,
+                                     audio_io_handle_t requestedInput,
+                                     audio_port_handle_t requestedDeviceId,
+                                     audio_config_base_t config,
+                                     audio_input_flags_t flags,
+                                     audio_unique_id_t riid,
+                                     audio_session_t session,
+                                     const AttributionSourceState& attributionSource,
+                                     input_type_t *inputType)
 {
     ALOGV("%s() source %d, sampling rate %d, format %#x, channel mask %#x, session %d, "
           "flags %#x attributes=%s requested device ID %d",
-          __func__, attr->source, config->sample_rate, config->format, config->channel_mask,
-          session, flags, toString(*attr).c_str(), *selectedDeviceId);
+          __func__, attributes.source, config.sample_rate, config.format, config.channel_mask,
+          session, flags, toString(attributes).c_str(), requestedDeviceId);
 
-    status_t status = NO_ERROR;
-    audio_attributes_t attributes = *attr;
     sp<AudioPolicyMix> policyMix;
     sp<DeviceDescriptor> device;
     sp<AudioInputDescriptor> inputDesc;
     sp<AudioInputDescriptor> previousInputDesc;
     sp<RecordClientDescriptor> clientDesc;
-    audio_port_handle_t requestedDeviceId = *selectedDeviceId;
-    uid_t uid = VALUE_OR_RETURN_STATUS(aidl2legacy_int32_t_uid_t(attributionSource.uid));
+    uid_t uid = static_cast<uid_t>(attributionSource.uid);
     bool isSoundTrigger;
+    int vdi = 0 /* default device id */;
+    audio_io_handle_t input = AUDIO_IO_HANDLE_NONE;
 
-    // The supplied portId must be AUDIO_PORT_HANDLE_NONE
-    if (*portId != AUDIO_PORT_HANDLE_NONE) {
-        return INVALID_OPERATION;
-    }
-
-    if (attr->source == AUDIO_SOURCE_DEFAULT) {
+    if (attributes.source == AUDIO_SOURCE_DEFAULT) {
         attributes.source = AUDIO_SOURCE_MIC;
     }
 
     // Explicit routing?
     sp<DeviceDescriptor> explicitRoutingDevice =
-            mAvailableInputDevices.getDeviceFromId(*selectedDeviceId);
+            mAvailableInputDevices.getDeviceFromId(requestedDeviceId);
 
     // special case for mmap capture: if an input IO handle is specified, we reuse this input if
     // possible
     if ((flags & AUDIO_INPUT_FLAG_MMAP_NOIRQ) == AUDIO_INPUT_FLAG_MMAP_NOIRQ &&
-            *input != AUDIO_IO_HANDLE_NONE) {
-        ssize_t index = mInputs.indexOfKey(*input);
+            requestedInput != AUDIO_IO_HANDLE_NONE) {
+        input = requestedInput;
+        ssize_t index = mInputs.indexOfKey(requestedInput);
         if (index < 0) {
-            ALOGW("getInputForAttr() unknown MMAP input %d", *input);
-            status = BAD_VALUE;
-            goto error;
+            return base::unexpected{Status::fromExceptionCode(
+                    EX_ILLEGAL_ARGUMENT,
+                    String8::format("%s unknown MMAP input %d", __func__, requestedInput))};
         }
         sp<AudioInputDescriptor> inputDesc = mInputs.valueAt(index);
         RecordClientVector clients = inputDesc->getClientsForSession(session);
         if (clients.size() == 0) {
-            ALOGW("getInputForAttr() unknown session %d on input %d", session, *input);
-            status = BAD_VALUE;
-            goto error;
+            return base::unexpected{Status::fromExceptionCode(
+                    EX_ILLEGAL_ARGUMENT, String8::format("%s unknown session %d on input %d",
+                                                         __func__, session, requestedInput))};
         }
         // For MMAP mode, the first call to getInputForAttr() is made on behalf of audioflinger.
         // The second call is for the first active client and sets the UID. Any further call
@@ -2997,146 +2993,139 @@
                     continue;
                 }
                 if (uid != client->uid() && !client->isSilenced()) {
-                    ALOGW("getInputForAttr() bad uid %d for client %d uid %d",
-                          uid, client->portId(), client->uid());
-                    status = INVALID_OPERATION;
-                    goto error;
+                    return base::unexpected{Status::fromExceptionCode(
+                            EX_ILLEGAL_STATE,
+                            String8::format("%s bad uid %d for client %d uid %d", __func__, uid,
+                                            client->portId(), client->uid()))};
                 }
             }
         }
         *inputType = API_INPUT_LEGACY;
         device = inputDesc->getDevice();
-
-        ALOGV("%s reusing MMAP input %d for session %d", __FUNCTION__, *input, session);
-        goto exit;
-    }
-
-    *input = AUDIO_IO_HANDLE_NONE;
-    *inputType = API_INPUT_INVALID;
-
-    if (attributes.source == AUDIO_SOURCE_REMOTE_SUBMIX &&
-            extractAddressFromAudioAttributes(attributes).has_value()) {
-        status = mPolicyMixes.getInputMixForAttr(attributes, &policyMix);
-        if (status != NO_ERROR) {
-            ALOGW("%s could not find input mix for attr %s",
-                    __func__, toString(attributes).c_str());
-            goto error;
-        }
-        device = mAvailableInputDevices.getDevice(AUDIO_DEVICE_IN_REMOTE_SUBMIX,
-                                                  String8(attr->tags + strlen("addr=")),
-                                                  AUDIO_FORMAT_DEFAULT);
-        if (device == nullptr) {
-            ALOGW("%s could not find in Remote Submix device for source %d, tags %s",
-                    __func__, attributes.source, attributes.tags);
-            status = BAD_VALUE;
-            goto error;
-        }
-
-        if (is_mix_loopback_render(policyMix->mRouteFlags)) {
-            *inputType = API_INPUT_MIX_PUBLIC_CAPTURE_PLAYBACK;
-        } else {
-            *inputType = API_INPUT_MIX_EXT_POLICY_REROUTE;
-        }
-        if (virtualDeviceId) {
-            *virtualDeviceId = policyMix->mVirtualDeviceId;
-        }
+        ALOGV("%s reusing MMAP input %d for session %d", __FUNCTION__, requestedInput, session);
+        // TODO perm check
     } else {
-        if (explicitRoutingDevice != nullptr) {
-            device = explicitRoutingDevice;
+        *inputType = API_INPUT_INVALID;
+
+        if (attributes.source == AUDIO_SOURCE_REMOTE_SUBMIX &&
+                extractAddressFromAudioAttributes(attributes).has_value()) {
+            status_t status = mPolicyMixes.getInputMixForAttr(attributes, &policyMix);
+            if (status != NO_ERROR) {
+                ALOGW("%s could not find input mix for attr %s",
+                        __func__, toString(attributes).c_str());
+                return base::unexpected {aidl_utils::binderStatusFromStatusT(status)};
+            }
+            device = mAvailableInputDevices.getDevice(AUDIO_DEVICE_IN_REMOTE_SUBMIX,
+                                                      String8(attributes.tags + strlen("addr=")),
+                                                      AUDIO_FORMAT_DEFAULT);
+            if (device == nullptr) {
+                return base::unexpected{Status::fromExceptionCode(
+                        EX_ILLEGAL_ARGUMENT,
+                        String8::format(
+                                "%s could not find in Remote Submix device for source %d, tags %s",
+                                __func__, attributes.source, attributes.tags))};
+            }
+
+            if (is_mix_loopback_render(policyMix->mRouteFlags)) {
+                *inputType = API_INPUT_MIX_PUBLIC_CAPTURE_PLAYBACK;
+            } else {
+                *inputType = API_INPUT_MIX_EXT_POLICY_REROUTE;
+            }
+            // TODO is this correct?
+            vdi = policyMix->mVirtualDeviceId;
         } else {
-            // Prevent from storing invalid requested device id in clients
-            requestedDeviceId = AUDIO_PORT_HANDLE_NONE;
-            device = mEngine->getInputDeviceForAttributes(attributes, uid, session, &policyMix);
-            ALOGV_IF(device != nullptr, "%s found device type is 0x%X",
-                __FUNCTION__, device->type());
-        }
-        if (device == nullptr) {
-            ALOGW("getInputForAttr() could not find device for source %d", attributes.source);
-            status = BAD_VALUE;
-            goto error;
-        }
-        if (device->type() == AUDIO_DEVICE_IN_ECHO_REFERENCE) {
-            *inputType = API_INPUT_MIX_CAPTURE;
-        } else if (policyMix) {
-            ALOG_ASSERT(policyMix->mMixType == MIX_TYPE_RECORDERS, "Invalid Mix Type");
-            // there is an external policy, but this input is attached to a mix of recorders,
-            // 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;
+            if (explicitRoutingDevice != nullptr) {
+                device = explicitRoutingDevice;
+            } else {
+                // Prevent from storing invalid requested device id in clients
+                requestedDeviceId = AUDIO_PORT_HANDLE_NONE;
+                device = mEngine->getInputDeviceForAttributes(attributes, uid, session, &policyMix);
+                ALOGV_IF(device != nullptr, "%s found device type is 0x%X",
+                    __FUNCTION__, device->type());
             }
-        } else if (audio_is_remote_submix_device(device->type())) {
-            *inputType = API_INPUT_MIX_CAPTURE;
-        } else if (device->type() == AUDIO_DEVICE_IN_TELEPHONY_RX) {
-            *inputType = API_INPUT_TELEPHONY_RX;
-        } else {
-            *inputType = API_INPUT_LEGACY;
+            if (device == nullptr) {
+                return base::unexpected{Status::fromExceptionCode(
+                        EX_ILLEGAL_ARGUMENT,
+                        String8::format("%s could not find device for source %d", __func__,
+                                        attributes.source))};
+            }
+            if (device->type() == AUDIO_DEVICE_IN_ECHO_REFERENCE) {
+                *inputType = API_INPUT_MIX_CAPTURE;
+            } else if (policyMix) {
+                ALOG_ASSERT(policyMix->mMixType == MIX_TYPE_RECORDERS, "Invalid Mix Type");
+                // there is an external policy, but this input is attached to a mix of recorders,
+                // 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;
+                vdi = 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) {
+                *inputType = API_INPUT_TELEPHONY_RX;
+            } else {
+                *inputType = API_INPUT_LEGACY;
+            }
         }
 
+        // TODO perm check
+
+        input = getInputForDevice(device, session, attributes, config, flags, policyMix);
+        if (input == AUDIO_IO_HANDLE_NONE) {
+            AudioProfileVector profiles;
+            status_t ret = getProfilesForDevices(
+                    DeviceVector(device), profiles, flags, true /*isInput*/);
+            if (ret == NO_ERROR && !profiles.empty()) {
+                const auto channels = profiles[0]->getChannels();
+                if (!channels.empty() && (channels.find(config.channel_mask) == channels.end())) {
+                    config.channel_mask = *channels.begin();
+                }
+                const auto sampleRates = profiles[0]->getSampleRates();
+                if (!sampleRates.empty() &&
+                        (sampleRates.find(config.sample_rate) == sampleRates.end())) {
+                    config.sample_rate = *sampleRates.begin();
+                }
+                config.format = profiles[0]->getFormat();
+            }
+            const auto suggestedConfig = VALUE_OR_FATAL(
+                legacy2aidl_audio_config_base_t_AudioConfigBase(config, true /*isInput*/));
+            return base::unexpected {suggestedConfig};
+        }
     }
 
-    *input = getInputForDevice(device, session, attributes, config, flags, policyMix);
-    if (*input == AUDIO_IO_HANDLE_NONE) {
-        status = INVALID_OPERATION;
-        AudioProfileVector profiles;
-        status_t ret = getProfilesForDevices(
-                DeviceVector(device), profiles, flags, true /*isInput*/);
-        if (ret == NO_ERROR && !profiles.empty()) {
-            const auto channels = profiles[0]->getChannels();
-            if (!channels.empty() && (channels.find(config->channel_mask) == channels.end())) {
-                config->channel_mask = *channels.begin();
-            }
-            const auto sampleRates = profiles[0]->getSampleRates();
-            if (!sampleRates.empty() &&
-                    (sampleRates.find(config->sample_rate) == sampleRates.end())) {
-                config->sample_rate = *sampleRates.begin();
-            }
-            config->format = profiles[0]->getFormat();
-        }
-        goto error;
-    }
-
-
-    if (policyMix != nullptr && virtualDeviceId != nullptr) {
-        *virtualDeviceId = policyMix->mVirtualDeviceId;
-    }
-
-exit:
-
-    *selectedDeviceId = mAvailableInputDevices.contains(device) ?
+    auto selectedDeviceId = mAvailableInputDevices.contains(device) ?
                 device->getId() : AUDIO_PORT_HANDLE_NONE;
 
     isSoundTrigger = attributes.source == AUDIO_SOURCE_HOTWORD &&
         mSoundTriggerSessions.indexOfKey(session) >= 0;
-    *portId = PolicyAudioPort::getNextUniqueId();
 
-    clientDesc = new RecordClientDescriptor(*portId, riid, uid, session, attributes, *config,
+    const auto allocatedPortId = PolicyAudioPort::getNextUniqueId();
+
+    clientDesc = new RecordClientDescriptor(allocatedPortId, riid, uid, session, attributes, config,
                                             requestedDeviceId, attributes.source, flags,
                                             isSoundTrigger);
-    inputDesc = mInputs.valueFor(*input);
+    inputDesc = mInputs.valueFor(input);
     // Move (if found) effect for the client session to its input
-    mEffects.moveEffectsForIo(session, *input, &mInputs, mpClientInterface);
+    mEffects.moveEffectsForIo(session, input, &mInputs, mpClientInterface);
     inputDesc->addClient(clientDesc);
 
     ALOGV("getInputForAttr() returns input %d type %d selectedDeviceId %d for port ID %d",
-            *input, *inputType, *selectedDeviceId, *portId);
+            input, *inputType, selectedDeviceId, allocatedPortId);
 
-    return NO_ERROR;
-
-error:
-    return status;
+    auto ret = media::GetInputForAttrResponse {};
+    ret.input = input;
+    ret.selectedDeviceId = selectedDeviceId;
+    ret.portId = allocatedPortId;
+    ret.virtualDeviceId = vdi;
+    ret.config = legacy2aidl_audio_config_base_t_AudioConfigBase(config, true /*isInput*/).value();
+    return ret;
 }
 
-
-audio_io_handle_t AudioPolicyManager::getInputForDevice(const sp<DeviceDescriptor> &device,
+audio_io_handle_t AudioPolicyManager::getInputForDevice(const sp<DeviceDescriptor>& device,
                                                         audio_session_t session,
-                                                        const audio_attributes_t &attributes,
-                                                        audio_config_base_t *config,
+                                                        const audio_attributes_t& attributes,
+                                                        const audio_config_base_t& config,
                                                         audio_input_flags_t flags,
-                                                        const sp<AudioPolicyMix> &policyMix)
-{
+                                                        const sp<AudioPolicyMix>& policyMix) {
     audio_io_handle_t input = AUDIO_IO_HANDLE_NONE;
     audio_source_t halInputSource = attributes.source;
     bool isSoundTrigger = false;
@@ -3152,7 +3141,7 @@
             halInputSource = AUDIO_SOURCE_VOICE_RECOGNITION;
         }
     } else if (attributes.source == AUDIO_SOURCE_VOICE_COMMUNICATION &&
-               audio_is_linear_pcm(config->format)) {
+               audio_is_linear_pcm(config.format)) {
         flags = (audio_input_flags_t)(flags | AUDIO_INPUT_FLAG_VOIP_TX);
     }
 
@@ -3161,10 +3150,10 @@
     }
 
     // sampling rate and flags may be updated by getInputProfile
-    uint32_t profileSamplingRate = (config->sample_rate == 0) ?
-            SAMPLE_RATE_HZ_DEFAULT : config->sample_rate;
-    audio_format_t profileFormat = config->format;
-    audio_channel_mask_t profileChannelMask = config->channel_mask;
+    uint32_t profileSamplingRate = (config.sample_rate == 0) ?
+            SAMPLE_RATE_HZ_DEFAULT : config.sample_rate;
+    audio_format_t profileFormat = config.format;
+    audio_channel_mask_t profileChannelMask = config.channel_mask;
     audio_input_flags_t profileFlags = flags;
     // find a compatible input profile (not necessarily identical in parameters)
     sp<IOProfile> profile = getInputProfile(
@@ -3174,7 +3163,7 @@
     }
 
     // Pick input sampling rate if not specified by client
-    uint32_t samplingRate = config->sample_rate;
+    uint32_t samplingRate = config.sample_rate;
     if (samplingRate == 0) {
         samplingRate = profileSamplingRate;
     }