Loading services/audioflinger/AudioFlinger.h +2 −0 Original line number Diff line number Diff line Loading @@ -54,7 +54,9 @@ #include <utils/TypeHelpers.h> #include <utils/Vector.h> #include <binder/AppOpsManager.h> #include <binder/BinderService.h> #include <binder/IAppOpsCallback.h> #include <binder/MemoryDealer.h> #include <system/audio.h> Loading services/audioflinger/PlaybackTracks.h +34 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,36 @@ #error This header file should only be included from AudioFlinger.h #endif // Checks and monitors OP_PLAY_AUDIO class OpPlayAudioMonitor : public RefBase { public: OpPlayAudioMonitor(uid_t uid, audio_usage_t usage, int id, audio_stream_type_t streamType); ~OpPlayAudioMonitor() override; bool hasOpPlayAudio() const; private: AppOpsManager mAppOpsManager; class PlayAudioOpCallback : public BnAppOpsCallback { public: explicit PlayAudioOpCallback(const wp<OpPlayAudioMonitor>& monitor); void opChanged(int32_t op, const String16& packageName) override; private: const wp<OpPlayAudioMonitor> mMonitor; }; sp<PlayAudioOpCallback> mOpCallback; // called by PlayAudioOpCallback when OP_PLAY_AUDIO is updated in AppOp callback void checkPlayAudioForUsage(); std::atomic_bool mHasOpPlayAudio; Vector<String16> mPackages; const uid_t mUid; const int32_t mUsage; // on purpose not audio_usage_t because always checked in appOps as int32_t const int mId; // for logging purposes only }; // playback track class Track : public TrackBase, public VolumeProvider { public: Loading Loading @@ -179,6 +209,8 @@ public: int fastIndex() const { return mFastIndex; } bool isPlaybackRestricted() const { return !mOpPlayAudioMonitor->hasOpPlayAudio(); } protected: // FILLED state is used for suppressing volume ramp at begin of playing Loading Loading @@ -207,6 +239,8 @@ protected: sp<media::VolumeHandler> mVolumeHandler; // handles multiple VolumeShaper configs and operations sp<OpPlayAudioMonitor> mOpPlayAudioMonitor; bool mHapticPlaybackEnabled = false; // indicates haptic playback enabled or not // intensity to play haptic data AudioMixer::haptic_intensity_t mHapticIntensity = AudioMixer::HAPTIC_SCALE_MUTE; Loading services/audioflinger/Threads.cpp +9 −3 Original line number Diff line number Diff line Loading @@ -4705,9 +4705,14 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac // lacks any synchronization or barrier so VolumeProvider may read a stale value const float vh = track->getVolumeHandler()->getVolume( proxy->framesReleased()).first; float volume = masterVolume float volume; if (track->isPlaybackRestricted()) { volume = 0.f; } else { volume = masterVolume * mStreamTypes[track->streamType()].volume * vh; } track->mCachedVolume = volume; gain_minifloat_packed_t vlr = proxy->getVolumeLR(); float vlf = volume * float_from_gain(gain_minifloat_unpack_left(vlr)); Loading Loading @@ -4857,7 +4862,8 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac float typeVolume = mStreamTypes[track->streamType()].volume; float v = masterVolume * typeVolume; if (track->isPausing() || mStreamTypes[track->streamType()].mute) { if (track->isPausing() || mStreamTypes[track->streamType()].mute || track->isPlaybackRestricted()) { vl = vr = 0; vlf = vrf = vaf = 0.; if (track->isPausing()) { Loading Loading @@ -5444,7 +5450,7 @@ void AudioFlinger::DirectOutputThread::processVolume_l(Track *track, bool lastTr { float left, right; if (mMasterMute || mStreamTypes[track->streamType()].mute) { if (mMasterMute || mStreamTypes[track->streamType()].mute || track->isPlaybackRestricted()) { left = right = 0; } else { float typeVolume = mStreamTypes[track->streamType()].volume; Loading services/audioflinger/Tracks.cpp +77 −0 Original line number Diff line number Diff line Loading @@ -378,6 +378,82 @@ status_t AudioFlinger::TrackHandle::onTransact( return BnAudioTrack::onTransact(code, data, reply, flags); } // ---------------------------------------------------------------------------- // AppOp for audio playback // ------------------------------- AudioFlinger::PlaybackThread::OpPlayAudioMonitor::OpPlayAudioMonitor(uid_t uid, audio_usage_t usage, int id, audio_stream_type_t streamType) : mHasOpPlayAudio(true), mUid(uid), mUsage((int32_t) usage), mId(id) { if (isAudioServerOrRootUid(uid)) { ALOGD("OpPlayAudio: not muting track:%d usage:%d root or audioserver", mId, usage); return; } // stream type has been filtered by audio policy to indicate whether it can be muted if (streamType == AUDIO_STREAM_ENFORCED_AUDIBLE) { ALOGD("OpPlayAudio: not muting track:%d usage:%d ENFORCED_AUDIBLE", mId, usage); return; } PermissionController permissionController; permissionController.getPackagesForUid(uid, mPackages); checkPlayAudioForUsage(); if (!mPackages.isEmpty()) { mOpCallback = new PlayAudioOpCallback(this); mAppOpsManager.startWatchingMode(AppOpsManager::OP_PLAY_AUDIO, mPackages[0], mOpCallback); } } AudioFlinger::PlaybackThread::OpPlayAudioMonitor::~OpPlayAudioMonitor() { if (mOpCallback != 0) { mAppOpsManager.stopWatchingMode(mOpCallback); } mOpCallback.clear(); } bool AudioFlinger::PlaybackThread::OpPlayAudioMonitor::hasOpPlayAudio() const { return mHasOpPlayAudio.load(); } // Note this method is never called (and never to be) for audio server / root track // - not called from constructor due to check on UID, // - not called from PlayAudioOpCallback because the callback is not installed in this case void AudioFlinger::PlaybackThread::OpPlayAudioMonitor::checkPlayAudioForUsage() { if (mPackages.isEmpty()) { mHasOpPlayAudio.store(false); } else { bool hasIt = true; for (const String16& packageName : mPackages) { const int32_t mode = mAppOpsManager.checkAudioOpNoThrow(AppOpsManager::OP_PLAY_AUDIO, mUsage, mUid, packageName); if (mode != AppOpsManager::MODE_ALLOWED) { hasIt = false; break; } } ALOGD("OpPlayAudio: track:%d usage:%d %smuted", mId, mUsage, hasIt ? "not " : ""); mHasOpPlayAudio.store(hasIt); } } AudioFlinger::PlaybackThread::OpPlayAudioMonitor::PlayAudioOpCallback::PlayAudioOpCallback( const wp<OpPlayAudioMonitor>& monitor) : mMonitor(monitor) { } void AudioFlinger::PlaybackThread::OpPlayAudioMonitor::PlayAudioOpCallback::opChanged(int32_t op, const String16& packageName) { // we only have uid, so we need to check all package names anyway UNUSED(packageName); if (op != AppOpsManager::OP_PLAY_AUDIO) { return; } sp<OpPlayAudioMonitor> monitor = mMonitor.promote(); if (monitor != NULL) { monitor->checkPlayAudioForUsage(); } } // ---------------------------------------------------------------------------- #undef LOG_TAG #define LOG_TAG "AF::Track" Loading Loading @@ -416,6 +492,7 @@ AudioFlinger::PlaybackThread::Track::Track( mPresentationCompleteFrames(0), mFrameMap(16 /* sink-frame-to-track-frame map memory */), mVolumeHandler(new media::VolumeHandler(sampleRate)), mOpPlayAudioMonitor(new OpPlayAudioMonitor(uid, attr.usage, id(), streamType)), // mSinkTimestamp mFastIndex(-1), mCachedVolume(1.0), Loading services/audiopolicy/engine/common/src/EngineBase.cpp +14 −1 Original line number Diff line number Diff line Loading @@ -70,7 +70,20 @@ product_strategy_t EngineBase::getProductStrategyForAttributes(const audio_attri audio_stream_type_t EngineBase::getStreamTypeForAttributes(const audio_attributes_t &attr) const { return mProductStrategies.getStreamTypeForAttributes(attr); audio_stream_type_t engineStream = mProductStrategies.getStreamTypeForAttributes(attr); // ensure the audibility flag for sonification is honored for stream types // Note this is typically implemented in the product strategy configuration files, but is // duplicated here for safety. if (attr.usage == AUDIO_USAGE_ASSISTANCE_SONIFICATION && ((attr.flags & AUDIO_FLAG_AUDIBILITY_ENFORCED) != 0)) { engineStream = AUDIO_STREAM_ENFORCED_AUDIBLE; } // ensure the ENFORCED_AUDIBLE stream type reflects the "force use" setting: if ((getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) != AUDIO_POLICY_FORCE_SYSTEM_ENFORCED) && (engineStream == AUDIO_STREAM_ENFORCED_AUDIBLE)) { return AUDIO_STREAM_SYSTEM; } return engineStream; } audio_attributes_t EngineBase::getAttributesForStreamType(audio_stream_type_t stream) const Loading Loading
services/audioflinger/AudioFlinger.h +2 −0 Original line number Diff line number Diff line Loading @@ -54,7 +54,9 @@ #include <utils/TypeHelpers.h> #include <utils/Vector.h> #include <binder/AppOpsManager.h> #include <binder/BinderService.h> #include <binder/IAppOpsCallback.h> #include <binder/MemoryDealer.h> #include <system/audio.h> Loading
services/audioflinger/PlaybackTracks.h +34 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,36 @@ #error This header file should only be included from AudioFlinger.h #endif // Checks and monitors OP_PLAY_AUDIO class OpPlayAudioMonitor : public RefBase { public: OpPlayAudioMonitor(uid_t uid, audio_usage_t usage, int id, audio_stream_type_t streamType); ~OpPlayAudioMonitor() override; bool hasOpPlayAudio() const; private: AppOpsManager mAppOpsManager; class PlayAudioOpCallback : public BnAppOpsCallback { public: explicit PlayAudioOpCallback(const wp<OpPlayAudioMonitor>& monitor); void opChanged(int32_t op, const String16& packageName) override; private: const wp<OpPlayAudioMonitor> mMonitor; }; sp<PlayAudioOpCallback> mOpCallback; // called by PlayAudioOpCallback when OP_PLAY_AUDIO is updated in AppOp callback void checkPlayAudioForUsage(); std::atomic_bool mHasOpPlayAudio; Vector<String16> mPackages; const uid_t mUid; const int32_t mUsage; // on purpose not audio_usage_t because always checked in appOps as int32_t const int mId; // for logging purposes only }; // playback track class Track : public TrackBase, public VolumeProvider { public: Loading Loading @@ -179,6 +209,8 @@ public: int fastIndex() const { return mFastIndex; } bool isPlaybackRestricted() const { return !mOpPlayAudioMonitor->hasOpPlayAudio(); } protected: // FILLED state is used for suppressing volume ramp at begin of playing Loading Loading @@ -207,6 +239,8 @@ protected: sp<media::VolumeHandler> mVolumeHandler; // handles multiple VolumeShaper configs and operations sp<OpPlayAudioMonitor> mOpPlayAudioMonitor; bool mHapticPlaybackEnabled = false; // indicates haptic playback enabled or not // intensity to play haptic data AudioMixer::haptic_intensity_t mHapticIntensity = AudioMixer::HAPTIC_SCALE_MUTE; Loading
services/audioflinger/Threads.cpp +9 −3 Original line number Diff line number Diff line Loading @@ -4705,9 +4705,14 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac // lacks any synchronization or barrier so VolumeProvider may read a stale value const float vh = track->getVolumeHandler()->getVolume( proxy->framesReleased()).first; float volume = masterVolume float volume; if (track->isPlaybackRestricted()) { volume = 0.f; } else { volume = masterVolume * mStreamTypes[track->streamType()].volume * vh; } track->mCachedVolume = volume; gain_minifloat_packed_t vlr = proxy->getVolumeLR(); float vlf = volume * float_from_gain(gain_minifloat_unpack_left(vlr)); Loading Loading @@ -4857,7 +4862,8 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac float typeVolume = mStreamTypes[track->streamType()].volume; float v = masterVolume * typeVolume; if (track->isPausing() || mStreamTypes[track->streamType()].mute) { if (track->isPausing() || mStreamTypes[track->streamType()].mute || track->isPlaybackRestricted()) { vl = vr = 0; vlf = vrf = vaf = 0.; if (track->isPausing()) { Loading Loading @@ -5444,7 +5450,7 @@ void AudioFlinger::DirectOutputThread::processVolume_l(Track *track, bool lastTr { float left, right; if (mMasterMute || mStreamTypes[track->streamType()].mute) { if (mMasterMute || mStreamTypes[track->streamType()].mute || track->isPlaybackRestricted()) { left = right = 0; } else { float typeVolume = mStreamTypes[track->streamType()].volume; Loading
services/audioflinger/Tracks.cpp +77 −0 Original line number Diff line number Diff line Loading @@ -378,6 +378,82 @@ status_t AudioFlinger::TrackHandle::onTransact( return BnAudioTrack::onTransact(code, data, reply, flags); } // ---------------------------------------------------------------------------- // AppOp for audio playback // ------------------------------- AudioFlinger::PlaybackThread::OpPlayAudioMonitor::OpPlayAudioMonitor(uid_t uid, audio_usage_t usage, int id, audio_stream_type_t streamType) : mHasOpPlayAudio(true), mUid(uid), mUsage((int32_t) usage), mId(id) { if (isAudioServerOrRootUid(uid)) { ALOGD("OpPlayAudio: not muting track:%d usage:%d root or audioserver", mId, usage); return; } // stream type has been filtered by audio policy to indicate whether it can be muted if (streamType == AUDIO_STREAM_ENFORCED_AUDIBLE) { ALOGD("OpPlayAudio: not muting track:%d usage:%d ENFORCED_AUDIBLE", mId, usage); return; } PermissionController permissionController; permissionController.getPackagesForUid(uid, mPackages); checkPlayAudioForUsage(); if (!mPackages.isEmpty()) { mOpCallback = new PlayAudioOpCallback(this); mAppOpsManager.startWatchingMode(AppOpsManager::OP_PLAY_AUDIO, mPackages[0], mOpCallback); } } AudioFlinger::PlaybackThread::OpPlayAudioMonitor::~OpPlayAudioMonitor() { if (mOpCallback != 0) { mAppOpsManager.stopWatchingMode(mOpCallback); } mOpCallback.clear(); } bool AudioFlinger::PlaybackThread::OpPlayAudioMonitor::hasOpPlayAudio() const { return mHasOpPlayAudio.load(); } // Note this method is never called (and never to be) for audio server / root track // - not called from constructor due to check on UID, // - not called from PlayAudioOpCallback because the callback is not installed in this case void AudioFlinger::PlaybackThread::OpPlayAudioMonitor::checkPlayAudioForUsage() { if (mPackages.isEmpty()) { mHasOpPlayAudio.store(false); } else { bool hasIt = true; for (const String16& packageName : mPackages) { const int32_t mode = mAppOpsManager.checkAudioOpNoThrow(AppOpsManager::OP_PLAY_AUDIO, mUsage, mUid, packageName); if (mode != AppOpsManager::MODE_ALLOWED) { hasIt = false; break; } } ALOGD("OpPlayAudio: track:%d usage:%d %smuted", mId, mUsage, hasIt ? "not " : ""); mHasOpPlayAudio.store(hasIt); } } AudioFlinger::PlaybackThread::OpPlayAudioMonitor::PlayAudioOpCallback::PlayAudioOpCallback( const wp<OpPlayAudioMonitor>& monitor) : mMonitor(monitor) { } void AudioFlinger::PlaybackThread::OpPlayAudioMonitor::PlayAudioOpCallback::opChanged(int32_t op, const String16& packageName) { // we only have uid, so we need to check all package names anyway UNUSED(packageName); if (op != AppOpsManager::OP_PLAY_AUDIO) { return; } sp<OpPlayAudioMonitor> monitor = mMonitor.promote(); if (monitor != NULL) { monitor->checkPlayAudioForUsage(); } } // ---------------------------------------------------------------------------- #undef LOG_TAG #define LOG_TAG "AF::Track" Loading Loading @@ -416,6 +492,7 @@ AudioFlinger::PlaybackThread::Track::Track( mPresentationCompleteFrames(0), mFrameMap(16 /* sink-frame-to-track-frame map memory */), mVolumeHandler(new media::VolumeHandler(sampleRate)), mOpPlayAudioMonitor(new OpPlayAudioMonitor(uid, attr.usage, id(), streamType)), // mSinkTimestamp mFastIndex(-1), mCachedVolume(1.0), Loading
services/audiopolicy/engine/common/src/EngineBase.cpp +14 −1 Original line number Diff line number Diff line Loading @@ -70,7 +70,20 @@ product_strategy_t EngineBase::getProductStrategyForAttributes(const audio_attri audio_stream_type_t EngineBase::getStreamTypeForAttributes(const audio_attributes_t &attr) const { return mProductStrategies.getStreamTypeForAttributes(attr); audio_stream_type_t engineStream = mProductStrategies.getStreamTypeForAttributes(attr); // ensure the audibility flag for sonification is honored for stream types // Note this is typically implemented in the product strategy configuration files, but is // duplicated here for safety. if (attr.usage == AUDIO_USAGE_ASSISTANCE_SONIFICATION && ((attr.flags & AUDIO_FLAG_AUDIBILITY_ENFORCED) != 0)) { engineStream = AUDIO_STREAM_ENFORCED_AUDIBLE; } // ensure the ENFORCED_AUDIBLE stream type reflects the "force use" setting: if ((getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) != AUDIO_POLICY_FORCE_SYSTEM_ENFORCED) && (engineStream == AUDIO_STREAM_ENFORCED_AUDIBLE)) { return AUDIO_STREAM_SYSTEM; } return engineStream; } audio_attributes_t EngineBase::getAttributesForStreamType(audio_stream_type_t stream) const Loading