Skip to content

Commit 24938df

Browse files
Eric LaurentAndroid (Google) Code Review
authored andcommitted
Merge "AudioService: synchronized access to volume index" into jb-dev
2 parents 718af32 + 3172d5e commit 24938df

File tree

1 file changed

+118
-113
lines changed

1 file changed

+118
-113
lines changed

media/java/android/media/AudioService.java

Lines changed: 118 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@
7070
import java.io.IOException;
7171
import java.io.PrintWriter;
7272
import java.util.ArrayList;
73+
import java.util.concurrent.ConcurrentHashMap;
7374
import java.util.HashMap;
7475
import java.util.Iterator;
7576
import java.util.List;
@@ -515,12 +516,14 @@ private void createStreamStates() {
515516
int index = rescaleIndex(streams[i].getIndex(device, false /* lastAudible */),
516517
mStreamVolumeAlias[i],
517518
i);
518-
streams[i].mIndex.put(device, streams[i].getValidIndex(index));
519-
streams[i].applyDeviceVolume(device);
520-
index = rescaleIndex(streams[i].getIndex(device, true /* lastAudible */),
521-
mStreamVolumeAlias[i],
522-
i);
523-
streams[i].mLastAudibleIndex.put(device, streams[i].getValidIndex(index));
519+
synchronized (streams[i]) {
520+
streams[i].mIndex.put(device, streams[i].getValidIndex(index));
521+
streams[i].applyDeviceVolume(device);
522+
index = rescaleIndex(streams[i].getIndex(device, true /* lastAudible */),
523+
mStreamVolumeAlias[i],
524+
i);
525+
streams[i].mLastAudibleIndex.put(device, streams[i].getValidIndex(index));
526+
}
524527
}
525528
}
526529
}
@@ -1112,12 +1115,14 @@ private void setRingerModeInt(int ringerMode, boolean persist) {
11121115
// on voice capable devices
11131116
if (mVoiceCapable &&
11141117
mStreamVolumeAlias[streamType] == AudioSystem.STREAM_RING) {
1115-
Set set = mStreamStates[streamType].mLastAudibleIndex.entrySet();
1116-
Iterator i = set.iterator();
1117-
while (i.hasNext()) {
1118-
Map.Entry entry = (Map.Entry)i.next();
1119-
if ((Integer)entry.getValue() == 0) {
1120-
entry.setValue(10);
1118+
synchronized (mStreamStates[streamType]) {
1119+
Set set = mStreamStates[streamType].mLastAudibleIndex.entrySet();
1120+
Iterator i = set.iterator();
1121+
while (i.hasNext()) {
1122+
Map.Entry entry = (Map.Entry)i.next();
1123+
if ((Integer)entry.getValue() == 0) {
1124+
entry.setValue(10);
1125+
}
11211126
}
11221127
}
11231128
}
@@ -1583,19 +1588,21 @@ public void reloadAudioSettings() {
15831588
for (int streamType = 0; streamType < numStreamTypes; streamType++) {
15841589
VolumeStreamState streamState = mStreamStates[streamType];
15851590

1586-
streamState.readSettings();
1591+
synchronized (streamState) {
1592+
streamState.readSettings();
15871593

1588-
// unmute stream that was muted but is not affect by mute anymore
1589-
if (streamState.muteCount() != 0 && !isStreamAffectedByMute(streamType)) {
1590-
int size = streamState.mDeathHandlers.size();
1591-
for (int i = 0; i < size; i++) {
1592-
streamState.mDeathHandlers.get(i).mMuteCount = 1;
1593-
streamState.mDeathHandlers.get(i).mute(false);
1594+
// unmute stream that was muted but is not affect by mute anymore
1595+
if (streamState.muteCount() != 0 && !isStreamAffectedByMute(streamType)) {
1596+
int size = streamState.mDeathHandlers.size();
1597+
for (int i = 0; i < size; i++) {
1598+
streamState.mDeathHandlers.get(i).mMuteCount = 1;
1599+
streamState.mDeathHandlers.get(i).mute(false);
1600+
}
1601+
}
1602+
// apply stream volume
1603+
if (streamState.muteCount() == 0) {
1604+
streamState.applyAllVolumes();
15941605
}
1595-
}
1596-
// apply stream volume
1597-
if (streamState.muteCount() == 0) {
1598-
streamState.applyAllVolumes();
15991606
}
16001607
}
16011608

@@ -2232,9 +2239,10 @@ public class VolumeStreamState {
22322239
private String mVolumeIndexSettingName;
22332240
private String mLastAudibleVolumeIndexSettingName;
22342241
private int mIndexMax;
2235-
private final HashMap <Integer, Integer> mIndex = new HashMap <Integer, Integer>();
2236-
private final HashMap <Integer, Integer> mLastAudibleIndex =
2237-
new HashMap <Integer, Integer>();
2242+
private final ConcurrentHashMap<Integer, Integer> mIndex =
2243+
new ConcurrentHashMap<Integer, Integer>(8, 0.75f, 4);
2244+
private final ConcurrentHashMap<Integer, Integer> mLastAudibleIndex =
2245+
new ConcurrentHashMap<Integer, Integer>(8, 0.75f, 4);
22382246
private ArrayList<VolumeDeathHandler> mDeathHandlers; //handles mute/solo clients death
22392247

22402248
private VolumeStreamState(String settingName, int streamType) {
@@ -2265,7 +2273,7 @@ public String getSettingNameForDevice(boolean lastAudible, int device) {
22652273
return name + "_" + suffix;
22662274
}
22672275

2268-
public void readSettings() {
2276+
public synchronized void readSettings() {
22692277
int remainingDevices = AudioSystem.DEVICE_OUT_ALL;
22702278

22712279
for (int i = 0; remainingDevices != 0; i++) {
@@ -2339,7 +2347,7 @@ public void applyDeviceVolume(int device) {
23392347
device);
23402348
}
23412349

2342-
public void applyAllVolumes() {
2350+
public synchronized void applyAllVolumes() {
23432351
// apply default volume first: by convention this will reset all
23442352
// devices volumes in audio policy manager to the supplied value
23452353
AudioSystem.setStreamVolumeIndex(mStreamType,
@@ -2366,7 +2374,7 @@ public boolean adjustIndex(int deltaIndex, int device) {
23662374
true /* lastAudible */);
23672375
}
23682376

2369-
public boolean setIndex(int index, int device, boolean lastAudible) {
2377+
public synchronized boolean setIndex(int index, int device, boolean lastAudible) {
23702378
int oldIndex = getIndex(device, false /* lastAudible */);
23712379
index = getValidIndex(index);
23722380
mIndex.put(device, getValidIndex(index));
@@ -2400,8 +2408,8 @@ public boolean setIndex(int index, int device, boolean lastAudible) {
24002408
}
24012409
}
24022410

2403-
public int getIndex(int device, boolean lastAudible) {
2404-
HashMap <Integer, Integer> indexes;
2411+
public synchronized int getIndex(int device, boolean lastAudible) {
2412+
ConcurrentHashMap <Integer, Integer> indexes;
24052413
if (lastAudible) {
24062414
indexes = mLastAudibleIndex;
24072415
} else {
@@ -2415,11 +2423,11 @@ public int getIndex(int device, boolean lastAudible) {
24152423
return index.intValue();
24162424
}
24172425

2418-
public void setLastAudibleIndex(int index, int device) {
2426+
public synchronized void setLastAudibleIndex(int index, int device) {
24192427
mLastAudibleIndex.put(device, getValidIndex(index));
24202428
}
24212429

2422-
public void adjustLastAudibleIndex(int deltaIndex, int device) {
2430+
public synchronized void adjustLastAudibleIndex(int deltaIndex, int device) {
24232431
setLastAudibleIndex(getIndex(device,
24242432
true /* lastAudible */) + deltaIndex * 10,
24252433
device);
@@ -2429,16 +2437,17 @@ public int getMaxIndex() {
24292437
return mIndexMax;
24302438
}
24312439

2432-
public HashMap <Integer, Integer> getAllIndexes(boolean lastAudible) {
2440+
// only called by setAllIndexes() which is already synchronized
2441+
public ConcurrentHashMap <Integer, Integer> getAllIndexes(boolean lastAudible) {
24332442
if (lastAudible) {
24342443
return mLastAudibleIndex;
24352444
} else {
24362445
return mIndex;
24372446
}
24382447
}
24392448

2440-
public void setAllIndexes(VolumeStreamState srcStream, boolean lastAudible) {
2441-
HashMap <Integer, Integer> indexes = srcStream.getAllIndexes(lastAudible);
2449+
public synchronized void setAllIndexes(VolumeStreamState srcStream, boolean lastAudible) {
2450+
ConcurrentHashMap <Integer, Integer> indexes = srcStream.getAllIndexes(lastAudible);
24422451
Set set = indexes.entrySet();
24432452
Iterator i = set.iterator();
24442453
while (i.hasNext()) {
@@ -2450,7 +2459,7 @@ public void setAllIndexes(VolumeStreamState srcStream, boolean lastAudible) {
24502459
}
24512460
}
24522461

2453-
public void mute(IBinder cb, boolean state) {
2462+
public synchronized void mute(IBinder cb, boolean state) {
24542463
VolumeDeathHandler handler = getDeathHandler(cb, state);
24552464
if (handler == null) {
24562465
Log.e(TAG, "Could not get client death handler for stream: "+mStreamType);
@@ -2481,25 +2490,68 @@ private class VolumeDeathHandler implements IBinder.DeathRecipient {
24812490
mICallback = cb;
24822491
}
24832492

2493+
// must be called while synchronized on parent VolumeStreamState
24842494
public void mute(boolean state) {
2485-
synchronized(mDeathHandlers) {
2486-
if (state) {
2487-
if (mMuteCount == 0) {
2488-
// Register for client death notification
2489-
try {
2490-
// mICallback can be 0 if muted by AudioService
2491-
if (mICallback != null) {
2492-
mICallback.linkToDeath(this, 0);
2495+
if (state) {
2496+
if (mMuteCount == 0) {
2497+
// Register for client death notification
2498+
try {
2499+
// mICallback can be 0 if muted by AudioService
2500+
if (mICallback != null) {
2501+
mICallback.linkToDeath(this, 0);
2502+
}
2503+
mDeathHandlers.add(this);
2504+
// If the stream is not yet muted by any client, set level to 0
2505+
if (muteCount() == 0) {
2506+
Set set = mIndex.entrySet();
2507+
Iterator i = set.iterator();
2508+
while (i.hasNext()) {
2509+
Map.Entry entry = (Map.Entry)i.next();
2510+
int device = ((Integer)entry.getKey()).intValue();
2511+
setIndex(0, device, false /* lastAudible */);
24932512
}
2494-
mDeathHandlers.add(this);
2495-
// If the stream is not yet muted by any client, set level to 0
2496-
if (muteCount() == 0) {
2513+
sendMsg(mAudioHandler,
2514+
MSG_SET_ALL_VOLUMES,
2515+
SENDMSG_QUEUE,
2516+
0,
2517+
0,
2518+
VolumeStreamState.this, 0);
2519+
}
2520+
} catch (RemoteException e) {
2521+
// Client has died!
2522+
binderDied();
2523+
return;
2524+
}
2525+
} else {
2526+
Log.w(TAG, "stream: "+mStreamType+" was already muted by this client");
2527+
}
2528+
mMuteCount++;
2529+
} else {
2530+
if (mMuteCount == 0) {
2531+
Log.e(TAG, "unexpected unmute for stream: "+mStreamType);
2532+
} else {
2533+
mMuteCount--;
2534+
if (mMuteCount == 0) {
2535+
// Unregister from client death notification
2536+
mDeathHandlers.remove(this);
2537+
// mICallback can be 0 if muted by AudioService
2538+
if (mICallback != null) {
2539+
mICallback.unlinkToDeath(this, 0);
2540+
}
2541+
if (muteCount() == 0) {
2542+
// If the stream is not muted any more, restore its volume if
2543+
// ringer mode allows it
2544+
if (!isStreamAffectedByRingerMode(mStreamType) ||
2545+
mRingerMode == AudioManager.RINGER_MODE_NORMAL) {
24972546
Set set = mIndex.entrySet();
24982547
Iterator i = set.iterator();
24992548
while (i.hasNext()) {
25002549
Map.Entry entry = (Map.Entry)i.next();
25012550
int device = ((Integer)entry.getKey()).intValue();
2502-
setIndex(0, device, false /* lastAudible */);
2551+
setIndex(getIndex(device,
2552+
true /* lastAudible */),
2553+
device,
2554+
false /* lastAudible */);
25032555
}
25042556
sendMsg(mAudioHandler,
25052557
MSG_SET_ALL_VOLUMES,
@@ -2508,55 +2560,9 @@ public void mute(boolean state) {
25082560
0,
25092561
VolumeStreamState.this, 0);
25102562
}
2511-
} catch (RemoteException e) {
2512-
// Client has died!
2513-
binderDied();
2514-
mDeathHandlers.notify();
2515-
return;
2516-
}
2517-
} else {
2518-
Log.w(TAG, "stream: "+mStreamType+" was already muted by this client");
2519-
}
2520-
mMuteCount++;
2521-
} else {
2522-
if (mMuteCount == 0) {
2523-
Log.e(TAG, "unexpected unmute for stream: "+mStreamType);
2524-
} else {
2525-
mMuteCount--;
2526-
if (mMuteCount == 0) {
2527-
// Unregistr from client death notification
2528-
mDeathHandlers.remove(this);
2529-
// mICallback can be 0 if muted by AudioService
2530-
if (mICallback != null) {
2531-
mICallback.unlinkToDeath(this, 0);
2532-
}
2533-
if (muteCount() == 0) {
2534-
// If the stream is not muted any more, restore it's volume if
2535-
// ringer mode allows it
2536-
if (!isStreamAffectedByRingerMode(mStreamType) ||
2537-
mRingerMode == AudioManager.RINGER_MODE_NORMAL) {
2538-
Set set = mIndex.entrySet();
2539-
Iterator i = set.iterator();
2540-
while (i.hasNext()) {
2541-
Map.Entry entry = (Map.Entry)i.next();
2542-
int device = ((Integer)entry.getKey()).intValue();
2543-
setIndex(getIndex(device,
2544-
true /* lastAudible */),
2545-
device,
2546-
false /* lastAudible */);
2547-
}
2548-
sendMsg(mAudioHandler,
2549-
MSG_SET_ALL_VOLUMES,
2550-
SENDMSG_QUEUE,
2551-
0,
2552-
0,
2553-
VolumeStreamState.this, 0);
2554-
}
2555-
}
25562563
}
25572564
}
25582565
}
2559-
mDeathHandlers.notify();
25602566
}
25612567
}
25622568

@@ -2570,7 +2576,7 @@ public void binderDied() {
25702576
}
25712577
}
25722578

2573-
private int muteCount() {
2579+
private synchronized int muteCount() {
25742580
int count = 0;
25752581
int size = mDeathHandlers.size();
25762582
for (int i = 0; i < size; i++) {
@@ -2579,26 +2585,25 @@ private int muteCount() {
25792585
return count;
25802586
}
25812587

2588+
// only called by mute() which is already synchronized
25822589
private VolumeDeathHandler getDeathHandler(IBinder cb, boolean state) {
2583-
synchronized(mDeathHandlers) {
2584-
VolumeDeathHandler handler;
2585-
int size = mDeathHandlers.size();
2586-
for (int i = 0; i < size; i++) {
2587-
handler = mDeathHandlers.get(i);
2588-
if (cb == handler.mICallback) {
2589-
return handler;
2590-
}
2591-
}
2592-
// If this is the first mute request for this client, create a new
2593-
// client death handler. Otherwise, it is an out of sequence unmute request.
2594-
if (state) {
2595-
handler = new VolumeDeathHandler(cb);
2596-
} else {
2597-
Log.w(TAG, "stream was not muted by this client");
2598-
handler = null;
2590+
VolumeDeathHandler handler;
2591+
int size = mDeathHandlers.size();
2592+
for (int i = 0; i < size; i++) {
2593+
handler = mDeathHandlers.get(i);
2594+
if (cb == handler.mICallback) {
2595+
return handler;
25992596
}
2600-
return handler;
26012597
}
2598+
// If this is the first mute request for this client, create a new
2599+
// client death handler. Otherwise, it is an out of sequence unmute request.
2600+
if (state) {
2601+
handler = new VolumeDeathHandler(cb);
2602+
} else {
2603+
Log.w(TAG, "stream was not muted by this client");
2604+
handler = null;
2605+
}
2606+
return handler;
26022607
}
26032608

26042609
private void dump(PrintWriter pw) {

0 commit comments

Comments
 (0)