Merge "Changes to support updating location providers." into jb-mr1-dev

This commit is contained in:
Jeff Hamilton
2012-10-18 12:45:02 -07:00
committed by Android (Google) Code Review
5 changed files with 112 additions and 38 deletions

View File

@@ -636,19 +636,12 @@
of new location providers at run-time. The new package does not of new location providers at run-time. The new package does not
have to be explicitly listed here, however it must have a signature have to be explicitly listed here, however it must have a signature
that matches the signature of at least one package on this list. that matches the signature of at least one package on this list.
Platforms should overlay additional packages in
config_overlay_locationProviderPackageNames, instead of overlaying
this config, if they only want to append packages and not replace
the entire array.
--> -->
<string-array name="config_locationProviderPackageNames" translatable="false"> <string-array name="config_locationProviderPackageNames" translatable="false">
<!-- The standard AOSP fused location provider -->
<item>com.android.location.fused</item> <item>com.android.location.fused</item>
</string-array> </string-array>
<!-- Pacakge name(s) supplied by overlay, and appended to
config_locationProviderPackageNames. -->
<string-array name="config_overlay_locationProviderPackageNames" translatable="false" />
<!-- 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 -->
<bool name="config_bluetooth_sco_off_call">true</bool> <bool name="config_bluetooth_sco_off_call">true</bool>

View File

@@ -1475,7 +1475,6 @@
<java-symbol type="array" name="radioAttributes" /> <java-symbol type="array" name="radioAttributes" />
<java-symbol type="array" name="config_oemUsbModeOverride" /> <java-symbol type="array" name="config_oemUsbModeOverride" />
<java-symbol type="array" name="config_locationProviderPackageNames" /> <java-symbol type="array" name="config_locationProviderPackageNames" />
<java-symbol type="array" name="config_overlay_locationProviderPackageNames" />
<java-symbol type="bool" name="config_animateScreenLights" /> <java-symbol type="bool" name="config_animateScreenLights" />
<java-symbol type="bool" name="config_automatic_brightness_available" /> <java-symbol type="bool" name="config_automatic_brightness_available" />
<java-symbol type="bool" name="config_sf_limitedAlpha" /> <java-symbol type="bool" name="config_sf_limitedAlpha" />

View File

@@ -18,7 +18,8 @@
--> -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.location.fused" package="com.android.location.fused"
coreApp="true"> coreApp="true"
android:sharedUserId="android.uid.system">
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
@@ -39,7 +40,7 @@
<intent-filter> <intent-filter>
<action android:name="com.android.location.service.FusedLocationProvider" /> <action android:name="com.android.location.service.FusedLocationProvider" />
</intent-filter> </intent-filter>
<meta-data android:name="version" android:value="1" /> <meta-data android:name="serviceVersion" android:value="0" />
</service> </service>
</application> </application>
</manifest> </manifest>

View File

@@ -23,8 +23,11 @@ import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.IntentFilter; import android.content.IntentFilter;
import android.content.pm.ApplicationInfo; import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.content.pm.Signature;
import android.content.res.Resources; import android.content.res.Resources;
import android.database.ContentObserver; import android.database.ContentObserver;
import android.location.Address; import android.location.Address;
@@ -249,6 +252,74 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
updateProvidersLocked(); updateProvidersLocked();
} }
private void ensureFallbackFusedProviderPresentLocked(ArrayList<String> pkgs) {
PackageManager pm = mContext.getPackageManager();
String systemPackageName = mContext.getPackageName();
ArrayList<HashSet<Signature>> sigSets = ServiceWatcher.getSignatureSets(mContext, pkgs);
List<ResolveInfo> rInfos = pm.queryIntentServicesAsUser(
new Intent(FUSED_LOCATION_SERVICE_ACTION),
PackageManager.GET_META_DATA, mCurrentUserId);
for (ResolveInfo rInfo : rInfos) {
String packageName = rInfo.serviceInfo.packageName;
// Check that the signature is in the list of supported sigs. If it's not in
// this list the standard provider binding logic won't bind to it.
try {
PackageInfo pInfo;
pInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
if (!ServiceWatcher.isSignatureMatch(pInfo.signatures, sigSets)) {
Log.w(TAG, packageName + " resolves service " + FUSED_LOCATION_SERVICE_ACTION +
", but has wrong signature, ignoring");
continue;
}
} catch (NameNotFoundException e) {
Log.e(TAG, "missing package: " + packageName);
continue;
}
// Get the version info
if (rInfo.serviceInfo.metaData == null) {
Log.w(TAG, "Found fused provider without metadata: " + packageName);
continue;
}
int version = rInfo.serviceInfo.metaData.getInt(
ServiceWatcher.EXTRA_SERVICE_VERSION, -1);
if (version == 0) {
// This should be the fallback fused location provider.
// Make sure it's in the system partition.
if ((rInfo.serviceInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
if (D) Log.d(TAG, "Fallback candidate not in /system: " + packageName);
continue;
}
// Check that the fallback is signed the same as the OS
// as a proxy for coreApp="true"
if (pm.checkSignatures(systemPackageName, packageName)
!= PackageManager.SIGNATURE_MATCH) {
if (D) Log.d(TAG, "Fallback candidate not signed the same as system: "
+ packageName);
continue;
}
// Found a valid fallback.
if (D) Log.d(TAG, "Found fallback provider: " + packageName);
return;
} else {
if (D) Log.d(TAG, "Fallback candidate not version 0: " + packageName);
}
}
throw new IllegalStateException("Unable to find a fused location provider that is in the "
+ "system partition with version 0 and signed with the platform certificate. "
+ "Such a package is needed to provide a default fused location provider in the "
+ "event that no other fused location provider has been installed or is currently "
+ "available. For example, coreOnly boot mode when decrypting the data "
+ "partition. The fallback must also be marked coreApp=\"true\" in the manifest");
}
private void loadProvidersLocked() { private void loadProvidersLocked() {
// create a passive location provider, which is always enabled // create a passive location provider, which is always enabled
PassiveProvider passiveProvider = new PassiveProvider(this); PassiveProvider passiveProvider = new PassiveProvider(this);
@@ -278,14 +349,13 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
*/ */
Resources resources = mContext.getResources(); Resources resources = mContext.getResources();
ArrayList<String> providerPackageNames = new ArrayList<String>(); ArrayList<String> providerPackageNames = new ArrayList<String>();
String[] pkgs1 = resources.getStringArray( String[] pkgs = resources.getStringArray(
com.android.internal.R.array.config_locationProviderPackageNames); com.android.internal.R.array.config_locationProviderPackageNames);
String[] pkgs2 = resources.getStringArray( if (D) Log.d(TAG, "certificates for location providers pulled from: " +
com.android.internal.R.array.config_overlay_locationProviderPackageNames); Arrays.toString(pkgs));
if (D) Log.d(TAG, "built-in location providers: " + Arrays.toString(pkgs1)); if (pkgs != null) providerPackageNames.addAll(Arrays.asList(pkgs));
if (D) Log.d(TAG, "overlay location providers: " + Arrays.toString(pkgs2));
if (pkgs1 != null) providerPackageNames.addAll(Arrays.asList(pkgs1)); ensureFallbackFusedProviderPresentLocked(providerPackageNames);
if (pkgs2 != null) providerPackageNames.addAll(Arrays.asList(pkgs2));
// bind to network provider // bind to network provider
LocationProviderProxy networkProvider = LocationProviderProxy.createAndBind( LocationProviderProxy networkProvider = LocationProviderProxy.createAndBind(

View File

@@ -43,7 +43,7 @@ import java.util.List;
*/ */
public class ServiceWatcher implements ServiceConnection { public class ServiceWatcher implements ServiceConnection {
private static final boolean D = false; private static final boolean D = false;
private static final String EXTRA_VERSION = "version"; public static final String EXTRA_SERVICE_VERSION = "serviceVersion";
private final String mTag; private final String mTag;
private final Context mContext; private final Context mContext;
@@ -58,9 +58,27 @@ public class ServiceWatcher implements ServiceConnection {
// all fields below synchronized on mLock // all fields below synchronized on mLock
private IBinder mBinder; // connected service private IBinder mBinder; // connected service
private String mPackageName; // current best package private String mPackageName; // current best package
private int mVersion; // current best version private int mVersion = Integer.MIN_VALUE; // current best version
private int mCurrentUserId; private int mCurrentUserId;
public static ArrayList<HashSet<Signature>> getSignatureSets(Context context,
List<String> initialPackageNames) {
PackageManager pm = context.getPackageManager();
ArrayList<HashSet<Signature>> sigSets = new ArrayList<HashSet<Signature>>();
for (int i = 0, size = initialPackageNames.size(); i < size; i++) {
String pkg = initialPackageNames.get(i);
try {
HashSet<Signature> set = new HashSet<Signature>();
Signature[] sigs = pm.getPackageInfo(pkg, PackageManager.GET_SIGNATURES).signatures;
set.addAll(Arrays.asList(sigs));
sigSets.add(set);
} catch (NameNotFoundException e) {
Log.w("ServiceWatcher", pkg + " not found");
}
}
return sigSets;
}
public ServiceWatcher(Context context, String logTag, String action, public ServiceWatcher(Context context, String logTag, String action,
List<String> initialPackageNames, Runnable newServiceWork, Handler handler, int userId) { List<String> initialPackageNames, Runnable newServiceWork, Handler handler, int userId) {
mContext = context; mContext = context;
@@ -71,20 +89,7 @@ public class ServiceWatcher implements ServiceConnection {
mHandler = handler; mHandler = handler;
mCurrentUserId = userId; mCurrentUserId = userId;
mSignatureSets = new ArrayList<HashSet<Signature>>(); mSignatureSets = getSignatureSets(context, initialPackageNames);
for (int i=0; i < initialPackageNames.size(); i++) {
String pkg = initialPackageNames.get(i);
HashSet<Signature> set = new HashSet<Signature>();
try {
Signature[] sigs =
mPm.getPackageInfo(pkg, PackageManager.GET_SIGNATURES).signatures;
set.addAll(Arrays.asList(sigs));
mSignatureSets.add(set);
} catch (NameNotFoundException e) {
Log.w(logTag, pkg + " not found");
}
}
} }
public boolean start() { public boolean start() {
@@ -132,15 +137,16 @@ public class ServiceWatcher implements ServiceConnection {
// check version // check version
int version = 0; int version = 0;
if (rInfo.serviceInfo.metaData != null) { if (rInfo.serviceInfo.metaData != null) {
version = rInfo.serviceInfo.metaData.getInt(EXTRA_VERSION, 0); version = rInfo.serviceInfo.metaData.getInt(EXTRA_SERVICE_VERSION, 0);
} }
if (version > mVersion) { if (version > mVersion) {
bestVersion = version; bestVersion = version;
bestPackage = packageName; bestPackage = packageName;
} }
} }
if (D) Log.d(mTag, String.format("bindBestPackage %s found %d, %s", if (D) Log.d(mTag, String.format("bindBestPackage for %s : %s found %d, %s", mAction,
(justCheckThisPackage == null ? "" : "(" + justCheckThisPackage + ") "), (justCheckThisPackage == null ? "" : "(" + justCheckThisPackage + ") "),
rInfos.size(), rInfos.size(),
(bestPackage == null ? "no new best package" : "new best packge: " + bestPackage))); (bestPackage == null ? "no new best package" : "new best packge: " + bestPackage)));
@@ -174,7 +180,8 @@ public class ServiceWatcher implements ServiceConnection {
| Context.BIND_ALLOW_OOM_MANAGEMENT | Context.BIND_NOT_VISIBLE, mCurrentUserId); | Context.BIND_ALLOW_OOM_MANAGEMENT | Context.BIND_NOT_VISIBLE, mCurrentUserId);
} }
private boolean isSignatureMatch(Signature[] signatures) { public static boolean isSignatureMatch(Signature[] signatures,
List<HashSet<Signature>> sigSets) {
if (signatures == null) return false; if (signatures == null) return false;
// build hashset of input to test against // build hashset of input to test against
@@ -184,7 +191,7 @@ public class ServiceWatcher implements ServiceConnection {
} }
// test input against each of the signature sets // test input against each of the signature sets
for (HashSet<Signature> referenceSet : mSignatureSets) { for (HashSet<Signature> referenceSet : sigSets) {
if (referenceSet.equals(inputSet)) { if (referenceSet.equals(inputSet)) {
return true; return true;
} }
@@ -192,6 +199,10 @@ public class ServiceWatcher implements ServiceConnection {
return false; return false;
} }
private boolean isSignatureMatch(Signature[] signatures) {
return isSignatureMatch(signatures, mSignatureSets);
}
private final PackageMonitor mPackageMonitor = new PackageMonitor() { private final PackageMonitor mPackageMonitor = new PackageMonitor() {
/** /**
* Called when package has been reinstalled * Called when package has been reinstalled