Remove races in Geocoder/LocationProvider Proxy
The proxy must ensure that enable/disable calls are not reordered when proxied; this change adds synchronization to prevent such reordering that could happen following an onServiceConnected() callback, and to ensure cross-thread visibility of writes. Also, when the package is updated, the old service instance must be unbound and the new one bound. This changes uses a separate Connection object per service instance (package version) to avoid confusing the binder objects. Change-Id: I0907f7eed211b97ccfffa395754f1eb8ea8d8fec
This commit is contained in:
@@ -41,8 +41,8 @@ public class GeocoderProxy {
|
||||
|
||||
private final Context mContext;
|
||||
private final Intent mIntent;
|
||||
private final Connection mServiceConnection = new Connection();
|
||||
private IGeocodeProvider mProvider;
|
||||
private final Object mMutex = new Object(); // synchronizes access to mServiceConnection
|
||||
private Connection mServiceConnection = new Connection(); // never null
|
||||
|
||||
public GeocoderProxy(Context context, String serviceName) {
|
||||
mContext = context;
|
||||
@@ -50,34 +50,48 @@ public class GeocoderProxy {
|
||||
mContext.bindService(mIntent, mServiceConnection, Context.BIND_AUTO_CREATE);
|
||||
}
|
||||
|
||||
/**
|
||||
* When unbundled NetworkLocationService package is updated, we
|
||||
* need to unbind from the old version and re-bind to the new one.
|
||||
*/
|
||||
public void reconnect() {
|
||||
synchronized (mServiceConnection) {
|
||||
synchronized (mMutex) {
|
||||
mContext.unbindService(mServiceConnection);
|
||||
mServiceConnection = new Connection();
|
||||
mContext.bindService(mIntent, mServiceConnection, Context.BIND_AUTO_CREATE);
|
||||
}
|
||||
}
|
||||
|
||||
private class Connection implements ServiceConnection {
|
||||
|
||||
private IGeocodeProvider mProvider;
|
||||
|
||||
public void onServiceConnected(ComponentName className, IBinder service) {
|
||||
Log.d(TAG, "onServiceConnected " + className);
|
||||
synchronized (mServiceConnection) {
|
||||
synchronized (this) {
|
||||
mProvider = IGeocodeProvider.Stub.asInterface(service);
|
||||
}
|
||||
}
|
||||
|
||||
public void onServiceDisconnected(ComponentName className) {
|
||||
Log.d(TAG, "onServiceDisconnected " + className);
|
||||
synchronized (mServiceConnection) {
|
||||
synchronized (this) {
|
||||
mProvider = null;
|
||||
}
|
||||
}
|
||||
|
||||
public IGeocodeProvider getProvider() {
|
||||
synchronized (this) {
|
||||
return mProvider;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String getFromLocation(double latitude, double longitude, int maxResults,
|
||||
GeocoderParams params, List<Address> addrs) {
|
||||
IGeocodeProvider provider;
|
||||
synchronized (mServiceConnection) {
|
||||
provider = mProvider;
|
||||
synchronized (mMutex) {
|
||||
provider = mServiceConnection.getProvider();
|
||||
}
|
||||
if (provider != null) {
|
||||
try {
|
||||
@@ -95,8 +109,8 @@ public class GeocoderProxy {
|
||||
double upperRightLatitude, double upperRightLongitude, int maxResults,
|
||||
GeocoderParams params, List<Address> addrs) {
|
||||
IGeocodeProvider provider;
|
||||
synchronized (mServiceConnection) {
|
||||
provider = mProvider;
|
||||
synchronized (mMutex) {
|
||||
provider = mServiceConnection.getProvider();
|
||||
}
|
||||
if (provider != null) {
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user