am ba64d298: Merge "AudioService: fix cross deadlock in VolumeStreamState"

* commit 'ba64d298bee228b8e27ea17fb31fbff4b4188304':
  AudioService: fix cross deadlock in VolumeStreamState
This commit is contained in:
Eric Laurent
2014-05-23 21:37:54 +00:00
committed by Android Git Automerger

View File

@@ -2863,54 +2863,56 @@ public class AudioService extends IAudioService.Stub {
return name + "_" + suffix; return name + "_" + suffix;
} }
public synchronized void readSettings() { public void readSettings() {
// force maximum volume on all streams if fixed volume property is set synchronized (VolumeStreamState.class) {
if (mUseFixedVolume) { // force maximum volume on all streams if fixed volume property is set
mIndex.put(AudioSystem.DEVICE_OUT_DEFAULT, mIndexMax); if (mUseFixedVolume) {
return; mIndex.put(AudioSystem.DEVICE_OUT_DEFAULT, mIndexMax);
} return;
// do not read system stream volume from settings: this stream is always aliased }
// to another stream type and its volume is never persisted. Values in settings can // do not read system stream volume from settings: this stream is always aliased
// only be stale values // to another stream type and its volume is never persisted. Values in settings can
if ((mStreamType == AudioSystem.STREAM_SYSTEM) || // only be stale values
(mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED)) { if ((mStreamType == AudioSystem.STREAM_SYSTEM) ||
int index = 10 * AudioManager.DEFAULT_STREAM_VOLUME[mStreamType]; (mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED)) {
synchronized (mCameraSoundForced) { int index = 10 * AudioManager.DEFAULT_STREAM_VOLUME[mStreamType];
if (mCameraSoundForced) { synchronized (mCameraSoundForced) {
index = mIndexMax; if (mCameraSoundForced) {
index = mIndexMax;
}
} }
} mIndex.put(AudioSystem.DEVICE_OUT_DEFAULT, index);
mIndex.put(AudioSystem.DEVICE_OUT_DEFAULT, index); return;
return;
}
int remainingDevices = AudioSystem.DEVICE_OUT_ALL;
for (int i = 0; remainingDevices != 0; i++) {
int device = (1 << i);
if ((device & remainingDevices) == 0) {
continue;
}
remainingDevices &= ~device;
// retrieve current volume for device
String name = getSettingNameForDevice(device);
// if no volume stored for current stream and device, use default volume if default
// device, continue otherwise
int defaultIndex = (device == AudioSystem.DEVICE_OUT_DEFAULT) ?
AudioManager.DEFAULT_STREAM_VOLUME[mStreamType] : -1;
int index = Settings.System.getIntForUser(
mContentResolver, name, defaultIndex, UserHandle.USER_CURRENT);
if (index == -1) {
continue;
} }
// ignore settings for fixed volume devices: volume should always be at max or 0 int remainingDevices = AudioSystem.DEVICE_OUT_ALL;
if ((mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_MUSIC) &&
((device & mFixedVolumeDevices) != 0)) { for (int i = 0; remainingDevices != 0; i++) {
mIndex.put(device, (index != 0) ? mIndexMax : 0); int device = (1 << i);
} else { if ((device & remainingDevices) == 0) {
mIndex.put(device, getValidIndex(10 * index)); continue;
}
remainingDevices &= ~device;
// retrieve current volume for device
String name = getSettingNameForDevice(device);
// if no volume stored for current stream and device, use default volume if default
// device, continue otherwise
int defaultIndex = (device == AudioSystem.DEVICE_OUT_DEFAULT) ?
AudioManager.DEFAULT_STREAM_VOLUME[mStreamType] : -1;
int index = Settings.System.getIntForUser(
mContentResolver, name, defaultIndex, UserHandle.USER_CURRENT);
if (index == -1) {
continue;
}
// ignore settings for fixed volume devices: volume should always be at max or 0
if ((mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_MUSIC) &&
((device & mFixedVolumeDevices) != 0)) {
mIndex.put(device, (index != 0) ? mIndexMax : 0);
} else {
mIndex.put(device, getValidIndex(10 * index));
}
} }
} }
} }
@@ -2928,32 +2930,34 @@ public class AudioService extends IAudioService.Stub {
AudioSystem.setStreamVolumeIndex(mStreamType, index, device); AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
} }
public synchronized void applyAllVolumes() { public void applyAllVolumes() {
// apply default volume first: by convention this will reset all synchronized (VolumeStreamState.class) {
// devices volumes in audio policy manager to the supplied value // apply default volume first: by convention this will reset all
int index; // devices volumes in audio policy manager to the supplied value
if (isMuted()) { int index;
index = 0; if (isMuted()) {
} else { index = 0;
index = (getIndex(AudioSystem.DEVICE_OUT_DEFAULT) + 5)/10; } else {
} index = (getIndex(AudioSystem.DEVICE_OUT_DEFAULT) + 5)/10;
AudioSystem.setStreamVolumeIndex(mStreamType, index, AudioSystem.DEVICE_OUT_DEFAULT); }
// then apply device specific volumes AudioSystem.setStreamVolumeIndex(mStreamType, index, AudioSystem.DEVICE_OUT_DEFAULT);
Set set = mIndex.entrySet(); // then apply device specific volumes
Iterator i = set.iterator(); Set set = mIndex.entrySet();
while (i.hasNext()) { Iterator i = set.iterator();
Map.Entry entry = (Map.Entry)i.next(); while (i.hasNext()) {
int device = ((Integer)entry.getKey()).intValue(); Map.Entry entry = (Map.Entry)i.next();
if (device != AudioSystem.DEVICE_OUT_DEFAULT) { int device = ((Integer)entry.getKey()).intValue();
if (isMuted()) { if (device != AudioSystem.DEVICE_OUT_DEFAULT) {
index = 0; if (isMuted()) {
} else if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 && index = 0;
mAvrcpAbsVolSupported) { } else if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
index = (mIndexMax + 5)/10; mAvrcpAbsVolSupported) {
} else { index = (mIndexMax + 5)/10;
index = ((Integer)entry.getValue() + 5)/10; } else {
index = ((Integer)entry.getValue() + 5)/10;
}
AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
} }
AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
} }
} }
} }
@@ -2963,94 +2967,104 @@ public class AudioService extends IAudioService.Stub {
device); device);
} }
public synchronized boolean setIndex(int index, int device) { public boolean setIndex(int index, int device) {
int oldIndex = getIndex(device); synchronized (VolumeStreamState.class) {
index = getValidIndex(index); int oldIndex = getIndex(device);
synchronized (mCameraSoundForced) { index = getValidIndex(index);
if ((mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED) && mCameraSoundForced) { synchronized (mCameraSoundForced) {
index = mIndexMax; if ((mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED) && mCameraSoundForced) {
} index = mIndexMax;
}
mIndex.put(device, index);
if (oldIndex != index) {
// Apply change to all streams using this one as alias
// if changing volume of current device, also change volume of current
// device on aliased stream
boolean currentDevice = (device == getDeviceForStream(mStreamType));
int numStreamTypes = AudioSystem.getNumStreamTypes();
for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
if (streamType != mStreamType &&
mStreamVolumeAlias[streamType] == mStreamType) {
int scaledIndex = rescaleIndex(index, mStreamType, streamType);
mStreamStates[streamType].setIndex(scaledIndex,
device);
if (currentDevice) {
mStreamStates[streamType].setIndex(scaledIndex,
getDeviceForStream(streamType));
}
} }
} }
return true; mIndex.put(device, index);
} else {
return false; if (oldIndex != index) {
// Apply change to all streams using this one as alias
// if changing volume of current device, also change volume of current
// device on aliased stream
boolean currentDevice = (device == getDeviceForStream(mStreamType));
int numStreamTypes = AudioSystem.getNumStreamTypes();
for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
if (streamType != mStreamType &&
mStreamVolumeAlias[streamType] == mStreamType) {
int scaledIndex = rescaleIndex(index, mStreamType, streamType);
mStreamStates[streamType].setIndex(scaledIndex,
device);
if (currentDevice) {
mStreamStates[streamType].setIndex(scaledIndex,
getDeviceForStream(streamType));
}
}
}
return true;
} else {
return false;
}
} }
} }
public synchronized int getIndex(int device) { public int getIndex(int device) {
Integer index = mIndex.get(device); synchronized (VolumeStreamState.class) {
if (index == null) { Integer index = mIndex.get(device);
// there is always an entry for AudioSystem.DEVICE_OUT_DEFAULT if (index == null) {
index = mIndex.get(AudioSystem.DEVICE_OUT_DEFAULT); // there is always an entry for AudioSystem.DEVICE_OUT_DEFAULT
index = mIndex.get(AudioSystem.DEVICE_OUT_DEFAULT);
}
return index.intValue();
} }
return index.intValue();
} }
public int getMaxIndex() { public int getMaxIndex() {
return mIndexMax; return mIndexMax;
} }
public synchronized void setAllIndexes(VolumeStreamState srcStream) { public void setAllIndexes(VolumeStreamState srcStream) {
int srcStreamType = srcStream.getStreamType(); synchronized (VolumeStreamState.class) {
// apply default device volume from source stream to all devices first in case int srcStreamType = srcStream.getStreamType();
// some devices are present in this stream state but not in source stream state // apply default device volume from source stream to all devices first in case
int index = srcStream.getIndex(AudioSystem.DEVICE_OUT_DEFAULT); // some devices are present in this stream state but not in source stream state
index = rescaleIndex(index, srcStreamType, mStreamType); int index = srcStream.getIndex(AudioSystem.DEVICE_OUT_DEFAULT);
Set set = mIndex.entrySet();
Iterator i = set.iterator();
while (i.hasNext()) {
Map.Entry entry = (Map.Entry)i.next();
entry.setValue(index);
}
// Now apply actual volume for devices in source stream state
set = srcStream.mIndex.entrySet();
i = set.iterator();
while (i.hasNext()) {
Map.Entry entry = (Map.Entry)i.next();
int device = ((Integer)entry.getKey()).intValue();
index = ((Integer)entry.getValue()).intValue();
index = rescaleIndex(index, srcStreamType, mStreamType); index = rescaleIndex(index, srcStreamType, mStreamType);
Set set = mIndex.entrySet();
Iterator i = set.iterator();
while (i.hasNext()) {
Map.Entry entry = (Map.Entry)i.next();
entry.setValue(index);
}
// Now apply actual volume for devices in source stream state
set = srcStream.mIndex.entrySet();
i = set.iterator();
while (i.hasNext()) {
Map.Entry entry = (Map.Entry)i.next();
int device = ((Integer)entry.getKey()).intValue();
index = ((Integer)entry.getValue()).intValue();
index = rescaleIndex(index, srcStreamType, mStreamType);
setIndex(index, device); setIndex(index, device);
}
} }
} }
public synchronized void setAllIndexesToMax() { public void setAllIndexesToMax() {
Set set = mIndex.entrySet(); synchronized (VolumeStreamState.class) {
Iterator i = set.iterator(); Set set = mIndex.entrySet();
while (i.hasNext()) { Iterator i = set.iterator();
Map.Entry entry = (Map.Entry)i.next(); while (i.hasNext()) {
entry.setValue(mIndexMax); Map.Entry entry = (Map.Entry)i.next();
entry.setValue(mIndexMax);
}
} }
} }
public synchronized void mute(IBinder cb, boolean state) { public void mute(IBinder cb, boolean state) {
VolumeDeathHandler handler = getDeathHandler(cb, state); synchronized (VolumeStreamState.class) {
if (handler == null) { VolumeDeathHandler handler = getDeathHandler(cb, state);
Log.e(TAG, "Could not get client death handler for stream: "+mStreamType); if (handler == null) {
return; Log.e(TAG, "Could not get client death handler for stream: "+mStreamType);
return;
}
handler.mute(state);
} }
handler.mute(state);
} }
public int getStreamType() { public int getStreamType() {