audio policy: more concurrent capture fixes

Fix two concurrent capture scenarii when VoIP call is active:
1) when the audio mode is IN_COMMUNICATION, only allow capture
from the app owning the audio mode.
2) fix capture by a privileged app when a privacy sensitive capture is
active: capture was silecend if the privacy sensitive capture was
started after the privileged capture.

Bug: 148368476
Test: Manual test of various VoIP apps and phone calls scenarii
Test: cts AudioRecordTest
Change-Id: I166f91c43ce86bb23c2f171700ece634091caaad
gugelfrei
Eric Laurent 4 years ago
parent b31dab4d2d
commit c21d569900

@ -446,17 +446,19 @@ void AudioPolicyService::updateUidStates_l()
sp<AudioRecordClient> topActive;
sp<AudioRecordClient> latestActive;
sp<AudioRecordClient> topSensitiveActive;
sp<AudioRecordClient> latestSensitiveActive;
nsecs_t topStartNs = 0;
nsecs_t latestStartNs = 0;
nsecs_t topSensitiveStartNs = 0;
nsecs_t latestSensitiveStartNs = 0;
bool isA11yOnTop = mUidPolicy->isA11yOnTop();
bool isAssistantOnTop = false;
bool isSensitiveActive = false;
bool isInCall = mPhoneState == AUDIO_MODE_IN_CALL;
bool rttCallActive =
(mPhoneState == AUDIO_MODE_IN_CALL || mPhoneState == AUDIO_MODE_IN_COMMUNICATION)
bool isInCommunication = mPhoneState == AUDIO_MODE_IN_COMMUNICATION;
bool rttCallActive = (isInCall || isInCommunication)
&& mUidPolicy->isRttEnabled();
bool onlyHotwordActive = true;
@ -479,32 +481,46 @@ void AudioPolicyService::updateUidStates_l()
continue;
}
bool isAssistant = mUidPolicy->isAssistantUid(current->uid);
bool isAccessibility = mUidPolicy->isA11yUid(current->uid);
if (appState == APP_STATE_TOP && !isAccessibility) {
if (current->startTimeNs > topStartNs) {
topActive = current;
topStartNs = current->startTimeNs;
}
if (isAssistant) {
isAssistantOnTop = true;
// Clients capturing for Accessibility services are not considered
// for top or latest active to avoid masking regular clients started before
if (!isAccessibility) {
bool isAssistant = mUidPolicy->isAssistantUid(current->uid);
bool isPrivacySensitive =
(current->attributes.flags & AUDIO_FLAG_CAPTURE_PRIVATE) != 0;
if (appState == APP_STATE_TOP) {
if (isPrivacySensitive) {
if (current->startTimeNs > topSensitiveStartNs) {
topSensitiveActive = current;
topSensitiveStartNs = current->startTimeNs;
}
} else {
if (current->startTimeNs > topStartNs) {
topActive = current;
topStartNs = current->startTimeNs;
}
}
if (isAssistant) {
isAssistantOnTop = true;
}
}
}
// Client capturing for HOTWORD or Accessibility services not considered
// for latest active to avoid masking regular clients started before
if (current->startTimeNs > latestStartNs
&& !(current->attributes.source == AUDIO_SOURCE_HOTWORD
|| ((isA11yOnTop || rttCallActive) && isAssistant))
&& !isAccessibility) {
latestActive = current;
latestStartNs = current->startTimeNs;
}
if ((current->attributes.flags & AUDIO_FLAG_CAPTURE_PRIVATE) != 0) {
if (current->startTimeNs > latestSensitiveStartNs) {
latestSensitiveActive = current;
latestSensitiveStartNs = current->startTimeNs;
// Clients capturing for HOTWORD are not considered
// for latest active to avoid masking regular clients started before
if (!(current->attributes.source == AUDIO_SOURCE_HOTWORD
|| ((isA11yOnTop || rttCallActive) && isAssistant))) {
if (isPrivacySensitive) {
if (current->startTimeNs > latestSensitiveStartNs) {
latestSensitiveActive = current;
latestSensitiveStartNs = current->startTimeNs;
}
isSensitiveActive = true;
} else {
if (current->startTimeNs > latestStartNs) {
latestActive = current;
latestStartNs = current->startTimeNs;
}
}
}
isSensitiveActive = true;
}
if (current->attributes.source != AUDIO_SOURCE_HOTWORD) {
onlyHotwordActive = false;
@ -514,6 +530,21 @@ void AudioPolicyService::updateUidStates_l()
// if no active client with UI on Top, consider latest active as top
if (topActive == nullptr) {
topActive = latestActive;
topStartNs = latestStartNs;
}
if (topSensitiveActive == nullptr) {
topSensitiveActive = latestSensitiveActive;
topSensitiveStartNs = latestSensitiveStartNs;
}
// If both privacy sensitive and regular capture are active:
// if the regular capture is privileged
// allow concurrency
// else
// favor the privacy sensitive case
if (topActive != nullptr && topSensitiveActive != nullptr
&& !topActive->canCaptureCallOrOutput) {
topActive = nullptr;
}
for (size_t i =0; i < mAudioRecordClients.size(); i++) {
@ -524,8 +555,17 @@ void AudioPolicyService::updateUidStates_l()
audio_source_t source = current->attributes.source;
bool isTopOrLatestActive = topActive == nullptr ? false : current->uid == topActive->uid;
bool isLatestSensitive = latestSensitiveActive == nullptr ?
false : current->uid == latestSensitiveActive->uid;
bool isTopOrLatestSensitive = topSensitiveActive == nullptr ?
false : current->uid == topSensitiveActive->uid;
auto canCaptureIfInCallOrCommunication = [&](const auto &recordClient) {
bool canCaptureCall = recordClient->canCaptureCallOrOutput;
bool canCaptureCommunication = recordClient->canCaptureCallOrOutput
|| recordClient->uid == mPhoneStateOwnerUid
|| isServiceUid(mPhoneStateOwnerUid);
return !(isInCall && !canCaptureCall)
&& !(isInCommunication && !canCaptureCommunication);
};
// By default allow capture if:
// The assistant is not on TOP
@ -533,9 +573,10 @@ void AudioPolicyService::updateUidStates_l()
// AND there is no active privacy sensitive capture or call
// OR client has CAPTURE_AUDIO_OUTPUT privileged permission
bool allowCapture = !isAssistantOnTop
&& ((isTopOrLatestActive && !isLatestSensitive) || isLatestSensitive)
&& !(isSensitiveActive && !(isLatestSensitive || current->canCaptureCallOrOutput))
&& !(isInCall && !current->canCaptureCallOrOutput);
&& (isTopOrLatestActive || isTopOrLatestSensitive)
&& !(isSensitiveActive
&& !(isTopOrLatestSensitive || current->canCaptureCallOrOutput))
&& canCaptureIfInCallOrCommunication(current);
if (isVirtualSource(source)) {
// Allow capture for virtual (remote submix, call audio TX or RX...) sources
@ -554,8 +595,9 @@ void AudioPolicyService::updateUidStates_l()
}
} else {
if (((isAssistantOnTop && source == AUDIO_SOURCE_VOICE_RECOGNITION) ||
source == AUDIO_SOURCE_HOTWORD) &&
(!(isSensitiveActive || isInCall) || current->canCaptureCallOrOutput)) {
source == AUDIO_SOURCE_HOTWORD)
&& !(isSensitiveActive && !current->canCaptureCallOrOutput)
&& canCaptureIfInCallOrCommunication(current)) {
allowCapture = true;
}
}
@ -567,7 +609,8 @@ void AudioPolicyService::updateUidStates_l()
// OR
// Is on TOP AND the source is VOICE_RECOGNITION or HOTWORD
if (!isAssistantOnTop
&& (!(isSensitiveActive || isInCall) || current->canCaptureCallOrOutput)) {
&& !(isSensitiveActive && !current->canCaptureCallOrOutput)
&& canCaptureIfInCallOrCommunication(current)) {
allowCapture = true;
}
if (isA11yOnTop) {
@ -580,7 +623,8 @@ void AudioPolicyService::updateUidStates_l()
// All active clients are using HOTWORD source
// AND no call is active
// OR client has CAPTURE_AUDIO_OUTPUT privileged permission
if (onlyHotwordActive && !(isInCall && !current->canCaptureCallOrOutput)) {
if (onlyHotwordActive
&& canCaptureIfInCallOrCommunication(current)) {
allowCapture = true;
}
}

Loading…
Cancel
Save