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; 18 19 import android.Manifest; 20 import android.annotation.NonNull; 21 import android.annotation.Nullable; 22 import android.content.Intent; 23 import android.content.IntentFilter; 24 25 import com.android.internal.util.ArrayUtils; 26 import com.android.server.pm.parsing.pkg.AndroidPackage; 27 import com.android.server.pm.pkg.PackageStateInternal; 28 import com.android.server.pm.pkg.component.ParsedComponent; 29 import com.android.server.pm.pkg.component.ParsedIntentInfo; 30 import com.android.server.pm.pkg.component.ParsedMainComponent; 31 import com.android.server.pm.pkg.component.ParsedProvider; 32 import com.android.server.utils.WatchedArrayList; 33 34 import java.util.List; 35 import java.util.Set; 36 import java.util.StringTokenizer; 37 38 final class AppsFilterUtils { requestsQueryAllPackages(@onNull AndroidPackage pkg)39 public static boolean requestsQueryAllPackages(@NonNull AndroidPackage pkg) { 40 // we're not guaranteed to have permissions yet analyzed at package add, so we inspect the 41 // package directly 42 return pkg.getRequestedPermissions().contains( 43 Manifest.permission.QUERY_ALL_PACKAGES); 44 } 45 46 /** Returns true if the querying package may query for the potential target package */ canQueryViaComponents(AndroidPackage querying, AndroidPackage potentialTarget, WatchedArrayList<String> protectedBroadcasts)47 public static boolean canQueryViaComponents(AndroidPackage querying, 48 AndroidPackage potentialTarget, WatchedArrayList<String> protectedBroadcasts) { 49 if (!querying.getQueriesIntents().isEmpty()) { 50 for (Intent intent : querying.getQueriesIntents()) { 51 if (matchesPackage(intent, potentialTarget, protectedBroadcasts)) { 52 return true; 53 } 54 } 55 } 56 if (!querying.getQueriesProviders().isEmpty() 57 && matchesProviders(querying.getQueriesProviders(), potentialTarget)) { 58 return true; 59 } 60 return false; 61 } 62 canQueryViaPackage(AndroidPackage querying, AndroidPackage potentialTarget)63 public static boolean canQueryViaPackage(AndroidPackage querying, 64 AndroidPackage potentialTarget) { 65 return !querying.getQueriesPackages().isEmpty() 66 && querying.getQueriesPackages().contains(potentialTarget.getPackageName()); 67 } 68 canQueryAsInstaller(PackageStateInternal querying, AndroidPackage potentialTarget)69 public static boolean canQueryAsInstaller(PackageStateInternal querying, 70 AndroidPackage potentialTarget) { 71 final InstallSource installSource = querying.getInstallSource(); 72 if (potentialTarget.getPackageName().equals(installSource.installerPackageName)) { 73 return true; 74 } 75 if (!installSource.isInitiatingPackageUninstalled 76 && potentialTarget.getPackageName().equals(installSource.initiatingPackageName)) { 77 return true; 78 } 79 return false; 80 } 81 canQueryViaUsesLibrary(AndroidPackage querying, AndroidPackage potentialTarget)82 public static boolean canQueryViaUsesLibrary(AndroidPackage querying, 83 AndroidPackage potentialTarget) { 84 if (potentialTarget.getLibraryNames().isEmpty()) { 85 return false; 86 } 87 final List<String> libNames = potentialTarget.getLibraryNames(); 88 for (int i = 0, size = libNames.size(); i < size; i++) { 89 final String libName = libNames.get(i); 90 if (querying.getUsesLibraries().contains(libName) 91 || querying.getUsesOptionalLibraries().contains(libName)) { 92 return true; 93 } 94 } 95 return false; 96 } 97 matchesProviders( Set<String> queriesAuthorities, AndroidPackage potentialTarget)98 private static boolean matchesProviders( 99 Set<String> queriesAuthorities, AndroidPackage potentialTarget) { 100 for (int p = ArrayUtils.size(potentialTarget.getProviders()) - 1; p >= 0; p--) { 101 ParsedProvider provider = potentialTarget.getProviders().get(p); 102 if (!provider.isExported()) { 103 continue; 104 } 105 if (provider.getAuthority() == null) { 106 continue; 107 } 108 StringTokenizer authorities = new StringTokenizer(provider.getAuthority(), ";", 109 false); 110 while (authorities.hasMoreElements()) { 111 if (queriesAuthorities.contains(authorities.nextToken())) { 112 return true; 113 } 114 } 115 } 116 return false; 117 } 118 matchesPackage(Intent intent, AndroidPackage potentialTarget, WatchedArrayList<String> protectedBroadcasts)119 private static boolean matchesPackage(Intent intent, AndroidPackage potentialTarget, 120 WatchedArrayList<String> protectedBroadcasts) { 121 if (matchesAnyComponents( 122 intent, potentialTarget.getServices(), null /*protectedBroadcasts*/)) { 123 return true; 124 } 125 if (matchesAnyComponents( 126 intent, potentialTarget.getActivities(), null /*protectedBroadcasts*/)) { 127 return true; 128 } 129 if (matchesAnyComponents(intent, potentialTarget.getReceivers(), protectedBroadcasts)) { 130 return true; 131 } 132 if (matchesAnyComponents( 133 intent, potentialTarget.getProviders(), null /*protectedBroadcasts*/)) { 134 return true; 135 } 136 return false; 137 } 138 matchesAnyComponents(Intent intent, List<? extends ParsedMainComponent> components, WatchedArrayList<String> protectedBroadcasts)139 private static boolean matchesAnyComponents(Intent intent, 140 List<? extends ParsedMainComponent> components, 141 WatchedArrayList<String> protectedBroadcasts) { 142 for (int i = ArrayUtils.size(components) - 1; i >= 0; i--) { 143 ParsedMainComponent component = components.get(i); 144 if (!component.isExported()) { 145 continue; 146 } 147 if (matchesAnyFilter(intent, component, protectedBroadcasts)) { 148 return true; 149 } 150 } 151 return false; 152 } 153 matchesAnyFilter(Intent intent, ParsedComponent component, WatchedArrayList<String> protectedBroadcasts)154 private static boolean matchesAnyFilter(Intent intent, ParsedComponent component, 155 WatchedArrayList<String> protectedBroadcasts) { 156 List<ParsedIntentInfo> intents = component.getIntents(); 157 for (int i = ArrayUtils.size(intents) - 1; i >= 0; i--) { 158 IntentFilter intentFilter = intents.get(i).getIntentFilter(); 159 if (matchesIntentFilter(intent, intentFilter, protectedBroadcasts)) { 160 return true; 161 } 162 } 163 return false; 164 } 165 matchesIntentFilter(Intent intent, IntentFilter intentFilter, @Nullable WatchedArrayList<String> protectedBroadcasts)166 private static boolean matchesIntentFilter(Intent intent, IntentFilter intentFilter, 167 @Nullable WatchedArrayList<String> protectedBroadcasts) { 168 return intentFilter.match(intent.getAction(), intent.getType(), intent.getScheme(), 169 intent.getData(), intent.getCategories(), "AppsFilter", true, 170 protectedBroadcasts != null ? protectedBroadcasts.untrackedStorage() : null) > 0; 171 } 172 } 173