getInputForAttr perm check cleanup pt1

Pull permission checking logic out of main function.

No behavior changes for now.

Test: Compiles
Bug: 374870131
Bug: 343523722
Flag: EXEMPT mechanical refactoring
Change-Id: I3a3dc2b876612f63757570fd6fe9b2f9d5437fa9
diff --git a/media/libaudioclient/AudioSystem.cpp b/media/libaudioclient/AudioSystem.cpp
index b8dadb4..cfa3011 100644
--- a/media/libaudioclient/AudioSystem.cpp
+++ b/media/libaudioclient/AudioSystem.cpp
@@ -1379,13 +1379,14 @@
 
     media::GetInputForAttrResponse response;
 
-    status_t status = statusTFromBinderStatus(
-            aps->getInputForAttr(attrAidl, inputAidl, riidAidl, sessionAidl, attributionSource,
-                configAidl, flagsAidl, selectedDeviceIdAidl, &response));
-    if (status != NO_ERROR) {
+    const Status res = aps->getInputForAttr(attrAidl, inputAidl, riidAidl, sessionAidl,
+                                            attributionSource, configAidl, flagsAidl,
+                                            selectedDeviceIdAidl, &response);
+    if (!res.isOk()) {
+        ALOGE("getInputForAttr error: %s", res.toString8().c_str());
         *config = VALUE_OR_RETURN_STATUS(
                 aidl2legacy_AudioConfigBase_audio_config_base_t(response.config, true /*isInput*/));
-        return status;
+        return statusTFromBinderStatus(res);
     }
 
     *input = VALUE_OR_RETURN_STATUS(aidl2legacy_int32_t_audio_io_handle_t(response.input));
diff --git a/media/utils/ServiceUtilities.cpp b/media/utils/ServiceUtilities.cpp
index ee0f2bc..39a172f 100644
--- a/media/utils/ServiceUtilities.cpp
+++ b/media/utils/ServiceUtilities.cpp
@@ -77,15 +77,24 @@
     return packages[0];
 }
 
+// NOTE/TODO(b/379754682):
+// AUDIO_SOURCE_VOICE_DOWNLINK and AUDIO_SOURCE_VOICE_CALL are handled specially:
+// DOWNLINK is an output source, but we still require RecordOp in addition to
+// OP_RECORD_INCOMING_PHONE_AUDIO
+// CALL includes both uplink and downlink, but we attribute RECORD_OP (only), since
+// there is not support for noting multiple ops.
 int32_t getOpForSource(audio_source_t source) {
   switch (source) {
+    // BEGIN output sources
     case AUDIO_SOURCE_FM_TUNER:
         return AppOpsManager::OP_NONE;
     case AUDIO_SOURCE_ECHO_REFERENCE: // fallthrough
     case AUDIO_SOURCE_REMOTE_SUBMIX:
+        // TODO -- valid in all cases?
       return AppOpsManager::OP_RECORD_AUDIO_OUTPUT;
     case AUDIO_SOURCE_VOICE_DOWNLINK:
       return AppOpsManager::OP_RECORD_INCOMING_PHONE_AUDIO;
+    // END output sources
     case AUDIO_SOURCE_HOTWORD:
       return AppOpsManager::OP_RECORD_AUDIO_HOTWORD;
     case AUDIO_SOURCE_DEFAULT:
@@ -99,6 +108,7 @@
     case AUDIO_SOURCE_FM_TUNER:
     case AUDIO_SOURCE_ECHO_REFERENCE: // fallthrough
     case AUDIO_SOURCE_REMOTE_SUBMIX:
+    // case AUDIO_SOURCE_VOICE_DOWNLINK:
         return false;
     default:
       return true;
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index df7077c..20bc788 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -24,6 +24,7 @@
 #include <android/content/AttributionSourceState.h>
 #include <android_media_audiopolicy.h>
 #include <android_media_audio.h>
+#include <binder/Enums.h>
 #include <com_android_media_audio.h>
 #include <cutils/properties.h>
 #include <error/expected_utils.h>
@@ -51,6 +52,8 @@
 #define CHECK_PERM(expr1, expr2) \
     VALUE_OR_RETURN_STATUS(getPermissionProvider().checkPermission((expr1), (expr2)))
 
+#define PROPAGATE_FALSEY(val) do { if (!val.has_value() || !val.value()) return val; } while (0)
+
 #define MAX_ITEMS_PER_LIST 1024
 
 namespace android {
@@ -60,6 +63,7 @@
 using android::media::audio::concurrent_audio_record_bypass_permission;
 using com::android::media::audio::audioserver_permissions;
 using com::android::media::permission::NativePermissionController;
+using com::android::media::permission::PermissionEnum;
 using com::android::media::permission::PermissionEnum::ACCESS_ULTRASOUND;
 using com::android::media::permission::PermissionEnum::CALL_AUDIO_INTERCEPTION;
 using com::android::media::permission::PermissionEnum::CAPTURE_AUDIO_HOTWORD;
@@ -661,6 +665,146 @@
     mAudioPolicyManager->releaseOutput(portId);
 }
 
+// These are sources for which CAPTURE_AUDIO_OUTPUT granted access
+// for legacy reasons, before more specific permissions were deployed.
+// TODO: remove this access
+static bool isLegacyOutputSource(AudioSource source) {
+    switch (source) {
+        case AudioSource::VOICE_CALL:
+        case AudioSource::VOICE_DOWNLINK:
+        case AudioSource::VOICE_UPLINK:
+        case AudioSource::FM_TUNER:
+            return true;
+        default:
+            return false;
+    }
+}
+
+error::BinderResult<bool> AudioPolicyService::evaluatePermsForSource(
+        const AttributionSourceState& attrSource, AudioSource source, bool isHotword) {
+    error::BinderResult<bool> permRes = true;
+    const auto check_perm = [&](PermissionEnum perm, uid_t uid) {
+        return getPermissionProvider().checkPermission(perm, uid);
+    };
+    switch (source) {
+        case AudioSource::VOICE_UPLINK:
+        case AudioSource::VOICE_DOWNLINK:
+        case AudioSource::VOICE_CALL:
+            permRes = audioserver_permissions()
+                              ? check_perm(CALL_AUDIO_INTERCEPTION, attrSource.uid)
+                              : callAudioInterceptionAllowed(attrSource);
+            break;
+        case AudioSource::ECHO_REFERENCE:
+            permRes = audioserver_permissions() ? check_perm(CAPTURE_AUDIO_OUTPUT, attrSource.uid)
+                                                : captureAudioOutputAllowed(attrSource);
+            break;
+        case AudioSource::FM_TUNER:
+            permRes = audioserver_permissions()
+                              ? check_perm(CAPTURE_TUNER_AUDIO_INPUT, attrSource.uid)
+                              : captureTunerAudioInputAllowed(attrSource);
+            break;
+        case AudioSource::HOTWORD:
+            permRes = audioserver_permissions() ? check_perm(CAPTURE_AUDIO_HOTWORD, attrSource.uid)
+                                                : captureHotwordAllowed(attrSource);
+            break;
+        case AudioSource::ULTRASOUND:
+            permRes = audioserver_permissions() ? check_perm(ACCESS_ULTRASOUND, attrSource.uid)
+                                                : accessUltrasoundAllowed(attrSource);
+            break;
+        case AudioSource::SYS_RESERVED_INVALID:
+        case AudioSource::DEFAULT:
+        case AudioSource::MIC:
+        case AudioSource::CAMCORDER:
+        case AudioSource::VOICE_RECOGNITION:
+        case AudioSource::VOICE_COMMUNICATION:
+        case AudioSource::UNPROCESSED:
+        case AudioSource::VOICE_PERFORMANCE:
+            // No additional check intended
+        case AudioSource::REMOTE_SUBMIX:
+            // special-case checked based on device (evaluatePermsForDevice)
+            break;
+    }
+
+    bool isAllowed = VALUE_OR_RETURN(permRes);
+
+    if (!isAllowed) {
+        if (isLegacyOutputSource(source)) {
+            permRes = audioserver_permissions() ? check_perm(CAPTURE_AUDIO_OUTPUT, attrSource.uid)
+                                                : captureAudioOutputAllowed(attrSource);
+            PROPAGATE_FALSEY(permRes);
+        } else {
+            return false;
+        }
+    }
+
+    if (isHotword) {
+        permRes = audioserver_permissions() ? check_perm(CAPTURE_AUDIO_HOTWORD, attrSource.uid)
+                                            : captureHotwordAllowed(attrSource);
+        PROPAGATE_FALSEY(permRes);
+    }
+
+    // All sources which aren't output capture require RECORD as well,
+    // as well as vdi policy mix
+    const auto legacySource = aidl2legacy_AudioSource_audio_source_t(source).value();
+    if (isRecordOpRequired(legacySource)) {
+        permRes = audioserver_permissions() ? check_perm(RECORD_AUDIO, attrSource.uid)
+                                            : recordingAllowed(attrSource, legacySource);
+        PROPAGATE_FALSEY(permRes);
+    }
+    return true;
+}
+
+error::BinderResult<bool> AudioPolicyService::evaluatePermsForDevice(
+        const AttributionSourceState& attrSource, AudioSource source,
+        AudioPolicyInterface::input_type_t inputType, uint32_t vdi, bool isCallRedir) {
+    // enforce permission (if any) required for each type of input
+    error::BinderResult<bool> permRes = true;
+    const auto check_perm = [&](PermissionEnum perm, uid_t uid) {
+        return getPermissionProvider().checkPermission(perm, uid);
+    };
+    bool isAllowedDueToCallPerm = false;
+    if (isCallRedir) {
+        const auto checkCall = audioserver_permissions()
+                                       ? check_perm(CALL_AUDIO_INTERCEPTION, attrSource.uid)
+                                       : callAudioInterceptionAllowed(attrSource);
+        isAllowedDueToCallPerm = VALUE_OR_RETURN(checkCall);
+    }
+    switch (inputType) {
+        case AudioPolicyInterface::API_INPUT_MIX_PUBLIC_CAPTURE_PLAYBACK:
+            // this use case has been validated in audio service with a MediaProjection token,
+            // and doesn't rely on regular permissions
+        case AudioPolicyInterface::API_INPUT_LEGACY:
+            break;
+        case AudioPolicyInterface::API_INPUT_TELEPHONY_RX:
+            if (isAllowedDueToCallPerm) break;
+            // FIXME: use the same permission as for remote submix for now.
+            FALLTHROUGH_INTENDED;
+        case AudioPolicyInterface::API_INPUT_MIX_CAPTURE:
+            permRes = audioserver_permissions() ? check_perm(CAPTURE_AUDIO_OUTPUT, attrSource.uid)
+                                                : captureAudioOutputAllowed(attrSource);
+            break;
+        case AudioPolicyInterface::API_INPUT_MIX_EXT_POLICY_REROUTE: {
+            // TODO intended?
+            if (isAllowedDueToCallPerm) break;
+            permRes = audioserver_permissions() ? check_perm(MODIFY_AUDIO_ROUTING, attrSource.uid)
+                                                : modifyAudioRoutingAllowed(attrSource);
+            break;
+        }
+        case AudioPolicyInterface::API_INPUT_INVALID:
+        default:
+            LOG_ALWAYS_FATAL("%s encountered an invalid input type %d", __func__, (int)inputType);
+    }
+
+    PROPAGATE_FALSEY(permRes);
+
+    if (audiopolicy_flags::record_audio_device_aware_permission()) {
+        // enforce device-aware RECORD_AUDIO permission
+        const auto legacySource = aidl2legacy_AudioSource_audio_source_t(source).value();
+        return vdi == kDefaultVirtualDeviceId || recordingAllowed(attrSource, vdi, legacySource);
+    }
+    return true;
+}
+
 Status AudioPolicyService::getInputForAttr(const media::audio::common::AudioAttributes& attrAidl,
                                            int32_t inputAidl,
                                            int32_t riidAidl,
@@ -670,6 +814,7 @@
                                            int32_t flagsAidl,
                                            int32_t selectedDeviceIdAidl,
                                            media::GetInputForAttrResponse* _aidl_return) {
+    auto inputSource = attrAidl.source;
     audio_attributes_t attr = VALUE_OR_RETURN_BINDER_STATUS(
             aidl2legacy_AudioAttributes_audio_attributes_t(attrAidl));
     audio_io_handle_t input = VALUE_OR_RETURN_BINDER_STATUS(
@@ -694,49 +839,24 @@
     RETURN_IF_BINDER_ERROR(
             binderStatusFromStatusT(AudioValidator::validateAudioAttributes(attr, "68953950")));
 
-    audio_source_t inputSource = attr.source;
-    if (inputSource == AUDIO_SOURCE_DEFAULT) {
-        inputSource = AUDIO_SOURCE_MIC;
-    }
-
-    // already checked by client, but double-check in case the client wrapper is bypassed
-    if ((inputSource < AUDIO_SOURCE_DEFAULT)
-            || (inputSource >= AUDIO_SOURCE_CNT
-                && inputSource != AUDIO_SOURCE_HOTWORD
-                && inputSource != AUDIO_SOURCE_FM_TUNER
-                && inputSource != AUDIO_SOURCE_ECHO_REFERENCE
-                && inputSource != AUDIO_SOURCE_ULTRASOUND)) {
+    if (inputSource == AudioSource::SYS_RESERVED_INVALID ||
+            std::find(enum_range<AudioSource>().begin(), enum_range<AudioSource>().end(),
+                inputSource) == enum_range<AudioSource>().end()) {
         return binderStatusFromStatusT(BAD_VALUE);
     }
 
-    RETURN_IF_BINDER_ERROR(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:
-    // - FM_TUNER source is controlled by captureTunerAudioInputAllowed() or
-    // captureAudioOutputAllowed() (deprecated).
-    // - REMOTE_SUBMIX source is controlled by captureAudioOutputAllowed() if the input
-    // type is API_INPUT_MIX_EXT_POLICY_REROUTE and by AudioService if a media projection
-    // is used and input type is API_INPUT_MIX_PUBLIC_CAPTURE_PLAYBACK
-    // - ECHO_REFERENCE source is controlled by captureAudioOutputAllowed()
-    const auto isRecordingAllowed = audioserver_permissions() ?
-            CHECK_PERM(RECORD_AUDIO, attributionSource.uid) :
-            recordingAllowed(attributionSource, inputSource);
-    if (!(isRecordingAllowed
-            || inputSource == AUDIO_SOURCE_FM_TUNER
-            || inputSource == AUDIO_SOURCE_REMOTE_SUBMIX
-            || inputSource == AUDIO_SOURCE_ECHO_REFERENCE)) {
-        ALOGE("%s permission denied: recording not allowed for %s",
-                __func__, attributionSource.toString().c_str());
-        return binderStatusFromStatusT(PERMISSION_DENIED);
+    if (inputSource == AudioSource::DEFAULT) {
+        inputSource = AudioSource::MIC;
     }
 
-    bool canCaptureOutput = audioserver_permissions() ?
-                        CHECK_PERM(CAPTURE_AUDIO_OUTPUT, attributionSource.uid)
-                        : captureAudioOutputAllowed(attributionSource);
+    const bool isHotword = (flags & (AUDIO_INPUT_FLAG_HW_HOTWORD | AUDIO_INPUT_FLAG_HOTWORD_TAP |
+                        AUDIO_INPUT_FLAG_HW_LOOKBACK)) != 0;
+
+    const bool isCallRedir = (attr.flags & AUDIO_FLAG_CALL_REDIRECTION) != 0;
+
+    const bool canCaptureOutput = audioserver_permissions()
+                                ? CHECK_PERM(CAPTURE_AUDIO_OUTPUT, attributionSource.uid)
+                                : captureAudioOutputAllowed(attributionSource);
 
     //TODO(b/374751406): remove forcing canBypassConcurrentPolicy to canCaptureOutput
     // once all system apps using CAPTURE_AUDIO_OUTPUT to capture during calls
@@ -748,53 +868,20 @@
                                        attributionSource.uid)
                             : bypassConcurrentPolicyAllowed(attributionSource);
     }
-    bool canInterceptCallAudio = audioserver_permissions() ?
-                        CHECK_PERM(CALL_AUDIO_INTERCEPTION, attributionSource.uid)
-                        : callAudioInterceptionAllowed(attributionSource);
-    bool isCallAudioSource = inputSource == AUDIO_SOURCE_VOICE_UPLINK
-             || inputSource == AUDIO_SOURCE_VOICE_DOWNLINK
-             || inputSource == AUDIO_SOURCE_VOICE_CALL;
 
-    if (isCallAudioSource && !canInterceptCallAudio && !canCaptureOutput) {
-        return binderStatusFromStatusT(PERMISSION_DENIED);
-    }
-    if (inputSource == AUDIO_SOURCE_ECHO_REFERENCE
-            && !canCaptureOutput) {
-        return binderStatusFromStatusT(PERMISSION_DENIED);
-    }
-    if (inputSource == AUDIO_SOURCE_FM_TUNER
-        && !canCaptureOutput
-        && !(audioserver_permissions() ?
-                        CHECK_PERM(CAPTURE_TUNER_AUDIO_INPUT, attributionSource.uid)
-            : captureTunerAudioInputAllowed(attributionSource))) {
-        return binderStatusFromStatusT(PERMISSION_DENIED);
+    const bool hasPerm = VALUE_OR_RETURN_STATUS(evaluatePermsForSource(
+                attributionSource,
+                inputSource,
+                isHotword));
+
+    if (!hasPerm) {
+        return Status::fromExceptionCode(
+                EX_SECURITY, String8::format("%s: %s missing perms for source %s", __func__,
+                                             attributionSource.toString().c_str(),
+                                             toString(inputSource).c_str()));
     }
 
-    bool canCaptureHotword = audioserver_permissions() ?
-                        CHECK_PERM(CAPTURE_AUDIO_HOTWORD, attributionSource.uid)
-                        : captureHotwordAllowed(attributionSource);
-    if ((inputSource == AUDIO_SOURCE_HOTWORD) && !canCaptureHotword) {
-        return binderStatusFromStatusT(PERMISSION_DENIED);
-    }
-
-    if (((flags & (AUDIO_INPUT_FLAG_HW_HOTWORD |
-                        AUDIO_INPUT_FLAG_HOTWORD_TAP |
-                        AUDIO_INPUT_FLAG_HW_LOOKBACK)) != 0)
-            && !canCaptureHotword) {
-        ALOGE("%s: permission denied: hotword mode not allowed"
-              " for uid %d pid %d", __func__, attributionSource.uid, attributionSource.pid);
-        return binderStatusFromStatusT(PERMISSION_DENIED);
-    }
-
-    if (attr.source == AUDIO_SOURCE_ULTRASOUND) {
-        if (!(audioserver_permissions() ?
-                CHECK_PERM(ACCESS_ULTRASOUND, attributionSource.uid)
-                : accessUltrasoundAllowed(attributionSource))) {
-            ALOGE("%s: permission denied: ultrasound not allowed for uid %d pid %d",
-                    __func__, attributionSource.uid, attributionSource.pid);
-            return binderStatusFromStatusT(PERMISSION_DENIED);
-        }
-    }
+    uint32_t virtualDeviceId = kDefaultVirtualDeviceId;
 
     sp<AudioPolicyEffects>audioPolicyEffects;
     {
@@ -815,72 +902,29 @@
         audioPolicyEffects = mAudioPolicyEffects;
 
         if (status == NO_ERROR) {
-            // enforce permission (if any) required for each type of input
-            switch (inputType) {
-            case AudioPolicyInterface::API_INPUT_MIX_PUBLIC_CAPTURE_PLAYBACK:
-                // this use case has been validated in audio service with a MediaProjection token,
-                // and doesn't rely on regular permissions
-            case AudioPolicyInterface::API_INPUT_LEGACY:
-                break;
-            case AudioPolicyInterface::API_INPUT_TELEPHONY_RX:
-                if ((attr.flags & AUDIO_FLAG_CALL_REDIRECTION) != 0
-                        && canInterceptCallAudio) {
-                    break;
-                }
-                // FIXME: use the same permission as for remote submix for now.
-                FALLTHROUGH_INTENDED;
-            case AudioPolicyInterface::API_INPUT_MIX_CAPTURE:
-                if (!canCaptureOutput) {
-                    ALOGE("%s permission denied: capture not allowed", __func__);
-                    status = PERMISSION_DENIED;
-                }
-                break;
-            case AudioPolicyInterface::API_INPUT_MIX_EXT_POLICY_REROUTE: {
-                bool modAudioRoutingAllowed;
-                if (audioserver_permissions()) {
-                        auto result = getPermissionProvider().checkPermission(
-                                MODIFY_AUDIO_ROUTING, attributionSource.uid);
-                        if (!result.ok()) {
-                            ALOGE("%s permission provider error: %s", __func__,
-                                    result.error().toString8().c_str());
-                            status = aidl_utils::statusTFromBinderStatus(result.error());
-                            break;
-                        }
-                        modAudioRoutingAllowed = result.value();
-                } else {
-                    modAudioRoutingAllowed = modifyAudioRoutingAllowed(attributionSource);
-                }
-                if (!(modAudioRoutingAllowed
-                        || ((attr.flags & AUDIO_FLAG_CALL_REDIRECTION) != 0
-                            && canInterceptCallAudio))) {
-                    ALOGE("%s permission denied for remote submix capture", __func__);
-                    status = PERMISSION_DENIED;
-                }
-                break;
-            }
-            case AudioPolicyInterface::API_INPUT_INVALID:
-            default:
-                LOG_ALWAYS_FATAL("%s encountered an invalid input type %d",
-                        __func__, (int)inputType);
-            }
+            const auto permResult = evaluatePermsForDevice(attributionSource,
+                    inputSource, inputType, virtualDeviceId,
+                    isCallRedir);
 
-            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 (!permResult.has_value()) {
+                AutoCallerClear acc;
+                mAudioPolicyManager->releaseInput(portId);
+                return permResult.error();
+            } else if (!permResult.value()) {
+                AutoCallerClear acc;
+                mAudioPolicyManager->releaseInput(portId);
+                return Status::fromExceptionCode(
+                        EX_SECURITY,
+                        String8::format(
+                                "%s: %s missing perms for input type %d, inputSource %d, vdi %d",
+                                __func__, attributionSource.toString().c_str(), inputType,
+                                inputSource, virtualDeviceId));
             }
         }
 
         if (status != NO_ERROR) {
-            if (status == PERMISSION_DENIED) {
-                AutoCallerClear acc;
-                mAudioPolicyManager->releaseInput(portId);
-            } else {
-                _aidl_return->config = VALUE_OR_RETURN_BINDER_STATUS(
-                        legacy2aidl_audio_config_base_t_AudioConfigBase(config, true /*isInput*/));
-            }
+            _aidl_return->config = VALUE_OR_RETURN_BINDER_STATUS(
+                    legacy2aidl_audio_config_base_t_AudioConfigBase(config, true /*isInput*/));
             return binderStatusFromStatusT(status);
         }
 
@@ -889,14 +933,14 @@
                                                              selectedDeviceIds, attributionSource,
                                                              virtualDeviceId,
                                                              canBypassConcurrentPolicy,
-                                                             canCaptureHotword,
                                                              mOutputCommandThread);
         mAudioRecordClients.add(portId, client);
     }
 
     if (audioPolicyEffects != 0) {
         // create audio pre processors according to input source
-        status_t status = audioPolicyEffects->addInputEffects(input, inputSource, session);
+        status_t status = audioPolicyEffects->addInputEffects(input,
+                aidl2legacy_AudioSource_audio_source_t(inputSource).value(), session);
         if (status != NO_ERROR && status != ALREADY_EXISTS) {
             ALOGW("Failed to add effects on input %d", input);
         }
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index eeac9a6..5fe200c 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -504,6 +504,14 @@
                             const audio_output_flags_t flags);
     status_t unregisterOutput(audio_io_handle_t output);
 
+    error::BinderResult<bool> evaluatePermsForSource(const AttributionSourceState& attrSource,
+                                                     AudioSource source, bool isHotword);
+
+    error::BinderResult<bool> evaluatePermsForDevice(const AttributionSourceState& attrSource,
+                                                     AudioSource source,
+                                                     AudioPolicyInterface::input_type_t inputType,
+                                                     uint32_t vdi, bool isCallRedir);
+
     // If recording we need to make sure the UID is allowed to do that. If the UID is idle
     // then it cannot record and gets buffers with zeros - silence. As soon as the UID
     // transitions to an active state we will start reporting buffers with data. This approach
diff --git a/services/audiopolicy/service/AudioRecordClient.h b/services/audiopolicy/service/AudioRecordClient.h
index 2135575..f45b4de 100644
--- a/services/audiopolicy/service/AudioRecordClient.h
+++ b/services/audiopolicy/service/AudioRecordClient.h
@@ -90,14 +90,13 @@
                       const DeviceIdVector deviceIds,
                       const AttributionSourceState& attributionSource,
                       const uint32_t virtualDeviceId,
-                      bool canBypassConcurrentPolicy, bool canCaptureHotword,
+                      bool canBypassConcurrentPolicy,
                       wp<AudioPolicyService::AudioCommandThread> commandThread) :
                 AudioClient(attributes, io, attributionSource,
                     session, portId, deviceIds), attributionSource(attributionSource),
                     virtualDeviceId(virtualDeviceId),
                     startTimeNs(0), canBypassConcurrentPolicy(canBypassConcurrentPolicy),
-                    canCaptureHotword(canCaptureHotword), silenced(false),
-                    mOpRecordAudioMonitor(
+                    silenced(false), mOpRecordAudioMonitor(
                             OpRecordAudioMonitor::createIfNeeded(attributionSource,
                                                                  virtualDeviceId,
                                                                  attributes, commandThread)) {
@@ -113,7 +112,6 @@
     const uint32_t virtualDeviceId; // id of the virtual device associated with the audio device
     nsecs_t startTimeNs;
     const bool canBypassConcurrentPolicy;
-    const bool canCaptureHotword;
     bool silenced;
 
 private: