Skip to content

Commit 82b3b1b

Browse files
Nick PellyAndroid (Google) Code Review
authored andcommitted
Merge "Make location providers upgradeable." into jb-dev
2 parents 817a243 + 00355d5 commit 82b3b1b

File tree

5 files changed

+142
-57
lines changed

5 files changed

+142
-57
lines changed

core/res/res/values/config.xml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -577,11 +577,11 @@
577577
<!-- True if WallpaperService is enabled -->
578578
<bool name="config_enableWallpaperService">true</bool>
579579

580-
<!-- Component name of the service providing network location support. -->
581-
<string name="config_networkLocationProvider" translatable="false">@null</string>
580+
<!-- Package name providing network location support. -->
581+
<string name="config_networkLocationProviderPackageName" translatable="false">@null</string>
582582

583-
<!-- Component name of the service providing geocoder API support. -->
584-
<string name="config_geocodeProvider" translatable="false">@null</string>
583+
<!-- Package name providing geocoder API support. -->
584+
<string name="config_geocodeProviderPackageName" translatable="false">@null</string>
585585

586586
<!-- Boolean indicating if current platform supports bluetooth SCO for off call
587587
use cases -->

core/res/res/values/public.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1460,8 +1460,8 @@
14601460
<java-symbol type="string" name="car_mode_disable_notification_title" />
14611461
<java-symbol type="string" name="chooser_wallpaper" />
14621462
<java-symbol type="string" name="config_datause_iface" />
1463-
<java-symbol type="string" name="config_geocodeProvider" />
1464-
<java-symbol type="string" name="config_networkLocationProvider" />
1463+
<java-symbol type="string" name="config_geocodeProviderPackageName" />
1464+
<java-symbol type="string" name="config_networkLocationProviderPackageName" />
14651465
<java-symbol type="string" name="config_wimaxManagerClassname" />
14661466
<java-symbol type="string" name="config_wimaxNativeLibLocation" />
14671467
<java-symbol type="string" name="config_wimaxServiceClassname" />

services/java/com/android/server/LocationManagerService.java

Lines changed: 108 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,11 @@
2626
import android.content.Intent;
2727
import android.content.IntentFilter;
2828
import android.content.ServiceConnection;
29+
import android.content.pm.PackageInfo;
2930
import android.content.pm.PackageManager;
31+
import android.content.pm.ResolveInfo;
32+
import android.content.pm.PackageManager.NameNotFoundException;
33+
import android.content.pm.Signature;
3034
import android.content.res.Resources;
3135
import android.database.Cursor;
3236
import 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

services/java/com/android/server/location/GeocoderProxy.java

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -39,27 +39,28 @@ public class GeocoderProxy {
3939

4040
private static final String TAG = "GeocoderProxy";
4141

42+
public static final String SERVICE_ACTION =
43+
"com.android.location.service.GeocodeProvider";
44+
4245
private final Context mContext;
4346
private final Intent mIntent;
4447
private final Object mMutex = new Object(); // synchronizes access to mServiceConnection
45-
private Connection mServiceConnection = new Connection(); // never null
48+
private Connection mServiceConnection; // never null after ctor
4649

47-
public GeocoderProxy(Context context, String serviceName) {
50+
public GeocoderProxy(Context context, String packageName) {
4851
mContext = context;
49-
mIntent = new Intent(serviceName);
50-
mContext.bindService(mIntent, mServiceConnection,
51-
Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND
52-
| Context.BIND_ALLOW_OOM_MANAGEMENT);
52+
mIntent = new Intent(SERVICE_ACTION);
53+
reconnect(packageName);
5354
}
5455

55-
/**
56-
* When unbundled NetworkLocationService package is updated, we
57-
* need to unbind from the old version and re-bind to the new one.
58-
*/
59-
public void reconnect() {
56+
/** Bind to service. Will reconnect if already connected */
57+
public void reconnect(String packageName) {
6058
synchronized (mMutex) {
61-
mContext.unbindService(mServiceConnection);
59+
if (mServiceConnection != null) {
60+
mContext.unbindService(mServiceConnection);
61+
}
6262
mServiceConnection = new Connection();
63+
mIntent.setPackage(packageName);
6364
mContext.bindService(mIntent, mServiceConnection,
6465
Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND
6566
| Context.BIND_ALLOW_OOM_MANAGEMENT);

services/java/com/android/server/location/LocationProviderProxy.java

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,15 @@ public class LocationProviderProxy implements LocationProviderInterface {
4242

4343
private static final String TAG = "LocationProviderProxy";
4444

45+
public static final String SERVICE_ACTION =
46+
"com.android.location.service.NetworkLocationProvider";
47+
4548
private final Context mContext;
4649
private final String mName;
4750
private final Intent mIntent;
4851
private final Handler mHandler;
4952
private final Object mMutex = new Object(); // synchronizes access to non-final members
50-
private Connection mServiceConnection = new Connection(); // never null
53+
private Connection mServiceConnection; // never null after ctor
5154

5255
// cached values set by the location manager
5356
private boolean mLocationTracking = false;
@@ -58,28 +61,26 @@ public class LocationProviderProxy implements LocationProviderInterface {
5861
private NetworkInfo mNetworkInfo;
5962

6063
// constructor for proxying location providers implemented in a separate service
61-
public LocationProviderProxy(Context context, String name, String serviceName,
64+
public LocationProviderProxy(Context context, String name, String packageName,
6265
Handler handler) {
6366
mContext = context;
6467
mName = name;
65-
mIntent = new Intent(serviceName);
68+
mIntent = new Intent(SERVICE_ACTION);
6669
mHandler = handler;
67-
mContext.bindService(mIntent, mServiceConnection,
68-
Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND
69-
| Context.BIND_ALLOW_OOM_MANAGEMENT);
70+
reconnect(packageName);
7071
}
7172

72-
/**
73-
* When unbundled NetworkLocationService package is updated, we
74-
* need to unbind from the old version and re-bind to the new one.
75-
*/
76-
public void reconnect() {
73+
/** Bind to service. Will reconnect if already connected */
74+
public void reconnect(String packageName) {
7775
synchronized (mMutex) {
78-
mContext.unbindService(mServiceConnection);
76+
if (mServiceConnection != null) {
77+
mContext.unbindService(mServiceConnection);
78+
}
7979
mServiceConnection = new Connection();
80+
mIntent.setPackage(packageName);
8081
mContext.bindService(mIntent, mServiceConnection,
81-
Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND
82-
| Context.BIND_ALLOW_OOM_MANAGEMENT);
82+
Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND |
83+
Context.BIND_ALLOW_OOM_MANAGEMENT);
8384
}
8485
}
8586

0 commit comments

Comments
 (0)