Loading media/utils/ServiceUtilities.cpp +105 −38 Original line number Diff line number Diff line Loading @@ -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"); Loading Loading @@ -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<AttributionSourceState> resolveAttributionSource( const AttributionSourceState& callerAttributionSource) { AttributionSourceState nextAttributionSource = callerAttributionSource; Loading Loading @@ -113,7 +132,7 @@ std::optional<AttributionSourceState> resolveAttributionSource( return std::optional<AttributionSourceState>{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. Loading @@ -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; 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. const std::optional<AttributionSourceState> resolvedAttributionSource = std::optional<AttributionSourceState> resolvedAttributionSource = resolveAttributionSource(attributionSource); if (!resolvedAttributionSource.has_value()) { return false; return PERMISSION_HARD_DENIED; } const int32_t attributedOpCode = getOpForSource(source); permission::PermissionChecker permissionChecker; bool permitted = false; int permitted; if (start) { permitted = (permissionChecker.checkPermissionForStartDataDeliveryFromDatasource( // 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) != permission::PermissionChecker::PERMISSION_HARD_DENIED); attributedOpCode); } else { permitted = (permissionChecker.checkPermissionForPreflightFromDatasource( // intentionally don't set permitted permissionChecker.checkPermissionForDataDeliveryFromDatasource( sAndroidPermissionRecordAudio, resolvedAttributionSource.value(), msg, attributedOpCode) != permission::PermissionChecker::PERMISSION_HARD_DENIED); attributedOpCode); } } else { permitted = permissionChecker.checkPermissionForPreflightFromDatasource( sAndroidPermissionRecordAudio, resolvedAttributionSource.value(), msg, attributedOpCode); } return permitted; } else { 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); } } 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); } Loading @@ -164,6 +218,8 @@ void finishRecording(const AttributionSourceState& attributionSource, audio_sour uid_t uid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(attributionSource.uid)); if (isAudioServerOrMediaServerOrSystemServerOrRootUid(uid)) return; 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. Loading @@ -173,10 +229,21 @@ void finishRecording(const AttributionSourceState& attributionSource, audio_sour return; } const int32_t attributedOpCode = getOpForSource(source); 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) { Loading media/utils/include/mediautils/ServiceUtilities.h +3 −1 Original line number Diff line number Diff line Loading @@ -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<AttributionSourceState> resolveAttributionSource( Loading @@ -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>& iMemory); Loading services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp +25 −13 Original line number Diff line number Diff line Loading @@ -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<audio_usage_t>& SYSTEM_USAGES = { AUDIO_USAGE_CALL_ASSISTANT, AUDIO_USAGE_EMERGENCY, Loading Loading @@ -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); Loading @@ -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) if (permitted == PERMISSION_GRANTED) { setAppState_l(client, APP_STATE_TOP); } else { setAppState_l(client, APP_STATE_IDLE); } client->active = true; client->startTimeNs = systemTime(); Loading Loading @@ -924,8 +932,10 @@ Status AudioPolicyService::startInput(int32_t portIdAidl) client->active = false; client->startTimeNs = 0; updateUidStates_l(); if (!client->silenced) { finishRecording(client->attributionSource, client->attributes.source); } } return binderStatusFromStatusT(status); } Loading Loading @@ -953,7 +963,9 @@ Status AudioPolicyService::stopInput(int32_t portIdAidl) updateUidStates_l(); // finish the recording app op if (!client->silenced) { finishRecording(client->attributionSource, client->attributes.source); } AutoCallerClear acc; return binderStatusFromStatusT(mAudioPolicyManager->stopInput(portId)); } Loading services/audiopolicy/service/AudioPolicyService.cpp +7 −3 Original line number Diff line number Diff line Loading @@ -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) \ Loading Loading @@ -1196,9 +1200,9 @@ void AudioPolicyService::setAppState_l(sp<AudioRecordClient> 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; } } } Loading services/audiopolicy/service/AudioRecordClient.cpp +90 −30 Original line number Diff line number Diff line Loading @@ -18,14 +18,17 @@ #include "AudioRecordClient.h" #include "AudioPolicyService.h" #include "binder/AppOpsManager.h" #include "mediautils/ServiceUtilities.h" #include <algorithm> 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: Loading @@ -45,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; Loading @@ -54,8 +57,47 @@ 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<OpRecordAudioMonitor> OpRecordAudioMonitor::createIfNeeded( Loading @@ -78,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<AudioPolicyService::AudioCommandThread> commandThread) : mHasOp(true), mAttributionSource(attributionSource), mAppOp(appOp), mCommandThread(commandThread) { } OpRecordAudioMonitor::OpRecordAudioMonitor(const AttributionSourceState& attributionSource, int32_t appOp, bool shouldMonitorRecord, wp<AudioPolicyService::AudioCommandThread> commandThread) : mHasOp(true), mAttributionSource(attributionSource), mAppOp(appOp), mShouldMonitorRecord(shouldMonitorRecord), mCommandThread(commandThread) {} OpRecordAudioMonitor::~OpRecordAudioMonitor() { Loading @@ -103,15 +148,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 && mShouldMonitorRecord) { reg(AppOpsManager::OP_RECORD_AUDIO); } } bool OpRecordAudioMonitor::hasOp() const { Loading @@ -124,14 +178,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 && mShouldMonitorRecord) { 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", Loading Loading @@ -161,4 +221,4 @@ void OpRecordAudioMonitor::RecordAudioOpCallback::opChanged(int32_t op, } } } // android::media::audiopolicy::internal } // namespace android::media::audiopolicy Loading
media/utils/ServiceUtilities.cpp +105 −38 Original line number Diff line number Diff line Loading @@ -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"); Loading Loading @@ -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<AttributionSourceState> resolveAttributionSource( const AttributionSourceState& callerAttributionSource) { AttributionSourceState nextAttributionSource = callerAttributionSource; Loading Loading @@ -113,7 +132,7 @@ std::optional<AttributionSourceState> resolveAttributionSource( return std::optional<AttributionSourceState>{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. Loading @@ -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; 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. const std::optional<AttributionSourceState> resolvedAttributionSource = std::optional<AttributionSourceState> resolvedAttributionSource = resolveAttributionSource(attributionSource); if (!resolvedAttributionSource.has_value()) { return false; return PERMISSION_HARD_DENIED; } const int32_t attributedOpCode = getOpForSource(source); permission::PermissionChecker permissionChecker; bool permitted = false; int permitted; if (start) { permitted = (permissionChecker.checkPermissionForStartDataDeliveryFromDatasource( // 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) != permission::PermissionChecker::PERMISSION_HARD_DENIED); attributedOpCode); } else { permitted = (permissionChecker.checkPermissionForPreflightFromDatasource( // intentionally don't set permitted permissionChecker.checkPermissionForDataDeliveryFromDatasource( sAndroidPermissionRecordAudio, resolvedAttributionSource.value(), msg, attributedOpCode) != permission::PermissionChecker::PERMISSION_HARD_DENIED); attributedOpCode); } } else { permitted = permissionChecker.checkPermissionForPreflightFromDatasource( sAndroidPermissionRecordAudio, resolvedAttributionSource.value(), msg, attributedOpCode); } return permitted; } else { 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); } } 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); } Loading @@ -164,6 +218,8 @@ void finishRecording(const AttributionSourceState& attributionSource, audio_sour uid_t uid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(attributionSource.uid)); if (isAudioServerOrMediaServerOrSystemServerOrRootUid(uid)) return; 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. Loading @@ -173,10 +229,21 @@ void finishRecording(const AttributionSourceState& attributionSource, audio_sour return; } const int32_t attributedOpCode = getOpForSource(source); 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) { Loading
media/utils/include/mediautils/ServiceUtilities.h +3 −1 Original line number Diff line number Diff line Loading @@ -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<AttributionSourceState> resolveAttributionSource( Loading @@ -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>& iMemory); Loading
services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp +25 −13 Original line number Diff line number Diff line Loading @@ -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<audio_usage_t>& SYSTEM_USAGES = { AUDIO_USAGE_CALL_ASSISTANT, AUDIO_USAGE_EMERGENCY, Loading Loading @@ -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); Loading @@ -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) if (permitted == PERMISSION_GRANTED) { setAppState_l(client, APP_STATE_TOP); } else { setAppState_l(client, APP_STATE_IDLE); } client->active = true; client->startTimeNs = systemTime(); Loading Loading @@ -924,8 +932,10 @@ Status AudioPolicyService::startInput(int32_t portIdAidl) client->active = false; client->startTimeNs = 0; updateUidStates_l(); if (!client->silenced) { finishRecording(client->attributionSource, client->attributes.source); } } return binderStatusFromStatusT(status); } Loading Loading @@ -953,7 +963,9 @@ Status AudioPolicyService::stopInput(int32_t portIdAidl) updateUidStates_l(); // finish the recording app op if (!client->silenced) { finishRecording(client->attributionSource, client->attributes.source); } AutoCallerClear acc; return binderStatusFromStatusT(mAudioPolicyManager->stopInput(portId)); } Loading
services/audiopolicy/service/AudioPolicyService.cpp +7 −3 Original line number Diff line number Diff line Loading @@ -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) \ Loading Loading @@ -1196,9 +1200,9 @@ void AudioPolicyService::setAppState_l(sp<AudioRecordClient> 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; } } } Loading
services/audiopolicy/service/AudioRecordClient.cpp +90 −30 Original line number Diff line number Diff line Loading @@ -18,14 +18,17 @@ #include "AudioRecordClient.h" #include "AudioPolicyService.h" #include "binder/AppOpsManager.h" #include "mediautils/ServiceUtilities.h" #include <algorithm> 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: Loading @@ -45,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; Loading @@ -54,8 +57,47 @@ 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<OpRecordAudioMonitor> OpRecordAudioMonitor::createIfNeeded( Loading @@ -78,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<AudioPolicyService::AudioCommandThread> commandThread) : mHasOp(true), mAttributionSource(attributionSource), mAppOp(appOp), mCommandThread(commandThread) { } OpRecordAudioMonitor::OpRecordAudioMonitor(const AttributionSourceState& attributionSource, int32_t appOp, bool shouldMonitorRecord, wp<AudioPolicyService::AudioCommandThread> commandThread) : mHasOp(true), mAttributionSource(attributionSource), mAppOp(appOp), mShouldMonitorRecord(shouldMonitorRecord), mCommandThread(commandThread) {} OpRecordAudioMonitor::~OpRecordAudioMonitor() { Loading @@ -103,15 +148,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 && mShouldMonitorRecord) { reg(AppOpsManager::OP_RECORD_AUDIO); } } bool OpRecordAudioMonitor::hasOp() const { Loading @@ -124,14 +178,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 && mShouldMonitorRecord) { 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", Loading Loading @@ -161,4 +221,4 @@ void OpRecordAudioMonitor::RecordAudioOpCallback::opChanged(int32_t op, } } } // android::media::audiopolicy::internal } // namespace android::media::audiopolicy