AudioDeviceBroker: ignore communication route requests by idle apps am: 43e951b21d

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/23783543

Change-Id: Id6fb47c64d84495bdf14c9e44049000215e7a0a8
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Eric Laurent
2023-07-03 08:58:23 +00:00
committed by Automerger Merge Worker
3 changed files with 205 additions and 110 deletions

View File

@@ -30,6 +30,8 @@ import android.media.AudioAttributes;
import android.media.AudioDeviceAttributes; import android.media.AudioDeviceAttributes;
import android.media.AudioDeviceInfo; import android.media.AudioDeviceInfo;
import android.media.AudioManager; import android.media.AudioManager;
import android.media.AudioPlaybackConfiguration;
import android.media.AudioRecordingConfiguration;
import android.media.AudioRoutesInfo; import android.media.AudioRoutesInfo;
import android.media.AudioSystem; import android.media.AudioSystem;
import android.media.BluetoothProfileConnectionInfo; import android.media.BluetoothProfileConnectionInfo;
@@ -289,37 +291,38 @@ import java.util.concurrent.atomic.AtomicBoolean;
* @param on * @param on
* @param eventSource for logging purposes * @param eventSource for logging purposes
*/ */
/*package*/ void setSpeakerphoneOn(IBinder cb, int pid, boolean on, String eventSource) { /*package*/ void setSpeakerphoneOn(
IBinder cb, int uid, boolean on, boolean isPrivileged, String eventSource) {
if (AudioService.DEBUG_COMM_RTE) { if (AudioService.DEBUG_COMM_RTE) {
Log.v(TAG, "setSpeakerphoneOn, on: " + on + " pid: " + pid); Log.v(TAG, "setSpeakerphoneOn, on: " + on + " uid: " + uid);
} }
postSetCommunicationDeviceForClient(new CommunicationDeviceInfo( postSetCommunicationDeviceForClient(new CommunicationDeviceInfo(
cb, pid, new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_SPEAKER, ""), cb, uid, new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_SPEAKER, ""),
on, BtHelper.SCO_MODE_UNDEFINED, eventSource, false)); on, BtHelper.SCO_MODE_UNDEFINED, eventSource, false, isPrivileged));
} }
/** /**
* Select device for use for communication use cases. * Select device for use for communication use cases.
* @param cb Client binder for death detection * @param cb Client binder for death detection
* @param pid Client pid * @param uid Client uid
* @param device Device selected or null to unselect. * @param device Device selected or null to unselect.
* @param eventSource for logging purposes * @param eventSource for logging purposes
*/ */
private static final long SET_COMMUNICATION_DEVICE_TIMEOUT_MS = 3000; private static final long SET_COMMUNICATION_DEVICE_TIMEOUT_MS = 3000;
/*package*/ boolean setCommunicationDevice( /*package*/ boolean setCommunicationDevice(IBinder cb, int uid, AudioDeviceInfo device,
IBinder cb, int pid, AudioDeviceInfo device, String eventSource) { boolean isPrivileged, String eventSource) {
if (AudioService.DEBUG_COMM_RTE) { if (AudioService.DEBUG_COMM_RTE) {
Log.v(TAG, "setCommunicationDevice, device: " + device + ", pid: " + pid); Log.v(TAG, "setCommunicationDevice, device: " + device + ", uid: " + uid);
} }
AudioDeviceAttributes deviceAttr = AudioDeviceAttributes deviceAttr =
(device != null) ? new AudioDeviceAttributes(device) : null; (device != null) ? new AudioDeviceAttributes(device) : null;
CommunicationDeviceInfo deviceInfo = new CommunicationDeviceInfo(cb, pid, deviceAttr, CommunicationDeviceInfo deviceInfo = new CommunicationDeviceInfo(cb, uid, deviceAttr,
device != null, BtHelper.SCO_MODE_UNDEFINED, eventSource, true); device != null, BtHelper.SCO_MODE_UNDEFINED, eventSource, true, isPrivileged);
postSetCommunicationDeviceForClient(deviceInfo); postSetCommunicationDeviceForClient(deviceInfo);
boolean status; boolean status;
synchronized (deviceInfo) { synchronized (deviceInfo) {
@@ -353,7 +356,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
Log.v(TAG, "onSetCommunicationDeviceForClient: " + deviceInfo); Log.v(TAG, "onSetCommunicationDeviceForClient: " + deviceInfo);
} }
if (!deviceInfo.mOn) { if (!deviceInfo.mOn) {
CommunicationRouteClient client = getCommunicationRouteClientForPid(deviceInfo.mPid); CommunicationRouteClient client = getCommunicationRouteClientForUid(deviceInfo.mUid);
if (client == null || (deviceInfo.mDevice != null if (client == null || (deviceInfo.mDevice != null
&& !deviceInfo.mDevice.equals(client.getDevice()))) { && !deviceInfo.mDevice.equals(client.getDevice()))) {
return false; return false;
@@ -361,22 +364,22 @@ import java.util.concurrent.atomic.AtomicBoolean;
} }
AudioDeviceAttributes device = deviceInfo.mOn ? deviceInfo.mDevice : null; AudioDeviceAttributes device = deviceInfo.mOn ? deviceInfo.mDevice : null;
setCommunicationRouteForClient(deviceInfo.mCb, deviceInfo.mPid, device, setCommunicationRouteForClient(deviceInfo.mCb, deviceInfo.mUid, device,
deviceInfo.mScoAudioMode, deviceInfo.mEventSource); deviceInfo.mScoAudioMode, deviceInfo.mIsPrivileged, deviceInfo.mEventSource);
return true; return true;
} }
@GuardedBy("mDeviceStateLock") @GuardedBy("mDeviceStateLock")
/*package*/ void setCommunicationRouteForClient( /*package*/ void setCommunicationRouteForClient(
IBinder cb, int pid, AudioDeviceAttributes device, IBinder cb, int uid, AudioDeviceAttributes device,
int scoAudioMode, String eventSource) { int scoAudioMode, boolean isPrivileged, String eventSource) {
if (AudioService.DEBUG_COMM_RTE) { if (AudioService.DEBUG_COMM_RTE) {
Log.v(TAG, "setCommunicationRouteForClient: device: " + device); Log.v(TAG, "setCommunicationRouteForClient: device: " + device);
} }
AudioService.sDeviceLogger.enqueue((new EventLogger.StringEvent( AudioService.sDeviceLogger.enqueue((new EventLogger.StringEvent(
"setCommunicationRouteForClient for pid: " + pid "setCommunicationRouteForClient for uid: " + uid
+ " device: " + device + " device: " + device + " isPrivileged: " + isPrivileged
+ " from API: " + eventSource)).printLog(TAG)); + " from API: " + eventSource)).printLog(TAG));
final boolean wasBtScoRequested = isBluetoothScoRequested(); final boolean wasBtScoRequested = isBluetoothScoRequested();
@@ -385,16 +388,18 @@ import java.util.concurrent.atomic.AtomicBoolean;
// Save previous client route in case of failure to start BT SCO audio // Save previous client route in case of failure to start BT SCO audio
AudioDeviceAttributes prevClientDevice = null; AudioDeviceAttributes prevClientDevice = null;
client = getCommunicationRouteClientForPid(pid); boolean prevPrivileged = false;
client = getCommunicationRouteClientForUid(uid);
if (client != null) { if (client != null) {
prevClientDevice = client.getDevice(); prevClientDevice = client.getDevice();
prevPrivileged = client.isPrivileged();
} }
if (device != null) { if (device != null) {
client = addCommunicationRouteClient(cb, pid, device); client = addCommunicationRouteClient(cb, uid, device, isPrivileged);
if (client == null) { if (client == null) {
Log.w(TAG, "setCommunicationRouteForClient: could not add client for pid: " Log.w(TAG, "setCommunicationRouteForClient: could not add client for uid: "
+ pid + " and device: " + device); + uid + " and device: " + device);
} }
} else { } else {
client = removeCommunicationRouteClient(cb, true); client = removeCommunicationRouteClient(cb, true);
@@ -406,11 +411,11 @@ import java.util.concurrent.atomic.AtomicBoolean;
boolean isBtScoRequested = isBluetoothScoRequested(); boolean isBtScoRequested = isBluetoothScoRequested();
if (isBtScoRequested && (!wasBtScoRequested || !isBluetoothScoActive())) { if (isBtScoRequested && (!wasBtScoRequested || !isBluetoothScoActive())) {
if (!mBtHelper.startBluetoothSco(scoAudioMode, eventSource)) { if (!mBtHelper.startBluetoothSco(scoAudioMode, eventSource)) {
Log.w(TAG, "setCommunicationRouteForClient: failure to start BT SCO for pid: " Log.w(TAG, "setCommunicationRouteForClient: failure to start BT SCO for uid: "
+ pid); + uid);
// clean up or restore previous client selection // clean up or restore previous client selection
if (prevClientDevice != null) { if (prevClientDevice != null) {
addCommunicationRouteClient(cb, pid, prevClientDevice); addCommunicationRouteClient(cb, uid, prevClientDevice, prevPrivileged);
} else { } else {
removeCommunicationRouteClient(cb, true); removeCommunicationRouteClient(cb, true);
} }
@@ -447,11 +452,12 @@ import java.util.concurrent.atomic.AtomicBoolean;
@GuardedBy("mDeviceStateLock") @GuardedBy("mDeviceStateLock")
private CommunicationRouteClient topCommunicationRouteClient() { private CommunicationRouteClient topCommunicationRouteClient() {
for (CommunicationRouteClient crc : mCommunicationRouteClients) { for (CommunicationRouteClient crc : mCommunicationRouteClients) {
if (crc.getPid() == mAudioModeOwner.mPid) { if (crc.getUid() == mAudioModeOwner.mUid) {
return crc; return crc;
} }
} }
if (!mCommunicationRouteClients.isEmpty() && mAudioModeOwner.mPid == 0) { if (!mCommunicationRouteClients.isEmpty() && mAudioModeOwner.mPid == 0
&& mCommunicationRouteClients.get(0).isActive()) {
return mCommunicationRouteClients.get(0); return mCommunicationRouteClients.get(0);
} }
return null; return null;
@@ -1107,26 +1113,26 @@ import java.util.concurrent.atomic.AtomicBoolean;
sendLMsgNoDelay(MSG_L_BLUETOOTH_DEVICE_CONFIG_CHANGE, SENDMSG_QUEUE, info); sendLMsgNoDelay(MSG_L_BLUETOOTH_DEVICE_CONFIG_CHANGE, SENDMSG_QUEUE, info);
} }
/*package*/ void startBluetoothScoForClient(IBinder cb, int pid, int scoAudioMode, /*package*/ void startBluetoothScoForClient(IBinder cb, int uid, int scoAudioMode,
@NonNull String eventSource) { boolean isPrivileged, @NonNull String eventSource) {
if (AudioService.DEBUG_COMM_RTE) { if (AudioService.DEBUG_COMM_RTE) {
Log.v(TAG, "startBluetoothScoForClient, pid: " + pid); Log.v(TAG, "startBluetoothScoForClient, uid: " + uid);
} }
postSetCommunicationDeviceForClient(new CommunicationDeviceInfo( postSetCommunicationDeviceForClient(new CommunicationDeviceInfo(
cb, pid, new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_BLUETOOTH_SCO, ""), cb, uid, new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_BLUETOOTH_SCO, ""),
true, scoAudioMode, eventSource, false)); true, scoAudioMode, eventSource, false, isPrivileged));
} }
/*package*/ void stopBluetoothScoForClient( /*package*/ void stopBluetoothScoForClient(
IBinder cb, int pid, @NonNull String eventSource) { IBinder cb, int uid, boolean isPrivileged, @NonNull String eventSource) {
if (AudioService.DEBUG_COMM_RTE) { if (AudioService.DEBUG_COMM_RTE) {
Log.v(TAG, "stopBluetoothScoForClient, pid: " + pid); Log.v(TAG, "stopBluetoothScoForClient, uid: " + uid);
} }
postSetCommunicationDeviceForClient(new CommunicationDeviceInfo( postSetCommunicationDeviceForClient(new CommunicationDeviceInfo(
cb, pid, new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_BLUETOOTH_SCO, ""), cb, uid, new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_BLUETOOTH_SCO, ""),
false, BtHelper.SCO_MODE_UNDEFINED, eventSource, false)); false, BtHelper.SCO_MODE_UNDEFINED, eventSource, false, isPrivileged));
} }
/*package*/ int setPreferredDevicesForStrategySync(int strategy, /*package*/ int setPreferredDevicesForStrategySync(int strategy,
@@ -1367,22 +1373,24 @@ import java.util.concurrent.atomic.AtomicBoolean;
/*package*/ static final class CommunicationDeviceInfo { /*package*/ static final class CommunicationDeviceInfo {
final @NonNull IBinder mCb; // Identifies the requesting client for death handler final @NonNull IBinder mCb; // Identifies the requesting client for death handler
final int mPid; // Requester process ID final int mUid; // Requester UID
final @Nullable AudioDeviceAttributes mDevice; // Device being set or reset. final @Nullable AudioDeviceAttributes mDevice; // Device being set or reset.
final boolean mOn; // true if setting, false if resetting final boolean mOn; // true if setting, false if resetting
final int mScoAudioMode; // only used for SCO: requested audio mode final int mScoAudioMode; // only used for SCO: requested audio mode
final boolean mIsPrivileged; // true if the client app has MODIFY_PHONE_STATE permission
final @NonNull String mEventSource; // caller identifier for logging final @NonNull String mEventSource; // caller identifier for logging
boolean mWaitForStatus; // true if the caller waits for a completion status (API dependent) boolean mWaitForStatus; // true if the caller waits for a completion status (API dependent)
boolean mStatus = false; // completion status only used if mWaitForStatus is true boolean mStatus = false; // completion status only used if mWaitForStatus is true
CommunicationDeviceInfo(@NonNull IBinder cb, int pid, CommunicationDeviceInfo(@NonNull IBinder cb, int uid,
@Nullable AudioDeviceAttributes device, boolean on, int scoAudioMode, @Nullable AudioDeviceAttributes device, boolean on, int scoAudioMode,
@NonNull String eventSource, boolean waitForStatus) { @NonNull String eventSource, boolean waitForStatus, boolean isPrivileged) {
mCb = cb; mCb = cb;
mPid = pid; mUid = uid;
mDevice = device; mDevice = device;
mOn = on; mOn = on;
mScoAudioMode = scoAudioMode; mScoAudioMode = scoAudioMode;
mIsPrivileged = isPrivileged;
mEventSource = eventSource; mEventSource = eventSource;
mWaitForStatus = waitForStatus; mWaitForStatus = waitForStatus;
} }
@@ -1401,16 +1409,17 @@ import java.util.concurrent.atomic.AtomicBoolean;
} }
return mCb.equals(((CommunicationDeviceInfo) o).mCb) return mCb.equals(((CommunicationDeviceInfo) o).mCb)
&& mPid == ((CommunicationDeviceInfo) o).mPid; && mUid == ((CommunicationDeviceInfo) o).mUid;
} }
@Override @Override
public String toString() { public String toString() {
return "CommunicationDeviceInfo mCb=" + mCb.toString() return "CommunicationDeviceInfo mCb=" + mCb.toString()
+ " mPid=" + mPid + " mUid=" + mUid
+ " mDevice=[" + (mDevice != null ? mDevice.toString() : "null") + "]" + " mDevice=[" + (mDevice != null ? mDevice.toString() : "null") + "]"
+ " mOn=" + mOn + " mOn=" + mOn
+ " mScoAudioMode=" + mScoAudioMode + " mScoAudioMode=" + mScoAudioMode
+ " mIsPrivileged=" + mIsPrivileged
+ " mEventSource=" + mEventSource + " mEventSource=" + mEventSource
+ " mWaitForStatus=" + mWaitForStatus + " mWaitForStatus=" + mWaitForStatus
+ " mStatus=" + mStatus; + " mStatus=" + mStatus;
@@ -1507,8 +1516,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
pw.println("\n" + prefix + "Communication route clients:"); pw.println("\n" + prefix + "Communication route clients:");
mCommunicationRouteClients.forEach((cl) -> { mCommunicationRouteClients.forEach((cl) -> {
pw.println(" " + prefix + "pid: " + cl.getPid() + " device: " pw.println(" " + prefix + cl.toString()); });
+ cl.getDevice() + " cb: " + cl.getBinder()); });
pw.println("\n" + prefix + "Computed Preferred communication device: " pw.println("\n" + prefix + "Computed Preferred communication device: "
+ preferredCommunicationDevice()); + preferredCommunicationDevice());
@@ -2101,13 +2109,20 @@ import java.util.concurrent.atomic.AtomicBoolean;
private class CommunicationRouteClient implements IBinder.DeathRecipient { private class CommunicationRouteClient implements IBinder.DeathRecipient {
private final IBinder mCb; private final IBinder mCb;
private final int mPid; private final int mUid;
private final boolean mIsPrivileged;
private AudioDeviceAttributes mDevice; private AudioDeviceAttributes mDevice;
private boolean mPlaybackActive;
private boolean mRecordingActive;
CommunicationRouteClient(IBinder cb, int pid, AudioDeviceAttributes device) { CommunicationRouteClient(IBinder cb, int uid, AudioDeviceAttributes device,
boolean isPrivileged) {
mCb = cb; mCb = cb;
mPid = pid; mUid = uid;
mDevice = device; mDevice = device;
mIsPrivileged = isPrivileged;
mPlaybackActive = mAudioService.isPlaybackActiveForUid(uid);
mRecordingActive = mAudioService.isRecordingActiveForUid(uid);
} }
public boolean registerDeathRecipient() { public boolean registerDeathRecipient() {
@@ -2138,13 +2153,38 @@ import java.util.concurrent.atomic.AtomicBoolean;
return mCb; return mCb;
} }
int getPid() { int getUid() {
return mPid; return mUid;
}
boolean isPrivileged() {
return mIsPrivileged;
} }
AudioDeviceAttributes getDevice() { AudioDeviceAttributes getDevice() {
return mDevice; return mDevice;
} }
public void setPlaybackActive(boolean active) {
mPlaybackActive = active;
}
public void setRecordingActive(boolean active) {
mRecordingActive = active;
}
public boolean isActive() {
return mIsPrivileged || mRecordingActive || mPlaybackActive;
}
@Override
public String toString() {
return "[CommunicationRouteClient: mUid: " + mUid
+ " mDevice: " + mDevice.toString()
+ " mIsPrivileged: " + mIsPrivileged
+ " mPlaybackActive: " + mPlaybackActive
+ " mRecordingActive: " + mRecordingActive + "]";
}
} }
// @GuardedBy("mSetModeLock") // @GuardedBy("mSetModeLock")
@@ -2154,8 +2194,9 @@ import java.util.concurrent.atomic.AtomicBoolean;
return; return;
} }
Log.w(TAG, "Communication client died"); Log.w(TAG, "Communication client died");
setCommunicationRouteForClient(client.getBinder(), client.getPid(), null, setCommunicationRouteForClient(client.getBinder(), client.getUid(), null,
BtHelper.SCO_MODE_UNDEFINED, "onCommunicationRouteClientDied"); BtHelper.SCO_MODE_UNDEFINED, client.isPrivileged(),
"onCommunicationRouteClientDied");
} }
/** /**
@@ -2242,8 +2283,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
+ crc + " eventSource: " + eventSource); + crc + " eventSource: " + eventSource);
} }
if (crc != null) { if (crc != null) {
setCommunicationRouteForClient(crc.getBinder(), crc.getPid(), crc.getDevice(), setCommunicationRouteForClient(crc.getBinder(), crc.getUid(), crc.getDevice(),
BtHelper.SCO_MODE_UNDEFINED, eventSource); BtHelper.SCO_MODE_UNDEFINED, crc.isPrivileged(), eventSource);
} }
} }
@@ -2282,11 +2323,12 @@ import java.util.concurrent.atomic.AtomicBoolean;
} }
@GuardedBy("mDeviceStateLock") @GuardedBy("mDeviceStateLock")
private CommunicationRouteClient addCommunicationRouteClient( private CommunicationRouteClient addCommunicationRouteClient(IBinder cb, int uid,
IBinder cb, int pid, AudioDeviceAttributes device) { AudioDeviceAttributes device, boolean isPrivileged) {
// always insert new request at first position // always insert new request at first position
removeCommunicationRouteClient(cb, true); removeCommunicationRouteClient(cb, true);
CommunicationRouteClient client = new CommunicationRouteClient(cb, pid, device); CommunicationRouteClient client =
new CommunicationRouteClient(cb, uid, device, isPrivileged);
if (client.registerDeathRecipient()) { if (client.registerDeathRecipient()) {
mCommunicationRouteClients.add(0, client); mCommunicationRouteClients.add(0, client);
return client; return client;
@@ -2295,9 +2337,9 @@ import java.util.concurrent.atomic.AtomicBoolean;
} }
@GuardedBy("mDeviceStateLock") @GuardedBy("mDeviceStateLock")
private CommunicationRouteClient getCommunicationRouteClientForPid(int pid) { private CommunicationRouteClient getCommunicationRouteClientForUid(int uid) {
for (CommunicationRouteClient cl : mCommunicationRouteClients) { for (CommunicationRouteClient cl : mCommunicationRouteClients) {
if (cl.getPid() == pid) { if (cl.getUid() == uid) {
return cl; return cl;
} }
} }
@@ -2330,6 +2372,45 @@ import java.util.concurrent.atomic.AtomicBoolean;
return device; return device;
} }
void updateCommunicationRouteClientsActivity(
List<AudioPlaybackConfiguration> playbackConfigs,
List<AudioRecordingConfiguration> recordConfigs) {
synchronized (mSetModeLock) {
synchronized (mDeviceStateLock) {
boolean updateCommunicationRoute = false;
for (CommunicationRouteClient crc : mCommunicationRouteClients) {
boolean wasActive = crc.isActive();
if (playbackConfigs != null) {
crc.setPlaybackActive(false);
for (AudioPlaybackConfiguration config : playbackConfigs) {
if (config.getClientUid() == crc.getUid()
&& config.isActive()) {
crc.setPlaybackActive(true);
break;
}
}
}
if (recordConfigs != null) {
crc.setRecordingActive(false);
for (AudioRecordingConfiguration config : recordConfigs) {
if (config.getClientUid() == crc.getUid()
&& !config.isClientSilenced()) {
crc.setRecordingActive(true);
break;
}
}
}
if (wasActive != crc.isActive()) {
updateCommunicationRoute = true;
}
}
if (updateCommunicationRoute) {
postUpdateCommunicationRouteClient("updateCommunicationRouteClientsActivity");
}
}
}
}
@Nullable UUID getDeviceSensorUuid(AudioDeviceAttributes device) { @Nullable UUID getDeviceSensorUuid(AudioDeviceAttributes device) {
synchronized (mDeviceStateLock) { synchronized (mDeviceStateLock) {
return mDeviceInventory.getDeviceSensorUuid(device); return mDeviceInventory.getDeviceSensorUuid(device);

View File

@@ -4261,22 +4261,41 @@ public class AudioService extends IAudioService.Stub
// When the audio mode owner becomes active, replace any delayed MSG_UPDATE_AUDIO_MODE // When the audio mode owner becomes active, replace any delayed MSG_UPDATE_AUDIO_MODE
// and request an audio mode update immediately. Upon any other change, queue the message // and request an audio mode update immediately. Upon any other change, queue the message
// and request an audio mode update after a grace period. // and request an audio mode update after a grace period.
updateAudioModeHandlers(
configs /* playbackConfigs */, null /* recordConfigs */);
mDeviceBroker.updateCommunicationRouteClientsActivity(
configs /* playbackConfigs */, null /* recordConfigs */);
}
void updateAudioModeHandlers(List<AudioPlaybackConfiguration> playbackConfigs,
List<AudioRecordingConfiguration> recordConfigs) {
synchronized (mDeviceBroker.mSetModeLock) { synchronized (mDeviceBroker.mSetModeLock) {
boolean updateAudioMode = false; boolean updateAudioMode = false;
int existingMsgPolicy = SENDMSG_QUEUE; int existingMsgPolicy = SENDMSG_QUEUE;
int delay = CHECK_MODE_FOR_UID_PERIOD_MS; int delay = CHECK_MODE_FOR_UID_PERIOD_MS;
for (SetModeDeathHandler h : mSetModeDeathHandlers) { for (SetModeDeathHandler h : mSetModeDeathHandlers) {
boolean wasActive = h.isActive(); boolean wasActive = h.isActive();
h.setPlaybackActive(false); if (playbackConfigs != null) {
for (AudioPlaybackConfiguration config : configs) { h.setPlaybackActive(false);
final int usage = config.getAudioAttributes().getUsage(); for (AudioPlaybackConfiguration config : playbackConfigs) {
if (config.getClientUid() == h.getUid() final int usage = config.getAudioAttributes().getUsage();
&& (usage == AudioAttributes.USAGE_VOICE_COMMUNICATION if (config.getClientUid() == h.getUid()
&& (usage == AudioAttributes.USAGE_VOICE_COMMUNICATION
|| usage == AudioAttributes.USAGE_VOICE_COMMUNICATION_SIGNALLING) || usage == AudioAttributes.USAGE_VOICE_COMMUNICATION_SIGNALLING)
&& config.getPlayerState() && config.isActive()) {
== AudioPlaybackConfiguration.PLAYER_STATE_STARTED) { h.setPlaybackActive(true);
h.setPlaybackActive(true); break;
break; }
}
}
if (recordConfigs != null) {
h.setRecordingActive(false);
for (AudioRecordingConfiguration config : recordConfigs) {
if (config.getClientUid() == h.getUid() && !config.isClientSilenced()
&& config.getAudioSource() == AudioSource.VOICE_COMMUNICATION) {
h.setRecordingActive(true);
break;
}
} }
} }
if (wasActive != h.isActive()) { if (wasActive != h.isActive()) {
@@ -4314,38 +4333,10 @@ public class AudioService extends IAudioService.Stub
// When the audio mode owner becomes active, replace any delayed MSG_UPDATE_AUDIO_MODE // When the audio mode owner becomes active, replace any delayed MSG_UPDATE_AUDIO_MODE
// and request an audio mode update immediately. Upon any other change, queue the message // and request an audio mode update immediately. Upon any other change, queue the message
// and request an audio mode update after a grace period. // and request an audio mode update after a grace period.
synchronized (mDeviceBroker.mSetModeLock) { updateAudioModeHandlers(
boolean updateAudioMode = false; null /* playbackConfigs */, configs /* recordConfigs */);
int existingMsgPolicy = SENDMSG_QUEUE; mDeviceBroker.updateCommunicationRouteClientsActivity(
int delay = CHECK_MODE_FOR_UID_PERIOD_MS; null /* playbackConfigs */, configs /* recordConfigs */);
for (SetModeDeathHandler h : mSetModeDeathHandlers) {
boolean wasActive = h.isActive();
h.setRecordingActive(false);
for (AudioRecordingConfiguration config : configs) {
if (config.getClientUid() == h.getUid()
&& config.getAudioSource() == AudioSource.VOICE_COMMUNICATION) {
h.setRecordingActive(true);
break;
}
}
if (wasActive != h.isActive()) {
updateAudioMode = true;
if (h.isActive() && h == getAudioModeOwnerHandler()) {
existingMsgPolicy = SENDMSG_REPLACE;
delay = 0;
}
}
}
if (updateAudioMode) {
sendMsg(mAudioHandler,
MSG_UPDATE_AUDIO_MODE,
existingMsgPolicy,
AudioSystem.MODE_CURRENT,
android.os.Process.myPid(),
mContext.getPackageName(),
delay);
}
}
} }
private void dumpAudioMode(PrintWriter pw) { private void dumpAudioMode(PrintWriter pw) {
@@ -6298,10 +6289,12 @@ public class AudioService extends IAudioService.Stub
? MediaMetrics.Value.CONNECTED : MediaMetrics.Value.DISCONNECTED) ? MediaMetrics.Value.CONNECTED : MediaMetrics.Value.DISCONNECTED)
.record(); .record();
} }
final boolean isPrivileged = mContext.checkCallingOrSelfPermission(
android.Manifest.permission.MODIFY_PHONE_STATE)
== PackageManager.PERMISSION_GRANTED;
final long ident = Binder.clearCallingIdentity(); final long ident = Binder.clearCallingIdentity();
try { try {
return mDeviceBroker.setCommunicationDevice(cb, pid, device, eventSource); return mDeviceBroker.setCommunicationDevice(cb, uid, device, isPrivileged, eventSource);
} finally { } finally {
Binder.restoreCallingIdentity(ident); Binder.restoreCallingIdentity(ident);
} }
@@ -6347,6 +6340,9 @@ public class AudioService extends IAudioService.Stub
if (!checkAudioSettingsPermission("setSpeakerphoneOn()")) { if (!checkAudioSettingsPermission("setSpeakerphoneOn()")) {
return; return;
} }
final boolean isPrivileged = mContext.checkCallingOrSelfPermission(
android.Manifest.permission.MODIFY_PHONE_STATE)
== PackageManager.PERMISSION_GRANTED;
// for logging only // for logging only
final int uid = Binder.getCallingUid(); final int uid = Binder.getCallingUid();
@@ -6362,9 +6358,10 @@ public class AudioService extends IAudioService.Stub
.set(MediaMetrics.Property.STATE, on .set(MediaMetrics.Property.STATE, on
? MediaMetrics.Value.ON : MediaMetrics.Value.OFF) ? MediaMetrics.Value.ON : MediaMetrics.Value.OFF)
.record(); .record();
final long ident = Binder.clearCallingIdentity(); final long ident = Binder.clearCallingIdentity();
try { try {
mDeviceBroker.setSpeakerphoneOn(cb, pid, on, eventSource); mDeviceBroker.setSpeakerphoneOn(cb, uid, on, isPrivileged, eventSource);
} finally { } finally {
Binder.restoreCallingIdentity(ident); Binder.restoreCallingIdentity(ident);
} }
@@ -6489,7 +6486,7 @@ public class AudioService extends IAudioService.Stub
.set(MediaMetrics.Property.SCO_AUDIO_MODE, .set(MediaMetrics.Property.SCO_AUDIO_MODE,
BtHelper.scoAudioModeToString(scoAudioMode)) BtHelper.scoAudioModeToString(scoAudioMode))
.record(); .record();
startBluetoothScoInt(cb, pid, scoAudioMode, eventSource); startBluetoothScoInt(cb, uid, scoAudioMode, eventSource);
} }
@@ -6512,10 +6509,10 @@ public class AudioService extends IAudioService.Stub
.set(MediaMetrics.Property.SCO_AUDIO_MODE, .set(MediaMetrics.Property.SCO_AUDIO_MODE,
BtHelper.scoAudioModeToString(BtHelper.SCO_MODE_VIRTUAL_CALL)) BtHelper.scoAudioModeToString(BtHelper.SCO_MODE_VIRTUAL_CALL))
.record(); .record();
startBluetoothScoInt(cb, pid, BtHelper.SCO_MODE_VIRTUAL_CALL, eventSource); startBluetoothScoInt(cb, uid, BtHelper.SCO_MODE_VIRTUAL_CALL, eventSource);
} }
void startBluetoothScoInt(IBinder cb, int pid, int scoAudioMode, @NonNull String eventSource) { void startBluetoothScoInt(IBinder cb, int uid, int scoAudioMode, @NonNull String eventSource) {
MediaMetrics.Item mmi = new MediaMetrics.Item(MediaMetrics.Name.AUDIO_BLUETOOTH) MediaMetrics.Item mmi = new MediaMetrics.Item(MediaMetrics.Name.AUDIO_BLUETOOTH)
.set(MediaMetrics.Property.EVENT, "startBluetoothScoInt") .set(MediaMetrics.Property.EVENT, "startBluetoothScoInt")
.set(MediaMetrics.Property.SCO_AUDIO_MODE, .set(MediaMetrics.Property.SCO_AUDIO_MODE,
@@ -6526,9 +6523,13 @@ public class AudioService extends IAudioService.Stub
mmi.set(MediaMetrics.Property.EARLY_RETURN, "permission or systemReady").record(); mmi.set(MediaMetrics.Property.EARLY_RETURN, "permission or systemReady").record();
return; return;
} }
final boolean isPrivileged = mContext.checkCallingOrSelfPermission(
android.Manifest.permission.MODIFY_PHONE_STATE)
== PackageManager.PERMISSION_GRANTED;
final long ident = Binder.clearCallingIdentity(); final long ident = Binder.clearCallingIdentity();
try { try {
mDeviceBroker.startBluetoothScoForClient(cb, pid, scoAudioMode, eventSource); mDeviceBroker.startBluetoothScoForClient(
cb, uid, scoAudioMode, isPrivileged, eventSource);
} finally { } finally {
Binder.restoreCallingIdentity(ident); Binder.restoreCallingIdentity(ident);
} }
@@ -6546,9 +6547,12 @@ public class AudioService extends IAudioService.Stub
final String eventSource = new StringBuilder("stopBluetoothSco()") final String eventSource = new StringBuilder("stopBluetoothSco()")
.append(") from u/pid:").append(uid).append("/") .append(") from u/pid:").append(uid).append("/")
.append(pid).toString(); .append(pid).toString();
final boolean isPrivileged = mContext.checkCallingOrSelfPermission(
android.Manifest.permission.MODIFY_PHONE_STATE)
== PackageManager.PERMISSION_GRANTED;
final long ident = Binder.clearCallingIdentity(); final long ident = Binder.clearCallingIdentity();
try { try {
mDeviceBroker.stopBluetoothScoForClient(cb, pid, eventSource); mDeviceBroker.stopBluetoothScoForClient(cb, uid, isPrivileged, eventSource);
} finally { } finally {
Binder.restoreCallingIdentity(ident); Binder.restoreCallingIdentity(ident);
} }
@@ -9283,8 +9287,8 @@ public class AudioService extends IAudioService.Stub
break; break;
} }
boolean wasActive = h.isActive(); boolean wasActive = h.isActive();
h.setPlaybackActive(mPlaybackMonitor.isPlaybackActiveForUid(h.getUid())); h.setPlaybackActive(isPlaybackActiveForUid(h.getUid()));
h.setRecordingActive(mRecordMonitor.isRecordingActiveForUid(h.getUid())); h.setRecordingActive(isRecordingActiveForUid(h.getUid()));
if (wasActive != h.isActive()) { if (wasActive != h.isActive()) {
onUpdateAudioMode(AudioSystem.MODE_CURRENT, android.os.Process.myPid(), onUpdateAudioMode(AudioSystem.MODE_CURRENT, android.os.Process.myPid(),
mContext.getPackageName(), false /*force*/); mContext.getPackageName(), false /*force*/);
@@ -12377,6 +12381,16 @@ public class AudioService extends IAudioService.Stub
} }
} }
/* package */
boolean isPlaybackActiveForUid(int uid) {
return mPlaybackMonitor.isPlaybackActiveForUid(uid);
}
/* package */
boolean isRecordingActiveForUid(int uid) {
return mRecordMonitor.isRecordingActiveForUid(uid);
}
//====================== //======================
// Audio device management // Audio device management
//====================== //======================

View File

@@ -227,8 +227,8 @@ public final class RecordingActivityMonitor implements AudioSystem.AudioRecordin
synchronized (mRecordStates) { synchronized (mRecordStates) {
for (RecordingState state : mRecordStates) { for (RecordingState state : mRecordStates) {
// Note: isActiveConfiguration() == true => state.getConfig() != null // Note: isActiveConfiguration() == true => state.getConfig() != null
if (state.isActiveConfiguration() if (state.isActiveConfiguration() && state.getConfig().getClientUid() == uid
&& state.getConfig().getClientUid() == uid) { && !state.getConfig().isClientSilenced()) {
return true; return true;
} }
} }