Merge changes from topic "comm_device_hardening_udc_qpr" into udc-qpr-dev
* changes: AudioDeviceBroker: clean communication route clients upon device disconnection AudioDeviceBroker: ignore communication route requests by idle apps
This commit is contained in:
@@ -30,6 +30,8 @@ import android.media.AudioAttributes;
|
||||
import android.media.AudioDeviceAttributes;
|
||||
import android.media.AudioDeviceInfo;
|
||||
import android.media.AudioManager;
|
||||
import android.media.AudioPlaybackConfiguration;
|
||||
import android.media.AudioRecordingConfiguration;
|
||||
import android.media.AudioRoutesInfo;
|
||||
import android.media.AudioSystem;
|
||||
import android.media.BluetoothProfileConnectionInfo;
|
||||
@@ -289,37 +291,38 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
* @param on
|
||||
* @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) {
|
||||
Log.v(TAG, "setSpeakerphoneOn, on: " + on + " pid: " + pid);
|
||||
Log.v(TAG, "setSpeakerphoneOn, on: " + on + " uid: " + uid);
|
||||
}
|
||||
postSetCommunicationDeviceForClient(new CommunicationDeviceInfo(
|
||||
cb, pid, new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_SPEAKER, ""),
|
||||
on, BtHelper.SCO_MODE_UNDEFINED, eventSource, false));
|
||||
cb, uid, new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_SPEAKER, ""),
|
||||
on, BtHelper.SCO_MODE_UNDEFINED, eventSource, false, isPrivileged));
|
||||
}
|
||||
|
||||
/**
|
||||
* Select device for use for communication use cases.
|
||||
* @param cb Client binder for death detection
|
||||
* @param pid Client pid
|
||||
* @param uid Client uid
|
||||
* @param device Device selected or null to unselect.
|
||||
* @param eventSource for logging purposes
|
||||
*/
|
||||
|
||||
private static final long SET_COMMUNICATION_DEVICE_TIMEOUT_MS = 3000;
|
||||
|
||||
/*package*/ boolean setCommunicationDevice(
|
||||
IBinder cb, int pid, AudioDeviceInfo device, String eventSource) {
|
||||
/*package*/ boolean setCommunicationDevice(IBinder cb, int uid, AudioDeviceInfo device,
|
||||
boolean isPrivileged, String eventSource) {
|
||||
|
||||
if (AudioService.DEBUG_COMM_RTE) {
|
||||
Log.v(TAG, "setCommunicationDevice, device: " + device + ", pid: " + pid);
|
||||
Log.v(TAG, "setCommunicationDevice, device: " + device + ", uid: " + uid);
|
||||
}
|
||||
|
||||
AudioDeviceAttributes deviceAttr =
|
||||
(device != null) ? new AudioDeviceAttributes(device) : null;
|
||||
CommunicationDeviceInfo deviceInfo = new CommunicationDeviceInfo(cb, pid, deviceAttr,
|
||||
device != null, BtHelper.SCO_MODE_UNDEFINED, eventSource, true);
|
||||
CommunicationDeviceInfo deviceInfo = new CommunicationDeviceInfo(cb, uid, deviceAttr,
|
||||
device != null, BtHelper.SCO_MODE_UNDEFINED, eventSource, true, isPrivileged);
|
||||
postSetCommunicationDeviceForClient(deviceInfo);
|
||||
boolean status;
|
||||
synchronized (deviceInfo) {
|
||||
@@ -353,7 +356,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
Log.v(TAG, "onSetCommunicationDeviceForClient: " + deviceInfo);
|
||||
}
|
||||
if (!deviceInfo.mOn) {
|
||||
CommunicationRouteClient client = getCommunicationRouteClientForPid(deviceInfo.mPid);
|
||||
CommunicationRouteClient client = getCommunicationRouteClientForUid(deviceInfo.mUid);
|
||||
if (client == null || (deviceInfo.mDevice != null
|
||||
&& !deviceInfo.mDevice.equals(client.getDevice()))) {
|
||||
return false;
|
||||
@@ -361,22 +364,23 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
}
|
||||
|
||||
AudioDeviceAttributes device = deviceInfo.mOn ? deviceInfo.mDevice : null;
|
||||
setCommunicationRouteForClient(deviceInfo.mCb, deviceInfo.mPid, device,
|
||||
deviceInfo.mScoAudioMode, deviceInfo.mEventSource);
|
||||
setCommunicationRouteForClient(deviceInfo.mCb, deviceInfo.mUid, device,
|
||||
deviceInfo.mScoAudioMode, deviceInfo.mIsPrivileged, deviceInfo.mEventSource);
|
||||
return true;
|
||||
}
|
||||
|
||||
@GuardedBy("mDeviceStateLock")
|
||||
/*package*/ void setCommunicationRouteForClient(
|
||||
IBinder cb, int pid, AudioDeviceAttributes device,
|
||||
int scoAudioMode, String eventSource) {
|
||||
IBinder cb, int uid, AudioDeviceAttributes device,
|
||||
int scoAudioMode, boolean isPrivileged, String eventSource) {
|
||||
|
||||
if (AudioService.DEBUG_COMM_RTE) {
|
||||
Log.v(TAG, "setCommunicationRouteForClient: device: " + device);
|
||||
Log.v(TAG, "setCommunicationRouteForClient: device: " + device
|
||||
+ ", eventSource: " + eventSource);
|
||||
}
|
||||
AudioService.sDeviceLogger.enqueue((new EventLogger.StringEvent(
|
||||
"setCommunicationRouteForClient for pid: " + pid
|
||||
+ " device: " + device
|
||||
"setCommunicationRouteForClient for uid: " + uid
|
||||
+ " device: " + device + " isPrivileged: " + isPrivileged
|
||||
+ " from API: " + eventSource)).printLog(TAG));
|
||||
|
||||
final boolean wasBtScoRequested = isBluetoothScoRequested();
|
||||
@@ -385,16 +389,18 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
// Save previous client route in case of failure to start BT SCO audio
|
||||
AudioDeviceAttributes prevClientDevice = null;
|
||||
client = getCommunicationRouteClientForPid(pid);
|
||||
boolean prevPrivileged = false;
|
||||
client = getCommunicationRouteClientForUid(uid);
|
||||
if (client != null) {
|
||||
prevClientDevice = client.getDevice();
|
||||
prevPrivileged = client.isPrivileged();
|
||||
}
|
||||
|
||||
if (device != null) {
|
||||
client = addCommunicationRouteClient(cb, pid, device);
|
||||
client = addCommunicationRouteClient(cb, uid, device, isPrivileged);
|
||||
if (client == null) {
|
||||
Log.w(TAG, "setCommunicationRouteForClient: could not add client for pid: "
|
||||
+ pid + " and device: " + device);
|
||||
Log.w(TAG, "setCommunicationRouteForClient: could not add client for uid: "
|
||||
+ uid + " and device: " + device);
|
||||
}
|
||||
} else {
|
||||
client = removeCommunicationRouteClient(cb, true);
|
||||
@@ -406,11 +412,11 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
boolean isBtScoRequested = isBluetoothScoRequested();
|
||||
if (isBtScoRequested && (!wasBtScoRequested || !isBluetoothScoActive())) {
|
||||
if (!mBtHelper.startBluetoothSco(scoAudioMode, eventSource)) {
|
||||
Log.w(TAG, "setCommunicationRouteForClient: failure to start BT SCO for pid: "
|
||||
+ pid);
|
||||
Log.w(TAG, "setCommunicationRouteForClient: failure to start BT SCO for uid: "
|
||||
+ uid);
|
||||
// clean up or restore previous client selection
|
||||
if (prevClientDevice != null) {
|
||||
addCommunicationRouteClient(cb, pid, prevClientDevice);
|
||||
addCommunicationRouteClient(cb, uid, prevClientDevice, prevPrivileged);
|
||||
} else {
|
||||
removeCommunicationRouteClient(cb, true);
|
||||
}
|
||||
@@ -447,11 +453,12 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
@GuardedBy("mDeviceStateLock")
|
||||
private CommunicationRouteClient topCommunicationRouteClient() {
|
||||
for (CommunicationRouteClient crc : mCommunicationRouteClients) {
|
||||
if (crc.getPid() == mAudioModeOwner.mPid) {
|
||||
if (crc.getUid() == mAudioModeOwner.mUid) {
|
||||
return crc;
|
||||
}
|
||||
}
|
||||
if (!mCommunicationRouteClients.isEmpty() && mAudioModeOwner.mPid == 0) {
|
||||
if (!mCommunicationRouteClients.isEmpty() && mAudioModeOwner.mPid == 0
|
||||
&& mCommunicationRouteClients.get(0).isActive()) {
|
||||
return mCommunicationRouteClients.get(0);
|
||||
}
|
||||
return null;
|
||||
@@ -491,14 +498,48 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
};
|
||||
|
||||
/*package */ static boolean isValidCommunicationDevice(AudioDeviceInfo device) {
|
||||
return isValidCommunicationDeviceType(device.getType());
|
||||
}
|
||||
|
||||
private static boolean isValidCommunicationDeviceType(int deviceType) {
|
||||
for (int type : VALID_COMMUNICATION_DEVICE_TYPES) {
|
||||
if (device.getType() == type) {
|
||||
if (deviceType == type) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*package */
|
||||
void postCheckCommunicationDeviceRemoval(@NonNull AudioDeviceAttributes device) {
|
||||
if (!isValidCommunicationDeviceType(
|
||||
AudioDeviceInfo.convertInternalDeviceToDeviceType(device.getInternalType()))) {
|
||||
return;
|
||||
}
|
||||
sendLMsgNoDelay(MSG_L_CHECK_COMMUNICATION_DEVICE_REMOVAL, SENDMSG_QUEUE, device);
|
||||
}
|
||||
|
||||
@GuardedBy("mDeviceStateLock")
|
||||
void onCheckCommunicationDeviceRemoval(@NonNull AudioDeviceAttributes device) {
|
||||
if (AudioService.DEBUG_COMM_RTE) {
|
||||
Log.v(TAG, "onCheckCommunicationDeviceRemoval device: " + device.toString());
|
||||
}
|
||||
for (CommunicationRouteClient crc : mCommunicationRouteClients) {
|
||||
if (device.equals(crc.getDevice())) {
|
||||
if (AudioService.DEBUG_COMM_RTE) {
|
||||
Log.v(TAG, "onCheckCommunicationDeviceRemoval removing client: "
|
||||
+ crc.toString());
|
||||
}
|
||||
// Cancelling the route for this client will remove it from the stack and update
|
||||
// the communication route.
|
||||
CommunicationDeviceInfo deviceInfo = new CommunicationDeviceInfo(
|
||||
crc.getBinder(), crc.getUid(), device, false,
|
||||
BtHelper.SCO_MODE_UNDEFINED, "onCheckCommunicationDeviceRemoval",
|
||||
false, crc.isPrivileged());
|
||||
postSetCommunicationDeviceForClient(deviceInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* package */ static List<AudioDeviceInfo> getAvailableCommunicationDevices() {
|
||||
ArrayList<AudioDeviceInfo> commDevices = new ArrayList<>();
|
||||
AudioDeviceInfo[] allDevices =
|
||||
@@ -1107,26 +1148,26 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
sendLMsgNoDelay(MSG_L_BLUETOOTH_DEVICE_CONFIG_CHANGE, SENDMSG_QUEUE, info);
|
||||
}
|
||||
|
||||
/*package*/ void startBluetoothScoForClient(IBinder cb, int pid, int scoAudioMode,
|
||||
@NonNull String eventSource) {
|
||||
/*package*/ void startBluetoothScoForClient(IBinder cb, int uid, int scoAudioMode,
|
||||
boolean isPrivileged, @NonNull String eventSource) {
|
||||
|
||||
if (AudioService.DEBUG_COMM_RTE) {
|
||||
Log.v(TAG, "startBluetoothScoForClient, pid: " + pid);
|
||||
Log.v(TAG, "startBluetoothScoForClient, uid: " + uid);
|
||||
}
|
||||
postSetCommunicationDeviceForClient(new CommunicationDeviceInfo(
|
||||
cb, pid, new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_BLUETOOTH_SCO, ""),
|
||||
true, scoAudioMode, eventSource, false));
|
||||
cb, uid, new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_BLUETOOTH_SCO, ""),
|
||||
true, scoAudioMode, eventSource, false, isPrivileged));
|
||||
}
|
||||
|
||||
/*package*/ void stopBluetoothScoForClient(
|
||||
IBinder cb, int pid, @NonNull String eventSource) {
|
||||
IBinder cb, int uid, boolean isPrivileged, @NonNull String eventSource) {
|
||||
|
||||
if (AudioService.DEBUG_COMM_RTE) {
|
||||
Log.v(TAG, "stopBluetoothScoForClient, pid: " + pid);
|
||||
Log.v(TAG, "stopBluetoothScoForClient, uid: " + uid);
|
||||
}
|
||||
postSetCommunicationDeviceForClient(new CommunicationDeviceInfo(
|
||||
cb, pid, new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_BLUETOOTH_SCO, ""),
|
||||
false, BtHelper.SCO_MODE_UNDEFINED, eventSource, false));
|
||||
cb, uid, new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_BLUETOOTH_SCO, ""),
|
||||
false, BtHelper.SCO_MODE_UNDEFINED, eventSource, false, isPrivileged));
|
||||
}
|
||||
|
||||
/*package*/ int setPreferredDevicesForStrategySync(int strategy,
|
||||
@@ -1367,22 +1408,24 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
/*package*/ static final class CommunicationDeviceInfo {
|
||||
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 boolean mOn; // true if setting, false if resetting
|
||||
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
|
||||
boolean mWaitForStatus; // true if the caller waits for a completion status (API dependent)
|
||||
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,
|
||||
@NonNull String eventSource, boolean waitForStatus) {
|
||||
@NonNull String eventSource, boolean waitForStatus, boolean isPrivileged) {
|
||||
mCb = cb;
|
||||
mPid = pid;
|
||||
mUid = uid;
|
||||
mDevice = device;
|
||||
mOn = on;
|
||||
mScoAudioMode = scoAudioMode;
|
||||
mIsPrivileged = isPrivileged;
|
||||
mEventSource = eventSource;
|
||||
mWaitForStatus = waitForStatus;
|
||||
}
|
||||
@@ -1401,16 +1444,17 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
}
|
||||
|
||||
return mCb.equals(((CommunicationDeviceInfo) o).mCb)
|
||||
&& mPid == ((CommunicationDeviceInfo) o).mPid;
|
||||
&& mUid == ((CommunicationDeviceInfo) o).mUid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "CommunicationDeviceInfo mCb=" + mCb.toString()
|
||||
+ " mPid=" + mPid
|
||||
+ " mUid=" + mUid
|
||||
+ " mDevice=[" + (mDevice != null ? mDevice.toString() : "null") + "]"
|
||||
+ " mOn=" + mOn
|
||||
+ " mScoAudioMode=" + mScoAudioMode
|
||||
+ " mIsPrivileged=" + mIsPrivileged
|
||||
+ " mEventSource=" + mEventSource
|
||||
+ " mWaitForStatus=" + mWaitForStatus
|
||||
+ " mStatus=" + mStatus;
|
||||
@@ -1440,7 +1484,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
}
|
||||
}
|
||||
|
||||
/*package*/ boolean handleDeviceConnection(AudioDeviceAttributes attributes,
|
||||
/*package*/ boolean handleDeviceConnection(@NonNull AudioDeviceAttributes attributes,
|
||||
boolean connect, @Nullable BluetoothDevice btDevice) {
|
||||
synchronized (mDeviceStateLock) {
|
||||
return mDeviceInventory.handleDeviceConnection(
|
||||
@@ -1507,8 +1551,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
pw.println("\n" + prefix + "Communication route clients:");
|
||||
mCommunicationRouteClients.forEach((cl) -> {
|
||||
pw.println(" " + prefix + "pid: " + cl.getPid() + " device: "
|
||||
+ cl.getDevice() + " cb: " + cl.getBinder()); });
|
||||
pw.println(" " + prefix + cl.toString()); });
|
||||
|
||||
pw.println("\n" + prefix + "Computed Preferred communication device: "
|
||||
+ preferredCommunicationDevice());
|
||||
@@ -1850,6 +1893,15 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
final BluetoothDevice btDevice = (BluetoothDevice) msg.obj;
|
||||
BtHelper.onNotifyPreferredAudioProfileApplied(btDevice);
|
||||
} break;
|
||||
|
||||
case MSG_L_CHECK_COMMUNICATION_DEVICE_REMOVAL: {
|
||||
synchronized (mSetModeLock) {
|
||||
synchronized (mDeviceStateLock) {
|
||||
onCheckCommunicationDeviceRemoval((AudioDeviceAttributes) msg.obj);
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
default:
|
||||
Log.wtf(TAG, "Invalid message " + msg.what);
|
||||
}
|
||||
@@ -1926,6 +1978,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
private static final int MSG_IL_BTLEAUDIO_TIMEOUT = 49;
|
||||
|
||||
private static final int MSG_L_NOTIFY_PREFERRED_AUDIOPROFILE_APPLIED = 52;
|
||||
private static final int MSG_L_CHECK_COMMUNICATION_DEVICE_REMOVAL = 53;
|
||||
|
||||
private static boolean isMessageHandledUnderWakelock(int msgId) {
|
||||
switch(msgId) {
|
||||
@@ -2101,13 +2154,20 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
private class CommunicationRouteClient implements IBinder.DeathRecipient {
|
||||
private final IBinder mCb;
|
||||
private final int mPid;
|
||||
private final int mUid;
|
||||
private final boolean mIsPrivileged;
|
||||
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;
|
||||
mPid = pid;
|
||||
mUid = uid;
|
||||
mDevice = device;
|
||||
mIsPrivileged = isPrivileged;
|
||||
mPlaybackActive = mAudioService.isPlaybackActiveForUid(uid);
|
||||
mRecordingActive = mAudioService.isRecordingActiveForUid(uid);
|
||||
}
|
||||
|
||||
public boolean registerDeathRecipient() {
|
||||
@@ -2138,13 +2198,38 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
return mCb;
|
||||
}
|
||||
|
||||
int getPid() {
|
||||
return mPid;
|
||||
int getUid() {
|
||||
return mUid;
|
||||
}
|
||||
|
||||
boolean isPrivileged() {
|
||||
return mIsPrivileged;
|
||||
}
|
||||
|
||||
AudioDeviceAttributes getDevice() {
|
||||
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")
|
||||
@@ -2154,8 +2239,9 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
return;
|
||||
}
|
||||
Log.w(TAG, "Communication client died");
|
||||
setCommunicationRouteForClient(client.getBinder(), client.getPid(), null,
|
||||
BtHelper.SCO_MODE_UNDEFINED, "onCommunicationRouteClientDied");
|
||||
setCommunicationRouteForClient(client.getBinder(), client.getUid(), null,
|
||||
BtHelper.SCO_MODE_UNDEFINED, client.isPrivileged(),
|
||||
"onCommunicationRouteClientDied");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2242,8 +2328,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
+ crc + " eventSource: " + eventSource);
|
||||
}
|
||||
if (crc != null) {
|
||||
setCommunicationRouteForClient(crc.getBinder(), crc.getPid(), crc.getDevice(),
|
||||
BtHelper.SCO_MODE_UNDEFINED, eventSource);
|
||||
setCommunicationRouteForClient(crc.getBinder(), crc.getUid(), crc.getDevice(),
|
||||
BtHelper.SCO_MODE_UNDEFINED, crc.isPrivileged(), eventSource);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2267,6 +2353,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
dispatchCommunicationDevice();
|
||||
}
|
||||
|
||||
@GuardedBy("mDeviceStateLock")
|
||||
private CommunicationRouteClient removeCommunicationRouteClient(
|
||||
IBinder cb, boolean unregister) {
|
||||
for (CommunicationRouteClient cl : mCommunicationRouteClients) {
|
||||
@@ -2282,11 +2369,12 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
}
|
||||
|
||||
@GuardedBy("mDeviceStateLock")
|
||||
private CommunicationRouteClient addCommunicationRouteClient(
|
||||
IBinder cb, int pid, AudioDeviceAttributes device) {
|
||||
private CommunicationRouteClient addCommunicationRouteClient(IBinder cb, int uid,
|
||||
AudioDeviceAttributes device, boolean isPrivileged) {
|
||||
// always insert new request at first position
|
||||
removeCommunicationRouteClient(cb, true);
|
||||
CommunicationRouteClient client = new CommunicationRouteClient(cb, pid, device);
|
||||
CommunicationRouteClient client =
|
||||
new CommunicationRouteClient(cb, uid, device, isPrivileged);
|
||||
if (client.registerDeathRecipient()) {
|
||||
mCommunicationRouteClients.add(0, client);
|
||||
return client;
|
||||
@@ -2295,9 +2383,9 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
}
|
||||
|
||||
@GuardedBy("mDeviceStateLock")
|
||||
private CommunicationRouteClient getCommunicationRouteClientForPid(int pid) {
|
||||
private CommunicationRouteClient getCommunicationRouteClientForUid(int uid) {
|
||||
for (CommunicationRouteClient cl : mCommunicationRouteClients) {
|
||||
if (cl.getPid() == pid) {
|
||||
if (cl.getUid() == uid) {
|
||||
return cl;
|
||||
}
|
||||
}
|
||||
@@ -2330,6 +2418,45 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
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) {
|
||||
synchronized (mDeviceStateLock) {
|
||||
return mDeviceInventory.getDeviceSensorUuid(device);
|
||||
|
||||
@@ -1245,8 +1245,9 @@ public class AudioDeviceInventory {
|
||||
* @param btDevice the corresponding Bluetooth device when relevant.
|
||||
* @return false if an error was reported by AudioSystem
|
||||
*/
|
||||
/*package*/ boolean handleDeviceConnection(AudioDeviceAttributes attributes, boolean connect,
|
||||
boolean isForTesting, @Nullable BluetoothDevice btDevice) {
|
||||
/*package*/ boolean handleDeviceConnection(@NonNull AudioDeviceAttributes attributes,
|
||||
boolean connect, boolean isForTesting,
|
||||
@Nullable BluetoothDevice btDevice) {
|
||||
int device = attributes.getInternalType();
|
||||
String address = attributes.getAddress();
|
||||
String deviceName = attributes.getName();
|
||||
@@ -1297,6 +1298,7 @@ public class AudioDeviceInventory {
|
||||
AudioSystem.DEVICE_STATE_UNAVAILABLE, AudioSystem.AUDIO_FORMAT_DEFAULT);
|
||||
// always remove even if disconnection failed
|
||||
mConnectedDevices.remove(deviceKey);
|
||||
mDeviceBroker.postCheckCommunicationDeviceRemoval(attributes);
|
||||
status = true;
|
||||
}
|
||||
if (status) {
|
||||
@@ -1801,8 +1803,9 @@ public class AudioDeviceInventory {
|
||||
|
||||
// device to remove was visible by APM, update APM
|
||||
mDeviceBroker.clearAvrcpAbsoluteVolumeSupported();
|
||||
final int res = mAudioSystem.setDeviceConnectionState(new AudioDeviceAttributes(
|
||||
AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address),
|
||||
AudioDeviceAttributes ada = new AudioDeviceAttributes(
|
||||
AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address);
|
||||
final int res = mAudioSystem.setDeviceConnectionState(ada,
|
||||
AudioSystem.DEVICE_STATE_UNAVAILABLE, a2dpCodec);
|
||||
|
||||
if (res != AudioSystem.AUDIO_STATUS_OK) {
|
||||
@@ -1816,11 +1819,13 @@ public class AudioDeviceInventory {
|
||||
"A2DP device addr=" + address + " made unavailable")).printLog(TAG));
|
||||
}
|
||||
mApmConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
|
||||
|
||||
// Remove A2DP routes as well
|
||||
setCurrentAudioRouteNameIfPossible(null, true /*fromA2dp*/);
|
||||
mmi.record();
|
||||
updateBluetoothPreferredModes_l(null /*connectedDevice*/);
|
||||
purgeDevicesRoles_l();
|
||||
mDeviceBroker.postCheckCommunicationDeviceRemoval(ada);
|
||||
}
|
||||
|
||||
@GuardedBy("mDevicesLock")
|
||||
@@ -1855,12 +1860,14 @@ public class AudioDeviceInventory {
|
||||
|
||||
@GuardedBy("mDevicesLock")
|
||||
private void makeA2dpSrcUnavailable(String address) {
|
||||
mAudioSystem.setDeviceConnectionState(new AudioDeviceAttributes(
|
||||
AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address),
|
||||
AudioDeviceAttributes ada = new AudioDeviceAttributes(
|
||||
AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address);
|
||||
mAudioSystem.setDeviceConnectionState(ada,
|
||||
AudioSystem.DEVICE_STATE_UNAVAILABLE,
|
||||
AudioSystem.AUDIO_FORMAT_DEFAULT);
|
||||
mConnectedDevices.remove(
|
||||
DeviceInfo.makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address));
|
||||
mDeviceBroker.postCheckCommunicationDeviceRemoval(ada);
|
||||
}
|
||||
|
||||
@GuardedBy("mDevicesLock")
|
||||
@@ -1893,8 +1900,9 @@ public class AudioDeviceInventory {
|
||||
|
||||
@GuardedBy("mDevicesLock")
|
||||
private void makeHearingAidDeviceUnavailable(String address) {
|
||||
mAudioSystem.setDeviceConnectionState(new AudioDeviceAttributes(
|
||||
AudioSystem.DEVICE_OUT_HEARING_AID, address),
|
||||
AudioDeviceAttributes ada = new AudioDeviceAttributes(
|
||||
AudioSystem.DEVICE_OUT_HEARING_AID, address);
|
||||
mAudioSystem.setDeviceConnectionState(ada,
|
||||
AudioSystem.DEVICE_STATE_UNAVAILABLE,
|
||||
AudioSystem.AUDIO_FORMAT_DEFAULT);
|
||||
mConnectedDevices.remove(
|
||||
@@ -1906,6 +1914,7 @@ public class AudioDeviceInventory {
|
||||
.set(MediaMetrics.Property.DEVICE,
|
||||
AudioSystem.getDeviceName(AudioSystem.DEVICE_OUT_HEARING_AID))
|
||||
.record();
|
||||
mDeviceBroker.postCheckCommunicationDeviceRemoval(ada);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2002,9 +2011,10 @@ public class AudioDeviceInventory {
|
||||
|
||||
@GuardedBy("mDevicesLock")
|
||||
private void makeLeAudioDeviceUnavailableNow(String address, int device) {
|
||||
AudioDeviceAttributes ada = null;
|
||||
if (device != AudioSystem.DEVICE_NONE) {
|
||||
final int res = AudioSystem.setDeviceConnectionState(new AudioDeviceAttributes(
|
||||
device, address),
|
||||
ada = new AudioDeviceAttributes(device, address);
|
||||
final int res = AudioSystem.setDeviceConnectionState(ada,
|
||||
AudioSystem.DEVICE_STATE_UNAVAILABLE,
|
||||
AudioSystem.AUDIO_FORMAT_DEFAULT);
|
||||
|
||||
@@ -2024,6 +2034,9 @@ public class AudioDeviceInventory {
|
||||
setCurrentAudioRouteNameIfPossible(null, false /*fromA2dp*/);
|
||||
updateBluetoothPreferredModes_l(null /*connectedDevice*/);
|
||||
purgeDevicesRoles_l();
|
||||
if (ada != null) {
|
||||
mDeviceBroker.postCheckCommunicationDeviceRemoval(ada);
|
||||
}
|
||||
}
|
||||
|
||||
@GuardedBy("mDevicesLock")
|
||||
|
||||
@@ -4262,22 +4262,41 @@ public class AudioService extends IAudioService.Stub
|
||||
// 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 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) {
|
||||
boolean updateAudioMode = false;
|
||||
int existingMsgPolicy = SENDMSG_QUEUE;
|
||||
int delay = CHECK_MODE_FOR_UID_PERIOD_MS;
|
||||
for (SetModeDeathHandler h : mSetModeDeathHandlers) {
|
||||
boolean wasActive = h.isActive();
|
||||
h.setPlaybackActive(false);
|
||||
for (AudioPlaybackConfiguration config : configs) {
|
||||
final int usage = config.getAudioAttributes().getUsage();
|
||||
if (config.getClientUid() == h.getUid()
|
||||
&& (usage == AudioAttributes.USAGE_VOICE_COMMUNICATION
|
||||
if (playbackConfigs != null) {
|
||||
h.setPlaybackActive(false);
|
||||
for (AudioPlaybackConfiguration config : playbackConfigs) {
|
||||
final int usage = config.getAudioAttributes().getUsage();
|
||||
if (config.getClientUid() == h.getUid()
|
||||
&& (usage == AudioAttributes.USAGE_VOICE_COMMUNICATION
|
||||
|| usage == AudioAttributes.USAGE_VOICE_COMMUNICATION_SIGNALLING)
|
||||
&& config.getPlayerState()
|
||||
== AudioPlaybackConfiguration.PLAYER_STATE_STARTED) {
|
||||
h.setPlaybackActive(true);
|
||||
break;
|
||||
&& config.isActive()) {
|
||||
h.setPlaybackActive(true);
|
||||
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()) {
|
||||
@@ -4315,38 +4334,10 @@ public class AudioService extends IAudioService.Stub
|
||||
// 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 after a grace period.
|
||||
synchronized (mDeviceBroker.mSetModeLock) {
|
||||
boolean updateAudioMode = false;
|
||||
int existingMsgPolicy = SENDMSG_QUEUE;
|
||||
int delay = CHECK_MODE_FOR_UID_PERIOD_MS;
|
||||
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);
|
||||
}
|
||||
}
|
||||
updateAudioModeHandlers(
|
||||
null /* playbackConfigs */, configs /* recordConfigs */);
|
||||
mDeviceBroker.updateCommunicationRouteClientsActivity(
|
||||
null /* playbackConfigs */, configs /* recordConfigs */);
|
||||
}
|
||||
|
||||
private void dumpAudioMode(PrintWriter pw) {
|
||||
@@ -6299,10 +6290,12 @@ public class AudioService extends IAudioService.Stub
|
||||
? MediaMetrics.Value.CONNECTED : MediaMetrics.Value.DISCONNECTED)
|
||||
.record();
|
||||
}
|
||||
|
||||
final boolean isPrivileged = mContext.checkCallingOrSelfPermission(
|
||||
android.Manifest.permission.MODIFY_PHONE_STATE)
|
||||
== PackageManager.PERMISSION_GRANTED;
|
||||
final long ident = Binder.clearCallingIdentity();
|
||||
try {
|
||||
return mDeviceBroker.setCommunicationDevice(cb, pid, device, eventSource);
|
||||
return mDeviceBroker.setCommunicationDevice(cb, uid, device, isPrivileged, eventSource);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(ident);
|
||||
}
|
||||
@@ -6348,6 +6341,9 @@ public class AudioService extends IAudioService.Stub
|
||||
if (!checkAudioSettingsPermission("setSpeakerphoneOn()")) {
|
||||
return;
|
||||
}
|
||||
final boolean isPrivileged = mContext.checkCallingOrSelfPermission(
|
||||
android.Manifest.permission.MODIFY_PHONE_STATE)
|
||||
== PackageManager.PERMISSION_GRANTED;
|
||||
|
||||
// for logging only
|
||||
final int uid = Binder.getCallingUid();
|
||||
@@ -6363,9 +6359,10 @@ public class AudioService extends IAudioService.Stub
|
||||
.set(MediaMetrics.Property.STATE, on
|
||||
? MediaMetrics.Value.ON : MediaMetrics.Value.OFF)
|
||||
.record();
|
||||
|
||||
final long ident = Binder.clearCallingIdentity();
|
||||
try {
|
||||
mDeviceBroker.setSpeakerphoneOn(cb, pid, on, eventSource);
|
||||
mDeviceBroker.setSpeakerphoneOn(cb, uid, on, isPrivileged, eventSource);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(ident);
|
||||
}
|
||||
@@ -6490,7 +6487,7 @@ public class AudioService extends IAudioService.Stub
|
||||
.set(MediaMetrics.Property.SCO_AUDIO_MODE,
|
||||
BtHelper.scoAudioModeToString(scoAudioMode))
|
||||
.record();
|
||||
startBluetoothScoInt(cb, pid, scoAudioMode, eventSource);
|
||||
startBluetoothScoInt(cb, uid, scoAudioMode, eventSource);
|
||||
|
||||
}
|
||||
|
||||
@@ -6513,10 +6510,10 @@ public class AudioService extends IAudioService.Stub
|
||||
.set(MediaMetrics.Property.SCO_AUDIO_MODE,
|
||||
BtHelper.scoAudioModeToString(BtHelper.SCO_MODE_VIRTUAL_CALL))
|
||||
.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)
|
||||
.set(MediaMetrics.Property.EVENT, "startBluetoothScoInt")
|
||||
.set(MediaMetrics.Property.SCO_AUDIO_MODE,
|
||||
@@ -6527,9 +6524,13 @@ public class AudioService extends IAudioService.Stub
|
||||
mmi.set(MediaMetrics.Property.EARLY_RETURN, "permission or systemReady").record();
|
||||
return;
|
||||
}
|
||||
final boolean isPrivileged = mContext.checkCallingOrSelfPermission(
|
||||
android.Manifest.permission.MODIFY_PHONE_STATE)
|
||||
== PackageManager.PERMISSION_GRANTED;
|
||||
final long ident = Binder.clearCallingIdentity();
|
||||
try {
|
||||
mDeviceBroker.startBluetoothScoForClient(cb, pid, scoAudioMode, eventSource);
|
||||
mDeviceBroker.startBluetoothScoForClient(
|
||||
cb, uid, scoAudioMode, isPrivileged, eventSource);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(ident);
|
||||
}
|
||||
@@ -6547,9 +6548,12 @@ public class AudioService extends IAudioService.Stub
|
||||
final String eventSource = new StringBuilder("stopBluetoothSco()")
|
||||
.append(") from u/pid:").append(uid).append("/")
|
||||
.append(pid).toString();
|
||||
final boolean isPrivileged = mContext.checkCallingOrSelfPermission(
|
||||
android.Manifest.permission.MODIFY_PHONE_STATE)
|
||||
== PackageManager.PERMISSION_GRANTED;
|
||||
final long ident = Binder.clearCallingIdentity();
|
||||
try {
|
||||
mDeviceBroker.stopBluetoothScoForClient(cb, pid, eventSource);
|
||||
mDeviceBroker.stopBluetoothScoForClient(cb, uid, isPrivileged, eventSource);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(ident);
|
||||
}
|
||||
@@ -9284,8 +9288,8 @@ public class AudioService extends IAudioService.Stub
|
||||
break;
|
||||
}
|
||||
boolean wasActive = h.isActive();
|
||||
h.setPlaybackActive(mPlaybackMonitor.isPlaybackActiveForUid(h.getUid()));
|
||||
h.setRecordingActive(mRecordMonitor.isRecordingActiveForUid(h.getUid()));
|
||||
h.setPlaybackActive(isPlaybackActiveForUid(h.getUid()));
|
||||
h.setRecordingActive(isRecordingActiveForUid(h.getUid()));
|
||||
if (wasActive != h.isActive()) {
|
||||
onUpdateAudioMode(AudioSystem.MODE_CURRENT, android.os.Process.myPid(),
|
||||
mContext.getPackageName(), false /*force*/);
|
||||
@@ -12378,6 +12382,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
|
||||
//======================
|
||||
|
||||
@@ -227,8 +227,8 @@ public final class RecordingActivityMonitor implements AudioSystem.AudioRecordin
|
||||
synchronized (mRecordStates) {
|
||||
for (RecordingState state : mRecordStates) {
|
||||
// Note: isActiveConfiguration() == true => state.getConfig() != null
|
||||
if (state.isActiveConfiguration()
|
||||
&& state.getConfig().getClientUid() == uid) {
|
||||
if (state.isActiveConfiguration() && state.getConfig().getClientUid() == uid
|
||||
&& !state.getConfig().isClientSilenced()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user