Merge "AudioDeviceBroker: Bluetooth LE communication route compatibility" into tm-qpr-dev

This commit is contained in:
Eric Laurent
2022-09-13 21:45:19 +00:00
committed by Android (Google) Code Review
3 changed files with 138 additions and 45 deletions

View File

@@ -17,9 +17,12 @@ package com.android.server.audio;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.compat.CompatChanges;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothProfile;
import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledSince;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
@@ -118,8 +121,39 @@ import java.util.concurrent.atomic.AtomicBoolean;
// TODO do not "share" the lock between AudioService and BtHelpr, see b/123769055
/*package*/ final Object mSetModeLock = new Object();
/** PID of current audio mode owner communicated by AudioService */
private int mModeOwnerPid = 0;
/** AudioModeInfo contains information on current audio mode owner
* communicated by AudioService */
/* package */ static final class AudioModeInfo {
/** Current audio mode */
final int mMode;
/** PID of current audio mode owner */
final int mPid;
/** UID of current audio mode owner */
final int mUid;
AudioModeInfo(int mode, int pid, int uid) {
mMode = mode;
mPid = pid;
mUid = uid;
}
@Override
public String toString() {
return "AudioModeInfo: mMode=" + AudioSystem.modeToString(mMode)
+ ", mPid=" + mPid
+ ", mUid=" + mUid;
}
};
private AudioModeInfo mAudioModeOwner = new AudioModeInfo(AudioSystem.MODE_NORMAL, 0, 0);
/**
* Indicates that default communication device is chosen by routing rules in audio policy
* manager and not forced by AudioDeviceBroker.
*/
@ChangeId
@EnabledSince(targetSdkVersion = android.os.Build.VERSION_CODES.S_V2)
public static final long USE_SET_COMMUNICATION_DEVICE = 243827847L;
//-------------------------------------------------------------------
/*package*/ AudioDeviceBroker(@NonNull Context context, @NonNull AudioService service) {
@@ -187,7 +221,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
/*package*/ void onSystemReady() {
synchronized (mSetModeLock) {
synchronized (mDeviceStateLock) {
mModeOwnerPid = mAudioService.getModeOwnerPid();
mAudioModeOwner = mAudioService.getAudioModeOwner();
mBtHelper.onSystemReady();
}
}
@@ -368,11 +402,11 @@ import java.util.concurrent.atomic.AtomicBoolean;
@GuardedBy("mDeviceStateLock")
private CommunicationRouteClient topCommunicationRouteClient() {
for (CommunicationRouteClient crc : mCommunicationRouteClients) {
if (crc.getPid() == mModeOwnerPid) {
if (crc.getPid() == mAudioModeOwner.mPid) {
return crc;
}
}
if (!mCommunicationRouteClients.isEmpty() && mModeOwnerPid == 0) {
if (!mCommunicationRouteClients.isEmpty() && mAudioModeOwner.mPid == 0) {
return mCommunicationRouteClients.get(0);
}
return null;
@@ -390,7 +424,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
AudioDeviceAttributes device = crc != null ? crc.getDevice() : null;
if (AudioService.DEBUG_COMM_RTE) {
Log.v(TAG, "requestedCommunicationDevice, device: "
+ device + " mode owner pid: " + mModeOwnerPid);
+ device + "mAudioModeOwner: " + mAudioModeOwner.toString());
}
return device;
}
@@ -774,8 +808,9 @@ import java.util.concurrent.atomic.AtomicBoolean;
sendLMsgNoDelay(MSG_II_SET_LE_AUDIO_OUT_VOLUME, SENDMSG_REPLACE, info);
}
/*package*/ void postSetModeOwnerPid(int pid, int mode) {
sendIIMsgNoDelay(MSG_I_SET_MODE_OWNER_PID, SENDMSG_REPLACE, pid, mode);
/*package*/ void postSetModeOwner(int mode, int pid, int uid) {
sendLMsgNoDelay(MSG_I_SET_MODE_OWNER, SENDMSG_REPLACE,
new AudioModeInfo(mode, pid, uid));
}
/*package*/ void postBluetoothA2dpDeviceConfigChange(@NonNull BluetoothDevice device) {
@@ -1162,7 +1197,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
pw.println(prefix + "mAccessibilityStrategyId: "
+ mAccessibilityStrategyId);
pw.println("\n" + prefix + "mModeOwnerPid: " + mModeOwnerPid);
pw.println("\n" + prefix + "mAudioModeOwner: " + mAudioModeOwner);
mBtHelper.dump(pw, prefix);
}
@@ -1288,12 +1323,19 @@ import java.util.concurrent.atomic.AtomicBoolean;
}
break;
case MSG_L_SET_BT_ACTIVE_DEVICE:
synchronized (mDeviceStateLock) {
BtDeviceInfo btInfo = (BtDeviceInfo) msg.obj;
mDeviceInventory.onSetBtActiveDevice(btInfo,
(btInfo.mProfile != BluetoothProfile.LE_AUDIO || btInfo.mIsLeOutput)
? mAudioService.getBluetoothContextualVolumeStream()
: AudioSystem.STREAM_DEFAULT);
synchronized (mSetModeLock) {
synchronized (mDeviceStateLock) {
BtDeviceInfo btInfo = (BtDeviceInfo) msg.obj;
mDeviceInventory.onSetBtActiveDevice(btInfo,
(btInfo.mProfile
!= BluetoothProfile.LE_AUDIO || btInfo.mIsLeOutput)
? mAudioService.getBluetoothContextualVolumeStream()
: AudioSystem.STREAM_DEFAULT);
if (btInfo.mProfile == BluetoothProfile.LE_AUDIO
|| btInfo.mProfile == BluetoothProfile.HEARING_AID) {
onUpdateCommunicationRouteClient("setBluetoothActiveDevice");
}
}
}
break;
case MSG_BT_HEADSET_CNCT_FAILED:
@@ -1337,11 +1379,11 @@ import java.util.concurrent.atomic.AtomicBoolean;
mBtHelper.setAvrcpAbsoluteVolumeIndex(msg.arg1);
}
break;
case MSG_I_SET_MODE_OWNER_PID:
case MSG_I_SET_MODE_OWNER:
synchronized (mSetModeLock) {
synchronized (mDeviceStateLock) {
mModeOwnerPid = msg.arg1;
if (msg.arg2 != AudioSystem.MODE_RINGTONE) {
mAudioModeOwner = (AudioModeInfo) msg.obj;
if (mAudioModeOwner.mMode != AudioSystem.MODE_RINGTONE) {
onUpdateCommunicationRouteClient("setNewModeOwner");
}
}
@@ -1503,7 +1545,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
private static final int MSG_REPORT_NEW_ROUTES = 13;
private static final int MSG_II_SET_HEARING_AID_VOLUME = 14;
private static final int MSG_I_SET_AVRCP_ABSOLUTE_VOLUME = 15;
private static final int MSG_I_SET_MODE_OWNER_PID = 16;
private static final int MSG_I_SET_MODE_OWNER = 16;
private static final int MSG_I_BT_SERVICE_DISCONNECTED_PROFILE = 22;
private static final int MSG_IL_BT_SERVICE_CONNECTED_PROFILE = 23;
@@ -1825,8 +1867,16 @@ import java.util.concurrent.atomic.AtomicBoolean;
AudioSystem.setParameters("BT_SCO=on");
}
if (preferredCommunicationDevice == null) {
removePreferredDevicesForStrategySync(mCommunicationStrategyId);
removePreferredDevicesForStrategySync(mAccessibilityStrategyId);
AudioDeviceAttributes defaultDevice = getDefaultCommunicationDevice();
if (defaultDevice != null) {
setPreferredDevicesForStrategySync(
mCommunicationStrategyId, Arrays.asList(defaultDevice));
setPreferredDevicesForStrategySync(
mAccessibilityStrategyId, Arrays.asList(defaultDevice));
} else {
removePreferredDevicesForStrategySync(mCommunicationStrategyId);
removePreferredDevicesForStrategySync(mAccessibilityStrategyId);
}
} else {
setPreferredDevicesForStrategySync(
mCommunicationStrategyId, Arrays.asList(preferredCommunicationDevice));
@@ -1855,26 +1905,24 @@ import java.util.concurrent.atomic.AtomicBoolean;
}
}
// @GuardedBy("mSetModeLock")
@GuardedBy("mDeviceStateLock")
private void onUpdatePhoneStrategyDevice(AudioDeviceAttributes device) {
synchronized (mSetModeLock) {
synchronized (mDeviceStateLock) {
boolean wasSpeakerphoneActive = isSpeakerphoneActive();
mPreferredCommunicationDevice = device;
updateActiveCommunicationDevice();
if (wasSpeakerphoneActive != isSpeakerphoneActive()) {
try {
mContext.sendBroadcastAsUser(
new Intent(AudioManager.ACTION_SPEAKERPHONE_STATE_CHANGED)
.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
UserHandle.ALL);
} catch (Exception e) {
Log.w(TAG, "failed to broadcast ACTION_SPEAKERPHONE_STATE_CHANGED: " + e);
}
}
mAudioService.postUpdateRingerModeServiceInt();
dispatchCommunicationDevice();
boolean wasSpeakerphoneActive = isSpeakerphoneActive();
mPreferredCommunicationDevice = device;
updateActiveCommunicationDevice();
if (wasSpeakerphoneActive != isSpeakerphoneActive()) {
try {
mContext.sendBroadcastAsUser(
new Intent(AudioManager.ACTION_SPEAKERPHONE_STATE_CHANGED)
.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
UserHandle.ALL);
} catch (Exception e) {
Log.w(TAG, "failed to broadcast ACTION_SPEAKERPHONE_STATE_CHANGED: " + e);
}
}
mAudioService.postUpdateRingerModeServiceInt();
dispatchCommunicationDevice();
}
private CommunicationRouteClient removeCommunicationRouteClient(
@@ -1914,6 +1962,32 @@ import java.util.concurrent.atomic.AtomicBoolean;
return null;
}
@GuardedBy("mDeviceStateLock")
private boolean communnicationDeviceCompatOn() {
return mAudioModeOwner.mMode == AudioSystem.MODE_IN_COMMUNICATION
&& !(CompatChanges.isChangeEnabled(
USE_SET_COMMUNICATION_DEVICE, mAudioModeOwner.mUid)
|| mAudioModeOwner.mUid == android.os.Process.SYSTEM_UID);
}
@GuardedBy("mDeviceStateLock")
AudioDeviceAttributes getDefaultCommunicationDevice() {
// For system server (Telecom) and APKs targeting S and above, we let the audio
// policy routing rules select the default communication device.
// For older APKs, we force Hearing Aid or LE Audio headset when connected as
// those APKs cannot select a LE Audio or Hearing Aid device explicitly.
AudioDeviceAttributes device = null;
if (communnicationDeviceCompatOn()) {
// If both LE and Hearing Aid are active (thie should not happen),
// priority to Hearing Aid.
device = mDeviceInventory.getDeviceOfType(AudioSystem.DEVICE_OUT_HEARING_AID);
if (device == null) {
device = mDeviceInventory.getDeviceOfType(AudioSystem.DEVICE_OUT_BLE_HEADSET);
}
}
return device;
}
@Nullable UUID getDeviceSensorUuid(AudioDeviceAttributes device) {
synchronized (mDeviceStateLock) {
return mDeviceInventory.getDeviceSensorUuid(device);

View File

@@ -294,6 +294,7 @@ public class AudioDeviceInventory {
}
}
// @GuardedBy("AudioDeviceBroker.mSetModeLock")
@GuardedBy("AudioDeviceBroker.mDeviceStateLock")
void onSetBtActiveDevice(@NonNull AudioDeviceBroker.BtDeviceInfo btInfo, int streamType) {
if (AudioService.DEBUG_DEVICES) {
@@ -1510,6 +1511,19 @@ public class AudioDeviceInventory {
return di.mSensorUuid;
}
}
/* package */ AudioDeviceAttributes getDeviceOfType(int type) {
synchronized (mDevicesLock) {
for (DeviceInfo di : mConnectedDevices.values()) {
if (di.mDeviceType == type) {
return new AudioDeviceAttributes(
di.mDeviceType, di.mDeviceAddress, di.mDeviceName);
}
}
}
return null;
}
//----------------------------------------------------------
// For tests only

View File

@@ -5225,16 +5225,17 @@ public class AudioService extends IAudioService.Stub
}
/**
* Return the pid of the current audio mode owner
* Return information on the current audio mode owner
* @return 0 if nobody owns the mode
*/
@GuardedBy("mDeviceBroker.mSetModeLock")
/*package*/ int getModeOwnerPid() {
/*package*/ AudioDeviceBroker.AudioModeInfo getAudioModeOwner() {
SetModeDeathHandler hdlr = getAudioModeOwnerHandler();
if (hdlr != null) {
return hdlr.getPid();
return new AudioDeviceBroker.AudioModeInfo(
hdlr.getMode(), hdlr.getPid(), hdlr.getUid());
}
return 0;
return new AudioDeviceBroker.AudioModeInfo(AudioSystem.MODE_NORMAL, 0 , 0);
}
/**
@@ -5420,7 +5421,7 @@ public class AudioService extends IAudioService.Stub
// when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all SCO
// connections not started by the application changing the mode when pid changes
mDeviceBroker.postSetModeOwnerPid(pid, mode);
mDeviceBroker.postSetModeOwner(mode, pid, uid);
} else {
Log.w(TAG, "onUpdateAudioMode: failed to set audio mode to: " + mode);
}
@@ -5748,7 +5749,10 @@ public class AudioService extends IAudioService.Stub
}
return deviceIds.stream().mapToInt(Integer::intValue).toArray();
}
/** @see AudioManager#setCommunicationDevice(int) */
/**
* @see AudioManager#setCommunicationDevice(int)
* @see AudioManager#clearCommunicationDevice()
*/
public boolean setCommunicationDevice(IBinder cb, int portId) {
final int uid = Binder.getCallingUid();
final int pid = Binder.getCallingPid();
@@ -5763,7 +5767,8 @@ public class AudioService extends IAudioService.Stub
throw new IllegalArgumentException("invalid device type " + device.getType());
}
}
final String eventSource = new StringBuilder("setCommunicationDevice(")
final String eventSource = new StringBuilder()
.append(device == null ? "clearCommunicationDevice(" : "setCommunicationDevice(")
.append(") from u/pid:").append(uid).append("/")
.append(pid).toString();