am 82b3b1bc: Merge "Make location providers upgradeable." into jb-dev

* commit '82b3b1bce9665a68b32ab0d7393ea63425677f70':
  Make location providers upgradeable.
This commit is contained in:
Nick Pelly
2012-05-29 15:30:01 -07:00
committed by Android Git Automerger
5 changed files with 142 additions and 57 deletions

View File

@@ -577,11 +577,11 @@
<!-- True if WallpaperService is enabled --> <!-- True if WallpaperService is enabled -->
<bool name="config_enableWallpaperService">true</bool> <bool name="config_enableWallpaperService">true</bool>
<!-- Component name of the service providing network location support. --> <!-- Package name providing network location support. -->
<string name="config_networkLocationProvider" translatable="false">@null</string> <string name="config_networkLocationProviderPackageName" translatable="false">@null</string>
<!-- Component name of the service providing geocoder API support. --> <!-- Package name providing geocoder API support. -->
<string name="config_geocodeProvider" translatable="false">@null</string> <string name="config_geocodeProviderPackageName" translatable="false">@null</string>
<!-- Boolean indicating if current platform supports bluetooth SCO for off call <!-- Boolean indicating if current platform supports bluetooth SCO for off call
use cases --> use cases -->

View File

@@ -1460,8 +1460,8 @@
<java-symbol type="string" name="car_mode_disable_notification_title" /> <java-symbol type="string" name="car_mode_disable_notification_title" />
<java-symbol type="string" name="chooser_wallpaper" /> <java-symbol type="string" name="chooser_wallpaper" />
<java-symbol type="string" name="config_datause_iface" /> <java-symbol type="string" name="config_datause_iface" />
<java-symbol type="string" name="config_geocodeProvider" /> <java-symbol type="string" name="config_geocodeProviderPackageName" />
<java-symbol type="string" name="config_networkLocationProvider" /> <java-symbol type="string" name="config_networkLocationProviderPackageName" />
<java-symbol type="string" name="config_wimaxManagerClassname" /> <java-symbol type="string" name="config_wimaxManagerClassname" />
<java-symbol type="string" name="config_wimaxNativeLibLocation" /> <java-symbol type="string" name="config_wimaxNativeLibLocation" />
<java-symbol type="string" name="config_wimaxServiceClassname" /> <java-symbol type="string" name="config_wimaxServiceClassname" />

View File

@@ -26,7 +26,11 @@ import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.IntentFilter; import android.content.IntentFilter;
import android.content.ServiceConnection; import android.content.ServiceConnection;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager; 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.content.res.Resources;
import android.database.Cursor; import android.database.Cursor;
import android.location.Address; import android.location.Address;
@@ -123,8 +127,9 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
private static boolean sProvidersLoaded = false; private static boolean sProvidersLoaded = false;
private final Context mContext; private final Context mContext;
private final String mNetworkLocationProviderPackageName; private PackageManager mPackageManager; // final after initialize()
private final String mGeocodeProviderPackageName; private String mNetworkLocationProviderPackageName; // only used on handler thread
private String mGeocodeProviderPackageName; // only used on handler thread
private GeocoderProxy mGeocodeProvider; private GeocoderProxy mGeocodeProvider;
private IGpsStatusProvider mGpsStatusProvider; private IGpsStatusProvider mGpsStatusProvider;
private INetInitiatedListener mNetInitiatedListener; private INetInitiatedListener mNetInitiatedListener;
@@ -490,25 +495,78 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
addProvider(passiveProvider); addProvider(passiveProvider);
mEnabledProviders.add(passiveProvider.getName()); mEnabledProviders.add(passiveProvider.getName());
// initialize external network location and geocoder services // initialize external network location and geocoder services.
PackageManager pm = mContext.getPackageManager(); // The initial value of mNetworkLocationProviderPackageName and
if (mNetworkLocationProviderPackageName != null && // mGeocodeProviderPackageName is just used to determine what
pm.resolveService(new Intent(mNetworkLocationProviderPackageName), 0) != null) { // signatures future mNetworkLocationProviderPackageName and
mNetworkLocationProvider = // mGeocodeProviderPackageName packages must have. So alternate
new LocationProviderProxy(mContext, LocationManager.NETWORK_PROVIDER, // providers can be installed under a different package name
mNetworkLocationProviderPackageName, mLocationHandler); // so long as they have the same signature as the original
// provider packages.
addProvider(mNetworkLocationProvider); 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) {
if (mGeocodeProviderPackageName != null && String packageName = findBestPackage(GeocoderProxy.SERVICE_ACTION,
pm.resolveService(new Intent(mGeocodeProviderPackageName), 0) != null) { mGeocodeProviderPackageName);
mGeocodeProvider = new GeocoderProxy(mContext, mGeocodeProviderPackageName); if (packageName != null) {
mGeocodeProvider = new GeocoderProxy(mContext, packageName);
mGeocodeProviderPackageName = packageName;
}
} }
updateProvidersLocked(); 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 * @param context the context that the LocationManagerService runs in
*/ */
@@ -516,10 +574,12 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
super(); super();
mContext = context; mContext = context;
Resources resources = context.getResources(); Resources resources = context.getResources();
mNetworkLocationProviderPackageName = resources.getString( mNetworkLocationProviderPackageName = resources.getString(
com.android.internal.R.string.config_networkLocationProvider); com.android.internal.R.string.config_networkLocationProviderPackageName);
mGeocodeProviderPackageName = resources.getString( mGeocodeProviderPackageName = resources.getString(
com.android.internal.R.string.config_geocodeProvider); com.android.internal.R.string.config_geocodeProviderPackageName);
mPackageMonitor.register(context, null, true); mPackageMonitor.register(context, null, true);
if (LOCAL_LOGV) { 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 // Create a wake lock, needs to be done before calling loadProviders() below
PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY); mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
mPackageManager = mContext.getPackageManager();
// Load providers // Load providers
loadProviders(); loadProviders();
@@ -1886,16 +1947,33 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
} }
} else if (msg.what == MESSAGE_PACKAGE_UPDATED) { } else if (msg.what == MESSAGE_PACKAGE_UPDATED) {
String packageName = (String) msg.obj; String packageName = (String) msg.obj;
String packageDot = packageName + ".";
// reconnect to external providers after their packages have been updated // reconnect to external providers if there is a better package
if (mNetworkLocationProvider != null && if (mNetworkLocationProviderPackageName != null &&
mNetworkLocationProviderPackageName.startsWith(packageDot)) { mPackageManager.resolveService(
mNetworkLocationProvider.reconnect(); 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 && if (mGeocodeProviderPackageName != null &&
mGeocodeProviderPackageName.startsWith(packageDot)) { mPackageManager.resolveService(
mGeocodeProvider.reconnect(); 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) { } catch (Exception e) {
@@ -2004,6 +2082,11 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
// Called by main thread; divert work to LocationWorker. // Called by main thread; divert work to LocationWorker.
Message.obtain(mLocationHandler, MESSAGE_PACKAGE_UPDATED, packageName).sendToTarget(); 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 // Wake locks

View File

@@ -39,27 +39,28 @@ public class GeocoderProxy {
private static final String TAG = "GeocoderProxy"; private static final String TAG = "GeocoderProxy";
public static final String SERVICE_ACTION =
"com.android.location.service.GeocodeProvider";
private final Context mContext; private final Context mContext;
private final Intent mIntent; private final Intent mIntent;
private final Object mMutex = new Object(); // synchronizes access to mServiceConnection 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; mContext = context;
mIntent = new Intent(serviceName); mIntent = new Intent(SERVICE_ACTION);
mContext.bindService(mIntent, mServiceConnection, reconnect(packageName);
Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND
| Context.BIND_ALLOW_OOM_MANAGEMENT);
} }
/** /** Bind to service. Will reconnect if already connected */
* When unbundled NetworkLocationService package is updated, we public void reconnect(String packageName) {
* need to unbind from the old version and re-bind to the new one.
*/
public void reconnect() {
synchronized (mMutex) { synchronized (mMutex) {
mContext.unbindService(mServiceConnection); if (mServiceConnection != null) {
mContext.unbindService(mServiceConnection);
}
mServiceConnection = new Connection(); mServiceConnection = new Connection();
mIntent.setPackage(packageName);
mContext.bindService(mIntent, mServiceConnection, mContext.bindService(mIntent, mServiceConnection,
Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND
| Context.BIND_ALLOW_OOM_MANAGEMENT); | Context.BIND_ALLOW_OOM_MANAGEMENT);

View File

@@ -42,12 +42,15 @@ public class LocationProviderProxy implements LocationProviderInterface {
private static final String TAG = "LocationProviderProxy"; private static final String TAG = "LocationProviderProxy";
public static final String SERVICE_ACTION =
"com.android.location.service.NetworkLocationProvider";
private final Context mContext; private final Context mContext;
private final String mName; private final String mName;
private final Intent mIntent; private final Intent mIntent;
private final Handler mHandler; private final Handler mHandler;
private final Object mMutex = new Object(); // synchronizes access to non-final members 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 // cached values set by the location manager
private boolean mLocationTracking = false; private boolean mLocationTracking = false;
@@ -58,28 +61,26 @@ public class LocationProviderProxy implements LocationProviderInterface {
private NetworkInfo mNetworkInfo; private NetworkInfo mNetworkInfo;
// constructor for proxying location providers implemented in a separate service // 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) { Handler handler) {
mContext = context; mContext = context;
mName = name; mName = name;
mIntent = new Intent(serviceName); mIntent = new Intent(SERVICE_ACTION);
mHandler = handler; mHandler = handler;
mContext.bindService(mIntent, mServiceConnection, reconnect(packageName);
Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND
| Context.BIND_ALLOW_OOM_MANAGEMENT);
} }
/** /** Bind to service. Will reconnect if already connected */
* When unbundled NetworkLocationService package is updated, we public void reconnect(String packageName) {
* need to unbind from the old version and re-bind to the new one.
*/
public void reconnect() {
synchronized (mMutex) { synchronized (mMutex) {
mContext.unbindService(mServiceConnection); if (mServiceConnection != null) {
mContext.unbindService(mServiceConnection);
}
mServiceConnection = new Connection(); mServiceConnection = new Connection();
mIntent.setPackage(packageName);
mContext.bindService(mIntent, mServiceConnection, mContext.bindService(mIntent, mServiceConnection,
Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND |
| Context.BIND_ALLOW_OOM_MANAGEMENT); Context.BIND_ALLOW_OOM_MANAGEMENT);
} }
} }