summaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
authorSvet Ganov <svetoslavganov@google.com>2015-04-28 12:06:02 -0700
committerSvetoslav Ganov <svetoslavganov@google.com>2015-04-29 19:06:41 +0000
commitbe71aa29a3c86d2e01cd17839d2a72ab09a1bce5 (patch)
treeca29cd10f78ff053761eb809c391019180836742 /services
parentf62a067a5b21c840c915d36392679346ac0abfd7 (diff)
downloadframeworks_av-be71aa29a3c86d2e01cd17839d2a72ab09a1bce5.zip
frameworks_av-be71aa29a3c86d2e01cd17839d2a72ab09a1bce5.tar.gz
frameworks_av-be71aa29a3c86d2e01cd17839d2a72ab09a1bce5.tar.bz2
Respect the record audio app op - media
Change-Id: I3a97977b6e9a09355e2008f780d22d480fb7308b
Diffstat (limited to 'services')
-rw-r--r--services/audioflinger/AudioFlinger.cpp6
-rw-r--r--services/audioflinger/AudioFlinger.h2
-rw-r--r--services/audioflinger/ServiceUtilities.cpp84
-rw-r--r--services/audioflinger/ServiceUtilities.h3
-rw-r--r--services/audiopolicy/service/AudioPolicyEffects.cpp6
5 files changed, 82 insertions, 19 deletions
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 5002099..48f7514 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -1416,6 +1416,7 @@ sp<IAudioRecord> AudioFlinger::openRecord(
uint32_t sampleRate,
audio_format_t format,
audio_channel_mask_t channelMask,
+ const String16& opPackageName,
size_t *frameCount,
IAudioFlinger::track_flags_t *flags,
pid_t tid,
@@ -1435,7 +1436,7 @@ sp<IAudioRecord> AudioFlinger::openRecord(
buffers.clear();
// check calling permissions
- if (!recordingAllowed()) {
+ if (!recordingAllowed(opPackageName)) {
ALOGE("openRecord() permission denied: recording not allowed");
lStatus = PERMISSION_DENIED;
goto Exit;
@@ -2447,6 +2448,7 @@ sp<IEffect> AudioFlinger::createEffect(
int32_t priority,
audio_io_handle_t io,
int sessionId,
+ const String16& opPackageName,
status_t *status,
int *id,
int *enabled)
@@ -2543,7 +2545,7 @@ sp<IEffect> AudioFlinger::createEffect(
// check recording permission for visualizer
if ((memcmp(&desc.type, SL_IID_VISUALIZATION, sizeof(effect_uuid_t)) == 0) &&
- !recordingAllowed()) {
+ !recordingAllowed(opPackageName)) {
lStatus = PERMISSION_DENIED;
goto Exit;
}
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index e1ddcbc..3c4517f 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -120,6 +120,7 @@ public:
uint32_t sampleRate,
audio_format_t format,
audio_channel_mask_t channelMask,
+ const String16& opPackageName,
size_t *pFrameCount,
IAudioFlinger::track_flags_t *flags,
pid_t tid,
@@ -216,6 +217,7 @@ public:
int32_t priority,
audio_io_handle_t io,
int sessionId,
+ const String16& opPackageName,
status_t *status /*non-NULL*/,
int *id,
int *enabled);
diff --git a/services/audioflinger/ServiceUtilities.cpp b/services/audioflinger/ServiceUtilities.cpp
index 8246fef..0a718fb 100644
--- a/services/audioflinger/ServiceUtilities.cpp
+++ b/services/audioflinger/ServiceUtilities.cpp
@@ -14,38 +14,97 @@
* limitations under the License.
*/
+#include <binder/AppOpsManager.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <binder/PermissionCache.h>
#include "ServiceUtilities.h"
+/* When performing permission checks we do not use permission cache for
+ * runtime permissions (protection level dangerous) as they may change at
+ * runtime. All other permissions (protection level normal and dangerous)
+ * can be cached as they never change. Of course all permission checked
+ * here are platform defined.
+ */
+
namespace android {
// Not valid until initialized by AudioFlinger constructor. It would have to be
// re-initialized if the process containing AudioFlinger service forks (which it doesn't).
pid_t getpid_cached;
-bool recordingAllowed() {
+bool recordingAllowed(const String16& opPackageName) {
+ // Note: We are getting the UID from the calling IPC thread state because all
+ // clients that perform recording create AudioRecord in their own processes
+ // and the system does not create AudioRecord objects on behalf of apps. This
+ // differs from playback where in some situations the system recreates AudioTrack
+ // instances associated with a client's MediaPlayer on behalf of this client.
+ // In the latter case we have to store the client UID and pass in along for
+ // security checks.
+
if (getpid_cached == IPCThreadState::self()->getCallingPid()) return true;
static const String16 sRecordAudio("android.permission.RECORD_AUDIO");
- // don't use PermissionCache; this is not a system permission
- bool ok = checkCallingPermission(sRecordAudio);
- if (!ok) ALOGE("Request requires android.permission.RECORD_AUDIO");
- return ok;
+
+ // IMPORTANT: Don't use PermissionCache - a runtime permission and may change.
+ const bool ok = checkCallingPermission(sRecordAudio);
+ if (!ok) {
+ ALOGE("Request requires android.permission.RECORD_AUDIO");
+ return false;
+ }
+
+ const uid_t uid = IPCThreadState::self()->getCallingUid();
+ String16 checkedOpPackageName = opPackageName;
+
+ // In some cases the calling code has no access to the package it runs under.
+ // For example, code using the wilhelm framework's OpenSL-ES APIs. In this
+ // case we will get the packages for the calling UID and pick the first one
+ // for attributing the app op. This will work correctly for runtime permissions
+ // as for legacy apps we will toggle the app op for all packages in the UID.
+ // The caveat is that the operation may be attributed to the wrong package and
+ // stats based on app ops may be slightly off.
+ if (checkedOpPackageName.size() <= 0) {
+ sp<IServiceManager> sm = defaultServiceManager();
+ sp<IBinder> binder = sm->getService(String16("permission"));
+ if (binder == 0) {
+ ALOGE("Cannot get permission service");
+ return false;
+ }
+
+ sp<IPermissionController> permCtrl = interface_cast<IPermissionController>(binder);
+ Vector<String16> packages;
+
+ permCtrl->getPackagesForUid(uid, packages);
+
+ if (packages.isEmpty()) {
+ ALOGE("No packages for calling UID");
+ return false;
+ }
+ checkedOpPackageName = packages[0];
+ }
+
+ AppOpsManager appOps;
+ if (appOps.noteOp(AppOpsManager::OP_RECORD_AUDIO, uid, opPackageName)
+ != AppOpsManager::MODE_ALLOWED) {
+ ALOGE("Request denied by app op OP_RECORD_AUDIO");
+ return false;
+ }
+
+ return true;
}
bool captureAudioOutputAllowed() {
if (getpid_cached == IPCThreadState::self()->getCallingPid()) return true;
static const String16 sCaptureAudioOutput("android.permission.CAPTURE_AUDIO_OUTPUT");
- // don't use PermissionCache; this is not a system permission
- bool ok = checkCallingPermission(sCaptureAudioOutput);
+ // IMPORTANT: Use PermissionCache - not a runtime permission and may not change.
+ bool ok = PermissionCache::checkCallingPermission(sCaptureAudioOutput);
if (!ok) ALOGE("Request requires android.permission.CAPTURE_AUDIO_OUTPUT");
return ok;
}
bool captureHotwordAllowed() {
static const String16 sCaptureHotwordAllowed("android.permission.CAPTURE_AUDIO_HOTWORD");
- bool ok = checkCallingPermission(sCaptureHotwordAllowed);
+ // IMPORTANT: Use PermissionCache - not a runtime permission and may not change.
+ bool ok = PermissionCache::checkCallingPermission(sCaptureHotwordAllowed);
if (!ok) ALOGE("android.permission.CAPTURE_AUDIO_HOTWORD");
return ok;
}
@@ -53,15 +112,16 @@ bool captureHotwordAllowed() {
bool settingsAllowed() {
if (getpid_cached == IPCThreadState::self()->getCallingPid()) return true;
static const String16 sAudioSettings("android.permission.MODIFY_AUDIO_SETTINGS");
- // don't use PermissionCache; this is not a system permission
- bool ok = checkCallingPermission(sAudioSettings);
+ // IMPORTANT: Use PermissionCache - not a runtime permission and may not change.
+ bool ok = PermissionCache::checkCallingPermission(sAudioSettings);
if (!ok) ALOGE("Request requires android.permission.MODIFY_AUDIO_SETTINGS");
return ok;
}
bool modifyAudioRoutingAllowed() {
static const String16 sModifyAudioRoutingAllowed("android.permission.MODIFY_AUDIO_ROUTING");
- bool ok = checkCallingPermission(sModifyAudioRoutingAllowed);
+ // IMPORTANT: Use PermissionCache - not a runtime permission and may not change.
+ bool ok = PermissionCache::checkCallingPermission(sModifyAudioRoutingAllowed);
if (!ok) ALOGE("android.permission.MODIFY_AUDIO_ROUTING");
return ok;
}
@@ -69,7 +129,7 @@ bool modifyAudioRoutingAllowed() {
bool dumpAllowed() {
// don't optimize for same pid, since mediaserver never dumps itself
static const String16 sDump("android.permission.DUMP");
- // OK to use PermissionCache; this is a system permission
+ // IMPORTANT: Use PermissionCache - not a runtime permission and may not change.
bool ok = PermissionCache::checkCallingPermission(sDump);
// convention is for caller to dump an error message to fd instead of logging here
//if (!ok) ALOGE("Request requires android.permission.DUMP");
diff --git a/services/audioflinger/ServiceUtilities.h b/services/audioflinger/ServiceUtilities.h
index df6f6f4..fba6dce 100644
--- a/services/audioflinger/ServiceUtilities.h
+++ b/services/audioflinger/ServiceUtilities.h
@@ -20,11 +20,10 @@ namespace android {
extern pid_t getpid_cached;
-bool recordingAllowed();
+bool recordingAllowed(const String16& opPackageName);
bool captureAudioOutputAllowed();
bool captureHotwordAllowed();
bool settingsAllowed();
bool modifyAudioRoutingAllowed();
bool dumpAllowed();
-
}
diff --git a/services/audiopolicy/service/AudioPolicyEffects.cpp b/services/audiopolicy/service/AudioPolicyEffects.cpp
index e6ace20..282ddeb 100644
--- a/services/audiopolicy/service/AudioPolicyEffects.cpp
+++ b/services/audiopolicy/service/AudioPolicyEffects.cpp
@@ -109,8 +109,8 @@ status_t AudioPolicyEffects::addInputEffects(audio_io_handle_t input,
Vector <EffectDesc *> effects = mInputSources.valueAt(index)->mEffects;
for (size_t i = 0; i < effects.size(); i++) {
EffectDesc *effect = effects[i];
- sp<AudioEffect> fx = new AudioEffect(NULL, &effect->mUuid, -1, 0, 0,
- audioSession, input);
+ sp<AudioEffect> fx = new AudioEffect(NULL, String16("android"), &effect->mUuid, -1, 0,
+ 0, audioSession, input);
status_t status = fx->initCheck();
if (status != NO_ERROR && status != ALREADY_EXISTS) {
ALOGW("addInputEffects(): failed to create Fx %s on source %d",
@@ -254,7 +254,7 @@ status_t AudioPolicyEffects::addOutputSessionEffects(audio_io_handle_t output,
Vector <EffectDesc *> effects = mOutputStreams.valueAt(index)->mEffects;
for (size_t i = 0; i < effects.size(); i++) {
EffectDesc *effect = effects[i];
- sp<AudioEffect> fx = new AudioEffect(NULL, &effect->mUuid, 0, 0, 0,
+ sp<AudioEffect> fx = new AudioEffect(NULL, String16("android"), &effect->mUuid, 0, 0, 0,
audioSession, output);
status_t status = fx->initCheck();
if (status != NO_ERROR && status != ALREADY_EXISTS) {