2626import android .content .Intent ;
2727import android .content .IntentFilter ;
2828import android .content .ServiceConnection ;
29+ import android .content .pm .PackageInfo ;
2930import android .content .pm .PackageManager ;
31+ import android .content .pm .ResolveInfo ;
32+ import android .content .pm .PackageManager .NameNotFoundException ;
33+ import android .content .pm .Signature ;
3034import android .content .res .Resources ;
3135import android .database .Cursor ;
3236import android .location .Address ;
@@ -123,8 +127,9 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
123127 private static boolean sProvidersLoaded = false ;
124128
125129 private final Context mContext ;
126- private final String mNetworkLocationProviderPackageName ;
127- private final String mGeocodeProviderPackageName ;
130+ private PackageManager mPackageManager ; // final after initialize()
131+ private String mNetworkLocationProviderPackageName ; // only used on handler thread
132+ private String mGeocodeProviderPackageName ; // only used on handler thread
128133 private GeocoderProxy mGeocodeProvider ;
129134 private IGpsStatusProvider mGpsStatusProvider ;
130135 private INetInitiatedListener mNetInitiatedListener ;
@@ -490,36 +495,91 @@ private void _loadProvidersLocked() {
490495 addProvider (passiveProvider );
491496 mEnabledProviders .add (passiveProvider .getName ());
492497
493- // initialize external network location and geocoder services
494- PackageManager pm = mContext .getPackageManager ();
495- if (mNetworkLocationProviderPackageName != null &&
496- pm .resolveService (new Intent (mNetworkLocationProviderPackageName ), 0 ) != null ) {
497- mNetworkLocationProvider =
498- new LocationProviderProxy (mContext , LocationManager .NETWORK_PROVIDER ,
499- mNetworkLocationProviderPackageName , mLocationHandler );
500-
501- addProvider (mNetworkLocationProvider );
498+ // initialize external network location and geocoder services.
499+ // The initial value of mNetworkLocationProviderPackageName and
500+ // mGeocodeProviderPackageName is just used to determine what
501+ // signatures future mNetworkLocationProviderPackageName and
502+ // mGeocodeProviderPackageName packages must have. So alternate
503+ // providers can be installed under a different package name
504+ // so long as they have the same signature as the original
505+ // provider packages.
506+ if (mNetworkLocationProviderPackageName != null ) {
507+ String packageName = findBestPackage (LocationProviderProxy .SERVICE_ACTION ,
508+ mNetworkLocationProviderPackageName );
509+ if (packageName != null ) {
510+ mNetworkLocationProvider = new LocationProviderProxy (mContext ,
511+ LocationManager .NETWORK_PROVIDER ,
512+ packageName , mLocationHandler );
513+ mNetworkLocationProviderPackageName = packageName ;
514+ addProvider (mNetworkLocationProvider );
515+ }
502516 }
503-
504- if (mGeocodeProviderPackageName != null &&
505- pm .resolveService (new Intent (mGeocodeProviderPackageName ), 0 ) != null ) {
506- mGeocodeProvider = new GeocoderProxy (mContext , mGeocodeProviderPackageName );
517+ if (mGeocodeProviderPackageName != null ) {
518+ String packageName = findBestPackage (GeocoderProxy .SERVICE_ACTION ,
519+ mGeocodeProviderPackageName );
520+ if (packageName != null ) {
521+ mGeocodeProvider = new GeocoderProxy (mContext , packageName );
522+ mGeocodeProviderPackageName = packageName ;
523+ }
507524 }
508525
509526 updateProvidersLocked ();
510527 }
511528
529+ /**
530+ * Pick the best (network location provider or geocode provider) package.
531+ * The best package:
532+ * - implements serviceIntentName
533+ * - has signatures that match that of sigPackageName
534+ * - has the highest version value in a meta-data field in the service component
535+ */
536+ String findBestPackage (String serviceIntentName , String sigPackageName ) {
537+ Intent intent = new Intent (serviceIntentName );
538+ List <ResolveInfo > infos = mPackageManager .queryIntentServices (intent ,
539+ PackageManager .GET_META_DATA );
540+ if (infos == null ) return null ;
541+
542+ int bestVersion = Integer .MIN_VALUE ;
543+ String bestPackage = null ;
544+ for (ResolveInfo info : infos ) {
545+ String packageName = info .serviceInfo .packageName ;
546+ // check signature
547+ if (mPackageManager .checkSignatures (packageName , sigPackageName ) !=
548+ PackageManager .SIGNATURE_MATCH ) {
549+ Slog .w (TAG , packageName + " implements " + serviceIntentName +
550+ " but its signatures don't match those in " + sigPackageName +
551+ ", ignoring" );
552+ continue ;
553+ }
554+ // read version
555+ int version = 0 ;
556+ if (info .serviceInfo .metaData != null ) {
557+ version = info .serviceInfo .metaData .getInt ("version" , 0 );
558+ }
559+ if (LOCAL_LOGV ) Slog .v (TAG , packageName + " implements " + serviceIntentName +
560+ " with version " + version );
561+ if (version > bestVersion ) {
562+ bestVersion = version ;
563+ bestPackage = packageName ;
564+ }
565+ }
566+
567+ return bestPackage ;
568+ }
569+
512570 /**
513571 * @param context the context that the LocationManagerService runs in
514572 */
515573 public LocationManagerService (Context context ) {
516574 super ();
517575 mContext = context ;
518576 Resources resources = context .getResources ();
577+
519578 mNetworkLocationProviderPackageName = resources .getString (
520- com .android .internal .R .string .config_networkLocationProvider );
579+ com .android .internal .R .string .config_networkLocationProviderPackageName );
521580 mGeocodeProviderPackageName = resources .getString (
522- com .android .internal .R .string .config_geocodeProvider );
581+ com .android .internal .R .string .config_geocodeProviderPackageName );
582+
523583 mPackageMonitor .register (context , null , true );
524584
525585 if (LOCAL_LOGV ) {
@@ -537,6 +597,7 @@ private void initialize() {
537597 // Create a wake lock, needs to be done before calling loadProviders() below
538598 PowerManager powerManager = (PowerManager ) mContext .getSystemService (Context .POWER_SERVICE );
539599 mWakeLock = powerManager .newWakeLock (PowerManager .PARTIAL_WAKE_LOCK , WAKELOCK_KEY );
600+ mPackageManager = mContext .getPackageManager ();
540601
541602 // Load providers
542603 loadProviders ();
@@ -1886,16 +1947,33 @@ public void handleMessage(Message msg) {
18861947 }
18871948 } else if (msg .what == MESSAGE_PACKAGE_UPDATED ) {
18881949 String packageName = (String ) msg .obj ;
1889- String packageDot = packageName + "." ;
18901950
1891- // reconnect to external providers after their packages have been updated
1892- if (mNetworkLocationProvider != null &&
1893- mNetworkLocationProviderPackageName .startsWith (packageDot )) {
1894- mNetworkLocationProvider .reconnect ();
1951+ // reconnect to external providers if there is a better package
1952+ if (mNetworkLocationProviderPackageName != null &&
1953+ mPackageManager .resolveService (
1954+ new Intent (LocationProviderProxy .SERVICE_ACTION )
1955+ .setPackage (packageName ), 0 ) != null ) {
1956+ // package implements service, perform full check
1957+ String bestPackage = findBestPackage (
1958+ LocationProviderProxy .SERVICE_ACTION ,
1959+ mNetworkLocationProviderPackageName );
1960+ if (packageName .equals (bestPackage )) {
1961+ mNetworkLocationProvider .reconnect (bestPackage );
1962+ mNetworkLocationProviderPackageName = packageName ;
1963+ }
18951964 }
1896- if (mGeocodeProvider != null &&
1897- mGeocodeProviderPackageName .startsWith (packageDot )) {
1898- mGeocodeProvider .reconnect ();
1965+ if (mGeocodeProviderPackageName != null &&
1966+ mPackageManager .resolveService (
1967+ new Intent (GeocoderProxy .SERVICE_ACTION )
1968+ .setPackage (packageName ), 0 ) != null ) {
1969+ // package implements service, perform full check
1970+ String bestPackage = findBestPackage (
1971+ GeocoderProxy .SERVICE_ACTION ,
1972+ mGeocodeProviderPackageName );
1973+ if (packageName .equals (bestPackage )) {
1974+ mGeocodeProvider .reconnect (bestPackage );
1975+ mGeocodeProviderPackageName = packageName ;
1976+ }
18991977 }
19001978 }
19011979 } catch (Exception e ) {
@@ -2004,6 +2082,11 @@ public void onPackageUpdateFinished(String packageName, int uid) {
20042082 // Called by main thread; divert work to LocationWorker.
20052083 Message .obtain (mLocationHandler , MESSAGE_PACKAGE_UPDATED , packageName ).sendToTarget ();
20062084 }
2085+ @ Override
2086+ public void onPackageAdded (String packageName , int uid ) {
2087+ // Called by main thread; divert work to LocationWorker.
2088+ Message .obtain (mLocationHandler , MESSAGE_PACKAGE_UPDATED , packageName ).sendToTarget ();
2089+ }
20072090 };
20082091
20092092 // Wake locks
0 commit comments