Audio policy: modify permission needed to capture from source FM_TUNER
Capturing from source AUDIO_SOURCE_FM_TUNER is possible only via @SystemApi
on one end and does not capture from an actual on the other end.
Accordingly, do not check android.permission.RECORD_AUDIO anymore but
check privileged permission android.permission.CAPTURE_AUDIO_OUTPUT instead.
Also bypass App Ops OP_RECORD_AUDIO check which is applicable only to capture from
microphones.
Also fix audio recording permission check in MediaRecordClient to use
recordingAllowed() from ServiceUtilities
Bug: 135717621
Test: CTS tests for AudioRecord
Change-Id: Ibb1d72f018d2e3ceee195338f2e262183eee2a23
diff --git a/media/libmediaplayerservice/MediaRecorderClient.cpp b/media/libmediaplayerservice/MediaRecorderClient.cpp
index 703da4b..c61ed1b 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.cpp
+++ b/media/libmediaplayerservice/MediaRecorderClient.cpp
@@ -32,6 +32,7 @@
#include <cutils/atomic.h>
#include <cutils/properties.h> // for property_get
#include <gui/IGraphicBufferProducer.h>
+#include <mediautils/ServiceUtilities.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <system/audio.h>
@@ -44,7 +45,6 @@
namespace android {
const char* cameraPermission = "android.permission.CAMERA";
-const char* recordAudioPermission = "android.permission.RECORD_AUDIO";
static bool checkPermission(const char* permissionString) {
if (getpid() == IPCThreadState::self()->getCallingPid()) return true;
@@ -118,7 +118,16 @@
status_t MediaRecorderClient::setAudioSource(int as)
{
ALOGV("setAudioSource(%d)", as);
- if (!checkPermission(recordAudioPermission)) {
+ if (as < AUDIO_SOURCE_DEFAULT
+ || (as >= AUDIO_SOURCE_CNT && as != AUDIO_SOURCE_FM_TUNER)) {
+ ALOGE("Invalid audio source: %d", as);
+ return BAD_VALUE;
+ }
+ pid_t pid = IPCThreadState::self()->getCallingPid();
+ uid_t uid = IPCThreadState::self()->getCallingUid();
+
+ if ((as == AUDIO_SOURCE_FM_TUNER && !captureAudioOutputAllowed(pid, uid))
+ || !recordingAllowed(String16(""), pid, uid)) {
return PERMISSION_DENIED;
}
Mutex::Autolock lock(mLock);
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index 63681fa..954ccc9 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -232,11 +232,6 @@
status_t StagefrightRecorder::setAudioSource(audio_source_t as) {
ALOGV("setAudioSource: %d", as);
- if (as < AUDIO_SOURCE_DEFAULT ||
- (as >= AUDIO_SOURCE_CNT && as != AUDIO_SOURCE_FM_TUNER)) {
- ALOGE("Invalid audio source: %d", as);
- return BAD_VALUE;
- }
if (as == AUDIO_SOURCE_DEFAULT) {
mAudioSource = AUDIO_SOURCE_MIC;
diff --git a/media/utils/ServiceUtilities.cpp b/media/utils/ServiceUtilities.cpp
index 990f318..971ae9f 100644
--- a/media/utils/ServiceUtilities.cpp
+++ b/media/utils/ServiceUtilities.cpp
@@ -61,12 +61,12 @@
static bool checkRecordingInternal(const String16& opPackageName, pid_t pid,
uid_t uid, bool start) {
- // Okay to not track in app ops as audio server is us and if
+ // 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.
// system_server loses its RECORD_AUDIO permission when a secondary
// 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
- if (isAudioServerOrSystemServerOrRootUid(uid)) return true;
+ 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.
diff --git a/media/utils/include/mediautils/ServiceUtilities.h b/media/utils/include/mediautils/ServiceUtilities.h
index e1089d5..2595761 100644
--- a/media/utils/include/mediautils/ServiceUtilities.h
+++ b/media/utils/include/mediautils/ServiceUtilities.h
@@ -58,10 +58,11 @@
return multiuser_get_app_id(uid) == AID_SYSTEM || uid == AID_AUDIOSERVER;
}
-// used for calls that should come from system_server or audio_server and
+// used for calls that should come from system_server or audio_server or media server and
// include AID_ROOT for command-line tests.
-static inline bool isAudioServerOrSystemServerOrRootUid(uid_t uid) {
- return multiuser_get_app_id(uid) == AID_SYSTEM || uid == AID_AUDIOSERVER || uid == AID_ROOT;
+static inline bool isAudioServerOrMediaServerOrSystemServerOrRootUid(uid_t uid) {
+ return multiuser_get_app_id(uid) == AID_SYSTEM || uid == AID_AUDIOSERVER
+ || uid == AID_MEDIA || uid == AID_ROOT;
}
// Mediaserver may forward the client PID and UID as part of a binder interface call;
diff --git a/services/audioflinger/RecordTracks.h b/services/audioflinger/RecordTracks.h
index d5257bd..d87239d 100644
--- a/services/audioflinger/RecordTracks.h
+++ b/services/audioflinger/RecordTracks.h
@@ -25,7 +25,8 @@
~OpRecordAudioMonitor() override;
bool hasOpRecordAudio() const;
- static sp<OpRecordAudioMonitor> createIfNeeded(uid_t uid, const String16& opPackageName);
+ static sp<OpRecordAudioMonitor> createIfNeeded
+ (uid_t uid, const audio_attributes_t& attr, const String16& opPackageName);
private:
OpRecordAudioMonitor(uid_t uid, const String16& opPackageName);
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 41a71d5..23c2209 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -1898,7 +1898,7 @@
// static
sp<AudioFlinger::RecordThread::OpRecordAudioMonitor>
AudioFlinger::RecordThread::OpRecordAudioMonitor::createIfNeeded(
- uid_t uid, const String16& opPackageName)
+ uid_t uid, const audio_attributes_t& attr, const String16& opPackageName)
{
if (isServiceUid(uid)) {
ALOGV("not silencing record for service uid:%d pack:%s",
@@ -1906,6 +1906,13 @@
return nullptr;
}
+ // Capturing from FM TUNER output is not controlled by OP_RECORD_AUDIO
+ // because it does not affect users privacy as does capturing from an actual microphone.
+ if (attr.source == AUDIO_SOURCE_FM_TUNER) {
+ ALOGV("not muting FM TUNER capture for uid %d", uid);
+ return nullptr;
+ }
+
if (opPackageName.size() == 0) {
Vector<String16> packages;
// no package name, happens with SL ES clients
@@ -2071,7 +2078,7 @@
mRecordBufferConverter(NULL),
mFlags(flags),
mSilenced(false),
- mOpRecordAudioMonitor(OpRecordAudioMonitor::createIfNeeded(uid, opPackageName))
+ mOpRecordAudioMonitor(OpRecordAudioMonitor::createIfNeeded(uid, attr, opPackageName))
{
if (mCblk == NULL) {
return;
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index 389f861..875f51d 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -377,8 +377,10 @@
pid = callingPid;
}
- // check calling permissions
- if (!recordingAllowed(opPackageName, pid, uid)) {
+ // check calling permissions.
+ // Capturing from FM_TUNER source is controlled by captureAudioOutputAllowed() only as this
+ // does not affect users privacy as does capturing from an actual microphone.
+ if (!(recordingAllowed(opPackageName, pid, uid) || attr->source == AUDIO_SOURCE_FM_TUNER)) {
ALOGE("%s permission denied: recording not allowed for uid %d pid %d",
__func__, uid, pid);
return PERMISSION_DENIED;
@@ -388,7 +390,8 @@
if ((attr->source == AUDIO_SOURCE_VOICE_UPLINK ||
attr->source == AUDIO_SOURCE_VOICE_DOWNLINK ||
attr->source == AUDIO_SOURCE_VOICE_CALL ||
- attr->source == AUDIO_SOURCE_ECHO_REFERENCE) &&
+ attr->source == AUDIO_SOURCE_ECHO_REFERENCE||
+ attr->source == AUDIO_SOURCE_FM_TUNER) &&
!canCaptureOutput) {
return PERMISSION_DENIED;
}
@@ -494,7 +497,8 @@
}
// check calling permissions
- if (!startRecording(client->opPackageName, client->pid, client->uid)) {
+ if (!(startRecording(client->opPackageName, client->pid, client->uid)
+ || client->attributes.source == AUDIO_SOURCE_FM_TUNER)) {
ALOGE("%s permission denied: recording not allowed for uid %d pid %d",
__func__, client->uid, client->pid);
return PERMISSION_DENIED;