1 /* 2 * Copyright (C) 2021 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; 18 19 import android.annotation.NonNull; 20 import android.content.ContentResolver; 21 import android.content.Intent; 22 import android.content.IntentFilter; 23 import android.net.Uri; 24 import android.os.PatternMatcher; 25 import android.util.Printer; 26 27 import com.android.server.utils.Snappable; 28 import com.android.server.utils.WatchableImpl; 29 30 import java.util.ArrayList; 31 import java.util.Collection; 32 import java.util.Iterator; 33 import java.util.List; 34 import java.util.Set; 35 import java.util.function.Consumer; 36 37 /** 38 * A watched variant of {@link IntentFilter}. The class consists of a 39 * {@link IntentFilter} attribute and methods that are identical to those in IntentFilter, 40 * forwarding to the attribute. 41 * 42 * @hide 43 */ 44 public class WatchedIntentFilter 45 extends WatchableImpl 46 implements Snappable<WatchedIntentFilter> { 47 48 // Watch for modifications made through an {@link Iterator}. 49 private class WatchedIterator<E> implements Iterator<E> { 50 private final Iterator<E> mIterator; WatchedIterator(@onNull Iterator<E> i)51 WatchedIterator(@NonNull Iterator<E> i) { 52 mIterator = i; 53 } hasNext()54 public boolean hasNext() { 55 return mIterator.hasNext(); 56 } next()57 public E next() { 58 return mIterator.next(); 59 } remove()60 public void remove() { 61 mIterator.remove(); 62 WatchedIntentFilter.this.onChanged(); 63 } forEachRemaining(Consumer<? super E> action)64 public void forEachRemaining(Consumer<? super E> action) { 65 mIterator.forEachRemaining(action); 66 WatchedIntentFilter.this.onChanged(); 67 } 68 } 69 70 // A convenience function to wrap an iterator result, but only if it is not null. maybeWatch(Iterator<E> i)71 private <E> Iterator<E> maybeWatch(Iterator<E> i) { 72 return i == null ? i : new WatchedIterator<>(i); 73 } 74 75 // The wrapped {@link IntentFilter} 76 protected IntentFilter mFilter; 77 onChanged()78 private void onChanged() { 79 dispatchChange(this); 80 } 81 WatchedIntentFilter()82 protected WatchedIntentFilter() { 83 mFilter = new IntentFilter(); 84 } 85 86 // Convert an {@link IntentFilter} to a {@link WatchedIntentFilter} WatchedIntentFilter(IntentFilter f)87 public WatchedIntentFilter(IntentFilter f) { 88 mFilter = new IntentFilter(f); 89 } 90 91 // The copy constructor is used to create a snapshot of the object. WatchedIntentFilter(WatchedIntentFilter f)92 protected WatchedIntentFilter(WatchedIntentFilter f) { 93 this(f.getIntentFilter()); 94 } 95 96 /** 97 * Create a WatchedIntentFilter based on an action 98 * @see IntentFilter#IntentFilter(String) 99 */ WatchedIntentFilter(String action)100 public WatchedIntentFilter(String action) { 101 mFilter = new IntentFilter(action); 102 } 103 104 /** 105 * Create a WatchedIntentFilter based on an action and a data type. 106 * @see IntentFilter#IntentFilter(String, String) 107 */ WatchedIntentFilter(String action, String dataType)108 public WatchedIntentFilter(String action, String dataType) 109 throws IntentFilter.MalformedMimeTypeException { 110 mFilter = new IntentFilter(action, dataType); 111 } 112 113 /** 114 * Return a clone of the filter represented by this object. 115 */ cloneFilter()116 public WatchedIntentFilter cloneFilter() { 117 return new WatchedIntentFilter(mFilter); 118 } 119 120 /** 121 * Return the {@link IntentFilter} represented by this object. 122 */ getIntentFilter()123 public IntentFilter getIntentFilter() { 124 return mFilter; 125 } 126 127 /** 128 * @see IntentFilter#setPriority(int) 129 */ setPriority(int priority)130 public final void setPriority(int priority) { 131 mFilter.setPriority(priority); 132 onChanged(); 133 } 134 135 /** 136 * @see IntentFilter#getPriority() 137 */ getPriority()138 public final int getPriority() { 139 return mFilter.getPriority(); 140 } 141 142 /** 143 * @see IntentFilter#setOrder(int) 144 */ setOrder(int order)145 public final void setOrder(int order) { 146 mFilter.setOrder(order); 147 onChanged(); 148 } 149 150 /** 151 * @see IntentFilter#getOrder() 152 */ getOrder()153 public final int getOrder() { 154 return mFilter.getOrder(); 155 } 156 157 /** 158 * @see IntentFilter#getAutoVerify() 159 */ getAutoVerify()160 public final boolean getAutoVerify() { 161 return mFilter.getAutoVerify(); 162 } 163 164 /** 165 * @see IntentFilter#handleAllWebDataURI() 166 */ handleAllWebDataURI()167 public final boolean handleAllWebDataURI() { 168 return mFilter.handleAllWebDataURI(); 169 } 170 171 /** 172 * @see IntentFilter#handlesWebUris(boolean) 173 */ handlesWebUris(boolean onlyWebSchemes)174 public final boolean handlesWebUris(boolean onlyWebSchemes) { 175 return mFilter.handlesWebUris(onlyWebSchemes); 176 } 177 178 /** 179 * @see IntentFilter#needsVerification() 180 */ needsVerification()181 public final boolean needsVerification() { 182 return mFilter.needsVerification(); 183 } 184 185 /** 186 * @see IntentFilter#setVerified(boolean) 187 */ setVerified(boolean verified)188 public void setVerified(boolean verified) { 189 mFilter.setVerified(verified); 190 onChanged(); 191 } 192 193 /** 194 * @see IntentFilter#setVisibilityToInstantApp(int) 195 */ setVisibilityToInstantApp(int visibility)196 public void setVisibilityToInstantApp(int visibility) { 197 mFilter.setVisibilityToInstantApp(visibility); 198 onChanged(); 199 } 200 201 /** 202 * @see IntentFilter#getVisibilityToInstantApp() 203 */ getVisibilityToInstantApp()204 public int getVisibilityToInstantApp() { 205 return mFilter.getVisibilityToInstantApp(); 206 } 207 208 /** 209 * @see IntentFilter#isVisibleToInstantApp() 210 */ isVisibleToInstantApp()211 public boolean isVisibleToInstantApp() { 212 return mFilter.isVisibleToInstantApp(); 213 } 214 215 /** 216 * @see IntentFilter#isExplicitlyVisibleToInstantApp() 217 */ isExplicitlyVisibleToInstantApp()218 public boolean isExplicitlyVisibleToInstantApp() { 219 return mFilter.isExplicitlyVisibleToInstantApp(); 220 } 221 222 /** 223 * @see IntentFilter#isImplicitlyVisibleToInstantApp() 224 */ isImplicitlyVisibleToInstantApp()225 public boolean isImplicitlyVisibleToInstantApp() { 226 return mFilter.isImplicitlyVisibleToInstantApp(); 227 } 228 229 /** 230 * @see IntentFilter#addAction(String) 231 */ addAction(String action)232 public final void addAction(String action) { 233 mFilter.addAction(action); 234 onChanged(); 235 } 236 237 /** 238 * @see IntentFilter#countActions() 239 */ countActions()240 public final int countActions() { 241 return mFilter.countActions(); 242 } 243 244 /** 245 * @see IntentFilter#getAction(int) 246 */ getAction(int index)247 public final String getAction(int index) { 248 return mFilter.getAction(index); 249 } 250 251 /** 252 * @see IntentFilter#hasAction(String) 253 */ hasAction(String action)254 public final boolean hasAction(String action) { 255 return mFilter.hasAction(action); 256 } 257 258 /** 259 * @see IntentFilter#matchAction(String) 260 */ matchAction(String action)261 public final boolean matchAction(String action) { 262 return mFilter.matchAction(action); 263 } 264 265 /** 266 * @see IntentFilter#actionsIterator() 267 */ actionsIterator()268 public final Iterator<String> actionsIterator() { 269 return maybeWatch(mFilter.actionsIterator()); 270 } 271 272 /** 273 * @see IntentFilter#addDataType(String) 274 */ addDataType(String type)275 public final void addDataType(String type) 276 throws IntentFilter.MalformedMimeTypeException { 277 mFilter.addDataType(type); 278 onChanged(); 279 } 280 281 /** 282 * @see IntentFilter#addDynamicDataType(String) 283 */ addDynamicDataType(String type)284 public final void addDynamicDataType(String type) 285 throws IntentFilter.MalformedMimeTypeException { 286 mFilter.addDynamicDataType(type); 287 onChanged(); 288 } 289 290 /** 291 * @see IntentFilter#clearDynamicDataTypes() 292 */ clearDynamicDataTypes()293 public final void clearDynamicDataTypes() { 294 mFilter.clearDynamicDataTypes(); 295 onChanged(); 296 } 297 298 /** 299 * @see IntentFilter#countStaticDataTypes() 300 */ countStaticDataTypes()301 public int countStaticDataTypes() { 302 return mFilter.countStaticDataTypes(); 303 } 304 305 /** 306 * @see IntentFilter#hasDataType(String) 307 */ hasDataType(String type)308 public final boolean hasDataType(String type) { 309 return mFilter.hasDataType(type); 310 } 311 312 /** 313 * @see IntentFilter#hasExactDynamicDataType(String) 314 */ hasExactDynamicDataType(String type)315 public final boolean hasExactDynamicDataType(String type) { 316 return mFilter.hasExactDynamicDataType(type); 317 } 318 319 /** 320 * @see IntentFilter#hasExactStaticDataType(String) 321 */ hasExactStaticDataType(String type)322 public final boolean hasExactStaticDataType(String type) { 323 return mFilter.hasExactStaticDataType(type); 324 } 325 326 /** 327 * @see IntentFilter#countDataTypes() 328 */ countDataTypes()329 public final int countDataTypes() { 330 return mFilter.countDataTypes(); 331 } 332 333 /** 334 * @see IntentFilter#getDataType(int) 335 */ getDataType(int index)336 public final String getDataType(int index) { 337 return mFilter.getDataType(index); 338 } 339 340 /** 341 * @see IntentFilter#typesIterator() 342 */ typesIterator()343 public final Iterator<String> typesIterator() { 344 return maybeWatch(mFilter.typesIterator()); 345 } 346 347 /** 348 /** 349 * @see IntentFilter#dataTypes() 350 */ dataTypes()351 public final List<String> dataTypes() { 352 return mFilter.dataTypes(); 353 } 354 355 /** 356 * @see IntentFilter#addMimeGroup(String) 357 */ addMimeGroup(String name)358 public final void addMimeGroup(String name) { 359 mFilter.addMimeGroup(name); 360 onChanged(); 361 } 362 363 /** 364 * @see IntentFilter#hasMimeGroup(String) 365 */ hasMimeGroup(String name)366 public final boolean hasMimeGroup(String name) { 367 return mFilter.hasMimeGroup(name); 368 } 369 370 /** 371 * @see IntentFilter#getMimeGroup(int) 372 */ getMimeGroup(int index)373 public final String getMimeGroup(int index) { 374 return mFilter.getMimeGroup(index); 375 } 376 377 /** 378 * @see IntentFilter#countMimeGroups() 379 */ countMimeGroups()380 public final int countMimeGroups() { 381 return mFilter.countMimeGroups(); 382 } 383 384 /** 385 * @see IntentAction@mimeGroupsIterator() 386 */ mimeGroupsIterator()387 public final Iterator<String> mimeGroupsIterator() { 388 return maybeWatch(mFilter.mimeGroupsIterator()); 389 } 390 391 /** 392 * @see IntentFilter#addDataScheme(String) 393 */ addDataScheme(String scheme)394 public final void addDataScheme(String scheme) { 395 mFilter.addDataScheme(scheme); 396 onChanged(); 397 } 398 399 /** 400 * @see IntentFilter#countDataSchemes() 401 */ countDataSchemes()402 public final int countDataSchemes() { 403 return mFilter.countDataSchemes(); 404 } 405 406 /** 407 * @see IntentFilter#getDataScheme(int) 408 */ getDataScheme(int index)409 public final String getDataScheme(int index) { 410 return mFilter.getDataScheme(index); 411 } 412 413 /** 414 * @see IntentFilter#hasDataScheme(String) 415 */ hasDataScheme(String scheme)416 public final boolean hasDataScheme(String scheme) { 417 return mFilter.hasDataScheme(scheme); 418 } 419 420 /** 421 * @see IntentFilter#schemesIterator() 422 */ schemesIterator()423 public final Iterator<String> schemesIterator() { 424 return maybeWatch(mFilter.schemesIterator()); 425 } 426 427 /** 428 * @see IntentFilter#addDataSchemeSpecificPart(String, int) 429 */ addDataSchemeSpecificPart(String ssp, int type)430 public final void addDataSchemeSpecificPart(String ssp, int type) { 431 mFilter.addDataSchemeSpecificPart(ssp, type); 432 onChanged(); 433 } 434 435 /** 436 * @see IntentFilter#addDataSchemeSpecificPart(PatternMatcher) 437 */ addDataSchemeSpecificPart(PatternMatcher ssp)438 public final void addDataSchemeSpecificPart(PatternMatcher ssp) { 439 mFilter.addDataSchemeSpecificPart(ssp); 440 onChanged(); 441 } 442 443 /** 444 * @see IntentFilter#countDataSchemeSpecificParts() 445 */ countDataSchemeSpecificParts()446 public final int countDataSchemeSpecificParts() { 447 return mFilter.countDataSchemeSpecificParts(); 448 } 449 450 /** 451 * @see IntentFilter#getDataSchemeSpecificPart(int) 452 */ getDataSchemeSpecificPart(int index)453 public final PatternMatcher getDataSchemeSpecificPart(int index) { 454 return mFilter.getDataSchemeSpecificPart(index); 455 } 456 457 /** 458 * @see IntentFilter#hasDataSchemeSpecificPart(String) 459 */ hasDataSchemeSpecificPart(String data)460 public final boolean hasDataSchemeSpecificPart(String data) { 461 return mFilter.hasDataSchemeSpecificPart(data); 462 } 463 464 /** 465 * @see IntentFilter#schemeSpecificPartsIterator() 466 */ schemeSpecificPartsIterator()467 public final Iterator<PatternMatcher> schemeSpecificPartsIterator() { 468 return maybeWatch(mFilter.schemeSpecificPartsIterator()); 469 } 470 471 /** 472 * @see IntentFilter#addDataAuthority(String, String) 473 */ addDataAuthority(String host, String port)474 public final void addDataAuthority(String host, String port) { 475 mFilter.addDataAuthority(host, port); 476 onChanged(); 477 } 478 479 /** 480 * @see IntentFilter#addDataAuthority(IntentFilter.AuthorityEntry) 481 */ addDataAuthority(IntentFilter.AuthorityEntry ent)482 public final void addDataAuthority(IntentFilter.AuthorityEntry ent) { 483 mFilter.addDataAuthority(ent); 484 onChanged(); 485 } 486 487 /** 488 * @see IntentFilter#countDataAuthorities() 489 */ countDataAuthorities()490 public final int countDataAuthorities() { 491 return mFilter.countDataAuthorities(); 492 } 493 494 /** 495 * @see IntentFilter#getDataAuthority(int) 496 */ getDataAuthority(int index)497 public final IntentFilter.AuthorityEntry getDataAuthority(int index) { 498 return mFilter.getDataAuthority(index); 499 } 500 501 /** 502 * @see IntentFilter#hasDataAuthority(Uri) 503 */ hasDataAuthority(Uri data)504 public final boolean hasDataAuthority(Uri data) { 505 return mFilter.hasDataAuthority(data); 506 } 507 508 /** 509 * @see IntentFilter#authoritiesIterator() 510 */ authoritiesIterator()511 public final Iterator<IntentFilter.AuthorityEntry> authoritiesIterator() { 512 return maybeWatch(mFilter.authoritiesIterator()); 513 } 514 515 /** 516 * @see IntentFilter#addDataPath(String, int) 517 */ addDataPath(String path, int type)518 public final void addDataPath(String path, int type) { 519 mFilter.addDataPath(path, type); 520 onChanged(); 521 } 522 523 /** 524 * @see IntentFilter#addDataPath(PatternMatcher) 525 */ addDataPath(PatternMatcher path)526 public final void addDataPath(PatternMatcher path) { 527 mFilter.addDataPath(path); 528 onChanged(); 529 } 530 531 /** 532 * @see IntentFilter#countDataPaths() 533 */ countDataPaths()534 public final int countDataPaths() { 535 return mFilter.countDataPaths(); 536 } 537 538 /** 539 * @see IntentFilter#getDataPath(int) 540 */ getDataPath(int index)541 public final PatternMatcher getDataPath(int index) { 542 return mFilter.getDataPath(index); 543 } 544 545 /** 546 * @see IntentFilter#hasDataPath(String) 547 */ hasDataPath(String data)548 public final boolean hasDataPath(String data) { 549 return mFilter.hasDataPath(data); 550 } 551 552 /** 553 * @see IntentFilter#pathsIterator() 554 */ pathsIterator()555 public final Iterator<PatternMatcher> pathsIterator() { 556 return maybeWatch(mFilter.pathsIterator()); 557 } 558 559 /** 560 * @see IntentFilter#matchDataAuthority(Uri) 561 */ matchDataAuthority(Uri data)562 public final int matchDataAuthority(Uri data) { 563 return mFilter.matchDataAuthority(data); 564 } 565 566 /** 567 * @see IntentFilter#matchDataAuthority(Uri, boolean) 568 */ matchDataAuthority(Uri data, boolean wildcardSupported)569 public final int matchDataAuthority(Uri data, boolean wildcardSupported) { 570 return mFilter.matchDataAuthority(data, wildcardSupported); 571 } 572 573 /** 574 * @see IntentFilter#matchData(String, String, Uri) 575 */ matchData(String type, String scheme, Uri data)576 public final int matchData(String type, String scheme, Uri data) { 577 return mFilter.matchData(type, scheme, data); 578 } 579 580 /** 581 * @see IntentFilter#addCategory(String) 582 */ addCategory(String category)583 public final void addCategory(String category) { 584 mFilter.addCategory(category); 585 } 586 587 /** 588 * @see IntentFilter#countCategories() 589 */ countCategories()590 public final int countCategories() { 591 return mFilter.countCategories(); 592 } 593 594 /** 595 * @see IntentFilter#getCategory(int) 596 */ getCategory(int index)597 public final String getCategory(int index) { 598 return mFilter.getCategory(index); 599 } 600 601 /** 602 * @see IntentFilter#hasCategory(String) 603 */ hasCategory(String category)604 public final boolean hasCategory(String category) { 605 return mFilter.hasCategory(category); 606 } 607 608 /** 609 * @see IntentFilter#categoriesIterator() 610 */ categoriesIterator()611 public final Iterator<String> categoriesIterator() { 612 return maybeWatch(mFilter.categoriesIterator()); 613 } 614 615 /** 616 * @see IntentFilter#matchCategories(Set<String>) 617 */ matchCategories(Set<String> categories)618 public final String matchCategories(Set<String> categories) { 619 return mFilter.matchCategories(categories); 620 } 621 622 /** 623 * @see IntentFilter#match(ContentResolver, Intent, boolean, String) 624 */ match(ContentResolver resolver, Intent intent, boolean resolve, String logTag)625 public final int match(ContentResolver resolver, Intent intent, 626 boolean resolve, String logTag) { 627 return mFilter.match(resolver, intent, 628 resolve, logTag); 629 } 630 631 /** 632 * @see IntentFilter#match(String, String, String, Uri, Set<String>, String) 633 */ match(String action, String type, String scheme, Uri data, Set<String> categories, String logTag)634 public final int match(String action, String type, String scheme, 635 Uri data, Set<String> categories, String logTag) { 636 return mFilter.match(action, type, scheme, 637 data, categories, logTag); 638 } 639 640 /** 641 * @see IntentFilter#match(String, String, String, Uri, Set<String>, String, boolean, 642 Collection<String> ignoreActions) 643 */ match(String action, String type, String scheme, Uri data, Set<String> categories, String logTag, boolean supportWildcards, Collection<String> ignoreActions)644 public final int match(String action, String type, String scheme, 645 Uri data, Set<String> categories, String logTag, boolean supportWildcards, 646 Collection<String> ignoreActions) { 647 return mFilter.match(action, type, scheme, 648 data, categories, logTag, supportWildcards, 649 ignoreActions); 650 } 651 652 /** 653 * @see IntentFilter#dump(Printer, String) 654 */ dump(Printer du, String prefix)655 public void dump(Printer du, String prefix) { 656 mFilter.dump(du, prefix); 657 } 658 659 /** 660 * @see IntentFilter#describeContents() 661 */ describeContents()662 public final int describeContents() { 663 return mFilter.describeContents(); 664 } 665 666 /** 667 * @see IntentFilter#debugCheck() 668 */ debugCheck()669 public boolean debugCheck() { 670 return mFilter.debugCheck(); 671 } 672 673 /** 674 * @see IntentFilter#checkDataPathAndSchemeSpecificParts() 675 */ checkDataPathAndSchemeSpecificParts()676 public boolean checkDataPathAndSchemeSpecificParts() { 677 return mFilter.checkDataPathAndSchemeSpecificParts(); 678 } 679 680 /** 681 * @see IntentFilter#getHostsList() 682 */ getHostsList()683 public ArrayList<String> getHostsList() { 684 return mFilter.getHostsList(); 685 } 686 687 /** 688 * @see IntentFilter#getHosts() 689 */ getHosts()690 public String[] getHosts() { 691 return mFilter.getHosts(); 692 } 693 694 /** 695 * Convert a list of {@link IntentFilter} into a list of {@link WatchedIntentFilter} 696 */ toWatchedIntentFilterList(List<IntentFilter> inList)697 public static List<WatchedIntentFilter> toWatchedIntentFilterList(List<IntentFilter> inList) { 698 ArrayList<WatchedIntentFilter> outList = new ArrayList<>(); 699 for (int i = 0; i < inList.size(); i++) { 700 outList.add(new WatchedIntentFilter(inList.get(i))); 701 } 702 return outList; 703 } 704 705 /** 706 * Convert a list of {@link IntentFilter} into a list of {@link WatchedIntentFilter} 707 */ toIntentFilterList(List<WatchedIntentFilter> inList)708 public static List<IntentFilter> toIntentFilterList(List<WatchedIntentFilter> inList) { 709 ArrayList<IntentFilter> outList = new ArrayList<>(); 710 for (int i = 0; i < inList.size(); i++) { 711 outList.add(inList.get(i).getIntentFilter()); 712 } 713 return outList; 714 } 715 716 /** 717 * Create a snapshot by cloning the object. 718 */ snapshot()719 public WatchedIntentFilter snapshot() { 720 return new WatchedIntentFilter(this); 721 } 722 } 723