summaryrefslogtreecommitdiffstats
path: root/services/audioflinger
diff options
context:
space:
mode:
authorJean-Michel Trivi <jmtrivi@google.com>2019-08-20 15:42:04 -0700
committerandroid-build-team Robot <android-build-team-robot@google.com>2019-10-11 18:50:35 +0000
commit59ec67efa6b0941113f5a160aed00529e612d0fe (patch)
tree90e0f48fde7d3f07367b62be0c2f98527fc327d6 /services/audioflinger
parentbcb57f62b0f75630a5c1199c78f5af311934b6ce (diff)
downloadframeworks_av-59ec67efa6b0941113f5a160aed00529e612d0fe.tar.gz
frameworks_av-59ec67efa6b0941113f5a160aed00529e612d0fe.tar.bz2
frameworks_av-59ec67efa6b0941113f5a160aed00529e612d0fe.zip
AudioFlinger: enforce OP_RECORD_AUDIO during recording
Fix issue where RecordTrack silencing didn't silence the full buffer: the memset to 0 was using the RecordThread frame size, not the RecordTrack frame size. OP_RECORD_AUDIO was only enforced at the start of a recording which would fail if not granted. This patch silences the recording (i.e. silence is recorded instead) when it is lost, and undoes that when granted again. This requires: - propagating the package name of the client to the RecordTrack class - registering an appOp callback in RecordTrack (through a new OpRecordAudioMonitor class) to (un)silence the recording - update the isSilenced() method to take into account the appOp. Bug: 138968594 Bug: 138636979 Test: run app that records audio, then "adb shell appops __pack_name__ 27 2" and verify recording is silent after that. Change-Id: Ib33f5b592185a67204997213bab1ac2594d90d37 (cherry picked from commit ddf87effa4d80f413a80fde861f73877ccd80599) Merged-In: Ib33f5b592185a67204997213bab1ac2594d90d37 (cherry picked from commit 7307293e8befafa12b244b74cd3c8cb84b27997c)
Diffstat (limited to 'services/audioflinger')
-rw-r--r--services/audioflinger/AudioFlinger.cpp3
-rw-r--r--services/audioflinger/RecordTracks.h41
-rw-r--r--services/audioflinger/Threads.cpp7
-rw-r--r--services/audioflinger/Threads.h3
-rw-r--r--services/audioflinger/TrackBase.h2
-rw-r--r--services/audioflinger/Tracks.cpp115
6 files changed, 162 insertions, 9 deletions
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 0b745ac834..d38190d95e 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -1933,7 +1933,8 @@ sp<media::IAudioRecord> 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 08660dd67a..c8397cd127 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<OpRecordAudioMonitor> 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<OpRecordAudioMonitor>& monitor);
+ void opChanged(int32_t op, const String16& packageName) override;
+
+ private:
+ const wp<OpRecordAudioMonitor> mMonitor;
+ };
+
+ sp<RecordAudioOpCallback> 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<media::MicrophoneInfo>* 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<OpRecordAudioMonitor> mOpRecordAudioMonitor;
};
// playback track, used by PatchPanel
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index bcd351d86b..bd9bf7b4b5 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -7291,7 +7291,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);
}
@@ -7452,7 +7452,8 @@ sp<AudioFlinger::RecordThread::RecordTrack> 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;
@@ -7586,7 +7587,7 @@ sp<AudioFlinger::RecordThread::RecordTrack> 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 fc8aa13cbb..87bebf3d89 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 8f720b58d5..65589e2dda 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 78db80ca0a..2a5a713ca3 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -442,7 +442,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()
@@ -1883,6 +1883,105 @@ void AudioFlinger::PlaybackThread::PatchTrack::restartIfDisabled()
// ----------------------------------------------------------------------------
// Record
// ----------------------------------------------------------------------------
+
+
+// ----------------------------------------------------------------------------
+// AppOp for audio recording
+// -------------------------------
+
+#undef LOG_TAG
+#define LOG_TAG "AF::OpRecordAudioMonitor"
+
+// static
+sp<AudioFlinger::RecordThread::OpRecordAudioMonitor>
+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<String16> 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<OpRecordAudioMonitor>& 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<OpRecordAudioMonitor> monitor = mMonitor.promote();
+ if (monitor != NULL) {
+ monitor->checkRecordAudio();
+ }
+}
+
+
+
#undef LOG_TAG
#define LOG_TAG "AF::RecordHandle"
@@ -1954,6 +2053,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,
@@ -1967,7 +2067,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;
@@ -2218,6 +2319,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<media::MicrophoneInfo>* activeMicrophones)
{
@@ -2268,7 +2377,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)
{