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:
Mark Vandevoorde
2010-10-04 14:23:24 -07:00
parent b9a40068b5
commit 8863c43d9e
3 changed files with 252 additions and 200 deletions

View File

@@ -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 {