location: rebind to network location and geocoder services after package update

Change-Id: I2d7db3512b9edd7e0ba27d97442967fc2278e3b9
Signed-off-by: Mike Lockwood <lockwood@android.com>
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index 643b2f5..361cd3b 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -58,6 +58,7 @@
 import android.util.Slog;
 import android.util.PrintWriterPrinter;
 
+import com.android.internal.content.PackageMonitor;
 import com.android.internal.location.GpsNetInitiatedHandler;
 
 import com.android.server.location.GeocoderProxy;
@@ -116,13 +117,15 @@
     private static boolean sProvidersLoaded = false;
 
     private final Context mContext;
+    private final String mNetworkLocationProviderPackageName;
+    private final String mGeocodeProviderPackageName;
     private GeocoderProxy mGeocodeProvider;
     private IGpsStatusProvider mGpsStatusProvider;
     private INetInitiatedListener mNetInitiatedListener;
     private LocationWorkerHandler mLocationHandler;
 
     // Cache the real providers for use in addTestProvider() and removeTestProvider()
-     LocationProviderInterface mNetworkLocationProvider;
+     LocationProviderProxy mNetworkLocationProvider;
      LocationProviderInterface mGpsLocationProvider;
 
     // Handler messages
@@ -472,19 +475,15 @@
         mEnabledProviders.add(passiveProvider.getName());
 
         // initialize external network location and geocoder services
-        Resources resources = mContext.getResources();
-        String serviceName = resources.getString(
-                com.android.internal.R.string.config_networkLocationProvider);
-        if (serviceName != null) {
+        if (mNetworkLocationProviderPackageName != null) {
             mNetworkLocationProvider =
                 new LocationProviderProxy(mContext, LocationManager.NETWORK_PROVIDER,
-                        serviceName, mLocationHandler);
+                        mNetworkLocationProviderPackageName, mLocationHandler);
             addProvider(mNetworkLocationProvider);
         }
 
-        serviceName = resources.getString(com.android.internal.R.string.config_geocodeProvider);
-        if (serviceName != null) {
-            mGeocodeProvider = new GeocoderProxy(mContext, serviceName);
+        if (mGeocodeProviderPackageName != null) {
+            mGeocodeProvider = new GeocoderProxy(mContext, mGeocodeProviderPackageName);
         }
 
         updateProvidersLocked();
@@ -496,6 +495,12 @@
     public LocationManagerService(Context context) {
         super();
         mContext = context;
+        Resources resources = context.getResources();
+        mNetworkLocationProviderPackageName = resources.getString(
+                com.android.internal.R.string.config_networkLocationProvider);
+        mGeocodeProviderPackageName = resources.getString(
+                com.android.internal.R.string.config_geocodeProvider);
+        mPackageMonitor.register(context, true);
 
         if (LOCAL_LOGV) {
             Slog.v(TAG, "Constructed LocationManager Service");
@@ -1920,6 +1925,23 @@
         }
     };
 
+    private final PackageMonitor mPackageMonitor = new PackageMonitor() {
+        @Override
+        public void onPackageUpdateFinished(String packageName, int uid) {
+            String packageDot = packageName + ".";
+
+            // reconnect to external providers after their packages have been updated
+            if (mNetworkLocationProvider != null &&
+                    mNetworkLocationProviderPackageName.startsWith(packageDot)) {
+                mNetworkLocationProvider.reconnect();
+            }
+            if (mGeocodeProvider != null &&
+                    mGeocodeProviderPackageName.startsWith(packageDot)) {
+                mGeocodeProvider.reconnect();
+            }
+        }
+    };
+
     // Wake locks
 
     private void incrementPendingBroadcasts() {
diff --git a/services/java/com/android/server/location/GeocoderProxy.java b/services/java/com/android/server/location/GeocoderProxy.java
index 3c05da2..d9b49fd 100644
--- a/services/java/com/android/server/location/GeocoderProxy.java
+++ b/services/java/com/android/server/location/GeocoderProxy.java
@@ -50,17 +50,24 @@
         mContext.bindService(mIntent, mServiceConnection, Context.BIND_AUTO_CREATE);
     }
 
+    public void reconnect() {
+        synchronized (mServiceConnection) {
+            mContext.unbindService(mServiceConnection);
+            mContext.bindService(mIntent, mServiceConnection, Context.BIND_AUTO_CREATE);
+        }
+    }
+
     private class Connection implements ServiceConnection {
         public void onServiceConnected(ComponentName className, IBinder service) {
             Log.d(TAG, "onServiceConnected " + className);
-            synchronized (this) {
+            synchronized (mServiceConnection) {
                 mProvider = IGeocodeProvider.Stub.asInterface(service);
             }
         }
 
         public void onServiceDisconnected(ComponentName className) {
             Log.d(TAG, "onServiceDisconnected " + className);
-            synchronized (this) {
+            synchronized (mServiceConnection) {
                 mProvider = null;
             }
         }
diff --git a/services/java/com/android/server/location/LocationProviderProxy.java b/services/java/com/android/server/location/LocationProviderProxy.java
index 7dc9920..ef2056b 100644
--- a/services/java/com/android/server/location/LocationProviderProxy.java
+++ b/services/java/com/android/server/location/LocationProviderProxy.java
@@ -45,6 +45,7 @@
 
     private final Context mContext;
     private final String mName;
+    private final String mServiceName;
     private ILocationProvider mProvider;
     private Handler mHandler;
     private final Connection mServiceConnection = new Connection();
@@ -65,14 +66,24 @@
             Handler handler) {
         mContext = context;
         mName = name;
+        mServiceName = serviceName;
         mHandler = handler;
         mContext.bindService(new Intent(serviceName), mServiceConnection, Context.BIND_AUTO_CREATE);
     }
 
+    public void reconnect() {
+        synchronized (mServiceConnection) {
+            // unbind first
+            mContext.unbindService(mServiceConnection);
+            mContext.bindService(new Intent(mServiceName), mServiceConnection,
+                Context.BIND_AUTO_CREATE);
+        }
+    }
+
     private class Connection implements ServiceConnection {
         public void onServiceConnected(ComponentName className, IBinder service) {
             Log.d(TAG, "LocationProviderProxy.onServiceConnected " + className);
-            synchronized (this) {
+            synchronized (mServiceConnection) {
                 mProvider = ILocationProvider.Stub.asInterface(service);
                 if (mProvider != null) {
                     mHandler.post(mServiceConnectedTask);
@@ -82,7 +93,7 @@
 
         public void onServiceDisconnected(ComponentName className) {
             Log.d(TAG, "LocationProviderProxy.onServiceDisconnected " + className);
-            synchronized (this) {
+            synchronized (mServiceConnection) {
                 mProvider = null;
             }
         }