diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 4698002e0e1b6..afd847f3c921d 100755 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -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. --> + com.android.location.fused - - - true diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index b3af161612e70..7c0547e3e0a17 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -1475,7 +1475,6 @@ - diff --git a/packages/FusedLocation/AndroidManifest.xml b/packages/FusedLocation/AndroidManifest.xml index 4c574016e276c..10b90644fcc47 100644 --- a/packages/FusedLocation/AndroidManifest.xml +++ b/packages/FusedLocation/AndroidManifest.xml @@ -18,7 +18,8 @@ --> + coreApp="true" + android:sharedUserId="android.uid.system"> @@ -39,7 +40,7 @@ - + diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java index 468f6967a62da..37dee1980c549 100644 --- a/services/java/com/android/server/LocationManagerService.java +++ b/services/java/com/android/server/LocationManagerService.java @@ -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 pkgs) { + PackageManager pm = mContext.getPackageManager(); + String systemPackageName = mContext.getPackageName(); + ArrayList> sigSets = ServiceWatcher.getSignatureSets(mContext, pkgs); + + List 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 providerPackageNames = new ArrayList(); - 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( diff --git a/services/java/com/android/server/ServiceWatcher.java b/services/java/com/android/server/ServiceWatcher.java index 5598b0ad38213..2e7c6d16ea3b4 100644 --- a/services/java/com/android/server/ServiceWatcher.java +++ b/services/java/com/android/server/ServiceWatcher.java @@ -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> getSignatureSets(Context context, + List initialPackageNames) { + PackageManager pm = context.getPackageManager(); + ArrayList> sigSets = new ArrayList>(); + for (int i = 0, size = initialPackageNames.size(); i < size; i++) { + String pkg = initialPackageNames.get(i); + try { + HashSet set = new HashSet(); + 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 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>(); - for (int i=0; i < initialPackageNames.size(); i++) { - String pkg = initialPackageNames.get(i); - HashSet set = new HashSet(); - 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> 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 referenceSet : mSignatureSets) { + for (HashSet 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