am 82b3b1bc: Merge "Make location providers upgradeable." into jb-dev
* commit '82b3b1bce9665a68b32ab0d7393ea63425677f70': Make location providers upgradeable.
This commit is contained in:
@@ -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 -->
|
||||||
|
|||||||
@@ -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" />
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user