|
23 | 23 | import android.content.Intent; |
24 | 24 | import android.content.IntentFilter; |
25 | 25 | import android.content.pm.ApplicationInfo; |
| 26 | +import android.content.pm.PackageInfo; |
26 | 27 | import android.content.pm.PackageManager; |
27 | 28 | import android.content.pm.PackageManager.NameNotFoundException; |
| 29 | +import android.content.pm.ResolveInfo; |
| 30 | +import android.content.pm.Signature; |
28 | 31 | import android.content.res.Resources; |
29 | 32 | import android.database.ContentObserver; |
30 | 33 | import android.location.Address; |
@@ -246,6 +249,74 @@ public void onReceive(Context context, Intent intent) { |
246 | 249 | updateProvidersLocked(); |
247 | 250 | } |
248 | 251 |
|
| 252 | + private void ensureFallbackFusedProviderPresentLocked(ArrayList<String> pkgs) { |
| 253 | + PackageManager pm = mContext.getPackageManager(); |
| 254 | + String systemPackageName = mContext.getPackageName(); |
| 255 | + ArrayList<HashSet<Signature>> sigSets = ServiceWatcher.getSignatureSets(mContext, pkgs); |
| 256 | + |
| 257 | + List<ResolveInfo> rInfos = pm.queryIntentServicesAsUser( |
| 258 | + new Intent(FUSED_LOCATION_SERVICE_ACTION), |
| 259 | + PackageManager.GET_META_DATA, mCurrentUserId); |
| 260 | + for (ResolveInfo rInfo : rInfos) { |
| 261 | + String packageName = rInfo.serviceInfo.packageName; |
| 262 | + |
| 263 | + // Check that the signature is in the list of supported sigs. If it's not in |
| 264 | + // this list the standard provider binding logic won't bind to it. |
| 265 | + try { |
| 266 | + PackageInfo pInfo; |
| 267 | + pInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES); |
| 268 | + if (!ServiceWatcher.isSignatureMatch(pInfo.signatures, sigSets)) { |
| 269 | + Log.w(TAG, packageName + " resolves service " + FUSED_LOCATION_SERVICE_ACTION + |
| 270 | + ", but has wrong signature, ignoring"); |
| 271 | + continue; |
| 272 | + } |
| 273 | + } catch (NameNotFoundException e) { |
| 274 | + Log.e(TAG, "missing package: " + packageName); |
| 275 | + continue; |
| 276 | + } |
| 277 | + |
| 278 | + // Get the version info |
| 279 | + if (rInfo.serviceInfo.metaData == null) { |
| 280 | + Log.w(TAG, "Found fused provider without metadata: " + packageName); |
| 281 | + continue; |
| 282 | + } |
| 283 | + |
| 284 | + int version = rInfo.serviceInfo.metaData.getInt( |
| 285 | + ServiceWatcher.EXTRA_SERVICE_VERSION, -1); |
| 286 | + if (version == 0) { |
| 287 | + // This should be the fallback fused location provider. |
| 288 | + |
| 289 | + // Make sure it's in the system partition. |
| 290 | + if ((rInfo.serviceInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) { |
| 291 | + if (D) Log.d(TAG, "Fallback candidate not in /system: " + packageName); |
| 292 | + continue; |
| 293 | + } |
| 294 | + |
| 295 | + // Check that the fallback is signed the same as the OS |
| 296 | + // as a proxy for coreApp="true" |
| 297 | + if (pm.checkSignatures(systemPackageName, packageName) |
| 298 | + != PackageManager.SIGNATURE_MATCH) { |
| 299 | + if (D) Log.d(TAG, "Fallback candidate not signed the same as system: " |
| 300 | + + packageName); |
| 301 | + continue; |
| 302 | + } |
| 303 | + |
| 304 | + // Found a valid fallback. |
| 305 | + if (D) Log.d(TAG, "Found fallback provider: " + packageName); |
| 306 | + return; |
| 307 | + } else { |
| 308 | + if (D) Log.d(TAG, "Fallback candidate not version 0: " + packageName); |
| 309 | + } |
| 310 | + } |
| 311 | + |
| 312 | + throw new IllegalStateException("Unable to find a fused location provider that is in the " |
| 313 | + + "system partition with version 0 and signed with the platform certificate. " |
| 314 | + + "Such a package is needed to provide a default fused location provider in the " |
| 315 | + + "event that no other fused location provider has been installed or is currently " |
| 316 | + + "available. For example, coreOnly boot mode when decrypting the data " |
| 317 | + + "partition. The fallback must also be marked coreApp=\"true\" in the manifest"); |
| 318 | + } |
| 319 | + |
249 | 320 | private void loadProvidersLocked() { |
250 | 321 | // create a passive location provider, which is always enabled |
251 | 322 | PassiveProvider passiveProvider = new PassiveProvider(this); |
@@ -275,14 +346,13 @@ Load package name(s) containing location provider support. |
275 | 346 | */ |
276 | 347 | Resources resources = mContext.getResources(); |
277 | 348 | ArrayList<String> providerPackageNames = new ArrayList<String>(); |
278 | | - String[] pkgs1 = resources.getStringArray( |
| 349 | + String[] pkgs = resources.getStringArray( |
279 | 350 | com.android.internal.R.array.config_locationProviderPackageNames); |
280 | | - String[] pkgs2 = resources.getStringArray( |
281 | | - com.android.internal.R.array.config_overlay_locationProviderPackageNames); |
282 | | - if (D) Log.d(TAG, "built-in location providers: " + Arrays.toString(pkgs1)); |
283 | | - if (D) Log.d(TAG, "overlay location providers: " + Arrays.toString(pkgs2)); |
284 | | - if (pkgs1 != null) providerPackageNames.addAll(Arrays.asList(pkgs1)); |
285 | | - if (pkgs2 != null) providerPackageNames.addAll(Arrays.asList(pkgs2)); |
| 351 | + if (D) Log.d(TAG, "certificates for location providers pulled from: " + |
| 352 | + Arrays.toString(pkgs)); |
| 353 | + if (pkgs != null) providerPackageNames.addAll(Arrays.asList(pkgs)); |
| 354 | + |
| 355 | + ensureFallbackFusedProviderPresentLocked(providerPackageNames); |
286 | 356 |
|
287 | 357 | // bind to network provider |
288 | 358 | LocationProviderProxy networkProvider = LocationProviderProxy.createAndBind( |
|
0 commit comments