summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
authorEric Laurent <elaurent@google.com>2012-05-09 11:38:16 -0700
committerEric Laurent <elaurent@google.com>2012-05-10 14:55:20 -0700
commit3172d5e3e7520a745fa37b71fc1c7bf244b57085 (patch)
tree8bf131deb607bffcb70ef15856b69bbca3ff27ff /media
parent3fcf1c85873008df43ee80f896216fb39e4c630e (diff)
downloadframeworks_base-3172d5e3e7520a745fa37b71fc1c7bf244b57085.zip
frameworks_base-3172d5e3e7520a745fa37b71fc1c7bf244b57085.tar.gz
frameworks_base-3172d5e3e7520a745fa37b71fc1c7bf244b57085.tar.bz2
AudioService: synchronized access to volume index
Add synchronization to prevent concurrent accesses to volume indexes HashMap in VolumeStreamState. Use ConcurrentHashMap for VolumeStreamState mIndex and mLastAudibleIndex. Issue 6421841. Change-Id: I6dee805a79aa5e2cd0ba4072014a2fcdda4ed507
Diffstat (limited to 'media')
-rw-r--r--media/java/android/media/AudioService.java231
1 files changed, 118 insertions, 113 deletions
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 1892fce..8d6ddbd 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -70,6 +70,7 @@ import java.io.FileDescriptor;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
@@ -515,12 +516,14 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
int index = rescaleIndex(streams[i].getIndex(device, false /* lastAudible */),
mStreamVolumeAlias[i],
i);
- streams[i].mIndex.put(device, streams[i].getValidIndex(index));
- streams[i].applyDeviceVolume(device);
- index = rescaleIndex(streams[i].getIndex(device, true /* lastAudible */),
- mStreamVolumeAlias[i],
- i);
- streams[i].mLastAudibleIndex.put(device, streams[i].getValidIndex(index));
+ synchronized (streams[i]) {
+ streams[i].mIndex.put(device, streams[i].getValidIndex(index));
+ streams[i].applyDeviceVolume(device);
+ index = rescaleIndex(streams[i].getIndex(device, true /* lastAudible */),
+ mStreamVolumeAlias[i],
+ i);
+ streams[i].mLastAudibleIndex.put(device, streams[i].getValidIndex(index));
+ }
}
}
}
@@ -1112,12 +1115,14 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
// on voice capable devices
if (mVoiceCapable &&
mStreamVolumeAlias[streamType] == AudioSystem.STREAM_RING) {
- Set set = mStreamStates[streamType].mLastAudibleIndex.entrySet();
- Iterator i = set.iterator();
- while (i.hasNext()) {
- Map.Entry entry = (Map.Entry)i.next();
- if ((Integer)entry.getValue() == 0) {
- entry.setValue(10);
+ synchronized (mStreamStates[streamType]) {
+ Set set = mStreamStates[streamType].mLastAudibleIndex.entrySet();
+ Iterator i = set.iterator();
+ while (i.hasNext()) {
+ Map.Entry entry = (Map.Entry)i.next();
+ if ((Integer)entry.getValue() == 0) {
+ entry.setValue(10);
+ }
}
}
}
@@ -1583,19 +1588,21 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
for (int streamType = 0; streamType < numStreamTypes; streamType++) {
VolumeStreamState streamState = mStreamStates[streamType];
- streamState.readSettings();
+ synchronized (streamState) {
+ streamState.readSettings();
- // unmute stream that was muted but is not affect by mute anymore
- if (streamState.muteCount() != 0 && !isStreamAffectedByMute(streamType)) {
- int size = streamState.mDeathHandlers.size();
- for (int i = 0; i < size; i++) {
- streamState.mDeathHandlers.get(i).mMuteCount = 1;
- streamState.mDeathHandlers.get(i).mute(false);
+ // unmute stream that was muted but is not affect by mute anymore
+ if (streamState.muteCount() != 0 && !isStreamAffectedByMute(streamType)) {
+ int size = streamState.mDeathHandlers.size();
+ for (int i = 0; i < size; i++) {
+ streamState.mDeathHandlers.get(i).mMuteCount = 1;
+ streamState.mDeathHandlers.get(i).mute(false);
+ }
+ }
+ // apply stream volume
+ if (streamState.muteCount() == 0) {
+ streamState.applyAllVolumes();
}
- }
- // apply stream volume
- if (streamState.muteCount() == 0) {
- streamState.applyAllVolumes();
}
}
@@ -2232,9 +2239,10 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
private String mVolumeIndexSettingName;
private String mLastAudibleVolumeIndexSettingName;
private int mIndexMax;
- private final HashMap <Integer, Integer> mIndex = new HashMap <Integer, Integer>();
- private final HashMap <Integer, Integer> mLastAudibleIndex =
- new HashMap <Integer, Integer>();
+ private final ConcurrentHashMap<Integer, Integer> mIndex =
+ new ConcurrentHashMap<Integer, Integer>(8, 0.75f, 4);
+ private final ConcurrentHashMap<Integer, Integer> mLastAudibleIndex =
+ new ConcurrentHashMap<Integer, Integer>(8, 0.75f, 4);
private ArrayList<VolumeDeathHandler> mDeathHandlers; //handles mute/solo clients death
private VolumeStreamState(String settingName, int streamType) {
@@ -2265,7 +2273,7 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
return name + "_" + suffix;
}
- public void readSettings() {
+ public synchronized void readSettings() {
int remainingDevices = AudioSystem.DEVICE_OUT_ALL;
for (int i = 0; remainingDevices != 0; i++) {
@@ -2339,7 +2347,7 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
device);
}
- public void applyAllVolumes() {
+ public synchronized void applyAllVolumes() {
// apply default volume first: by convention this will reset all
// devices volumes in audio policy manager to the supplied value
AudioSystem.setStreamVolumeIndex(mStreamType,
@@ -2366,7 +2374,7 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
true /* lastAudible */);
}
- public boolean setIndex(int index, int device, boolean lastAudible) {
+ public synchronized boolean setIndex(int index, int device, boolean lastAudible) {
int oldIndex = getIndex(device, false /* lastAudible */);
index = getValidIndex(index);
mIndex.put(device, getValidIndex(index));
@@ -2400,8 +2408,8 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
}
}
- public int getIndex(int device, boolean lastAudible) {
- HashMap <Integer, Integer> indexes;
+ public synchronized int getIndex(int device, boolean lastAudible) {
+ ConcurrentHashMap <Integer, Integer> indexes;
if (lastAudible) {
indexes = mLastAudibleIndex;
} else {
@@ -2415,11 +2423,11 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
return index.intValue();
}
- public void setLastAudibleIndex(int index, int device) {
+ public synchronized void setLastAudibleIndex(int index, int device) {
mLastAudibleIndex.put(device, getValidIndex(index));
}
- public void adjustLastAudibleIndex(int deltaIndex, int device) {
+ public synchronized void adjustLastAudibleIndex(int deltaIndex, int device) {
setLastAudibleIndex(getIndex(device,
true /* lastAudible */) + deltaIndex * 10,
device);
@@ -2429,7 +2437,8 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
return mIndexMax;
}
- public HashMap <Integer, Integer> getAllIndexes(boolean lastAudible) {
+ // only called by setAllIndexes() which is already synchronized
+ public ConcurrentHashMap <Integer, Integer> getAllIndexes(boolean lastAudible) {
if (lastAudible) {
return mLastAudibleIndex;
} else {
@@ -2437,8 +2446,8 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
}
}
- public void setAllIndexes(VolumeStreamState srcStream, boolean lastAudible) {
- HashMap <Integer, Integer> indexes = srcStream.getAllIndexes(lastAudible);
+ public synchronized void setAllIndexes(VolumeStreamState srcStream, boolean lastAudible) {
+ ConcurrentHashMap <Integer, Integer> indexes = srcStream.getAllIndexes(lastAudible);
Set set = indexes.entrySet();
Iterator i = set.iterator();
while (i.hasNext()) {
@@ -2450,7 +2459,7 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
}
}
- public void mute(IBinder cb, boolean state) {
+ public synchronized void mute(IBinder cb, boolean state) {
VolumeDeathHandler handler = getDeathHandler(cb, state);
if (handler == null) {
Log.e(TAG, "Could not get client death handler for stream: "+mStreamType);
@@ -2481,25 +2490,68 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
mICallback = cb;
}
+ // must be called while synchronized on parent VolumeStreamState
public void mute(boolean state) {
- synchronized(mDeathHandlers) {
- if (state) {
- if (mMuteCount == 0) {
- // Register for client death notification
- try {
- // mICallback can be 0 if muted by AudioService
- if (mICallback != null) {
- mICallback.linkToDeath(this, 0);
+ if (state) {
+ if (mMuteCount == 0) {
+ // Register for client death notification
+ try {
+ // mICallback can be 0 if muted by AudioService
+ if (mICallback != null) {
+ mICallback.linkToDeath(this, 0);
+ }
+ mDeathHandlers.add(this);
+ // If the stream is not yet muted by any client, set level to 0
+ if (muteCount() == 0) {
+ Set set = mIndex.entrySet();
+ Iterator i = set.iterator();
+ while (i.hasNext()) {
+ Map.Entry entry = (Map.Entry)i.next();
+ int device = ((Integer)entry.getKey()).intValue();
+ setIndex(0, device, false /* lastAudible */);
}
- mDeathHandlers.add(this);
- // If the stream is not yet muted by any client, set level to 0
- if (muteCount() == 0) {
+ sendMsg(mAudioHandler,
+ MSG_SET_ALL_VOLUMES,
+ SENDMSG_QUEUE,
+ 0,
+ 0,
+ VolumeStreamState.this, 0);
+ }
+ } catch (RemoteException e) {
+ // Client has died!
+ binderDied();
+ return;
+ }
+ } else {
+ Log.w(TAG, "stream: "+mStreamType+" was already muted by this client");
+ }
+ mMuteCount++;
+ } else {
+ if (mMuteCount == 0) {
+ Log.e(TAG, "unexpected unmute for stream: "+mStreamType);
+ } else {
+ mMuteCount--;
+ if (mMuteCount == 0) {
+ // Unregister from client death notification
+ mDeathHandlers.remove(this);
+ // mICallback can be 0 if muted by AudioService
+ if (mICallback != null) {
+ mICallback.unlinkToDeath(this, 0);
+ }
+ if (muteCount() == 0) {
+ // If the stream is not muted any more, restore its volume if
+ // ringer mode allows it
+ if (!isStreamAffectedByRingerMode(mStreamType) ||
+ mRingerMode == AudioManager.RINGER_MODE_NORMAL) {
Set set = mIndex.entrySet();
Iterator i = set.iterator();
while (i.hasNext()) {
Map.Entry entry = (Map.Entry)i.next();
int device = ((Integer)entry.getKey()).intValue();
- setIndex(0, device, false /* lastAudible */);
+ setIndex(getIndex(device,
+ true /* lastAudible */),
+ device,
+ false /* lastAudible */);
}
sendMsg(mAudioHandler,
MSG_SET_ALL_VOLUMES,
@@ -2508,55 +2560,9 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
0,
VolumeStreamState.this, 0);
}
- } catch (RemoteException e) {
- // Client has died!
- binderDied();
- mDeathHandlers.notify();
- return;
- }
- } else {
- Log.w(TAG, "stream: "+mStreamType+" was already muted by this client");
- }
- mMuteCount++;
- } else {
- if (mMuteCount == 0) {
- Log.e(TAG, "unexpected unmute for stream: "+mStreamType);
- } else {
- mMuteCount--;
- if (mMuteCount == 0) {
- // Unregistr from client death notification
- mDeathHandlers.remove(this);
- // mICallback can be 0 if muted by AudioService
- if (mICallback != null) {
- mICallback.unlinkToDeath(this, 0);
- }
- if (muteCount() == 0) {
- // If the stream is not muted any more, restore it's volume if
- // ringer mode allows it
- if (!isStreamAffectedByRingerMode(mStreamType) ||
- mRingerMode == AudioManager.RINGER_MODE_NORMAL) {
- Set set = mIndex.entrySet();
- Iterator i = set.iterator();
- while (i.hasNext()) {
- Map.Entry entry = (Map.Entry)i.next();
- int device = ((Integer)entry.getKey()).intValue();
- setIndex(getIndex(device,
- true /* lastAudible */),
- device,
- false /* lastAudible */);
- }
- sendMsg(mAudioHandler,
- MSG_SET_ALL_VOLUMES,
- SENDMSG_QUEUE,
- 0,
- 0,
- VolumeStreamState.this, 0);
- }
- }
}
}
}
- mDeathHandlers.notify();
}
}
@@ -2570,7 +2576,7 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
}
}
- private int muteCount() {
+ private synchronized int muteCount() {
int count = 0;
int size = mDeathHandlers.size();
for (int i = 0; i < size; i++) {
@@ -2579,26 +2585,25 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
return count;
}
+ // only called by mute() which is already synchronized
private VolumeDeathHandler getDeathHandler(IBinder cb, boolean state) {
- synchronized(mDeathHandlers) {
- VolumeDeathHandler handler;
- int size = mDeathHandlers.size();
- for (int i = 0; i < size; i++) {
- handler = mDeathHandlers.get(i);
- if (cb == handler.mICallback) {
- return handler;
- }
- }
- // If this is the first mute request for this client, create a new
- // client death handler. Otherwise, it is an out of sequence unmute request.
- if (state) {
- handler = new VolumeDeathHandler(cb);
- } else {
- Log.w(TAG, "stream was not muted by this client");
- handler = null;
+ VolumeDeathHandler handler;
+ int size = mDeathHandlers.size();
+ for (int i = 0; i < size; i++) {
+ handler = mDeathHandlers.get(i);
+ if (cb == handler.mICallback) {
+ return handler;
}
- return handler;
}
+ // If this is the first mute request for this client, create a new
+ // client death handler. Otherwise, it is an out of sequence unmute request.
+ if (state) {
+ handler = new VolumeDeathHandler(cb);
+ } else {
+ Log.w(TAG, "stream was not muted by this client");
+ handler = null;
+ }
+ return handler;
}
private void dump(PrintWriter pw) {