diff options
| author | 2012-05-29 15:28:00 -0700 | |
|---|---|---|
| committer | 2012-05-29 15:28:00 -0700 | |
| commit | 82b3b1bce9665a68b32ab0d7393ea63425677f70 (patch) | |
| tree | f1a9ee99ecdea63861d3b77ac4e6bd3ec5c4bca6 | |
| parent | 817a243c3be0920cfc0707c260e51c746bd26e01 (diff) | |
| parent | 00355d5a592533a3ecb0a5a74aef8e69dd16902a (diff) | |
Merge "Make location providers upgradeable." into jb-dev
| -rwxr-xr-x | core/res/res/values/config.xml | 8 | ||||
| -rw-r--r-- | core/res/res/values/public.xml | 4 | ||||
| -rw-r--r-- | services/java/com/android/server/LocationManagerService.java | 133 | ||||
| -rw-r--r-- | services/java/com/android/server/location/GeocoderProxy.java | 25 | ||||
| -rw-r--r-- | services/java/com/android/server/location/LocationProviderProxy.java | 29 |
5 files changed, 142 insertions, 57 deletions
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 98e7769e05a0..09e3fbba7ff9 100755 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -577,11 +577,11 @@ <!-- True if WallpaperService is enabled --> <bool name="config_enableWallpaperService">true</bool> - <!-- Component name of the service providing network location support. --> - <string name="config_networkLocationProvider" translatable="false">@null</string> + <!-- Package name providing network location support. --> + <string name="config_networkLocationProviderPackageName" translatable="false">@null</string> - <!-- Component name of the service providing geocoder API support. --> - <string name="config_geocodeProvider" translatable="false">@null</string> + <!-- Package name providing geocoder API support. --> + <string name="config_geocodeProviderPackageName" translatable="false">@null</string> <!-- Boolean indicating if current platform supports bluetooth SCO for off call use cases --> diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index 5d8ddc9a912c..4cfbff504da6 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -1460,8 +1460,8 @@ <java-symbol type="string" name="car_mode_disable_notification_title" /> <java-symbol type="string" name="chooser_wallpaper" /> <java-symbol type="string" name="config_datause_iface" /> - <java-symbol type="string" name="config_geocodeProvider" /> - <java-symbol type="string" name="config_networkLocationProvider" /> + <java-symbol type="string" name="config_geocodeProviderPackageName" /> + <java-symbol type="string" name="config_networkLocationProviderPackageName" /> <java-symbol type="string" name="config_wimaxManagerClassname" /> <java-symbol type="string" name="config_wimaxNativeLibLocation" /> <java-symbol type="string" name="config_wimaxServiceClassname" /> diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java index 1e707b239421..985249d8d6bc 100644 --- a/services/java/com/android/server/LocationManagerService.java +++ b/services/java/com/android/server/LocationManagerService.java @@ -26,7 +26,11 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.ServiceConnection; +import android.content.pm.PackageInfo; import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.content.pm.PackageManager.NameNotFoundException; +import android.content.pm.Signature; import android.content.res.Resources; import android.database.Cursor; import android.location.Address; @@ -123,8 +127,9 @@ public class LocationManagerService extends ILocationManager.Stub implements Run private static boolean sProvidersLoaded = false; private final Context mContext; - private final String mNetworkLocationProviderPackageName; - private final String mGeocodeProviderPackageName; + private PackageManager mPackageManager; // final after initialize() + private String mNetworkLocationProviderPackageName; // only used on handler thread + private String mGeocodeProviderPackageName; // only used on handler thread private GeocoderProxy mGeocodeProvider; private IGpsStatusProvider mGpsStatusProvider; private INetInitiatedListener mNetInitiatedListener; @@ -490,36 +495,91 @@ public class LocationManagerService extends ILocationManager.Stub implements Run addProvider(passiveProvider); mEnabledProviders.add(passiveProvider.getName()); - // initialize external network location and geocoder services - PackageManager pm = mContext.getPackageManager(); - if (mNetworkLocationProviderPackageName != null && - pm.resolveService(new Intent(mNetworkLocationProviderPackageName), 0) != null) { - mNetworkLocationProvider = - new LocationProviderProxy(mContext, LocationManager.NETWORK_PROVIDER, - mNetworkLocationProviderPackageName, mLocationHandler); - - addProvider(mNetworkLocationProvider); + // initialize external network location and geocoder services. + // The initial value of mNetworkLocationProviderPackageName and + // mGeocodeProviderPackageName is just used to determine what + // signatures future mNetworkLocationProviderPackageName and + // mGeocodeProviderPackageName packages must have. So alternate + // providers can be installed under a different package name + // so long as they have the same signature as the original + // provider packages. + if (mNetworkLocationProviderPackageName != null) { + String packageName = findBestPackage(LocationProviderProxy.SERVICE_ACTION, + mNetworkLocationProviderPackageName); + if (packageName != null) { + mNetworkLocationProvider = new LocationProviderProxy(mContext, + LocationManager.NETWORK_PROVIDER, + packageName, mLocationHandler); + mNetworkLocationProviderPackageName = packageName; + addProvider(mNetworkLocationProvider); + } } - - if (mGeocodeProviderPackageName != null && - pm.resolveService(new Intent(mGeocodeProviderPackageName), 0) != null) { - mGeocodeProvider = new GeocoderProxy(mContext, mGeocodeProviderPackageName); + if (mGeocodeProviderPackageName != null) { + String packageName = findBestPackage(GeocoderProxy.SERVICE_ACTION, + mGeocodeProviderPackageName); + if (packageName != null) { + mGeocodeProvider = new GeocoderProxy(mContext, packageName); + mGeocodeProviderPackageName = packageName; + } } updateProvidersLocked(); } /** + * Pick the best (network location provider or geocode provider) package. + * The best package: + * - implements serviceIntentName + * - has signatures that match that of sigPackageName + * - has the highest version value in a meta-data field in the service component + */ + String findBestPackage(String serviceIntentName, String sigPackageName) { + Intent intent = new Intent(serviceIntentName); + List<ResolveInfo> infos = mPackageManager.queryIntentServices(intent, + PackageManager.GET_META_DATA); + if (infos == null) return null; + + int bestVersion = Integer.MIN_VALUE; + String bestPackage = null; + for (ResolveInfo info : infos) { + String packageName = info.serviceInfo.packageName; + // check signature + if (mPackageManager.checkSignatures(packageName, sigPackageName) != + PackageManager.SIGNATURE_MATCH) { + Slog.w(TAG, packageName + " implements " + serviceIntentName + + " but its signatures don't match those in " + sigPackageName + + ", ignoring"); + continue; + } + // read version + int version = 0; + if (info.serviceInfo.metaData != null) { + version = info.serviceInfo.metaData.getInt("version", 0); + } + if (LOCAL_LOGV) Slog.v(TAG, packageName + " implements " + serviceIntentName + + " with version " + version); + if (version > bestVersion) { + bestVersion = version; + bestPackage = packageName; + } + } + + return bestPackage; + } + + /** * @param context the context that the LocationManagerService runs in */ public LocationManagerService(Context context) { super(); mContext = context; Resources resources = context.getResources(); + mNetworkLocationProviderPackageName = resources.getString( - com.android.internal.R.string.config_networkLocationProvider); + com.android.internal.R.string.config_networkLocationProviderPackageName); mGeocodeProviderPackageName = resources.getString( - com.android.internal.R.string.config_geocodeProvider); + com.android.internal.R.string.config_geocodeProviderPackageName); + mPackageMonitor.register(context, null, true); if (LOCAL_LOGV) { @@ -537,6 +597,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run // Create a wake lock, needs to be done before calling loadProviders() below PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY); + mPackageManager = mContext.getPackageManager(); // Load providers loadProviders(); @@ -1886,16 +1947,33 @@ public class LocationManagerService extends ILocationManager.Stub implements Run } } else if (msg.what == MESSAGE_PACKAGE_UPDATED) { String packageName = (String) msg.obj; - String packageDot = packageName + "."; - // reconnect to external providers after their packages have been updated - if (mNetworkLocationProvider != null && - mNetworkLocationProviderPackageName.startsWith(packageDot)) { - mNetworkLocationProvider.reconnect(); + // reconnect to external providers if there is a better package + if (mNetworkLocationProviderPackageName != null && + mPackageManager.resolveService( + new Intent(LocationProviderProxy.SERVICE_ACTION) + .setPackage(packageName), 0) != null) { + // package implements service, perform full check + String bestPackage = findBestPackage( + LocationProviderProxy.SERVICE_ACTION, + mNetworkLocationProviderPackageName); + if (packageName.equals(bestPackage)) { + mNetworkLocationProvider.reconnect(bestPackage); + mNetworkLocationProviderPackageName = packageName; + } } - if (mGeocodeProvider != null && - mGeocodeProviderPackageName.startsWith(packageDot)) { - mGeocodeProvider.reconnect(); + if (mGeocodeProviderPackageName != null && + mPackageManager.resolveService( + new Intent(GeocoderProxy.SERVICE_ACTION) + .setPackage(packageName), 0) != null) { + // package implements service, perform full check + String bestPackage = findBestPackage( + GeocoderProxy.SERVICE_ACTION, + mGeocodeProviderPackageName); + if (packageName.equals(bestPackage)) { + mGeocodeProvider.reconnect(bestPackage); + mGeocodeProviderPackageName = packageName; + } } } } catch (Exception e) { @@ -2004,6 +2082,11 @@ public class LocationManagerService extends ILocationManager.Stub implements Run // Called by main thread; divert work to LocationWorker. Message.obtain(mLocationHandler, MESSAGE_PACKAGE_UPDATED, packageName).sendToTarget(); } + @Override + public void onPackageAdded(String packageName, int uid) { + // Called by main thread; divert work to LocationWorker. + Message.obtain(mLocationHandler, MESSAGE_PACKAGE_UPDATED, packageName).sendToTarget(); + } }; // Wake locks diff --git a/services/java/com/android/server/location/GeocoderProxy.java b/services/java/com/android/server/location/GeocoderProxy.java index b38ea13d5946..07f3125977a5 100644 --- a/services/java/com/android/server/location/GeocoderProxy.java +++ b/services/java/com/android/server/location/GeocoderProxy.java @@ -39,27 +39,28 @@ public class GeocoderProxy { private static final String TAG = "GeocoderProxy"; + public static final String SERVICE_ACTION = + "com.android.location.service.GeocodeProvider"; + private final Context mContext; private final Intent mIntent; private final Object mMutex = new Object(); // synchronizes access to mServiceConnection - private Connection mServiceConnection = new Connection(); // never null + private Connection mServiceConnection; // never null after ctor - public GeocoderProxy(Context context, String serviceName) { + public GeocoderProxy(Context context, String packageName) { mContext = context; - mIntent = new Intent(serviceName); - mContext.bindService(mIntent, mServiceConnection, - Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND - | Context.BIND_ALLOW_OOM_MANAGEMENT); + mIntent = new Intent(SERVICE_ACTION); + reconnect(packageName); } - /** - * When unbundled NetworkLocationService package is updated, we - * need to unbind from the old version and re-bind to the new one. - */ - public void reconnect() { + /** Bind to service. Will reconnect if already connected */ + public void reconnect(String packageName) { synchronized (mMutex) { - mContext.unbindService(mServiceConnection); + if (mServiceConnection != null) { + mContext.unbindService(mServiceConnection); + } mServiceConnection = new Connection(); + mIntent.setPackage(packageName); mContext.bindService(mIntent, mServiceConnection, Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND | Context.BIND_ALLOW_OOM_MANAGEMENT); diff --git a/services/java/com/android/server/location/LocationProviderProxy.java b/services/java/com/android/server/location/LocationProviderProxy.java index 0bc166465bfa..a227ab66bfbc 100644 --- a/services/java/com/android/server/location/LocationProviderProxy.java +++ b/services/java/com/android/server/location/LocationProviderProxy.java @@ -42,12 +42,15 @@ public class LocationProviderProxy implements LocationProviderInterface { private static final String TAG = "LocationProviderProxy"; + public static final String SERVICE_ACTION = + "com.android.location.service.NetworkLocationProvider"; + private final Context mContext; private final String mName; private final Intent mIntent; private final Handler mHandler; private final Object mMutex = new Object(); // synchronizes access to non-final members - private Connection mServiceConnection = new Connection(); // never null + private Connection mServiceConnection; // never null after ctor // cached values set by the location manager private boolean mLocationTracking = false; @@ -58,28 +61,26 @@ public class LocationProviderProxy implements LocationProviderInterface { private NetworkInfo mNetworkInfo; // constructor for proxying location providers implemented in a separate service - public LocationProviderProxy(Context context, String name, String serviceName, + public LocationProviderProxy(Context context, String name, String packageName, Handler handler) { mContext = context; mName = name; - mIntent = new Intent(serviceName); + mIntent = new Intent(SERVICE_ACTION); mHandler = handler; - mContext.bindService(mIntent, mServiceConnection, - Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND - | Context.BIND_ALLOW_OOM_MANAGEMENT); + reconnect(packageName); } - /** - * When unbundled NetworkLocationService package is updated, we - * need to unbind from the old version and re-bind to the new one. - */ - public void reconnect() { + /** Bind to service. Will reconnect if already connected */ + public void reconnect(String packageName) { synchronized (mMutex) { - mContext.unbindService(mServiceConnection); + if (mServiceConnection != null) { + mContext.unbindService(mServiceConnection); + } mServiceConnection = new Connection(); + mIntent.setPackage(packageName); mContext.bindService(mIntent, mServiceConnection, - Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND - | Context.BIND_ALLOW_OOM_MANAGEMENT); + Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND | + Context.BIND_ALLOW_OOM_MANAGEMENT); } } |