diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp index 9497416869..8591efd771 100644 --- a/services/audioflinger/AudioFlinger.cpp +++ b/services/audioflinger/AudioFlinger.cpp @@ -1960,7 +1960,8 @@ sp AudioFlinger::createRecord(const CreateRecordInput& inpu &output.notificationFrameCount, callingPid, clientUid, &output.flags, input.clientInfo.clientTid, - &lStatus, portId); + &lStatus, portId, + input.opPackageName); LOG_ALWAYS_FATAL_IF((lStatus == NO_ERROR) && (recordTrack == 0)); // lStatus == BAD_TYPE means FAST flag was rejected: request a new input from diff --git a/services/audioflinger/RecordTracks.h b/services/audioflinger/RecordTracks.h index da05dac390..d5257bdd34 100644 --- a/services/audioflinger/RecordTracks.h +++ b/services/audioflinger/RecordTracks.h @@ -19,6 +19,39 @@ #error This header file should only be included from AudioFlinger.h #endif +// Checks and monitors OP_RECORD_AUDIO +class OpRecordAudioMonitor : public RefBase { +public: + ~OpRecordAudioMonitor() override; + bool hasOpRecordAudio() const; + + static sp createIfNeeded(uid_t uid, const String16& opPackageName); + +private: + OpRecordAudioMonitor(uid_t uid, const String16& opPackageName); + void onFirstRef() override; + + AppOpsManager mAppOpsManager; + + class RecordAudioOpCallback : public BnAppOpsCallback { + public: + explicit RecordAudioOpCallback(const wp& monitor); + void opChanged(int32_t op, const String16& packageName) override; + + private: + const wp mMonitor; + }; + + sp mOpCallback; + // called by RecordAudioOpCallback when OP_RECORD_AUDIO is updated in AppOp callback + // and in onFirstRef() + void checkRecordAudio(); + + std::atomic_bool mHasOpRecordAudio; + const uid_t mUid; + const String16 mPackage; +}; + // record track class RecordTrack : public TrackBase { public: @@ -36,6 +69,7 @@ public: uid_t uid, audio_input_flags_t flags, track_type type, + const String16& opPackageName, audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE); virtual ~RecordTrack(); virtual status_t initCheck() const; @@ -68,7 +102,7 @@ public: { return (mFlags & AUDIO_INPUT_FLAG_DIRECT) != 0; } void setSilenced(bool silenced) { if (!isPatchTrack()) mSilenced = silenced; } - bool isSilenced() const { return mSilenced; } + bool isSilenced() const; status_t getActiveMicrophones(std::vector* activeMicrophones); @@ -111,6 +145,11 @@ private: audio_input_flags_t mFlags; bool mSilenced; + + // used to enforce OP_RECORD_AUDIO + uid_t mUid; + String16 mOpPackageName; + sp mOpRecordAudioMonitor; }; // playback track, used by PatchPanel diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp index 73292d3439..ac892a5273 100644 --- a/services/audioflinger/Threads.cpp +++ b/services/audioflinger/Threads.cpp @@ -7303,7 +7303,7 @@ reacquire_wakelock: // Sanitize before releasing if the track has no access to the source data // An idle UID receives silence from non virtual devices until active if (activeTrack->isSilenced()) { - memset(activeTrack->mSink.raw, 0, framesOut * mFrameSize); + memset(activeTrack->mSink.raw, 0, framesOut * activeTrack->frameSize()); } activeTrack->releaseBuffer(&activeTrack->mSink); } @@ -7464,7 +7464,8 @@ sp AudioFlinger::RecordThread::createRe audio_input_flags_t *flags, pid_t tid, status_t *status, - audio_port_handle_t portId) + audio_port_handle_t portId, + const String16& opPackageName) { size_t frameCount = *pFrameCount; size_t notificationFrameCount = *pNotificationFrameCount; @@ -7598,7 +7599,7 @@ sp AudioFlinger::RecordThread::createRe track = new RecordTrack(this, client, attr, sampleRate, format, channelMask, frameCount, nullptr /* buffer */, (size_t)0 /* bufferSize */, sessionId, creatorPid, uid, - *flags, TrackBase::TYPE_DEFAULT, portId); + *flags, TrackBase::TYPE_DEFAULT, opPackageName, portId); lStatus = track->initCheck(); if (lStatus != NO_ERROR) { diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h index acb137080c..0a473d5d23 100644 --- a/services/audioflinger/Threads.h +++ b/services/audioflinger/Threads.h @@ -1553,7 +1553,8 @@ public: audio_input_flags_t *flags, pid_t tid, status_t *status /*non-NULL*/, - audio_port_handle_t portId); + audio_port_handle_t portId, + const String16& opPackageName); status_t start(RecordTrack* recordTrack, AudioSystem::sync_event_t event, diff --git a/services/audioflinger/TrackBase.h b/services/audioflinger/TrackBase.h index 7a3bb0de7e..52e7d59283 100644 --- a/services/audioflinger/TrackBase.h +++ b/services/audioflinger/TrackBase.h @@ -215,6 +215,8 @@ protected: uint32_t channelCount() const { return mChannelCount; } + size_t frameSize() const { return mFrameSize; } + audio_channel_mask_t channelMask() const { return mChannelMask; } virtual uint32_t sampleRate() const { return mSampleRate; } diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp index 16a8a84ac5..e4402bd291 100644 --- a/services/audioflinger/Tracks.cpp +++ b/services/audioflinger/Tracks.cpp @@ -444,7 +444,7 @@ bool AudioFlinger::PlaybackThread::OpPlayAudioMonitor::hasOpPlayAudio() const { return mHasOpPlayAudio.load(); } -// Note this method is never called (and never to be) for audio server / root track +// Note this method is never called (and never to be) for audio server / patch record 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() @@ -1885,6 +1885,105 @@ void AudioFlinger::PlaybackThread::PatchTrack::restartIfDisabled() // ---------------------------------------------------------------------------- // Record // ---------------------------------------------------------------------------- + + +// ---------------------------------------------------------------------------- +// AppOp for audio recording +// ------------------------------- + +#undef LOG_TAG +#define LOG_TAG "AF::OpRecordAudioMonitor" + +// static +sp +AudioFlinger::RecordThread::OpRecordAudioMonitor::createIfNeeded( + uid_t uid, const String16& opPackageName) +{ + if (isServiceUid(uid)) { + ALOGV("not silencing record for service uid:%d pack:%s", + uid, String8(opPackageName).string()); + return nullptr; + } + + if (opPackageName.size() == 0) { + Vector packages; + // no package name, happens with SL ES clients + // query package manager to find one + PermissionController permissionController; + permissionController.getPackagesForUid(uid, packages); + if (packages.isEmpty()) { + return nullptr; + } else { + ALOGV("using pack:%s for uid:%d", String8(packages[0]).string(), uid); + return new OpRecordAudioMonitor(uid, packages[0]); + } + } + + return new OpRecordAudioMonitor(uid, opPackageName); +} + +AudioFlinger::RecordThread::OpRecordAudioMonitor::OpRecordAudioMonitor( + uid_t uid, const String16& opPackageName) + : mHasOpRecordAudio(true), mUid(uid), mPackage(opPackageName) +{ +} + +AudioFlinger::RecordThread::OpRecordAudioMonitor::~OpRecordAudioMonitor() +{ + if (mOpCallback != 0) { + mAppOpsManager.stopWatchingMode(mOpCallback); + } + mOpCallback.clear(); +} + +void AudioFlinger::RecordThread::OpRecordAudioMonitor::onFirstRef() +{ + checkRecordAudio(); + mOpCallback = new RecordAudioOpCallback(this); + ALOGV("start watching OP_RECORD_AUDIO for pack:%s", String8(mPackage).string()); + mAppOpsManager.startWatchingMode(AppOpsManager::OP_RECORD_AUDIO, mPackage, mOpCallback); +} + +bool AudioFlinger::RecordThread::OpRecordAudioMonitor::hasOpRecordAudio() const { + return mHasOpRecordAudio.load(); +} + +// Called by RecordAudioOpCallback when OP_RECORD_AUDIO is updated in AppOp callback +// and in onFirstRef() +// Note this method is never called (and never to be) for audio server / root track +// 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 AudioFlinger::RecordThread::OpRecordAudioMonitor::checkRecordAudio() +{ + const int32_t mode = mAppOpsManager.checkOp(AppOpsManager::OP_RECORD_AUDIO, + mUid, mPackage); + const bool hasIt = (mode == AppOpsManager::MODE_ALLOWED); + // verbose logging only log when appOp changed + ALOGI_IF(hasIt != mHasOpRecordAudio.load(), + "OP_RECORD_AUDIO missing, %ssilencing record uid%d pack:%s", + hasIt ? "un" : "", mUid, String8(mPackage).string()); + mHasOpRecordAudio.store(hasIt); +} + +AudioFlinger::RecordThread::OpRecordAudioMonitor::RecordAudioOpCallback::RecordAudioOpCallback( + const wp& monitor) : mMonitor(monitor) +{ } + +void AudioFlinger::RecordThread::OpRecordAudioMonitor::RecordAudioOpCallback::opChanged(int32_t op, + const String16& packageName) { + UNUSED(packageName); + if (op != AppOpsManager::OP_RECORD_AUDIO) { + return; + } + sp monitor = mMonitor.promote(); + if (monitor != NULL) { + monitor->checkRecordAudio(); + } +} + + + #undef LOG_TAG #define LOG_TAG "AF::RecordHandle" @@ -1956,6 +2055,7 @@ AudioFlinger::RecordThread::RecordTrack::RecordTrack( uid_t uid, audio_input_flags_t flags, track_type type, + const String16& opPackageName, audio_port_handle_t portId) : TrackBase(thread, client, attr, sampleRate, format, channelMask, frameCount, buffer, bufferSize, sessionId, @@ -1969,7 +2069,8 @@ AudioFlinger::RecordThread::RecordTrack::RecordTrack( mResamplerBufferProvider(NULL), // initialize in case of early constructor exit mRecordBufferConverter(NULL), mFlags(flags), - mSilenced(false) + mSilenced(false), + mOpRecordAudioMonitor(OpRecordAudioMonitor::createIfNeeded(uid, opPackageName)) { if (mCblk == NULL) { return; @@ -2220,6 +2321,14 @@ void AudioFlinger::RecordThread::RecordTrack::updateTrackFrameInfo( mServerLatencyMs.store(latencyMs); } +bool AudioFlinger::RecordThread::RecordTrack::isSilenced() const { + if (mSilenced) { + return true; + } + // The monitor is only created for record tracks that can be silenced. + return mOpRecordAudioMonitor ? !mOpRecordAudioMonitor->hasOpRecordAudio() : false; +} + status_t AudioFlinger::RecordThread::RecordTrack::getActiveMicrophones( std::vector* activeMicrophones) { @@ -2270,7 +2379,7 @@ AudioFlinger::RecordThread::PatchRecord::PatchRecord(RecordThread *recordThread, audio_attributes_t{} /* currently unused for patch track */, sampleRate, format, channelMask, frameCount, buffer, bufferSize, AUDIO_SESSION_NONE, getpid(), AID_AUDIOSERVER, - flags, TYPE_PATCH), + flags, TYPE_PATCH, String16()), PatchTrackBase(new ClientProxy(mCblk, mBuffer, frameCount, mFrameSize, false, true), *recordThread, timeout) {