Skip to content

Commit

Permalink
Merge pull request #123 from furkanvarol/fix_consumer_concurrency
Browse files Browse the repository at this point in the history
fix concurrency exception when multiple consumer bound on start
  • Loading branch information
davidgyoung committed Mar 5, 2015
2 parents d7dc78f + 11b498f commit 4e9cab9
Showing 1 changed file with 34 additions and 30 deletions.
64 changes: 34 additions & 30 deletions src/main/java/org/altbeacon/beacon/BeaconManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,21 +23,6 @@
*/
package org.altbeacon.beacon;

import java.security.acl.LastOwnerException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.altbeacon.beacon.logging.LogManager;
import org.altbeacon.beacon.logging.Loggers;
import org.altbeacon.beacon.service.BeaconService;
import org.altbeacon.beacon.simulator.BeaconSimulator;
import org.altbeacon.beacon.service.StartRMData;

import android.annotation.TargetApi;
import android.bluetooth.BluetoothManager;
import android.content.ComponentName;
Expand All @@ -50,6 +35,22 @@
import android.os.Messenger;
import android.os.RemoteException;

import org.altbeacon.beacon.logging.LogManager;
import org.altbeacon.beacon.logging.Loggers;
import org.altbeacon.beacon.service.BeaconService;
import org.altbeacon.beacon.service.StartRMData;
import org.altbeacon.beacon.simulator.BeaconSimulator;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
* An class used to set up interaction with beacons from an <code>Activity</code> or <code>Service</code>.
* This class is used in conjunction with <code>BeaconConsumer</code> interface, which provides a callback
Expand Down Expand Up @@ -100,7 +101,7 @@ public class BeaconManager {
private static final String TAG = "BeaconManager";
private Context mContext;
protected static BeaconManager client = null;
private final Map<BeaconConsumer, ConsumerInfo> consumers = new HashMap<BeaconConsumer,ConsumerInfo>();
private final ConcurrentMap<BeaconConsumer, ConsumerInfo> consumers = new ConcurrentHashMap<BeaconConsumer,ConsumerInfo>();
private Messenger serviceMessenger = null;
protected RangeNotifier rangeNotifier = null;
protected RangeNotifier dataRequestNotifier = null;
Expand Down Expand Up @@ -269,12 +270,12 @@ public void bind(BeaconConsumer consumer) {
return;
}
synchronized (consumers) {
if (consumers.keySet().contains(consumer)) {
ConsumerInfo consumerInfo = consumers.putIfAbsent(consumer, new ConsumerInfo());
if (consumerInfo != null) {
LogManager.d(TAG, "This consumer is already bound");
}
else {
LogManager.d(TAG, "This consumer is not bound. binding: %s", consumer);
consumers.put(consumer, new ConsumerInfo());
Intent intent = new Intent(consumer.getApplicationContext(), BeaconService.class);
consumer.bindService(intent, beaconServiceConnection, Context.BIND_AUTO_CREATE);
LogManager.d(TAG, "consumer count is now: %s", consumers.size());
Expand All @@ -294,7 +295,7 @@ public void unbind(BeaconConsumer consumer) {
return;
}
synchronized (consumers) {
if (consumers.keySet().contains(consumer)) {
if (consumers.containsKey(consumer)) {
LogManager.d(TAG, "Unbinding");
consumer.unbindService(beaconServiceConnection);
consumers.remove(consumer);
Expand All @@ -309,7 +310,7 @@ public void unbind(BeaconConsumer consumer) {
LogManager.d(TAG, "Bound consumers: ");
Set<Map.Entry<BeaconConsumer, ConsumerInfo>> consumers = this.consumers.entrySet();
for (Map.Entry<BeaconConsumer, ConsumerInfo> consumerEntry : consumers) {
LogManager.i(TAG, String.valueOf(consumerEntry.getValue()));
LogManager.d(TAG, String.valueOf(consumerEntry.getValue()));
}
}
}
Expand All @@ -323,7 +324,7 @@ public void unbind(BeaconConsumer consumer) {
*/
public boolean isBound(BeaconConsumer consumer) {
synchronized(consumers) {
return consumers.get(consumer) != null && (serviceMessenger != null);
return consumer != null && consumers.get(consumer) != null && (serviceMessenger != null);
}
}

Expand All @@ -333,7 +334,9 @@ public boolean isBound(BeaconConsumer consumer) {
* @return
*/
public boolean isAnyConsumerBound() {
return consumers.size() > 0 && (serviceMessenger != null);
synchronized(consumers) {
return consumers.size() > 0 && (serviceMessenger != null);
}
}

/**
Expand Down Expand Up @@ -569,17 +572,18 @@ private String callbackPackageName() {
}

private ServiceConnection beaconServiceConnection = new ServiceConnection() {
// Called when the connection with the service is established
public void onServiceConnected(ComponentName className, IBinder service) {
// Called when the connection with the service is established
public void onServiceConnected(ComponentName className, IBinder service) {
LogManager.d(TAG, "we have a connection to the service now");
serviceMessenger = new Messenger(service);
synchronized(consumers) {
for (BeaconConsumer consumer : consumers.keySet()) {
Boolean alreadyConnected = consumers.get(consumer).isConnected;
if (!alreadyConnected) {
consumer.onBeaconServiceConnect();
ConsumerInfo consumerInfo = consumers.get(consumer);
consumerInfo.isConnected = true;
Iterator<Map.Entry<BeaconConsumer, ConsumerInfo>> iter = consumers.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry<BeaconConsumer, ConsumerInfo> entry = iter.next();

if (!entry.getValue().isConnected) {
entry.getKey().onBeaconServiceConnect();
entry.getValue().isConnected = true;
}
}
}
Expand Down

0 comments on commit 4e9cab9

Please sign in to comment.