1 /* 2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.pm.resolution; 18 19 import static android.content.pm.PackageManager.INSTALL_FAILED_CONFLICTING_PROVIDER; 20 21 import static com.android.server.pm.PackageManagerService.DEBUG_PACKAGE_SCANNING; 22 import static com.android.server.pm.PackageManagerService.DEBUG_REMOVE; 23 24 import android.annotation.NonNull; 25 import android.annotation.Nullable; 26 import android.annotation.UserIdInt; 27 import android.content.ComponentName; 28 import android.content.Intent; 29 import android.content.IntentFilter; 30 import android.content.pm.ActivityInfo; 31 import android.content.pm.ApplicationInfo; 32 import android.content.pm.AuxiliaryResolveInfo; 33 import android.content.pm.InstantAppResolveInfo; 34 import android.content.pm.PackageManager; 35 import android.content.pm.ProviderInfo; 36 import android.content.pm.ResolveInfo; 37 import android.content.pm.ServiceInfo; 38 import android.os.UserHandle; 39 import android.util.ArrayMap; 40 import android.util.ArraySet; 41 import android.util.DebugUtils; 42 import android.util.Log; 43 import android.util.LogPrinter; 44 import android.util.Pair; 45 import android.util.Slog; 46 47 import com.android.internal.annotations.GuardedBy; 48 import com.android.internal.util.ArrayUtils; 49 import com.android.server.IntentResolver; 50 import com.android.server.pm.Computer; 51 import com.android.server.pm.PackageManagerException; 52 import com.android.server.pm.UserManagerService; 53 import com.android.server.pm.UserNeedsBadgingCache; 54 import com.android.server.pm.parsing.PackageInfoUtils; 55 import com.android.server.pm.pkg.AndroidPackage; 56 import com.android.server.pm.pkg.PackageStateInternal; 57 import com.android.server.pm.pkg.PackageStateUtils; 58 import com.android.server.pm.pkg.PackageUserStateInternal; 59 import com.android.server.pm.pkg.component.ComponentMutateUtils; 60 import com.android.server.pm.pkg.component.ParsedActivity; 61 import com.android.server.pm.pkg.component.ParsedComponent; 62 import com.android.server.pm.pkg.component.ParsedIntentInfo; 63 import com.android.server.pm.pkg.component.ParsedMainComponent; 64 import com.android.server.pm.pkg.component.ParsedProvider; 65 import com.android.server.pm.pkg.component.ParsedProviderImpl; 66 import com.android.server.pm.pkg.component.ParsedService; 67 import com.android.server.pm.snapshot.PackageDataSnapshot; 68 import com.android.server.utils.Snappable; 69 import com.android.server.utils.SnapshotCache; 70 71 import java.io.PrintWriter; 72 import java.util.ArrayList; 73 import java.util.Collection; 74 import java.util.Collections; 75 import java.util.Comparator; 76 import java.util.Iterator; 77 import java.util.List; 78 import java.util.Objects; 79 import java.util.Set; 80 import java.util.function.Function; 81 82 /** Resolves all Android component types [activities, services, providers and receivers]. */ 83 public class ComponentResolver extends ComponentResolverLocked implements 84 Snappable<ComponentResolverApi> { 85 private static final boolean DEBUG = false; 86 private static final String TAG = "PackageManager"; 87 private static final boolean DEBUG_FILTERS = false; 88 private static final boolean DEBUG_SHOW_INFO = false; 89 90 // Convenience function to report that this object has changed. onChanged()91 private void onChanged() { 92 dispatchChange(this); 93 } 94 95 /** 96 * The set of all protected actions [i.e. those actions for which a high priority 97 * intent filter is disallowed]. 98 */ 99 private static final Set<String> PROTECTED_ACTIONS = new ArraySet<>(); 100 static { 101 PROTECTED_ACTIONS.add(Intent.ACTION_SEND); 102 PROTECTED_ACTIONS.add(Intent.ACTION_SENDTO); 103 PROTECTED_ACTIONS.add(Intent.ACTION_SEND_MULTIPLE); 104 PROTECTED_ACTIONS.add(Intent.ACTION_VIEW); 105 } 106 107 public static final Comparator<ResolveInfo> RESOLVE_PRIORITY_SORTER = (r1, r2) -> { 108 int v1 = r1.priority; 109 int v2 = r2.priority; 110 //System.out.println("Comparing: q1=" + q1 + " q2=" + q2); 111 if (v1 != v2) { 112 return (v1 > v2) ? -1 : 1; 113 } 114 v1 = r1.preferredOrder; 115 v2 = r2.preferredOrder; 116 if (v1 != v2) { 117 return (v1 > v2) ? -1 : 1; 118 } 119 if (r1.isDefault != r2.isDefault) { 120 return r1.isDefault ? -1 : 1; 121 } 122 v1 = r1.match; 123 v2 = r2.match; 124 //System.out.println("Comparing: m1=" + m1 + " m2=" + m2); 125 if (v1 != v2) { 126 return (v1 > v2) ? -1 : 1; 127 } 128 if (r1.system != r2.system) { 129 return r1.system ? -1 : 1; 130 } 131 if (r1.activityInfo != null) { 132 return r1.activityInfo.packageName.compareTo(r2.activityInfo.packageName); 133 } 134 if (r1.serviceInfo != null) { 135 return r1.serviceInfo.packageName.compareTo(r2.serviceInfo.packageName); 136 } 137 if (r1.providerInfo != null) { 138 return r1.providerInfo.packageName.compareTo(r2.providerInfo.packageName); 139 } 140 return 0; 141 }; 142 143 /** Whether or not processing protected filters should be deferred. */ 144 boolean mDeferProtectedFilters = true; 145 146 /** 147 * Tracks high priority intent filters for protected actions. During boot, certain 148 * filter actions are protected and should never be allowed to have a high priority 149 * intent filter for them. However, there is one, and only one exception -- the 150 * setup wizard. It must be able to define a high priority intent filter for these 151 * actions to ensure there are no escapes from the wizard. We need to delay processing 152 * of these during boot as we need to inspect at all of the intent filters on the 153 * /system partition in order to know which component is the setup wizard. This can 154 * only ever be non-empty if {@link #mDeferProtectedFilters} is {@code true}. 155 * 156 * This is a pair of component package name to actual filter, because we don't store the 157 * name inside the filter. It's technically independent of the component it's contained in. 158 */ 159 List<Pair<ParsedMainComponent, ParsedIntentInfo>> mProtectedFilters; 160 ComponentResolver(@onNull UserManagerService userManager, @NonNull UserNeedsBadgingCache userNeedsBadgingCache)161 public ComponentResolver(@NonNull UserManagerService userManager, 162 @NonNull UserNeedsBadgingCache userNeedsBadgingCache) { 163 super(userManager); 164 mActivities = new ActivityIntentResolver(userManager, userNeedsBadgingCache); 165 mProviders = new ProviderIntentResolver(userManager); 166 mReceivers = new ReceiverIntentResolver(userManager, userNeedsBadgingCache); 167 mServices = new ServiceIntentResolver(userManager); 168 mProvidersByAuthority = new ArrayMap<>(); 169 mDeferProtectedFilters = true; 170 171 mSnapshot = new SnapshotCache<>(this, this) { 172 @Override 173 public ComponentResolverApi createSnapshot() { 174 synchronized (mLock) { 175 return new ComponentResolverSnapshot(ComponentResolver.this, 176 userNeedsBadgingCache); 177 } 178 }}; 179 } 180 181 final SnapshotCache<ComponentResolverApi> mSnapshot; 182 183 /** 184 * Create a snapshot. 185 */ snapshot()186 public ComponentResolverApi snapshot() { 187 return mSnapshot.snapshot(); 188 } 189 190 /** Add all components defined in the given package to the internal structures. */ addAllComponents(AndroidPackage pkg, boolean chatty, @Nullable String setupWizardPackage, @NonNull Computer computer)191 public void addAllComponents(AndroidPackage pkg, boolean chatty, 192 @Nullable String setupWizardPackage, @NonNull Computer computer) { 193 final ArrayList<Pair<ParsedActivity, ParsedIntentInfo>> newIntents = new ArrayList<>(); 194 synchronized (mLock) { 195 addActivitiesLocked(computer, pkg, newIntents, chatty); 196 addReceiversLocked(computer, pkg, chatty); 197 addProvidersLocked(computer, pkg, chatty); 198 addServicesLocked(computer, pkg, chatty); 199 onChanged(); 200 } 201 202 for (int i = newIntents.size() - 1; i >= 0; --i) { 203 final Pair<ParsedActivity, ParsedIntentInfo> pair = newIntents.get(i); 204 final PackageStateInternal disabledPkgSetting = computer 205 .getDisabledSystemPackage(pair.first.getPackageName()); 206 final AndroidPackage disabledPkg = 207 disabledPkgSetting == null ? null : disabledPkgSetting.getPkg(); 208 final List<ParsedActivity> systemActivities = 209 disabledPkg != null ? disabledPkg.getActivities() : null; 210 adjustPriority(computer, systemActivities, pair.first, pair.second, setupWizardPackage); 211 onChanged(); 212 } 213 } 214 215 /** Removes all components defined in the given package from the internal structures. */ removeAllComponents(AndroidPackage pkg, boolean chatty)216 public void removeAllComponents(AndroidPackage pkg, boolean chatty) { 217 synchronized (mLock) { 218 removeAllComponentsLocked(pkg, chatty); 219 onChanged(); 220 } 221 } 222 223 /** 224 * Reprocess any protected filters that have been deferred. At this point, we've scanned 225 * all of the filters defined on the /system partition and know the special components. 226 */ fixProtectedFilterPriorities(@ullable String setupWizardPackage)227 public void fixProtectedFilterPriorities(@Nullable String setupWizardPackage) { 228 synchronized (mLock) { 229 if (!mDeferProtectedFilters) { 230 return; 231 } 232 mDeferProtectedFilters = false; 233 234 if (mProtectedFilters == null || mProtectedFilters.size() == 0) { 235 return; 236 } 237 final List<Pair<ParsedMainComponent, ParsedIntentInfo>> protectedFilters = 238 mProtectedFilters; 239 mProtectedFilters = null; 240 241 if (DEBUG_FILTERS && setupWizardPackage == null) { 242 Slog.i(TAG, "No setup wizard;" 243 + " All protected intents capped to priority 0"); 244 } 245 for (int i = protectedFilters.size() - 1; i >= 0; --i) { 246 final Pair<ParsedMainComponent, ParsedIntentInfo> pair = protectedFilters.get(i); 247 ParsedMainComponent component = pair.first; 248 ParsedIntentInfo intentInfo = pair.second; 249 IntentFilter filter = intentInfo.getIntentFilter(); 250 String packageName = component.getPackageName(); 251 String className = component.getClassName(); 252 if (packageName.equals(setupWizardPackage)) { 253 if (DEBUG_FILTERS) { 254 Slog.i(TAG, "Found setup wizard;" 255 + " allow priority " + filter.getPriority() + ";" 256 + " package: " + packageName 257 + " activity: " + className 258 + " priority: " + filter.getPriority()); 259 } 260 // skip setup wizard; allow it to keep the high priority filter 261 continue; 262 } 263 if (DEBUG_FILTERS) { 264 Slog.i(TAG, "Protected action; cap priority to 0;" 265 + " package: " + packageName 266 + " activity: " + className 267 + " origPrio: " + filter.getPriority()); 268 } 269 filter.setPriority(0); 270 } 271 onChanged(); 272 } 273 } 274 275 @GuardedBy("mLock") addActivitiesLocked(@onNull Computer computer, AndroidPackage pkg, List<Pair<ParsedActivity, ParsedIntentInfo>> newIntents, boolean chatty)276 private void addActivitiesLocked(@NonNull Computer computer, AndroidPackage pkg, 277 List<Pair<ParsedActivity, ParsedIntentInfo>> newIntents, boolean chatty) { 278 final int activitiesSize = ArrayUtils.size(pkg.getActivities()); 279 StringBuilder r = null; 280 for (int i = 0; i < activitiesSize; i++) { 281 ParsedActivity a = pkg.getActivities().get(i); 282 mActivities.addActivity(computer, a, "activity", newIntents); 283 if (DEBUG_PACKAGE_SCANNING && chatty) { 284 if (r == null) { 285 r = new StringBuilder(256); 286 } else { 287 r.append(' '); 288 } 289 r.append(a.getName()); 290 } 291 } 292 if (DEBUG_PACKAGE_SCANNING && chatty) { 293 Log.d(TAG, " Activities: " + (r == null ? "<NONE>" : r)); 294 } 295 } 296 297 @GuardedBy("mLock") addProvidersLocked(@onNull Computer computer, AndroidPackage pkg, boolean chatty)298 private void addProvidersLocked(@NonNull Computer computer, AndroidPackage pkg, boolean chatty) { 299 final int providersSize = ArrayUtils.size(pkg.getProviders()); 300 StringBuilder r = null; 301 for (int i = 0; i < providersSize; i++) { 302 ParsedProvider p = pkg.getProviders().get(i); 303 mProviders.addProvider(computer, p); 304 if (p.getAuthority() != null) { 305 String[] names = p.getAuthority().split(";"); 306 307 // TODO(b/135203078): Remove this mutation 308 ComponentMutateUtils.setAuthority(p, null); 309 for (int j = 0; j < names.length; j++) { 310 if (j == 1 && p.isSyncable()) { 311 // We only want the first authority for a provider to possibly be 312 // syncable, so if we already added this provider using a different 313 // authority clear the syncable flag. We copy the provider before 314 // changing it because the mProviders object contains a reference 315 // to a provider that we don't want to change. 316 // Only do this for the second authority since the resulting provider 317 // object can be the same for all future authorities for this provider. 318 p = new ParsedProviderImpl(p); 319 ComponentMutateUtils.setSyncable(p, false); 320 } 321 if (!mProvidersByAuthority.containsKey(names[j])) { 322 mProvidersByAuthority.put(names[j], p); 323 if (p.getAuthority() == null) { 324 ComponentMutateUtils.setAuthority(p, names[j]); 325 } else { 326 ComponentMutateUtils.setAuthority(p, p.getAuthority() + ";" + names[j]); 327 } 328 if (DEBUG_PACKAGE_SCANNING && chatty) { 329 Log.d(TAG, "Registered content provider: " + names[j] 330 + ", className = " + p.getName() 331 + ", isSyncable = " + p.isSyncable()); 332 } 333 } else { 334 final ParsedProvider other = 335 mProvidersByAuthority.get(names[j]); 336 final ComponentName component = 337 (other != null && other.getComponentName() != null) 338 ? other.getComponentName() : null; 339 final String packageName = 340 component != null ? component.getPackageName() : "?"; 341 Slog.w(TAG, "Skipping provider name " + names[j] 342 + " (in package " + pkg.getPackageName() + ")" 343 + ": name already used by " + packageName); 344 } 345 } 346 } 347 if (DEBUG_PACKAGE_SCANNING && chatty) { 348 if (r == null) { 349 r = new StringBuilder(256); 350 } else { 351 r.append(' '); 352 } 353 r.append(p.getName()); 354 } 355 } 356 if (DEBUG_PACKAGE_SCANNING && chatty) { 357 Log.d(TAG, " Providers: " + (r == null ? "<NONE>" : r)); 358 } 359 } 360 361 @GuardedBy("mLock") addReceiversLocked(@onNull Computer computer, AndroidPackage pkg, boolean chatty)362 private void addReceiversLocked(@NonNull Computer computer, AndroidPackage pkg, boolean chatty) { 363 final int receiversSize = ArrayUtils.size(pkg.getReceivers()); 364 StringBuilder r = null; 365 for (int i = 0; i < receiversSize; i++) { 366 ParsedActivity a = pkg.getReceivers().get(i); 367 mReceivers.addActivity(computer, a, "receiver", null); 368 if (DEBUG_PACKAGE_SCANNING && chatty) { 369 if (r == null) { 370 r = new StringBuilder(256); 371 } else { 372 r.append(' '); 373 } 374 r.append(a.getName()); 375 } 376 } 377 if (DEBUG_PACKAGE_SCANNING && chatty) { 378 Log.d(TAG, " Receivers: " + (r == null ? "<NONE>" : r)); 379 } 380 } 381 382 @GuardedBy("mLock") addServicesLocked(@onNull Computer computer, AndroidPackage pkg, boolean chatty)383 private void addServicesLocked(@NonNull Computer computer, AndroidPackage pkg, boolean chatty) { 384 final int servicesSize = ArrayUtils.size(pkg.getServices()); 385 StringBuilder r = null; 386 for (int i = 0; i < servicesSize; i++) { 387 ParsedService s = pkg.getServices().get(i); 388 mServices.addService(computer, s); 389 if (DEBUG_PACKAGE_SCANNING && chatty) { 390 if (r == null) { 391 r = new StringBuilder(256); 392 } else { 393 r.append(' '); 394 } 395 r.append(s.getName()); 396 } 397 } 398 if (DEBUG_PACKAGE_SCANNING && chatty) { 399 Log.d(TAG, " Services: " + (r == null ? "<NONE>" : r)); 400 } 401 } 402 403 /** 404 * <em>WARNING</em> for performance reasons, the passed in intentList WILL BE 405 * MODIFIED. Do not pass in a list that should not be changed. 406 */ getIntentListSubset(List<ParsedIntentInfo> intentList, Function<IntentFilter, Iterator<T>> generator, Iterator<T> searchIterator)407 private static <T> void getIntentListSubset(List<ParsedIntentInfo> intentList, 408 Function<IntentFilter, Iterator<T>> generator, Iterator<T> searchIterator) { 409 // loop through the set of actions; every one must be found in the intent filter 410 while (searchIterator.hasNext()) { 411 // we must have at least one filter in the list to consider a match 412 if (intentList.size() == 0) { 413 break; 414 } 415 416 final T searchAction = searchIterator.next(); 417 418 // loop through the set of intent filters 419 final Iterator<ParsedIntentInfo> intentIter = intentList.iterator(); 420 while (intentIter.hasNext()) { 421 final ParsedIntentInfo intentInfo = intentIter.next(); 422 boolean selectionFound = false; 423 424 // loop through the intent filter's selection criteria; at least one 425 // of them must match the searched criteria 426 final Iterator<T> intentSelectionIter = 427 generator.apply(intentInfo.getIntentFilter()); 428 while (intentSelectionIter != null && intentSelectionIter.hasNext()) { 429 final T intentSelection = intentSelectionIter.next(); 430 if (intentSelection != null && intentSelection.equals(searchAction)) { 431 selectionFound = true; 432 break; 433 } 434 } 435 436 // the selection criteria wasn't found in this filter's set; this filter 437 // is not a potential match 438 if (!selectionFound) { 439 intentIter.remove(); 440 } 441 } 442 } 443 } 444 isProtectedAction(IntentFilter filter)445 private static boolean isProtectedAction(IntentFilter filter) { 446 final Iterator<String> actionsIter = filter.actionsIterator(); 447 while (actionsIter != null && actionsIter.hasNext()) { 448 final String filterAction = actionsIter.next(); 449 if (PROTECTED_ACTIONS.contains(filterAction)) { 450 return true; 451 } 452 } 453 return false; 454 } 455 456 /** 457 * Finds a privileged activity that matches the specified activity names. 458 */ findMatchingActivity( List<ParsedActivity> activityList, ParsedActivity activityInfo)459 private static ParsedActivity findMatchingActivity( 460 List<ParsedActivity> activityList, ParsedActivity activityInfo) { 461 for (ParsedActivity sysActivity : activityList) { 462 if (sysActivity.getName().equals(activityInfo.getName())) { 463 return sysActivity; 464 } 465 if (sysActivity.getName().equals(activityInfo.getTargetActivity())) { 466 return sysActivity; 467 } 468 if (sysActivity.getTargetActivity() != null) { 469 if (sysActivity.getTargetActivity().equals(activityInfo.getName())) { 470 return sysActivity; 471 } 472 if (sysActivity.getTargetActivity().equals(activityInfo.getTargetActivity())) { 473 return sysActivity; 474 } 475 } 476 } 477 return null; 478 } 479 480 /** 481 * Adjusts the priority of the given intent filter according to policy. 482 * <p> 483 * <ul> 484 * <li>The priority for non privileged applications is capped to '0'</li> 485 * <li>The priority for protected actions on privileged applications is capped to '0'</li> 486 * <li>The priority for unbundled updates to privileged applications is capped to the 487 * priority defined on the system partition</li> 488 * </ul> 489 * <p> 490 * <em>NOTE:</em> There is one exception. For security reasons, the setup wizard is 491 * allowed to obtain any priority on any action. 492 */ adjustPriority(@onNull Computer computer, List<ParsedActivity> systemActivities, ParsedActivity activity, ParsedIntentInfo intentInfo, String setupWizardPackage)493 private void adjustPriority(@NonNull Computer computer, List<ParsedActivity> systemActivities, 494 ParsedActivity activity, ParsedIntentInfo intentInfo, String setupWizardPackage) { 495 // nothing to do; priority is fine as-is 496 IntentFilter intentFilter = intentInfo.getIntentFilter(); 497 if (intentFilter.getPriority() <= 0) { 498 return; 499 } 500 501 String packageName = activity.getPackageName(); 502 var packageState = computer.getPackageStateInternal(packageName); 503 504 final boolean privilegedApp = packageState.isPrivileged(); 505 String className = activity.getClassName(); 506 if (!privilegedApp) { 507 // non-privileged applications can never define a priority >0 508 if (DEBUG_FILTERS) { 509 Slog.i(TAG, "Non-privileged app; cap priority to 0;" 510 + " package: " + packageName 511 + " activity: " + className 512 + " origPrio: " + intentFilter.getPriority()); 513 } 514 intentFilter.setPriority(0); 515 return; 516 } 517 518 if (isProtectedAction(intentFilter)) { 519 if (mDeferProtectedFilters) { 520 // We can't deal with these just yet. No component should ever obtain a 521 // >0 priority for a protected actions, with ONE exception -- the setup 522 // wizard. The setup wizard, however, cannot be known until we're able to 523 // query it for the category CATEGORY_SETUP_WIZARD. Which we can't do 524 // until all intent filters have been processed. Chicken, meet egg. 525 // Let the filter temporarily have a high priority and rectify the 526 // priorities after all system packages have been scanned. 527 if (mProtectedFilters == null) { 528 mProtectedFilters = new ArrayList<>(); 529 } 530 mProtectedFilters.add(Pair.create(activity, intentInfo)); 531 if (DEBUG_FILTERS) { 532 Slog.i(TAG, "Protected action; save for later;" 533 + " package: " + packageName 534 + " activity: " + className 535 + " origPrio: " + intentFilter.getPriority()); 536 } 537 } else { 538 if (DEBUG_FILTERS && setupWizardPackage == null) { 539 Slog.i(TAG, "No setup wizard;" 540 + " All protected intents capped to priority 0"); 541 } 542 if (packageName.equals(setupWizardPackage)) { 543 if (DEBUG_FILTERS) { 544 Slog.i(TAG, "Found setup wizard;" 545 + " allow priority " + intentFilter.getPriority() + ";" 546 + " package: " + packageName 547 + " activity: " + className 548 + " priority: " + intentFilter.getPriority()); 549 } 550 // setup wizard gets whatever it wants 551 return; 552 } 553 if (DEBUG_FILTERS) { 554 Slog.i(TAG, "Protected action; cap priority to 0;" 555 + " package: " + packageName 556 + " activity: " + className 557 + " origPrio: " + intentFilter.getPriority()); 558 } 559 intentFilter.setPriority(0); 560 } 561 return; 562 } 563 564 if (systemActivities == null) { 565 // the system package is not disabled; we're parsing the system partition 566 567 // privileged apps on the system image get whatever priority they request 568 return; 569 } 570 571 // privileged app unbundled update ... try to find the same activity 572 573 ParsedActivity foundActivity = findMatchingActivity(systemActivities, activity); 574 if (foundActivity == null) { 575 // this is a new activity; it cannot obtain >0 priority 576 if (DEBUG_FILTERS) { 577 Slog.i(TAG, "New activity; cap priority to 0;" 578 + " package: " + packageName 579 + " activity: " + className 580 + " origPrio: " + intentFilter.getPriority()); 581 } 582 intentFilter.setPriority(0); 583 return; 584 } 585 586 // found activity, now check for filter equivalence 587 588 // a shallow copy is enough; we modify the list, not its contents 589 final List<ParsedIntentInfo> intentListCopy = 590 new ArrayList<>(foundActivity.getIntents()); 591 592 // find matching action subsets 593 final Iterator<String> actionsIterator = intentFilter.actionsIterator(); 594 if (actionsIterator != null) { 595 getIntentListSubset(intentListCopy, IntentFilter::actionsIterator, actionsIterator); 596 if (intentListCopy.size() == 0) { 597 // no more intents to match; we're not equivalent 598 if (DEBUG_FILTERS) { 599 Slog.i(TAG, "Mismatched action; cap priority to 0;" 600 + " package: " + packageName 601 + " activity: " + className 602 + " origPrio: " + intentFilter.getPriority()); 603 } 604 intentFilter.setPriority(0); 605 return; 606 } 607 } 608 609 // find matching category subsets 610 final Iterator<String> categoriesIterator = intentFilter.categoriesIterator(); 611 if (categoriesIterator != null) { 612 getIntentListSubset(intentListCopy, IntentFilter::categoriesIterator, 613 categoriesIterator); 614 if (intentListCopy.size() == 0) { 615 // no more intents to match; we're not equivalent 616 if (DEBUG_FILTERS) { 617 Slog.i(TAG, "Mismatched category; cap priority to 0;" 618 + " package: " + packageName 619 + " activity: " + className 620 + " origPrio: " + intentFilter.getPriority()); 621 } 622 intentFilter.setPriority(0); 623 return; 624 } 625 } 626 627 // find matching schemes subsets 628 final Iterator<String> schemesIterator = intentFilter.schemesIterator(); 629 if (schemesIterator != null) { 630 getIntentListSubset(intentListCopy, IntentFilter::schemesIterator, schemesIterator); 631 if (intentListCopy.size() == 0) { 632 // no more intents to match; we're not equivalent 633 if (DEBUG_FILTERS) { 634 Slog.i(TAG, "Mismatched scheme; cap priority to 0;" 635 + " package: " + packageName 636 + " activity: " + className 637 + " origPrio: " + intentFilter.getPriority()); 638 } 639 intentFilter.setPriority(0); 640 return; 641 } 642 } 643 644 // find matching authorities subsets 645 final Iterator<IntentFilter.AuthorityEntry> authoritiesIterator = 646 intentFilter.authoritiesIterator(); 647 if (authoritiesIterator != null) { 648 getIntentListSubset(intentListCopy, IntentFilter::authoritiesIterator, 649 authoritiesIterator); 650 if (intentListCopy.size() == 0) { 651 // no more intents to match; we're not equivalent 652 if (DEBUG_FILTERS) { 653 Slog.i(TAG, "Mismatched authority; cap priority to 0;" 654 + " package: " + packageName 655 + " activity: " + className 656 + " origPrio: " + intentFilter.getPriority()); 657 } 658 intentFilter.setPriority(0); 659 return; 660 } 661 } 662 663 // we found matching filter(s); app gets the max priority of all intents 664 int cappedPriority = 0; 665 for (int i = intentListCopy.size() - 1; i >= 0; --i) { 666 cappedPriority = Math.max(cappedPriority, 667 intentListCopy.get(i).getIntentFilter().getPriority()); 668 } 669 if (intentFilter.getPriority() > cappedPriority) { 670 if (DEBUG_FILTERS) { 671 Slog.i(TAG, "Found matching filter(s);" 672 + " cap priority to " + cappedPriority + ";" 673 + " package: " + packageName 674 + " activity: " + className 675 + " origPrio: " + intentFilter.getPriority()); 676 } 677 intentFilter.setPriority(cappedPriority); 678 return; 679 } 680 // all this for nothing; the requested priority was <= what was on the system 681 } 682 683 @GuardedBy("mLock") removeAllComponentsLocked(AndroidPackage pkg, boolean chatty)684 private void removeAllComponentsLocked(AndroidPackage pkg, boolean chatty) { 685 int componentSize; 686 StringBuilder r; 687 int i; 688 689 componentSize = ArrayUtils.size(pkg.getActivities()); 690 r = null; 691 for (i = 0; i < componentSize; i++) { 692 ParsedActivity a = pkg.getActivities().get(i); 693 mActivities.removeActivity(a, "activity"); 694 if (DEBUG_REMOVE && chatty) { 695 if (r == null) { 696 r = new StringBuilder(256); 697 } else { 698 r.append(' '); 699 } 700 r.append(a.getName()); 701 } 702 } 703 if (DEBUG_REMOVE && chatty) { 704 Log.d(TAG, " Activities: " + (r == null ? "<NONE>" : r)); 705 } 706 707 componentSize = ArrayUtils.size(pkg.getProviders()); 708 r = null; 709 for (i = 0; i < componentSize; i++) { 710 ParsedProvider p = pkg.getProviders().get(i); 711 mProviders.removeProvider(p); 712 if (p.getAuthority() == null) { 713 // Another content provider with this authority existed when this app was 714 // installed, so this authority is null. Ignore it as we don't have to 715 // unregister the provider. 716 continue; 717 } 718 String[] names = p.getAuthority().split(";"); 719 for (int j = 0; j < names.length; j++) { 720 if (mProvidersByAuthority.get(names[j]) == p) { 721 mProvidersByAuthority.remove(names[j]); 722 if (DEBUG_REMOVE && chatty) { 723 Log.d(TAG, "Unregistered content provider: " + names[j] 724 + ", className = " + p.getName() + ", isSyncable = " 725 + p.isSyncable()); 726 } 727 } 728 } 729 if (DEBUG_REMOVE && chatty) { 730 if (r == null) { 731 r = new StringBuilder(256); 732 } else { 733 r.append(' '); 734 } 735 r.append(p.getName()); 736 } 737 } 738 if (DEBUG_REMOVE && chatty) { 739 Log.d(TAG, " Providers: " + (r == null ? "<NONE>" : r)); 740 } 741 742 componentSize = ArrayUtils.size(pkg.getReceivers()); 743 r = null; 744 for (i = 0; i < componentSize; i++) { 745 ParsedActivity a = pkg.getReceivers().get(i); 746 mReceivers.removeActivity(a, "receiver"); 747 if (DEBUG_REMOVE && chatty) { 748 if (r == null) { 749 r = new StringBuilder(256); 750 } else { 751 r.append(' '); 752 } 753 r.append(a.getName()); 754 } 755 } 756 if (DEBUG_REMOVE && chatty) { 757 Log.d(TAG, " Receivers: " + (r == null ? "<NONE>" : r)); 758 } 759 760 componentSize = ArrayUtils.size(pkg.getServices()); 761 r = null; 762 for (i = 0; i < componentSize; i++) { 763 ParsedService s = pkg.getServices().get(i); 764 mServices.removeService(s); 765 if (DEBUG_REMOVE && chatty) { 766 if (r == null) { 767 r = new StringBuilder(256); 768 } else { 769 r.append(' '); 770 } 771 r.append(s.getName()); 772 } 773 } 774 if (DEBUG_REMOVE && chatty) { 775 Log.d(TAG, " Services: " + (r == null ? "<NONE>" : r)); 776 } 777 } 778 779 /** Asserts none of the providers defined in the given package haven't already been defined. */ assertProvidersNotDefined(@onNull AndroidPackage pkg)780 public void assertProvidersNotDefined(@NonNull AndroidPackage pkg) 781 throws PackageManagerException { 782 synchronized (mLock) { 783 final int providersSize = ArrayUtils.size(pkg.getProviders()); 784 int i; 785 for (i = 0; i < providersSize; i++) { 786 ParsedProvider p = pkg.getProviders().get(i); 787 if (p.getAuthority() != null) { 788 final String[] names = p.getAuthority().split(";"); 789 for (int j = 0; j < names.length; j++) { 790 if (mProvidersByAuthority.containsKey(names[j])) { 791 final ParsedProvider other = mProvidersByAuthority.get(names[j]); 792 final String otherPackageName = 793 (other != null && other.getComponentName() != null) 794 ? other.getComponentName().getPackageName() : "?"; 795 // if installing over the same already-installed package,this is ok 796 if (!otherPackageName.equals(pkg.getPackageName())) { 797 throw new PackageManagerException( 798 INSTALL_FAILED_CONFLICTING_PROVIDER, 799 "Can't install because provider name " + names[j] 800 + " (in package " + pkg.getPackageName() 801 + ") is already used by " + otherPackageName); 802 } 803 } 804 } 805 } 806 } 807 } 808 } 809 810 private abstract static class MimeGroupsAwareIntentResolver<F extends Pair<? 811 extends ParsedComponent, ParsedIntentInfo>, R> 812 extends IntentResolver<F, R> { 813 private final ArrayMap<String, F[]> mMimeGroupToFilter = new ArrayMap<>(); 814 private boolean mIsUpdatingMimeGroup = false; 815 816 @NonNull 817 protected final UserManagerService mUserManager; 818 819 // Default constructor MimeGroupsAwareIntentResolver(@onNull UserManagerService userManager)820 MimeGroupsAwareIntentResolver(@NonNull UserManagerService userManager) { 821 mUserManager = userManager; 822 } 823 824 // Copy constructor used in creating snapshots MimeGroupsAwareIntentResolver(MimeGroupsAwareIntentResolver<F, R> orig, @NonNull UserManagerService userManager)825 MimeGroupsAwareIntentResolver(MimeGroupsAwareIntentResolver<F, R> orig, 826 @NonNull UserManagerService userManager) { 827 mUserManager = userManager; 828 copyFrom(orig); 829 copyInto(mMimeGroupToFilter, orig.mMimeGroupToFilter); 830 mIsUpdatingMimeGroup = orig.mIsUpdatingMimeGroup; 831 } 832 833 @Override addFilter(@ullable PackageDataSnapshot snapshot, F f)834 public void addFilter(@Nullable PackageDataSnapshot snapshot, F f) { 835 IntentFilter intentFilter = getIntentFilter(f); 836 // We assume Computer is available for this class and all subclasses. Because this class 837 // uses subclass method override to handle logic, the Computer parameter must be in the 838 // base, leading to this odd nullability. 839 applyMimeGroups((Computer) snapshot, f); 840 super.addFilter(snapshot, f); 841 842 if (!mIsUpdatingMimeGroup) { 843 register_intent_filter(f, intentFilter.mimeGroupsIterator(), mMimeGroupToFilter, 844 " MimeGroup: "); 845 } 846 } 847 848 @Override removeFilterInternal(F f)849 protected void removeFilterInternal(F f) { 850 IntentFilter intentFilter = getIntentFilter(f); 851 if (!mIsUpdatingMimeGroup) { 852 unregister_intent_filter(f, intentFilter.mimeGroupsIterator(), mMimeGroupToFilter, 853 " MimeGroup: "); 854 } 855 856 super.removeFilterInternal(f); 857 intentFilter.clearDynamicDataTypes(); 858 } 859 860 /** 861 * Updates MIME group by applying changes to all IntentFilters 862 * that contain the group and repopulating m*ToFilter maps accordingly 863 * 864 * @param packageName package to which MIME group belongs 865 * @param mimeGroup MIME group to update 866 * @return true, if any intent filters were changed due to this update 867 */ updateMimeGroup(@onNull Computer computer, String packageName, String mimeGroup)868 public boolean updateMimeGroup(@NonNull Computer computer, String packageName, 869 String mimeGroup) { 870 F[] filters = mMimeGroupToFilter.get(mimeGroup); 871 int n = filters != null ? filters.length : 0; 872 873 mIsUpdatingMimeGroup = true; 874 boolean hasChanges = false; 875 F filter; 876 for (int i = 0; i < n && (filter = filters[i]) != null; i++) { 877 if (isPackageForFilter(packageName, filter)) { 878 hasChanges |= updateFilter(computer, filter); 879 } 880 } 881 mIsUpdatingMimeGroup = false; 882 return hasChanges; 883 } 884 updateFilter(@onNull Computer computer, F f)885 private boolean updateFilter(@NonNull Computer computer, F f) { 886 IntentFilter filter = getIntentFilter(f); 887 List<String> oldTypes = filter.dataTypes(); 888 removeFilter(f); 889 addFilter(computer, f); 890 List<String> newTypes = filter.dataTypes(); 891 return !equalLists(oldTypes, newTypes); 892 } 893 equalLists(List<String> first, List<String> second)894 private boolean equalLists(List<String> first, List<String> second) { 895 if (first == null) { 896 return second == null; 897 } else if (second == null) { 898 return false; 899 } 900 901 if (first.size() != second.size()) { 902 return false; 903 } 904 905 Collections.sort(first); 906 Collections.sort(second); 907 return first.equals(second); 908 } 909 applyMimeGroups(@onNull Computer computer, F f)910 private void applyMimeGroups(@NonNull Computer computer, F f) { 911 IntentFilter filter = getIntentFilter(f); 912 913 for (int i = filter.countMimeGroups() - 1; i >= 0; i--) { 914 final PackageStateInternal packageState = computer.getPackageStateInternal( 915 f.first.getPackageName()); 916 917 Collection<String> mimeTypes = packageState == null 918 ? Collections.emptyList() : packageState.getMimeGroups() 919 .get(filter.getMimeGroup(i)); 920 921 for (String mimeType : mimeTypes) { 922 try { 923 filter.addDynamicDataType(mimeType); 924 } catch (IntentFilter.MalformedMimeTypeException e) { 925 if (DEBUG) { 926 Slog.w(TAG, "Malformed mime type: " + mimeType, e); 927 } 928 } 929 } 930 } 931 } 932 933 @Override isFilterStopped(@onNull Computer computer, F filter, @UserIdInt int userId)934 protected boolean isFilterStopped(@NonNull Computer computer, F filter, 935 @UserIdInt int userId) { 936 if (!mUserManager.exists(userId)) { 937 return true; 938 } 939 940 final PackageStateInternal packageState = computer.getPackageStateInternal( 941 filter.first.getPackageName()); 942 if (packageState == null || packageState.getPkg() == null) { 943 return false; 944 } 945 946 return packageState.getUserStateOrDefault(userId).isStopped(); 947 } 948 } 949 950 public static class ActivityIntentResolver 951 extends MimeGroupsAwareIntentResolver<Pair<ParsedActivity, ParsedIntentInfo>, ResolveInfo> { 952 953 @NonNull 954 private UserNeedsBadgingCache mUserNeedsBadging; 955 956 // Default constructor ActivityIntentResolver(@onNull UserManagerService userManager, @NonNull UserNeedsBadgingCache userNeedsBadgingCache)957 ActivityIntentResolver(@NonNull UserManagerService userManager, 958 @NonNull UserNeedsBadgingCache userNeedsBadgingCache) { 959 super(userManager); 960 mUserNeedsBadging = userNeedsBadgingCache; 961 } 962 963 // Copy constructor used in creating snapshots ActivityIntentResolver(@onNull ActivityIntentResolver orig, @NonNull UserManagerService userManager, @NonNull UserNeedsBadgingCache userNeedsBadgingCache)964 ActivityIntentResolver(@NonNull ActivityIntentResolver orig, 965 @NonNull UserManagerService userManager, 966 @NonNull UserNeedsBadgingCache userNeedsBadgingCache) { 967 super(orig, userManager); 968 mActivities.putAll(orig.mActivities); 969 mUserNeedsBadging = userNeedsBadgingCache; 970 } 971 972 @Override queryIntent(@onNull PackageDataSnapshot snapshot, Intent intent, String resolvedType, boolean defaultOnly, @UserIdInt int userId)973 public List<ResolveInfo> queryIntent(@NonNull PackageDataSnapshot snapshot, Intent intent, 974 String resolvedType, boolean defaultOnly, @UserIdInt int userId) { 975 if (!mUserManager.exists(userId)) return null; 976 long flags = (defaultOnly ? PackageManager.MATCH_DEFAULT_ONLY : 0); 977 return super.queryIntent(snapshot, intent, resolvedType, defaultOnly, userId, flags); 978 } 979 queryIntent(@onNull Computer computer, Intent intent, String resolvedType, long flags, int userId)980 List<ResolveInfo> queryIntent(@NonNull Computer computer, Intent intent, 981 String resolvedType, long flags, int userId) { 982 if (!mUserManager.exists(userId)) { 983 return null; 984 } 985 return super.queryIntent(computer, intent, resolvedType, 986 (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0, userId, flags); 987 } 988 queryIntentForPackage(@onNull Computer computer, Intent intent, String resolvedType, long flags, List<ParsedActivity> packageActivities, int userId)989 List<ResolveInfo> queryIntentForPackage(@NonNull Computer computer, Intent intent, 990 String resolvedType, long flags, List<ParsedActivity> packageActivities, 991 int userId) { 992 if (!mUserManager.exists(userId)) { 993 return null; 994 } 995 if (packageActivities == null) { 996 return Collections.emptyList(); 997 } 998 final boolean defaultOnly = (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0; 999 final int activitiesSize = packageActivities.size(); 1000 ArrayList<Pair<ParsedActivity, ParsedIntentInfo>[]> listCut = 1001 new ArrayList<>(activitiesSize); 1002 1003 List<ParsedIntentInfo> intentFilters; 1004 for (int i = 0; i < activitiesSize; ++i) { 1005 ParsedActivity activity = packageActivities.get(i); 1006 intentFilters = activity.getIntents(); 1007 if (!intentFilters.isEmpty()) { 1008 Pair<ParsedActivity, ParsedIntentInfo>[] array = newArray(intentFilters.size()); 1009 for (int arrayIndex = 0; arrayIndex < intentFilters.size(); arrayIndex++) { 1010 array[arrayIndex] = Pair.create(activity, intentFilters.get(arrayIndex)); 1011 } 1012 listCut.add(array); 1013 } 1014 } 1015 return super.queryIntentFromList(computer, intent, resolvedType, 1016 defaultOnly, listCut, userId, flags); 1017 } 1018 addActivity(@onNull Computer computer, ParsedActivity a, String type, List<Pair<ParsedActivity, ParsedIntentInfo>> newIntents)1019 protected void addActivity(@NonNull Computer computer, ParsedActivity a, String type, 1020 List<Pair<ParsedActivity, ParsedIntentInfo>> newIntents) { 1021 mActivities.put(a.getComponentName(), a); 1022 if (DEBUG_SHOW_INFO) { 1023 Log.v(TAG, " " + type + ":"); 1024 Log.v(TAG, " Class=" + a.getName()); 1025 } 1026 final int intentsSize = a.getIntents().size(); 1027 for (int j = 0; j < intentsSize; j++) { 1028 ParsedIntentInfo intent = a.getIntents().get(j); 1029 IntentFilter intentFilter = intent.getIntentFilter(); 1030 if (newIntents != null && "activity".equals(type)) { 1031 newIntents.add(Pair.create(a, intent)); 1032 } 1033 if (DEBUG_SHOW_INFO) { 1034 Log.v(TAG, " IntentFilter:"); 1035 intentFilter.dump(new LogPrinter(Log.VERBOSE, TAG), " "); 1036 } 1037 if (!intentFilter.debugCheck()) { 1038 Log.w(TAG, "==> For Activity " + a.getName()); 1039 } 1040 addFilter(computer, Pair.create(a, intent)); 1041 } 1042 } 1043 removeActivity(ParsedActivity a, String type)1044 protected void removeActivity(ParsedActivity a, String type) { 1045 mActivities.remove(a.getComponentName()); 1046 if (DEBUG_SHOW_INFO) { 1047 Log.v(TAG, " " + type + ":"); 1048 Log.v(TAG, " Class=" + a.getName()); 1049 } 1050 final int intentsSize = a.getIntents().size(); 1051 for (int j = 0; j < intentsSize; j++) { 1052 ParsedIntentInfo intent = a.getIntents().get(j); 1053 IntentFilter intentFilter = intent.getIntentFilter(); 1054 if (DEBUG_SHOW_INFO) { 1055 Log.v(TAG, " IntentFilter:"); 1056 intentFilter.dump(new LogPrinter(Log.VERBOSE, TAG), " "); 1057 } 1058 removeFilter(Pair.create(a, intent)); 1059 } 1060 } 1061 1062 @Override allowFilterResult(Pair<ParsedActivity, ParsedIntentInfo> filter, List<ResolveInfo> dest)1063 protected boolean allowFilterResult(Pair<ParsedActivity, ParsedIntentInfo> filter, 1064 List<ResolveInfo> dest) { 1065 for (int i = dest.size() - 1; i >= 0; --i) { 1066 ActivityInfo destAi = dest.get(i).activityInfo; 1067 if (Objects.equals(destAi.name, filter.first.getName()) 1068 && Objects.equals(destAi.packageName, filter.first.getPackageName())) { 1069 return false; 1070 } 1071 } 1072 return true; 1073 } 1074 1075 @Override newArray(int size)1076 protected Pair<ParsedActivity, ParsedIntentInfo>[] newArray(int size) { 1077 //noinspection unchecked 1078 return (Pair<ParsedActivity, ParsedIntentInfo>[]) new Pair<?, ?>[size]; 1079 } 1080 1081 @Override isPackageForFilter(String packageName, Pair<ParsedActivity, ParsedIntentInfo> info)1082 protected boolean isPackageForFilter(String packageName, 1083 Pair<ParsedActivity, ParsedIntentInfo> info) { 1084 return packageName.equals(info.first.getPackageName()); 1085 } 1086 log(String reason, ParsedIntentInfo info, int match, int userId)1087 private void log(String reason, ParsedIntentInfo info, int match, 1088 int userId) { 1089 Slog.w(TAG, reason 1090 + "; match: " 1091 + DebugUtils.flagsToString(IntentFilter.class, "MATCH_", match) 1092 + "; userId: " + userId 1093 + "; intent info: " + info); 1094 } 1095 1096 @Override newResult(@onNull Computer computer, Pair<ParsedActivity, ParsedIntentInfo> pair, int match, int userId, long customFlags)1097 protected ResolveInfo newResult(@NonNull Computer computer, 1098 Pair<ParsedActivity, ParsedIntentInfo> pair, int match, int userId, 1099 long customFlags) { 1100 ParsedActivity activity = pair.first; 1101 ParsedIntentInfo info = pair.second; 1102 IntentFilter intentFilter = info.getIntentFilter(); 1103 1104 if (!mUserManager.exists(userId)) { 1105 if (DEBUG) { 1106 log("User doesn't exist", info, match, userId); 1107 } 1108 return null; 1109 } 1110 1111 final PackageStateInternal packageState = 1112 computer.getPackageStateInternal(activity.getPackageName()); 1113 if (packageState == null || packageState.getPkg() == null 1114 || !PackageStateUtils.isEnabledAndMatches(packageState, activity, customFlags, 1115 userId)) { 1116 if (DEBUG) { 1117 log("!PackageManagerInternal.isEnabledAndMatches; flags=" 1118 + DebugUtils.flagsToString(PackageManager.class, "MATCH_", customFlags), 1119 info, match, userId); 1120 } 1121 return null; 1122 } 1123 final PackageUserStateInternal userState = packageState.getUserStateOrDefault(userId); 1124 ActivityInfo ai = PackageInfoUtils.generateActivityInfo(packageState.getPkg(), activity, 1125 customFlags, userState, userId, packageState); 1126 if (ai == null) { 1127 if (DEBUG) { 1128 log("Failed to create ActivityInfo based on " + activity, info, match, 1129 userId); 1130 } 1131 return null; 1132 } 1133 final boolean matchExplicitlyVisibleOnly = 1134 (customFlags & PackageManager.MATCH_EXPLICITLY_VISIBLE_ONLY) != 0; 1135 final boolean matchVisibleToInstantApp = 1136 (customFlags & PackageManager.MATCH_VISIBLE_TO_INSTANT_APP_ONLY) != 0; 1137 final boolean componentVisible = 1138 matchVisibleToInstantApp 1139 && intentFilter.isVisibleToInstantApp() 1140 && (!matchExplicitlyVisibleOnly 1141 || intentFilter.isExplicitlyVisibleToInstantApp()); 1142 final boolean matchInstantApp = (customFlags & PackageManager.MATCH_INSTANT) != 0; 1143 // throw out filters that aren't visible to ephemeral apps 1144 if (matchVisibleToInstantApp && !(componentVisible || userState.isInstantApp())) { 1145 if (DEBUG) { 1146 log("Filter(s) not visible to ephemeral apps" 1147 + "; matchVisibleToInstantApp=" + matchVisibleToInstantApp 1148 + "; matchInstantApp=" + matchInstantApp 1149 + "; info.isVisibleToInstantApp()=" 1150 + intentFilter.isVisibleToInstantApp() 1151 + "; matchExplicitlyVisibleOnly=" + matchExplicitlyVisibleOnly 1152 + "; info.isExplicitlyVisibleToInstantApp()=" 1153 + intentFilter.isExplicitlyVisibleToInstantApp(), 1154 info, match, userId); 1155 } 1156 return null; 1157 } 1158 // throw out instant app filters if we're not explicitly requesting them 1159 if (!matchInstantApp && userState.isInstantApp()) { 1160 if (DEBUG) { 1161 log("Instant app filter is not explicitly requested", info, match, userId); 1162 } 1163 return null; 1164 } 1165 // throw out instant app filters if updates are available; will trigger 1166 // instant app resolution 1167 if (userState.isInstantApp() && packageState.isUpdateAvailable()) { 1168 if (DEBUG) { 1169 log("Instant app update is available", info, match, userId); 1170 } 1171 return null; 1172 } 1173 final ResolveInfo res = 1174 new ResolveInfo(intentFilter.hasCategory(Intent.CATEGORY_BROWSABLE)); 1175 res.activityInfo = ai; 1176 if ((customFlags & PackageManager.GET_RESOLVED_FILTER) != 0) { 1177 res.filter = intentFilter; 1178 } 1179 res.handleAllWebDataURI = intentFilter.handleAllWebDataURI(); 1180 res.priority = intentFilter.getPriority(); 1181 // TODO(b/135203078): This field was unwritten and does nothing 1182 // res.preferredOrder = pkg.getPreferredOrder(); 1183 //System.out.println("Result: " + res.activityInfo.className + 1184 // " = " + res.priority); 1185 res.match = match; 1186 res.isDefault = info.isHasDefault(); 1187 res.labelRes = info.getLabelRes(); 1188 res.nonLocalizedLabel = info.getNonLocalizedLabel(); 1189 if (mUserNeedsBadging.get(userId)) { 1190 res.noResourceId = true; 1191 } else { 1192 res.icon = info.getIcon(); 1193 } 1194 res.iconResourceId = info.getIcon(); 1195 res.system = res.activityInfo.applicationInfo.isSystemApp(); 1196 res.isInstantAppAvailable = userState.isInstantApp(); 1197 res.userHandle = UserHandle.of(userId); 1198 return res; 1199 } 1200 1201 @Override sortResults(List<ResolveInfo> results)1202 protected void sortResults(List<ResolveInfo> results) { 1203 results.sort(RESOLVE_PRIORITY_SORTER); 1204 } 1205 1206 @Override dumpFilter(PrintWriter out, String prefix, Pair<ParsedActivity, ParsedIntentInfo> pair)1207 protected void dumpFilter(PrintWriter out, String prefix, 1208 Pair<ParsedActivity, ParsedIntentInfo> pair) { 1209 ParsedActivity activity = pair.first; 1210 ParsedIntentInfo filter = pair.second; 1211 1212 out.print(prefix); 1213 out.print(Integer.toHexString(System.identityHashCode(activity))); 1214 out.print(' '); 1215 ComponentName.printShortString(out, activity.getPackageName(), 1216 activity.getClassName()); 1217 out.print(" filter "); 1218 out.println(Integer.toHexString(System.identityHashCode(filter))); 1219 } 1220 1221 @Override filterToLabel(Pair<ParsedActivity, ParsedIntentInfo> filter)1222 protected Object filterToLabel(Pair<ParsedActivity, ParsedIntentInfo> filter) { 1223 return filter; 1224 } 1225 dumpFilterLabel(PrintWriter out, String prefix, Object label, int count)1226 protected void dumpFilterLabel(PrintWriter out, String prefix, Object label, int count) { 1227 @SuppressWarnings("unchecked") Pair<ParsedActivity, ParsedIntentInfo> pair = 1228 (Pair<ParsedActivity, ParsedIntentInfo>) label; 1229 out.print(prefix); 1230 out.print(Integer.toHexString(System.identityHashCode(pair.first))); 1231 out.print(' '); 1232 ComponentName.printShortString(out, pair.first.getPackageName(), 1233 pair.first.getClassName()); 1234 if (count > 1) { 1235 out.print(" ("); out.print(count); out.print(" filters)"); 1236 } 1237 out.println(); 1238 } 1239 1240 @Override getIntentFilter( @onNull Pair<ParsedActivity, ParsedIntentInfo> input)1241 protected IntentFilter getIntentFilter( 1242 @NonNull Pair<ParsedActivity, ParsedIntentInfo> input) { 1243 return input.second.getIntentFilter(); 1244 } 1245 getResolveList(AndroidPackage pkg)1246 protected List<ParsedActivity> getResolveList(AndroidPackage pkg) { 1247 return pkg.getActivities(); 1248 } 1249 1250 // Keys are String (activity class name), values are Activity. This attribute is 1251 // protected because it is accessed directly from ComponentResolver. That works 1252 // even if the attribute is private, but fails for subclasses of 1253 // ActivityIntentResolver. 1254 protected final ArrayMap<ComponentName, ParsedActivity> mActivities = 1255 new ArrayMap<>(); 1256 } 1257 1258 // Both receivers and activities share a class, but point to different get methods 1259 public static final class ReceiverIntentResolver extends ActivityIntentResolver { 1260 1261 // Default constructor ReceiverIntentResolver(@onNull UserManagerService userManager, @NonNull UserNeedsBadgingCache userNeedsBadgingCache)1262 ReceiverIntentResolver(@NonNull UserManagerService userManager, 1263 @NonNull UserNeedsBadgingCache userNeedsBadgingCache) { 1264 super(userManager, userNeedsBadgingCache); 1265 } 1266 1267 // Copy constructor used in creating snapshots ReceiverIntentResolver(@onNull ReceiverIntentResolver orig, @NonNull UserManagerService userManager, @NonNull UserNeedsBadgingCache userNeedsBadgingCache)1268 ReceiverIntentResolver(@NonNull ReceiverIntentResolver orig, 1269 @NonNull UserManagerService userManager, 1270 @NonNull UserNeedsBadgingCache userNeedsBadgingCache) { 1271 super(orig, userManager, userNeedsBadgingCache); 1272 } 1273 1274 @Override getResolveList(AndroidPackage pkg)1275 protected List<ParsedActivity> getResolveList(AndroidPackage pkg) { 1276 return pkg.getReceivers(); 1277 } 1278 } 1279 1280 public static final class ProviderIntentResolver 1281 extends MimeGroupsAwareIntentResolver<Pair<ParsedProvider, ParsedIntentInfo>, ResolveInfo> { 1282 // Default constructor ProviderIntentResolver(@onNull UserManagerService userManager)1283 ProviderIntentResolver(@NonNull UserManagerService userManager) { 1284 super(userManager); 1285 } 1286 1287 // Copy constructor used in creating snapshots ProviderIntentResolver(@onNull ProviderIntentResolver orig, @NonNull UserManagerService userManager)1288 ProviderIntentResolver(@NonNull ProviderIntentResolver orig, 1289 @NonNull UserManagerService userManager) { 1290 super(orig, userManager); 1291 mProviders.putAll(orig.mProviders); 1292 } 1293 1294 @Override queryIntent(@onNull PackageDataSnapshot snapshot, Intent intent, String resolvedType, boolean defaultOnly, @UserIdInt int userId)1295 public List<ResolveInfo> queryIntent(@NonNull PackageDataSnapshot snapshot, Intent intent, 1296 String resolvedType, boolean defaultOnly, @UserIdInt int userId) { 1297 if (!mUserManager.exists(userId)) { 1298 return null; 1299 } 1300 long flags = defaultOnly ? PackageManager.MATCH_DEFAULT_ONLY : 0; 1301 return super.queryIntent(snapshot, intent, resolvedType, defaultOnly, userId, flags); 1302 } 1303 1304 @Nullable queryIntent(@onNull Computer computer, Intent intent, String resolvedType, long flags, int userId)1305 List<ResolveInfo> queryIntent(@NonNull Computer computer, Intent intent, 1306 String resolvedType, long flags, int userId) { 1307 if (!mUserManager.exists(userId)) { 1308 return null; 1309 } 1310 return super.queryIntent(computer, intent, resolvedType, 1311 (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0, userId, flags); 1312 } 1313 1314 @Nullable queryIntentForPackage(@onNull Computer computer, Intent intent, String resolvedType, long flags, List<ParsedProvider> packageProviders, int userId)1315 List<ResolveInfo> queryIntentForPackage(@NonNull Computer computer, Intent intent, 1316 String resolvedType, long flags, List<ParsedProvider> packageProviders, 1317 int userId) { 1318 if (!mUserManager.exists(userId)) { 1319 return null; 1320 } 1321 if (packageProviders == null) { 1322 return Collections.emptyList(); 1323 } 1324 final boolean defaultOnly = (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0; 1325 final int providersSize = packageProviders.size(); 1326 ArrayList<Pair<ParsedProvider, ParsedIntentInfo>[]> listCut = 1327 new ArrayList<>(providersSize); 1328 1329 List<ParsedIntentInfo> intentFilters; 1330 for (int i = 0; i < providersSize; ++i) { 1331 ParsedProvider provider = packageProviders.get(i); 1332 intentFilters = provider.getIntents(); 1333 if (!intentFilters.isEmpty()) { 1334 Pair<ParsedProvider, ParsedIntentInfo>[] array = newArray(intentFilters.size()); 1335 for (int arrayIndex = 0; arrayIndex < intentFilters.size(); arrayIndex++) { 1336 array[arrayIndex] = Pair.create(provider, intentFilters.get(arrayIndex)); 1337 } 1338 listCut.add(array); 1339 } 1340 } 1341 return super.queryIntentFromList(computer, intent, resolvedType, 1342 defaultOnly, listCut, userId, flags); 1343 } 1344 addProvider(@onNull Computer computer, ParsedProvider p)1345 void addProvider(@NonNull Computer computer, ParsedProvider p) { 1346 if (mProviders.containsKey(p.getComponentName())) { 1347 Slog.w(TAG, "Provider " + p.getComponentName() + " already defined; ignoring"); 1348 return; 1349 } 1350 1351 mProviders.put(p.getComponentName(), p); 1352 if (DEBUG_SHOW_INFO) { 1353 Log.v(TAG, " provider:"); 1354 Log.v(TAG, " Class=" + p.getName()); 1355 } 1356 final int intentsSize = p.getIntents().size(); 1357 int j; 1358 for (j = 0; j < intentsSize; j++) { 1359 ParsedIntentInfo intent = p.getIntents().get(j); 1360 IntentFilter intentFilter = intent.getIntentFilter(); 1361 if (DEBUG_SHOW_INFO) { 1362 Log.v(TAG, " IntentFilter:"); 1363 intentFilter.dump(new LogPrinter(Log.VERBOSE, TAG), " "); 1364 } 1365 if (!intentFilter.debugCheck()) { 1366 Log.w(TAG, "==> For Provider " + p.getName()); 1367 } 1368 addFilter(computer, Pair.create(p, intent)); 1369 } 1370 } 1371 removeProvider(ParsedProvider p)1372 void removeProvider(ParsedProvider p) { 1373 mProviders.remove(p.getComponentName()); 1374 if (DEBUG_SHOW_INFO) { 1375 Log.v(TAG, " provider:"); 1376 Log.v(TAG, " Class=" + p.getName()); 1377 } 1378 final int intentsSize = p.getIntents().size(); 1379 int j; 1380 for (j = 0; j < intentsSize; j++) { 1381 ParsedIntentInfo intent = p.getIntents().get(j); 1382 IntentFilter intentFilter = intent.getIntentFilter(); 1383 if (DEBUG_SHOW_INFO) { 1384 Log.v(TAG, " IntentFilter:"); 1385 intentFilter.dump(new LogPrinter(Log.VERBOSE, TAG), " "); 1386 } 1387 removeFilter(Pair.create(p, intent)); 1388 } 1389 } 1390 1391 @Override allowFilterResult(Pair<ParsedProvider, ParsedIntentInfo> filter, List<ResolveInfo> dest)1392 protected boolean allowFilterResult(Pair<ParsedProvider, ParsedIntentInfo> filter, 1393 List<ResolveInfo> dest) { 1394 for (int i = dest.size() - 1; i >= 0; i--) { 1395 ProviderInfo destPi = dest.get(i).providerInfo; 1396 if (Objects.equals(destPi.name, filter.first.getClassName()) 1397 && Objects.equals(destPi.packageName, filter.first.getPackageName())) { 1398 return false; 1399 } 1400 } 1401 return true; 1402 } 1403 1404 @Override newArray(int size)1405 protected Pair<ParsedProvider, ParsedIntentInfo>[] newArray(int size) { 1406 //noinspection unchecked 1407 return (Pair<ParsedProvider, ParsedIntentInfo>[]) new Pair<?, ?>[size]; 1408 } 1409 1410 @Override isPackageForFilter(String packageName, Pair<ParsedProvider, ParsedIntentInfo> info)1411 protected boolean isPackageForFilter(String packageName, 1412 Pair<ParsedProvider, ParsedIntentInfo> info) { 1413 return packageName.equals(info.first.getPackageName()); 1414 } 1415 1416 @Override newResult(@onNull Computer computer, Pair<ParsedProvider, ParsedIntentInfo> pair, int match, int userId, long customFlags)1417 protected ResolveInfo newResult(@NonNull Computer computer, 1418 Pair<ParsedProvider, ParsedIntentInfo> pair, int match, int userId, 1419 long customFlags) { 1420 if (!mUserManager.exists(userId)) { 1421 return null; 1422 } 1423 1424 ParsedProvider provider = pair.first; 1425 ParsedIntentInfo intentInfo = pair.second; 1426 IntentFilter filter = intentInfo.getIntentFilter(); 1427 1428 PackageStateInternal packageState = 1429 computer.getPackageStateInternal(provider.getPackageName()); 1430 if (packageState == null || packageState.getPkg() == null 1431 || !PackageStateUtils.isEnabledAndMatches(packageState, provider, customFlags, 1432 userId)) { 1433 return null; 1434 } 1435 1436 final PackageUserStateInternal userState = packageState.getUserStateOrDefault(userId); 1437 final boolean matchVisibleToInstantApp = (customFlags 1438 & PackageManager.MATCH_VISIBLE_TO_INSTANT_APP_ONLY) != 0; 1439 final boolean isInstantApp = (customFlags & PackageManager.MATCH_INSTANT) != 0; 1440 // throw out filters that aren't visible to instant applications 1441 if (matchVisibleToInstantApp 1442 && !(filter.isVisibleToInstantApp() || userState.isInstantApp())) { 1443 return null; 1444 } 1445 // throw out instant application filters if we're not explicitly requesting them 1446 if (!isInstantApp && userState.isInstantApp()) { 1447 return null; 1448 } 1449 // throw out instant application filters if updates are available; will trigger 1450 // instant application resolution 1451 if (userState.isInstantApp() && packageState.isUpdateAvailable()) { 1452 return null; 1453 } 1454 final ApplicationInfo appInfo = PackageInfoUtils.generateApplicationInfo( 1455 packageState.getPkg(), customFlags, userState, userId, packageState); 1456 if (appInfo == null) { 1457 return null; 1458 } 1459 ProviderInfo pi = PackageInfoUtils.generateProviderInfo(packageState.getPkg(), provider, 1460 customFlags, userState, appInfo, userId, packageState); 1461 if (pi == null) { 1462 return null; 1463 } 1464 final ResolveInfo res = new ResolveInfo(); 1465 res.providerInfo = pi; 1466 if ((customFlags & PackageManager.GET_RESOLVED_FILTER) != 0) { 1467 res.filter = filter; 1468 } 1469 res.priority = filter.getPriority(); 1470 // TODO(b/135203078): This field was unwritten and does nothing 1471 // res.preferredOrder = pkg.getPreferredOrder(); 1472 res.match = match; 1473 res.isDefault = intentInfo.isHasDefault(); 1474 res.labelRes = intentInfo.getLabelRes(); 1475 res.nonLocalizedLabel = intentInfo.getNonLocalizedLabel(); 1476 res.icon = intentInfo.getIcon(); 1477 res.system = res.providerInfo.applicationInfo.isSystemApp(); 1478 return res; 1479 } 1480 1481 @Override sortResults(List<ResolveInfo> results)1482 protected void sortResults(List<ResolveInfo> results) { 1483 results.sort(RESOLVE_PRIORITY_SORTER); 1484 } 1485 1486 @Override dumpFilter(PrintWriter out, String prefix, Pair<ParsedProvider, ParsedIntentInfo> pair)1487 protected void dumpFilter(PrintWriter out, String prefix, 1488 Pair<ParsedProvider, ParsedIntentInfo> pair) { 1489 ParsedProvider provider = pair.first; 1490 ParsedIntentInfo filter = pair.second; 1491 1492 out.print(prefix); 1493 out.print(Integer.toHexString(System.identityHashCode(provider))); 1494 out.print(' '); 1495 ComponentName.printShortString(out, provider.getPackageName(), provider.getClassName()); 1496 out.print(" filter "); 1497 out.println(Integer.toHexString(System.identityHashCode(filter))); 1498 } 1499 1500 @Override filterToLabel(Pair<ParsedProvider, ParsedIntentInfo> filter)1501 protected Object filterToLabel(Pair<ParsedProvider, ParsedIntentInfo> filter) { 1502 return filter; 1503 } 1504 dumpFilterLabel(PrintWriter out, String prefix, Object label, int count)1505 protected void dumpFilterLabel(PrintWriter out, String prefix, Object label, int count) { 1506 @SuppressWarnings("unchecked") final Pair<ParsedProvider, ParsedIntentInfo> pair = 1507 (Pair<ParsedProvider, ParsedIntentInfo>) label; 1508 out.print(prefix); 1509 out.print(Integer.toHexString(System.identityHashCode(pair.first))); 1510 out.print(' '); 1511 ComponentName.printShortString(out, pair.first.getPackageName(), 1512 pair.first.getClassName()); 1513 if (count > 1) { 1514 out.print(" ("); 1515 out.print(count); 1516 out.print(" filters)"); 1517 } 1518 out.println(); 1519 } 1520 1521 @Override getIntentFilter( @onNull Pair<ParsedProvider, ParsedIntentInfo> input)1522 protected IntentFilter getIntentFilter( 1523 @NonNull Pair<ParsedProvider, ParsedIntentInfo> input) { 1524 return input.second.getIntentFilter(); 1525 } 1526 1527 final ArrayMap<ComponentName, ParsedProvider> mProviders = new ArrayMap<>(); 1528 } 1529 1530 public static final class ServiceIntentResolver 1531 extends MimeGroupsAwareIntentResolver<Pair<ParsedService, ParsedIntentInfo>, ResolveInfo> { 1532 // Default constructor ServiceIntentResolver(@onNull UserManagerService userManager)1533 ServiceIntentResolver(@NonNull UserManagerService userManager) { 1534 super(userManager); 1535 } 1536 1537 // Copy constructor used in creating snapshots ServiceIntentResolver(@onNull ServiceIntentResolver orig, @NonNull UserManagerService userManager)1538 ServiceIntentResolver(@NonNull ServiceIntentResolver orig, 1539 @NonNull UserManagerService userManager) { 1540 super(orig, userManager); 1541 mServices.putAll(orig.mServices); 1542 } 1543 1544 @Override queryIntent(@onNull PackageDataSnapshot snapshot, Intent intent, String resolvedType, boolean defaultOnly, @UserIdInt int userId)1545 public List<ResolveInfo> queryIntent(@NonNull PackageDataSnapshot snapshot, Intent intent, 1546 String resolvedType, boolean defaultOnly, @UserIdInt int userId) { 1547 if (!mUserManager.exists(userId)) { 1548 return null; 1549 } 1550 long flags = defaultOnly ? PackageManager.MATCH_DEFAULT_ONLY : 0; 1551 return super.queryIntent(snapshot, intent, resolvedType, defaultOnly, userId, flags); 1552 } 1553 queryIntent(@onNull Computer computer, Intent intent, String resolvedType, long flags, int userId)1554 List<ResolveInfo> queryIntent(@NonNull Computer computer, Intent intent, 1555 String resolvedType, long flags, int userId) { 1556 if (!mUserManager.exists(userId)) return null; 1557 return super.queryIntent(computer, intent, resolvedType, 1558 (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0, userId, flags); 1559 } 1560 queryIntentForPackage(@onNull Computer computer, Intent intent, String resolvedType, long flags, List<ParsedService> packageServices, int userId)1561 List<ResolveInfo> queryIntentForPackage(@NonNull Computer computer, Intent intent, 1562 String resolvedType, long flags, List<ParsedService> packageServices, int userId) { 1563 if (!mUserManager.exists(userId)) return null; 1564 if (packageServices == null) { 1565 return Collections.emptyList(); 1566 } 1567 final boolean defaultOnly = (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0; 1568 final int servicesSize = packageServices.size(); 1569 ArrayList<Pair<ParsedService, ParsedIntentInfo>[]> listCut = 1570 new ArrayList<>(servicesSize); 1571 1572 List<ParsedIntentInfo> intentFilters; 1573 for (int i = 0; i < servicesSize; ++i) { 1574 ParsedService service = packageServices.get(i); 1575 intentFilters = service.getIntents(); 1576 if (intentFilters.size() > 0) { 1577 Pair<ParsedService, ParsedIntentInfo>[] array = newArray(intentFilters.size()); 1578 for (int arrayIndex = 0; arrayIndex < intentFilters.size(); arrayIndex++) { 1579 array[arrayIndex] = Pair.create(service, intentFilters.get(arrayIndex)); 1580 } 1581 listCut.add(array); 1582 } 1583 } 1584 return super.queryIntentFromList(computer, intent, resolvedType, 1585 defaultOnly, listCut, userId, flags); 1586 } 1587 addService(@onNull Computer computer, ParsedService s)1588 void addService(@NonNull Computer computer, ParsedService s) { 1589 mServices.put(s.getComponentName(), s); 1590 if (DEBUG_SHOW_INFO) { 1591 Log.v(TAG, " service:"); 1592 Log.v(TAG, " Class=" + s.getName()); 1593 } 1594 final int intentsSize = s.getIntents().size(); 1595 int j; 1596 for (j = 0; j < intentsSize; j++) { 1597 ParsedIntentInfo intent = s.getIntents().get(j); 1598 IntentFilter intentFilter = intent.getIntentFilter(); 1599 if (DEBUG_SHOW_INFO) { 1600 Log.v(TAG, " IntentFilter:"); 1601 intentFilter.dump(new LogPrinter(Log.VERBOSE, TAG), " "); 1602 } 1603 if (!intentFilter.debugCheck()) { 1604 Log.w(TAG, "==> For Service " + s.getName()); 1605 } 1606 addFilter(computer, Pair.create(s, intent)); 1607 } 1608 } 1609 removeService(ParsedService s)1610 void removeService(ParsedService s) { 1611 mServices.remove(s.getComponentName()); 1612 if (DEBUG_SHOW_INFO) { 1613 Log.v(TAG, " service:"); 1614 Log.v(TAG, " Class=" + s.getName()); 1615 } 1616 final int intentsSize = s.getIntents().size(); 1617 int j; 1618 for (j = 0; j < intentsSize; j++) { 1619 ParsedIntentInfo intent = s.getIntents().get(j); 1620 IntentFilter intentFilter = intent.getIntentFilter(); 1621 if (DEBUG_SHOW_INFO) { 1622 Log.v(TAG, " IntentFilter:"); 1623 intentFilter.dump(new LogPrinter(Log.VERBOSE, TAG), " "); 1624 } 1625 removeFilter(Pair.create(s, intent)); 1626 } 1627 } 1628 1629 @Override allowFilterResult(Pair<ParsedService, ParsedIntentInfo> filter, List<ResolveInfo> dest)1630 protected boolean allowFilterResult(Pair<ParsedService, ParsedIntentInfo> filter, 1631 List<ResolveInfo> dest) { 1632 for (int i = dest.size() - 1; i >= 0; --i) { 1633 ServiceInfo destAi = dest.get(i).serviceInfo; 1634 if (Objects.equals(destAi.name, filter.first.getClassName()) 1635 && Objects.equals(destAi.packageName, filter.first.getPackageName())) { 1636 return false; 1637 } 1638 } 1639 return true; 1640 } 1641 1642 @Override newArray(int size)1643 protected Pair<ParsedService, ParsedIntentInfo>[] newArray(int size) { 1644 //noinspection unchecked 1645 return (Pair<ParsedService, ParsedIntentInfo>[]) new Pair<?, ?>[size]; 1646 } 1647 1648 @Override isPackageForFilter(String packageName, Pair<ParsedService, ParsedIntentInfo> info)1649 protected boolean isPackageForFilter(String packageName, 1650 Pair<ParsedService, ParsedIntentInfo> info) { 1651 return packageName.equals(info.first.getPackageName()); 1652 } 1653 1654 @Override newResult(@onNull Computer computer, Pair<ParsedService, ParsedIntentInfo> pair, int match, int userId, long customFlags)1655 protected ResolveInfo newResult(@NonNull Computer computer, 1656 Pair<ParsedService, ParsedIntentInfo> pair, int match, int userId, 1657 long customFlags) { 1658 if (!mUserManager.exists(userId)) return null; 1659 1660 ParsedService service = pair.first; 1661 ParsedIntentInfo intentInfo = pair.second; 1662 IntentFilter filter = intentInfo.getIntentFilter(); 1663 1664 final PackageStateInternal packageState = computer.getPackageStateInternal( 1665 service.getPackageName()); 1666 if (packageState == null || packageState.getPkg() == null 1667 || !PackageStateUtils.isEnabledAndMatches(packageState, service, customFlags, 1668 userId)) { 1669 return null; 1670 } 1671 1672 final PackageUserStateInternal userState = packageState.getUserStateOrDefault(userId); 1673 ServiceInfo si = PackageInfoUtils.generateServiceInfo(packageState.getPkg(), service, 1674 customFlags, userState, userId, packageState); 1675 if (si == null) { 1676 return null; 1677 } 1678 final boolean matchVisibleToInstantApp = 1679 (customFlags & PackageManager.MATCH_VISIBLE_TO_INSTANT_APP_ONLY) != 0; 1680 final boolean isInstantApp = (customFlags & PackageManager.MATCH_INSTANT) != 0; 1681 // throw out filters that aren't visible to ephemeral apps 1682 if (matchVisibleToInstantApp 1683 && !(filter.isVisibleToInstantApp() || userState.isInstantApp())) { 1684 return null; 1685 } 1686 // throw out ephemeral filters if we're not explicitly requesting them 1687 if (!isInstantApp && userState.isInstantApp()) { 1688 return null; 1689 } 1690 // throw out instant app filters if updates are available; will trigger 1691 // instant app resolution 1692 if (userState.isInstantApp() && packageState.isUpdateAvailable()) { 1693 return null; 1694 } 1695 final ResolveInfo res = new ResolveInfo(); 1696 res.serviceInfo = si; 1697 if ((customFlags & PackageManager.GET_RESOLVED_FILTER) != 0) { 1698 res.filter = filter; 1699 } 1700 res.priority = filter.getPriority(); 1701 // TODO(b/135203078): This field was unwritten and does nothing 1702 // res.preferredOrder = pkg.getPreferredOrder(); 1703 res.match = match; 1704 res.isDefault = intentInfo.isHasDefault(); 1705 res.labelRes = intentInfo.getLabelRes(); 1706 res.nonLocalizedLabel = intentInfo.getNonLocalizedLabel(); 1707 res.icon = intentInfo.getIcon(); 1708 res.system = res.serviceInfo.applicationInfo.isSystemApp(); 1709 return res; 1710 } 1711 1712 @Override sortResults(List<ResolveInfo> results)1713 protected void sortResults(List<ResolveInfo> results) { 1714 results.sort(RESOLVE_PRIORITY_SORTER); 1715 } 1716 1717 @Override dumpFilter(PrintWriter out, String prefix, Pair<ParsedService, ParsedIntentInfo> pair)1718 protected void dumpFilter(PrintWriter out, String prefix, 1719 Pair<ParsedService, ParsedIntentInfo> pair) { 1720 ParsedService service = pair.first; 1721 ParsedIntentInfo filter = pair.second; 1722 1723 out.print(prefix); 1724 out.print(Integer.toHexString(System.identityHashCode(service))); 1725 out.print(' '); 1726 ComponentName.printShortString(out, service.getPackageName(), service.getClassName()); 1727 out.print(" filter "); 1728 out.print(Integer.toHexString(System.identityHashCode(filter))); 1729 if (service.getPermission() != null) { 1730 out.print(" permission "); out.println(service.getPermission()); 1731 } else { 1732 out.println(); 1733 } 1734 } 1735 1736 @Override filterToLabel(Pair<ParsedService, ParsedIntentInfo> filter)1737 protected Object filterToLabel(Pair<ParsedService, ParsedIntentInfo> filter) { 1738 return filter; 1739 } 1740 dumpFilterLabel(PrintWriter out, String prefix, Object label, int count)1741 protected void dumpFilterLabel(PrintWriter out, String prefix, Object label, int count) { 1742 @SuppressWarnings("unchecked") final Pair<ParsedService, ParsedIntentInfo> pair = 1743 (Pair<ParsedService, ParsedIntentInfo>) label; 1744 out.print(prefix); 1745 out.print(Integer.toHexString(System.identityHashCode(pair.first))); 1746 out.print(' '); 1747 ComponentName.printShortString(out, pair.first.getPackageName(), 1748 pair.first.getClassName()); 1749 if (count > 1) { 1750 out.print(" ("); out.print(count); out.print(" filters)"); 1751 } 1752 out.println(); 1753 } 1754 1755 @Override getIntentFilter( @onNull Pair<ParsedService, ParsedIntentInfo> input)1756 protected IntentFilter getIntentFilter( 1757 @NonNull Pair<ParsedService, ParsedIntentInfo> input) { 1758 return input.second.getIntentFilter(); 1759 } 1760 1761 // Keys are String (activity class name), values are Activity. 1762 final ArrayMap<ComponentName, ParsedService> mServices = new ArrayMap<>(); 1763 } 1764 1765 public static final class InstantAppIntentResolver 1766 extends IntentResolver<AuxiliaryResolveInfo.AuxiliaryFilter, 1767 AuxiliaryResolveInfo.AuxiliaryFilter> { 1768 /** 1769 * The result that has the highest defined order. Ordering applies on a 1770 * per-package basis. Mapping is from package name to Pair of order and 1771 * EphemeralResolveInfo. 1772 * <p> 1773 * NOTE: This is implemented as a field variable for convenience and efficiency. 1774 * By having a field variable, we're able to track filter ordering as soon as 1775 * a non-zero order is defined. Otherwise, multiple loops across the result set 1776 * would be needed to apply ordering. If the intent resolver becomes re-entrant, 1777 * this needs to be contained entirely within {@link #filterResults}. 1778 */ 1779 final ArrayMap<String, Pair<Integer, InstantAppResolveInfo>> mOrderResult = 1780 new ArrayMap<>(); 1781 1782 @NonNull 1783 private final UserManagerService mUserManager; 1784 InstantAppIntentResolver(@onNull UserManagerService userManager)1785 public InstantAppIntentResolver(@NonNull UserManagerService userManager) { 1786 mUserManager = userManager; 1787 } 1788 1789 @Override newArray(int size)1790 protected AuxiliaryResolveInfo.AuxiliaryFilter[] newArray(int size) { 1791 return new AuxiliaryResolveInfo.AuxiliaryFilter[size]; 1792 } 1793 1794 @Override isPackageForFilter(String packageName, AuxiliaryResolveInfo.AuxiliaryFilter responseObj)1795 protected boolean isPackageForFilter(String packageName, 1796 AuxiliaryResolveInfo.AuxiliaryFilter responseObj) { 1797 return true; 1798 } 1799 1800 @Override newResult(@onNull Computer computer, AuxiliaryResolveInfo.AuxiliaryFilter responseObj, int match, int userId, long customFlags)1801 protected AuxiliaryResolveInfo.AuxiliaryFilter newResult(@NonNull Computer computer, 1802 AuxiliaryResolveInfo.AuxiliaryFilter responseObj, int match, int userId, 1803 long customFlags) { 1804 if (!mUserManager.exists(userId)) { 1805 return null; 1806 } 1807 final String packageName = responseObj.resolveInfo.getPackageName(); 1808 final Integer order = responseObj.getOrder(); 1809 final Pair<Integer, InstantAppResolveInfo> lastOrderResult = 1810 mOrderResult.get(packageName); 1811 // ordering is enabled and this item's order isn't high enough 1812 if (lastOrderResult != null && lastOrderResult.first >= order) { 1813 return null; 1814 } 1815 final InstantAppResolveInfo res = responseObj.resolveInfo; 1816 if (order > 0) { 1817 // non-zero order, enable ordering 1818 mOrderResult.put(packageName, new Pair<>(order, res)); 1819 } 1820 return responseObj; 1821 } 1822 1823 @Override filterResults(List<AuxiliaryResolveInfo.AuxiliaryFilter> results)1824 protected void filterResults(List<AuxiliaryResolveInfo.AuxiliaryFilter> results) { 1825 // only do work if ordering is enabled [most of the time it won't be] 1826 if (mOrderResult.size() == 0) { 1827 return; 1828 } 1829 int resultSize = results.size(); 1830 for (int i = 0; i < resultSize; i++) { 1831 final InstantAppResolveInfo info = results.get(i).resolveInfo; 1832 final String packageName = info.getPackageName(); 1833 final Pair<Integer, InstantAppResolveInfo> savedInfo = 1834 mOrderResult.get(packageName); 1835 if (savedInfo == null) { 1836 // package doesn't having ordering 1837 continue; 1838 } 1839 if (savedInfo.second == info) { 1840 // circled back to the highest ordered item; remove from order list 1841 mOrderResult.remove(packageName); 1842 if (mOrderResult.size() == 0) { 1843 // no more ordered items 1844 break; 1845 } 1846 continue; 1847 } 1848 // item has a worse order, remove it from the result list 1849 results.remove(i); 1850 resultSize--; 1851 i--; 1852 } 1853 } 1854 1855 @Override getIntentFilter( @onNull AuxiliaryResolveInfo.AuxiliaryFilter input)1856 protected IntentFilter getIntentFilter( 1857 @NonNull AuxiliaryResolveInfo.AuxiliaryFilter input) { 1858 return input; 1859 } 1860 } 1861 1862 /** 1863 * Removes MIME type from the group, by delegating to IntentResolvers 1864 * @return true if any intent filters were changed due to this update 1865 */ updateMimeGroup(@onNull Computer computer, String packageName, String group)1866 public boolean updateMimeGroup(@NonNull Computer computer, String packageName, String group) { 1867 boolean hasChanges = false; 1868 synchronized (mLock) { 1869 hasChanges |= mActivities.updateMimeGroup(computer, packageName, group); 1870 hasChanges |= mProviders.updateMimeGroup(computer, packageName, group); 1871 hasChanges |= mReceivers.updateMimeGroup(computer, packageName, group); 1872 hasChanges |= mServices.updateMimeGroup(computer, packageName, group); 1873 if (hasChanges) { 1874 onChanged(); 1875 } 1876 } 1877 return hasChanges; 1878 } 1879 } 1880