DO NOT MERGE Attribute SOURCE_HOTWORD to OP_RECORD_AUDIO_HOTWORD.
Whenever we startRecording / finishRecording with a source
of SOURCE_HOTWORD, attribute them to OP_RECORD_AUDIO_HOTWORD
instead of OP_RECORD_AUDIO. In either case, OP_RECORD_AUDIO
is checked before the recording commences. Note that we also
check that all recordings with SOURCE_HOTWORD are initiated
by a uid that holds the privileged CAPTURE_AUDIO_HOTWORD
permission.
Note that this change will be superseded in the future once
we have stronger guarantees around hotword handling.
Bug: 162547999
Test: manual with dumpsys appops on AGSA
Change-Id: I70e0b652c357597770a18a5a385d62668a69059a
diff --git a/media/utils/ServiceUtilities.cpp b/media/utils/ServiceUtilities.cpp
index 87ea084..7699700 100644
--- a/media/utils/ServiceUtilities.cpp
+++ b/media/utils/ServiceUtilities.cpp
@@ -62,7 +62,7 @@
}
static bool checkRecordingInternal(const String16& opPackageName, pid_t pid,
- uid_t uid, bool start) {
+ uid_t uid, bool start, bool isHotwordSource) {
// 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
@@ -87,16 +87,21 @@
}
AppOpsManager appOps;
- const int32_t op = appOps.permissionToOpCode(sAndroidPermissionRecordAudio);
+ const int32_t opRecordAudio = appOps.permissionToOpCode(sAndroidPermissionRecordAudio);
+
if (start) {
+ const int32_t op = isHotwordSource ?
+ AppOpsManager::OP_RECORD_AUDIO_HOTWORD : opRecordAudio;
if (appOps.startOpNoThrow(op, uid, resolvedOpPackageName, /*startIfModeDefault*/ false)
!= AppOpsManager::MODE_ALLOWED) {
ALOGE("Request denied by app op: %d", op);
return false;
}
} else {
- if (appOps.checkOp(op, uid, resolvedOpPackageName) != AppOpsManager::MODE_ALLOWED) {
- ALOGE("Request denied by app op: %d", op);
+ // Always use OP_RECORD_AUDIO for checks at creation time.
+ if (appOps.checkOp(opRecordAudio, uid, resolvedOpPackageName)
+ != AppOpsManager::MODE_ALLOWED) {
+ ALOGE("Request denied by app op: %d", opRecordAudio);
return false;
}
}
@@ -105,14 +110,15 @@
}
bool recordingAllowed(const String16& opPackageName, pid_t pid, uid_t uid) {
- return checkRecordingInternal(opPackageName, pid, uid, /*start*/ false);
+ return checkRecordingInternal(opPackageName, pid, uid, /*start*/ false,
+ /*is_hotword_source*/ false);
}
-bool startRecording(const String16& opPackageName, pid_t pid, uid_t uid) {
- return checkRecordingInternal(opPackageName, pid, uid, /*start*/ true);
+bool startRecording(const String16& opPackageName, pid_t pid, uid_t uid, bool isHotwordSource) {
+ return checkRecordingInternal(opPackageName, pid, uid, /*start*/ true, isHotwordSource);
}
-void finishRecording(const String16& opPackageName, uid_t uid) {
+void finishRecording(const String16& opPackageName, uid_t uid, bool isHotwordSource) {
// Okay to not track in app ops as audio server is us and if
// device is rooted security model is considered compromised.
if (isAudioServerOrRootUid(uid)) return;
@@ -125,7 +131,8 @@
}
AppOpsManager appOps;
- const int32_t op = appOps.permissionToOpCode(sAndroidPermissionRecordAudio);
+ const int32_t op = isHotwordSource ? AppOpsManager::OP_RECORD_AUDIO_HOTWORD
+ : appOps.permissionToOpCode(sAndroidPermissionRecordAudio);
appOps.finishOp(op, uid, resolvedOpPackageName);
}
diff --git a/media/utils/include/mediautils/ServiceUtilities.h b/media/utils/include/mediautils/ServiceUtilities.h
index 212599a..431dd7a 100644
--- a/media/utils/include/mediautils/ServiceUtilities.h
+++ b/media/utils/include/mediautils/ServiceUtilities.h
@@ -79,8 +79,8 @@
}
bool recordingAllowed(const String16& opPackageName, pid_t pid, uid_t uid);
-bool startRecording(const String16& opPackageName, pid_t pid, uid_t uid);
-void finishRecording(const String16& opPackageName, uid_t uid);
+bool startRecording(const String16& opPackageName, pid_t pid, uid_t uid, bool isHotwordSource);
+void finishRecording(const String16& opPackageName, uid_t uid, bool isHotwordSource);
bool captureAudioOutputAllowed(pid_t pid, uid_t uid);
bool captureMediaOutputAllowed(pid_t pid, uid_t uid);
bool captureVoiceCommunicationOutputAllowed(pid_t pid, uid_t uid);
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index 34d07b6..df27f6e 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -572,7 +572,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_HOTWORD)
|| client->attributes.source == AUDIO_SOURCE_FM_TUNER)) {
ALOGE("%s permission denied: recording not allowed for uid %d pid %d",
__func__, client->uid, client->pid);
@@ -660,7 +661,8 @@
client->active = false;
client->startTimeNs = 0;
updateUidStates_l();
- finishRecording(client->opPackageName, client->uid);
+ finishRecording(client->opPackageName, client->uid,
+ client->attributes.source == AUDIO_SOURCE_HOTWORD);
}
return status;
@@ -686,7 +688,8 @@
updateUidStates_l();
// finish the recording app op
- finishRecording(client->opPackageName, client->uid);
+ finishRecording(client->opPackageName, client->uid,
+ client->attributes.source == AUDIO_SOURCE_HOTWORD);
AutoCallerClear acc;
return mAudioPolicyManager->stopInput(portId);
}