From 381a86a03e317985fa3b7161d24c502439a8d8be Mon Sep 17 00:00:00 2001 From: Atneya Nair Date: Fri, 27 Jun 2025 16:36:46 -0700 Subject: [PATCH 1/2] [RESTRICT AUTOMERGE] Validate full attr chain for recording We currently only re-validate and listen for changes in the top of the attr chain. Listen across the whole chain, and compute the appop state from the whole chain. Test: atest CtsMediaAudioPermissionTestCases Bug: 325912429 Flag: EXEMPT security (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:0a052f3a8290f516f150923a2469114351cc40f3) (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:bc6633b6b945c46f9ef18ee53eb122587437a1e6) Merged-In: I4af2bbb7ecd3c5450115400c7d5fac63056dc0b8 Change-Id: I4af2bbb7ecd3c5450115400c7d5fac63056dc0b8 --- .../audiopolicy/service/AudioRecordClient.cpp | 98 +++++++++++++++---- 1 file changed, 77 insertions(+), 21 deletions(-) diff --git a/services/audiopolicy/service/AudioRecordClient.cpp b/services/audiopolicy/service/AudioRecordClient.cpp index a89a84d7d4..491532ac61 100644 --- a/services/audiopolicy/service/AudioRecordClient.cpp +++ b/services/audiopolicy/service/AudioRecordClient.cpp @@ -18,14 +18,16 @@ #include "AudioRecordClient.h" #include "AudioPolicyService.h" +#include "binder/AppOpsManager.h" + +#include namespace android::media::audiopolicy { using android::AudioPolicyService; namespace { -bool isAppOpSource(audio_source_t source) -{ +bool isAppOpSource(audio_source_t source) { switch (source) { case AUDIO_SOURCE_FM_TUNER: case AUDIO_SOURCE_ECHO_REFERENCE: @@ -54,7 +56,46 @@ int getTargetSdkForPackageName(std::string_view packageName) { bool doesPackageTargetAtLeastU(std::string_view packageName) { return getTargetSdkForPackageName(packageName) >= __ANDROID_API_U__; } -} + +class AttrSourceItr { + public: + using iterator_category = std::forward_iterator_tag; + using difference_type = std::ptrdiff_t; + using value_type = AttributionSourceState; + using pointer = const value_type*; + using reference = const value_type&; + + AttrSourceItr() : mAttr(nullptr) {} + + AttrSourceItr(const AttributionSourceState& attr) : mAttr(&attr) {} + + reference operator*() const { return *mAttr; } + pointer operator->() const { return mAttr; } + + AttrSourceItr& operator++() { + mAttr = !mAttr->next.empty() ? mAttr->next.data() : nullptr; + return *this; + } + + AttrSourceItr operator++(int) { + AttrSourceItr tmp = *this; + ++(*this); + return tmp; + } + + friend bool operator==(const AttrSourceItr& a, const AttrSourceItr& b) { + return a.mAttr == b.mAttr; + } + + friend bool operator!=(const AttrSourceItr& a, const AttrSourceItr& b) { + return !operator==(a, b); + } + + static AttrSourceItr end() { return AttrSourceItr{}; } +private: + const AttributionSourceState * mAttr; +}; +} // anonymous // static sp @@ -103,15 +144,24 @@ void OpRecordAudioMonitor::onFirstRef() mOpCallback = new RecordAudioOpCallback(this); ALOGV("start watching op %d for %s", mAppOp, mAttributionSource.toString().c_str()); - int flags = doesPackageTargetAtLeastU( - mAttributionSource.packageName.value_or("")) ? - AppOpsManager::WATCH_FOREGROUND_CHANGES : 0; - // TODO: We need to always watch AppOpsManager::OP_RECORD_AUDIO too - // since it controls the mic permission for legacy apps. - mAppOpsManager.startWatchingMode(mAppOp, VALUE_OR_FATAL(aidl2legacy_string_view_String16( - mAttributionSource.packageName.value_or(""))), - flags, - mOpCallback); + int flags = doesPackageTargetAtLeastU(mAttributionSource.packageName.value_or("")) + ? AppOpsManager::WATCH_FOREGROUND_CHANGES + : 0; + + const auto reg = [&](int32_t op) { + std::for_each(AttrSourceItr{mAttributionSource}, AttrSourceItr::end(), + [&](const auto& attr) { + mAppOpsManager.startWatchingMode( + op, + VALUE_OR_FATAL(aidl2legacy_string_view_String16( + attr.packageName.value_or(""))), + flags, mOpCallback); + }); + }; + reg(mAppOp); + if (mAppOp != AppOpsManager::OP_RECORD_AUDIO) { + reg(AppOpsManager::OP_RECORD_AUDIO); + } } bool OpRecordAudioMonitor::hasOp() const { @@ -124,14 +174,20 @@ bool OpRecordAudioMonitor::hasOp() const { // due to the UID in createIfNeeded(). As a result for those record track, it's: // - not called from constructor, // - not called from RecordAudioOpCallback because the callback is not installed in this case -void OpRecordAudioMonitor::checkOp(bool updateUidStates) -{ - // TODO: We need to always check AppOpsManager::OP_RECORD_AUDIO too - // since it controls the mic permission for legacy apps. - 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); +void OpRecordAudioMonitor::checkOp(bool updateUidStates) { + const auto check = [&](int32_t op) -> bool { + return std::all_of( + AttrSourceItr{mAttributionSource}, AttrSourceItr::end(), [&](const auto& x) { + return mAppOpsManager.checkOp(op, x.uid, + VALUE_OR_FATAL(aidl2legacy_string_view_String16( + x.packageName.value_or("")))) == + AppOpsManager::MODE_ALLOWED; + }); + }; + bool hasIt = check(mAppOp); + if (mAppOp != AppOpsManager::OP_RECORD_AUDIO) { + hasIt = hasIt && check(AppOpsManager::OP_RECORD_AUDIO); + } // verbose logging only log when appOp changed ALOGI_IF(hasIt != mHasOp.load(), "App op %d missing, %ssilencing record %s", @@ -161,4 +217,4 @@ void OpRecordAudioMonitor::RecordAudioOpCallback::opChanged(int32_t op, } } -} // android::media::audiopolicy::internal +} // namespace android::media::audiopolicy -- GitLab From 5730d9b21ec56824c820d5283fcb6caa24758eca Mon Sep 17 00:00:00 2001 From: Atneya Nair Date: Mon, 30 Jun 2025 21:34:05 -0700 Subject: [PATCH 2/2] [RESTRICT AUTOMERGE] Fix audio AppOps refcount mismatch Iea630bb2bf1b54697ab6a95ee9f65db5cc4d134a I8a3498a08a31543219279cb063c043fd0c767cd7 The state of the appop corresponding to a recording must be consistent with the APS notion of whether a recording is silenced. Ensure that when we start recording, we only un-silence the track if the op is allowed from the appop side. This requires plumbing the exact perm state through the startRecording API. Correctly handle virtual sources by checking only their associated op state, rather than OP_RECORD. Update the appop callback listening/handling as well, by only listening/evaluating OP_RECORD for relevant sources. Ie7d2661b4027b5ce6bee9b6c63b70f0b120dcbcc When AppOp restrictions are in place, starting an op will return SOFT_DENY, but leave the op in a paused state, which can restart unexpectedly when the restriction is removed (despite no data delivery occurring). Work around this by first checking if recording is restricted, and avoiding the start call in that case. Instead, use a note call in order to maintain a rejected op for listeners (for prompting the mic unblock dialogue). Idd4389e7e79ee819c29ec2676d2e22d5a4b12249 Un-require RECORD_OP for VOICE_DOWNLINK Ibc735ea463aa6e09f8a24fc3cb50c39b70bbbea8 Handle targetSdk failures for recording Test: atest CtsMediaAudioPermissionTestCases Test: atest CtsMediaAudioTestCases Test: atest RuntimePermissionsAppOpTrackingTest Test: atest SensorPrivacyMicrophoneTest Test: atest AppOpsControllerTest Test: atest AudioPlaybackCaptureTest with mic blocked Test: sts-tradefed run sts-dynamic-develop -m \ CtsMediaAudioPermissionTestCases Test: manual oboetester app recording in background silenced Test: manual recorder with mic toggle disabled no indicator Test: manual poc Bug: 293603271 Flag: EXEMPT security (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:d39c3d158e625701341a24f7eeabc10650256083) (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:26ab27a9b41f4c69b18e1fddd08dce75dd3e2b80) Merged-In: Iea630bb2bf1b54697ab6a95ee9f65db5cc4d134a Change-Id: Iea630bb2bf1b54697ab6a95ee9f65db5cc4d134a --- media/utils/ServiceUtilities.cpp | 143 +++++++++++++----- .../include/mediautils/ServiceUtilities.h | 4 +- .../service/AudioPolicyInterfaceImpl.cpp | 38 +++-- .../service/AudioPolicyService.cpp | 10 +- .../audiopolicy/service/AudioRecordClient.cpp | 26 ++-- .../audiopolicy/service/AudioRecordClient.h | 4 +- 6 files changed, 158 insertions(+), 67 deletions(-) diff --git a/media/utils/ServiceUtilities.cpp b/media/utils/ServiceUtilities.cpp index c4f28082c8..bb6e8515f1 100644 --- a/media/utils/ServiceUtilities.cpp +++ b/media/utils/ServiceUtilities.cpp @@ -40,6 +40,11 @@ namespace android { +namespace { +constexpr auto PERMISSION_GRANTED = permission::PermissionChecker::PERMISSION_GRANTED; +constexpr auto PERMISSION_HARD_DENIED = permission::PermissionChecker::PERMISSION_HARD_DENIED; +} + using content::AttributionSourceState; static const String16 sAndroidPermissionRecordAudio("android.permission.RECORD_AUDIO"); @@ -71,19 +76,33 @@ static String16 resolveCallingPackage(PermissionController& permissionController int32_t getOpForSource(audio_source_t source) { switch (source) { - case AUDIO_SOURCE_HOTWORD: - return AppOpsManager::OP_RECORD_AUDIO_HOTWORD; + case AUDIO_SOURCE_FM_TUNER: + return AppOpsManager::OP_NONE; case AUDIO_SOURCE_ECHO_REFERENCE: // fallthrough case AUDIO_SOURCE_REMOTE_SUBMIX: return AppOpsManager::OP_RECORD_AUDIO_OUTPUT; case AUDIO_SOURCE_VOICE_DOWNLINK: return AppOpsManager::OP_RECORD_INCOMING_PHONE_AUDIO; + case AUDIO_SOURCE_HOTWORD: + return AppOpsManager::OP_RECORD_AUDIO_HOTWORD; case AUDIO_SOURCE_DEFAULT: default: return AppOpsManager::OP_RECORD_AUDIO; } } +bool isRecordOpRequired(audio_source_t source) { + switch (source) { + 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; + } +} + std::optional resolveAttributionSource( const AttributionSourceState& callerAttributionSource) { AttributionSourceState nextAttributionSource = callerAttributionSource; @@ -113,7 +132,7 @@ std::optional resolveAttributionSource( return std::optional{myAttributionSource}; } -static bool checkRecordingInternal(const AttributionSourceState& attributionSource, +static int checkRecordingInternal(const AttributionSourceState& attributionSource, 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. @@ -121,39 +140,74 @@ static bool checkRecordingInternal(const AttributionSourceState& attributionSour // user is active, but it is a core system service so let it through. // TODO(b/141210120): UserManager.DISALLOW_RECORD_AUDIO should not affect system user 0 uid_t uid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(attributionSource.uid)); - if (isAudioServerOrMediaServerOrSystemServerOrRootUid(uid)) return true; - - // 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 resolvedAttributionSource = - resolveAttributionSource(attributionSource); - if (!resolvedAttributionSource.has_value()) { - return false; - } + if (isAudioServerOrMediaServerOrSystemServerOrRootUid(uid)) return PERMISSION_GRANTED; const int32_t attributedOpCode = getOpForSource(source); + if (isRecordOpRequired(source)) { + // 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. + std::optional resolvedAttributionSource = + resolveAttributionSource(attributionSource); + if (!resolvedAttributionSource.has_value()) { + return PERMISSION_HARD_DENIED; + } - permission::PermissionChecker permissionChecker; - bool permitted = false; - if (start) { - permitted = (permissionChecker.checkPermissionForStartDataDeliveryFromDatasource( - sAndroidPermissionRecordAudio, resolvedAttributionSource.value(), msg, - attributedOpCode) != permission::PermissionChecker::PERMISSION_HARD_DENIED); + permission::PermissionChecker permissionChecker; + int permitted; + if (start) { + // Do a double-check, where we first check without actually starting in order to handle + // the behavior of AppOps where ops are sometimes started but paused for SOFT_DENIED. + // Since there is no way to maintain reference consensus due to this behavior, avoid + // starting an op when a restriction is in place by first checking. In the case where we + // startOp would fail, call a noteOp (which will also fail) instead. This preserves + // behavior that is reliant on listening to op rejected events (such as the hint + // dialogue to unmute the microphone). Technically racy, but very unlikely. + // + // TODO(b/294609684) To be removed when the pause state for an OP is removed. + permitted = permissionChecker.checkPermissionForPreflightFromDatasource( + sAndroidPermissionRecordAudio, resolvedAttributionSource.value(), msg, + attributedOpCode); + if (permitted == PERMISSION_GRANTED) { + permitted = permissionChecker.checkPermissionForStartDataDeliveryFromDatasource( + sAndroidPermissionRecordAudio, resolvedAttributionSource.value(), msg, + attributedOpCode); + } else { + // intentionally don't set permitted + permissionChecker.checkPermissionForDataDeliveryFromDatasource( + sAndroidPermissionRecordAudio, resolvedAttributionSource.value(), msg, + attributedOpCode); + } + } else { + permitted = permissionChecker.checkPermissionForPreflightFromDatasource( + sAndroidPermissionRecordAudio, resolvedAttributionSource.value(), msg, + attributedOpCode); + } + + return permitted; } else { - permitted = (permissionChecker.checkPermissionForPreflightFromDatasource( - sAndroidPermissionRecordAudio, resolvedAttributionSource.value(), msg, - attributedOpCode) != permission::PermissionChecker::PERMISSION_HARD_DENIED); + if (attributedOpCode == AppOpsManager::OP_NONE) return PERMISSION_GRANTED; // nothing to do + AppOpsManager ap{}; + PermissionController pc{}; + return ap.startOpNoThrow( + attributedOpCode, attributionSource.uid, + resolveCallingPackage(pc, + String16{attributionSource.packageName.value_or("").c_str()}, + attributionSource.uid), + false, + attributionSource.attributionTag.has_value() + ? String16{attributionSource.attributionTag.value().c_str()} + : String16{}, + msg); } - - return permitted; } bool recordingAllowed(const AttributionSourceState& attributionSource, audio_source_t source) { - return checkRecordingInternal(attributionSource, String16(), /*start*/ false, source); + return checkRecordingInternal(attributionSource, String16(), /*start*/ false, source) != + PERMISSION_HARD_DENIED; } -bool startRecording(const AttributionSourceState& attributionSource, const String16& msg, +int startRecording(const AttributionSourceState& attributionSource, const String16& msg, audio_source_t source) { return checkRecordingInternal(attributionSource, msg, /*start*/ true, source); } @@ -164,19 +218,32 @@ void finishRecording(const AttributionSourceState& attributionSource, audio_sour uid_t uid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(attributionSource.uid)); if (isAudioServerOrMediaServerOrSystemServerOrRootUid(uid)) return; - // 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 resolvedAttributionSource = - resolveAttributionSource(attributionSource); - if (!resolvedAttributionSource.has_value()) { - return; - } - const int32_t attributedOpCode = getOpForSource(source); - permission::PermissionChecker permissionChecker; - permissionChecker.finishDataDeliveryFromDatasource(attributedOpCode, - resolvedAttributionSource.value()); + if (isRecordOpRequired(source)) { + // 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 resolvedAttributionSource = + resolveAttributionSource(attributionSource); + if (!resolvedAttributionSource.has_value()) { + return; + } + + permission::PermissionChecker permissionChecker; + permissionChecker.finishDataDeliveryFromDatasource(attributedOpCode, + resolvedAttributionSource.value()); + } else { + if (attributedOpCode == AppOpsManager::OP_NONE) return; // nothing to do + AppOpsManager ap{}; + PermissionController pc{}; + ap.finishOp(attributedOpCode, attributionSource.uid, + resolveCallingPackage( + pc, String16{attributionSource.packageName.value_or("").c_str()}, + attributionSource.uid), + attributionSource.attributionTag.has_value() + ? String16{attributionSource.attributionTag.value().c_str()} + : String16{}); + } } bool captureAudioOutputAllowed(const AttributionSourceState& attributionSource) { diff --git a/media/utils/include/mediautils/ServiceUtilities.h b/media/utils/include/mediautils/ServiceUtilities.h index 0b3a3f96cd..b1746607c7 100644 --- a/media/utils/include/mediautils/ServiceUtilities.h +++ b/media/utils/include/mediautils/ServiceUtilities.h @@ -87,7 +87,7 @@ static inline bool isAudioServerOrMediaServerUid(uid_t uid) { bool recordingAllowed(const AttributionSourceState& attributionSource, audio_source_t source = AUDIO_SOURCE_DEFAULT); -bool startRecording(const AttributionSourceState& attributionSource, +int startRecording(const AttributionSourceState& attributionSource, const String16& msg, audio_source_t source); void finishRecording(const AttributionSourceState& attributionSource, audio_source_t source); std::optional resolveAttributionSource( @@ -114,6 +114,8 @@ void anonymizeBluetoothAddress(char *address); int32_t getOpForSource(audio_source_t source); +bool isRecordOpRequired(audio_source_t source); + AttributionSourceState getCallingAttributionSource(); status_t checkIMemory(const sp& iMemory); diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp index 19510456cc..d41a12acff 100644 --- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp +++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp @@ -62,6 +62,11 @@ using media::audio::common::AudioUsage; using media::audio::common::AudioUuid; using media::audio::common::Int; +namespace { +constexpr auto PERMISSION_HARD_DENIED = permission::PermissionChecker::PERMISSION_HARD_DENIED; +constexpr auto PERMISSION_GRANTED = permission::PermissionChecker::PERMISSION_GRANTED; +} + const std::vector& SYSTEM_USAGES = { AUDIO_USAGE_CALL_ASSISTANT, AUDIO_USAGE_EMERGENCY, @@ -807,13 +812,12 @@ Status AudioPolicyService::startInput(int32_t portIdAidl) std::stringstream msg; msg << "Audio recording on session " << client->session; + const auto permitted = startRecording(client->attributionSource, String16(msg.str().c_str()), + client->attributes.source); + // check calling permissions if (!isAudioServerOrMediaServerUid(client->attributionSource.uid) - && !(startRecording(client->attributionSource, String16(msg.str().c_str()), - client->attributes.source) - || client->attributes.source == AUDIO_SOURCE_FM_TUNER - || client->attributes.source == AUDIO_SOURCE_REMOTE_SUBMIX - || client->attributes.source == AUDIO_SOURCE_ECHO_REFERENCE)) { + && permitted == PERMISSION_HARD_DENIED) { ALOGE("%s permission denied: recording not allowed for attribution source %s", __func__, client->attributionSource.toString().c_str()); return binderStatusFromStatusT(PERMISSION_DENIED); @@ -832,13 +836,17 @@ Status AudioPolicyService::startInput(int32_t portIdAidl) return binderStatusFromStatusT(INVALID_OPERATION); } - // Force the possibly silenced client to be unsilenced since we just called - // startRecording (i.e. we have assumed it is unsilenced). - // At this point in time, the client is inactive, so no calls to appops are sent in - // setAppState_l. - // This ensures existing clients have the same behavior as new clients (starting unsilenced). + // Force the possibly silenced client to match the state on the appops side + // following the call to startRecording (i.e. unsilenced iff call succeeded) + // At this point in time, the client is inactive, so no calls to appops are + // sent in setAppState_l. This ensures existing clients have the same + // behavior as new clients. // TODO(b/282076713) - setAppState_l(client, APP_STATE_TOP); + if (permitted == PERMISSION_GRANTED) { + setAppState_l(client, APP_STATE_TOP); + } else { + setAppState_l(client, APP_STATE_IDLE); + } client->active = true; client->startTimeNs = systemTime(); @@ -924,7 +932,9 @@ Status AudioPolicyService::startInput(int32_t portIdAidl) client->active = false; client->startTimeNs = 0; updateUidStates_l(); - finishRecording(client->attributionSource, client->attributes.source); + if (!client->silenced) { + finishRecording(client->attributionSource, client->attributes.source); + } } return binderStatusFromStatusT(status); @@ -953,7 +963,9 @@ Status AudioPolicyService::stopInput(int32_t portIdAidl) updateUidStates_l(); // finish the recording app op - finishRecording(client->attributionSource, client->attributes.source); + if (!client->silenced) { + finishRecording(client->attributionSource, client->attributes.source); + } AutoCallerClear acc; return binderStatusFromStatusT(mAudioPolicyManager->stopInput(portId)); } diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp index e95147edba..728cc42448 100644 --- a/services/audiopolicy/service/AudioPolicyService.cpp +++ b/services/audiopolicy/service/AudioPolicyService.cpp @@ -64,6 +64,10 @@ static const nsecs_t kAudioCommandTimeoutNs = seconds(3); // 3 seconds static const String16 sManageAudioPolicyPermission("android.permission.MANAGE_AUDIO_POLICY"); +namespace { +constexpr auto PERMISSION_GRANTED = permission::PermissionChecker::PERMISSION_GRANTED; +} + // Creates an association between Binder code to name for IAudioPolicyService. #define IAUDIOPOLICYSERVICE_BINDER_METHOD_MACRO_LIST \ BINDER_METHOD_ENTRY(onNewAudioModulesAvailable) \ @@ -1196,9 +1200,9 @@ void AudioPolicyService::setAppState_l(sp client, app_state_t } else { std::stringstream msg; msg << "Audio recording un-silenced on session " << client->session; - if (!startRecording(client->attributionSource, String16(msg.str().c_str()), - client->attributes.source)) { - silenced = true; + if (startRecording(client->attributionSource, String16(msg.str().c_str()), + client->attributes.source) != PERMISSION_GRANTED) { + return; } } } diff --git a/services/audiopolicy/service/AudioRecordClient.cpp b/services/audiopolicy/service/AudioRecordClient.cpp index 491532ac61..00b43a85ba 100644 --- a/services/audiopolicy/service/AudioRecordClient.cpp +++ b/services/audiopolicy/service/AudioRecordClient.cpp @@ -19,6 +19,7 @@ #include "AudioRecordClient.h" #include "AudioPolicyService.h" #include "binder/AppOpsManager.h" +#include "mediautils/ServiceUtilities.h" #include @@ -47,7 +48,7 @@ int getTargetSdkForPackageName(std::string_view packageName) { if (pm != nullptr) { const auto status = pm->getTargetSdkVersionForPackage( String16{packageName.data(), packageName.size()}, &targetSdk); - return status.isOk() ? targetSdk : -1; + return status.isOk() ? targetSdk : __ANDROID_API_FUTURE__; } } return targetSdk; @@ -119,16 +120,19 @@ OpRecordAudioMonitor::createIfNeeded( || attributionSource.packageName.value().size() == 0) { return nullptr; } - return new OpRecordAudioMonitor(attributionSource, getOpForSource(attr.source), commandThread); + return new OpRecordAudioMonitor(attributionSource, getOpForSource(attr.source), + isRecordOpRequired(attr.source), + commandThread); } -OpRecordAudioMonitor::OpRecordAudioMonitor( - const AttributionSourceState& attributionSource, int32_t appOp, - wp commandThread) : - mHasOp(true), mAttributionSource(attributionSource), mAppOp(appOp), - mCommandThread(commandThread) -{ -} +OpRecordAudioMonitor::OpRecordAudioMonitor(const AttributionSourceState& attributionSource, + int32_t appOp, bool shouldMonitorRecord, + wp commandThread) + : mHasOp(true), + mAttributionSource(attributionSource), + mAppOp(appOp), + mShouldMonitorRecord(shouldMonitorRecord), + mCommandThread(commandThread) {} OpRecordAudioMonitor::~OpRecordAudioMonitor() { @@ -159,7 +163,7 @@ void OpRecordAudioMonitor::onFirstRef() }); }; reg(mAppOp); - if (mAppOp != AppOpsManager::OP_RECORD_AUDIO) { + if (mAppOp != AppOpsManager::OP_RECORD_AUDIO && mShouldMonitorRecord) { reg(AppOpsManager::OP_RECORD_AUDIO); } } @@ -185,7 +189,7 @@ void OpRecordAudioMonitor::checkOp(bool updateUidStates) { }); }; bool hasIt = check(mAppOp); - if (mAppOp != AppOpsManager::OP_RECORD_AUDIO) { + if (mAppOp != AppOpsManager::OP_RECORD_AUDIO && mShouldMonitorRecord) { hasIt = hasIt && check(AppOpsManager::OP_RECORD_AUDIO); } // verbose logging only log when appOp changed diff --git a/services/audiopolicy/service/AudioRecordClient.h b/services/audiopolicy/service/AudioRecordClient.h index d3be31618c..1c733d9517 100644 --- a/services/audiopolicy/service/AudioRecordClient.h +++ b/services/audiopolicy/service/AudioRecordClient.h @@ -43,7 +43,8 @@ public: private: OpRecordAudioMonitor(const AttributionSourceState& attributionSource, int32_t appOp, - wp commandThread); + bool shouldMonitorRecord, + wp commandThread); void onFirstRef() override; @@ -68,6 +69,7 @@ private: std::atomic_bool mHasOp; const AttributionSourceState mAttributionSource; const int32_t mAppOp; + const bool mShouldMonitorRecord; wp mCommandThread; }; -- GitLab