am ba2c79a5: am e09aed49: Merge "Changes to support updating location providers." into jb-mr1-dev

* commit 'ba2c79a59fa9640d3f54c81f05f664a47337a05c':
  Changes to support updating location providers.
This commit is contained in:
Jeff Hamilton
2012-10-18 12:50:34 -07:00
committed by Android Git Automerger
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
have to be explicitly listed here, however it must have a signature
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">
<!-- The standard AOSP fused location provider -->
<item>com.android.location.fused</item>
</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
use cases -->
<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="config_oemUsbModeOverride" />
<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_automatic_brightness_available" />
<java-symbol type="bool" name="config_sf_limitedAlpha" />

View File

@@ -18,7 +18,8 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
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_FINE_LOCATION" />
@@ -39,7 +40,7 @@
<intent-filter>
<action android:name="com.android.location.service.FusedLocationProvider" />
</intent-filter>
<meta-data android:name="version" android:value="1" />
<meta-data android:name="serviceVersion" android:value="0" />
</service>
</application>
</manifest>

View File

@@ -23,8 +23,11 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.content.pm.Signature;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.location.Address;
@@ -249,6 +252,74 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
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() {
// create a passive location provider, which is always enabled
PassiveProvider passiveProvider = new PassiveProvider(this);
@@ -278,14 +349,13 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
*/
Resources resources = mContext.getResources();
ArrayList<String> providerPackageNames = new ArrayList<String>();
String[] pkgs1 = resources.getStringArray(
String[] pkgs = resources.getStringArray(
com.android.internal.R.array.config_locationProviderPackageNames);
String[] pkgs2 = resources.getStringArray(
com.android.internal.R.array.config_overlay_locationProviderPackageNames);
if (D) Log.d(TAG, "built-in location providers: " + Arrays.toString(pkgs1));
if (D) Log.d(TAG, "overlay location providers: " + Arrays.toString(pkgs2));
if (pkgs1 != null) providerPackageNames.addAll(Arrays.asList(pkgs1));
if (pkgs2 != null) providerPackageNames.addAll(Arrays.asList(pkgs2));
if (D) Log.d(TAG, "certificates for location providers pulled from: " +
Arrays.toString(pkgs));
if (pkgs != null) providerPackageNames.addAll(Arrays.asList(pkgs));
ensureFallbackFusedProviderPresentLocked(providerPackageNames);
// bind to network provider
LocationProviderProxy networkProvider = LocationProviderProxy.createAndBind(

View File

@@ -43,7 +43,7 @@ import java.util.List;
*/
public class ServiceWatcher implements ServiceConnection {
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 Context mContext;
@@ -58,9 +58,27 @@ public class ServiceWatcher implements ServiceConnection {
// all fields below synchronized on mLock
private IBinder mBinder; // connected service
private String mPackageName; // current best package
private int mVersion; // current best version
private int mVersion = Integer.MIN_VALUE; // current best version
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,
List<String> initialPackageNames, Runnable newServiceWork, Handler handler, int userId) {
mContext = context;
@@ -71,20 +89,7 @@ public class ServiceWatcher implements ServiceConnection {
mHandler = handler;
mCurrentUserId = userId;
mSignatureSets = new ArrayList<HashSet<Signature>>();
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");
}
}
mSignatureSets = getSignatureSets(context, initialPackageNames);
}
public boolean start() {
@@ -132,15 +137,16 @@ public class ServiceWatcher implements ServiceConnection {
// check version
int version = 0;
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) {
bestVersion = version;
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 + ") "),
rInfos.size(),
(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);
}
private boolean isSignatureMatch(Signature[] signatures) {
public static boolean isSignatureMatch(Signature[] signatures,
List<HashSet<Signature>> sigSets) {
if (signatures == null) return false;
// build hashset of input to test against
@@ -184,7 +191,7 @@ public class ServiceWatcher implements ServiceConnection {
}
// test input against each of the signature sets
for (HashSet<Signature> referenceSet : mSignatureSets) {
for (HashSet<Signature> referenceSet : sigSets) {
if (referenceSet.equals(inputSet)) {
return true;
}
@@ -192,6 +199,10 @@ public class ServiceWatcher implements ServiceConnection {
return false;
}
private boolean isSignatureMatch(Signature[] signatures) {
return isSignatureMatch(signatures, mSignatureSets);
}
private final PackageMonitor mPackageMonitor = new PackageMonitor() {
/**
* Called when package has been reinstalled