1 /* 2 * Copyright (C) 2019 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.internal.infra; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.content.ComponentName; 22 import android.util.ArrayMap; 23 import android.util.ArraySet; 24 import android.util.Log; 25 26 import com.android.internal.util.Preconditions; 27 28 import java.io.PrintWriter; 29 import java.util.List; 30 31 /** 32 * Helper class for keeping track of whitelisted packages/activities. 33 * 34 * <p><b>NOTE: </b>this class is not thread safe. 35 * @hide 36 */ 37 public final class WhitelistHelper { 38 39 private static final String TAG = "WhitelistHelper"; 40 41 /** 42 * Map of whitelisted packages/activities. The whole package is whitelisted if its 43 * corresponding value is {@code null}. 44 */ 45 @Nullable 46 private ArrayMap<String, ArraySet<ComponentName>> mWhitelistedPackages; 47 48 /** 49 * Sets the whitelist with the given packages and activities. The list is cleared if both 50 * packageNames and components are {@code null}. 51 * 52 * @param packageNames packages to be whitelisted. 53 * @param components activities to be whitelisted. 54 * 55 * @throws IllegalArgumentException if packages or components are empty. 56 */ setWhitelist(@ullable ArraySet<String> packageNames, @Nullable ArraySet<ComponentName> components)57 public void setWhitelist(@Nullable ArraySet<String> packageNames, 58 @Nullable ArraySet<ComponentName> components) { 59 mWhitelistedPackages = null; 60 if (packageNames == null && components == null) return; 61 62 if ((packageNames != null && packageNames.isEmpty()) 63 || (components != null && components.isEmpty())) { 64 throw new IllegalArgumentException("Packages or Components cannot be empty."); 65 } 66 67 mWhitelistedPackages = new ArrayMap<>(); 68 69 if (packageNames != null) { 70 for (int i = 0; i < packageNames.size(); i++) { 71 mWhitelistedPackages.put(packageNames.valueAt(i), null); 72 } 73 } 74 75 if (components != null) { 76 for (int i = 0; i < components.size(); i++) { 77 final ComponentName component = components.valueAt(i); 78 if (component == null) { 79 Log.w(TAG, "setWhitelist(): component is null"); 80 continue; 81 } 82 83 final String packageName = component.getPackageName(); 84 ArraySet<ComponentName> set = mWhitelistedPackages.get(packageName); 85 if (set == null) { 86 set = new ArraySet<>(); 87 mWhitelistedPackages.put(packageName, set); 88 } 89 set.add(component); 90 } 91 } 92 } 93 94 /** 95 * Helper to use {@link #setWhitelist(ArraySet, ArraySet)} with {@link List Lists}. 96 */ setWhitelist(@ullable List<String> packageNames, @Nullable List<ComponentName> components)97 public void setWhitelist(@Nullable List<String> packageNames, 98 @Nullable List<ComponentName> components) { 99 final ArraySet<String> packageNamesSet = packageNames == null ? null 100 : new ArraySet<>(packageNames); 101 final ArraySet<ComponentName> componentsSet = components == null ? null 102 : new ArraySet<>(components); 103 setWhitelist(packageNamesSet, componentsSet); 104 } 105 106 /** 107 * Returns {@code true} if the entire package is whitelisted. 108 */ isWhitelisted(@onNull String packageName)109 public boolean isWhitelisted(@NonNull String packageName) { 110 Preconditions.checkNotNull(packageName); 111 112 if (mWhitelistedPackages == null) return false; 113 114 return mWhitelistedPackages.containsKey(packageName) 115 && mWhitelistedPackages.get(packageName) == null; 116 } 117 118 /** 119 * Returns {@code true} if the specified activity is whitelisted. 120 */ isWhitelisted(@onNull ComponentName componentName)121 public boolean isWhitelisted(@NonNull ComponentName componentName) { 122 Preconditions.checkNotNull(componentName); 123 124 final String packageName = componentName.getPackageName(); 125 final ArraySet<ComponentName> whitelistedComponents = getWhitelistedComponents(packageName); 126 if (whitelistedComponents != null) { 127 return whitelistedComponents.contains(componentName); 128 } 129 130 return isWhitelisted(packageName); 131 } 132 133 /** 134 * Returns a set of whitelisted components with the given package, or null if nothing is 135 * whitelisted. 136 */ 137 @Nullable getWhitelistedComponents(@onNull String packageName)138 public ArraySet<ComponentName> getWhitelistedComponents(@NonNull String packageName) { 139 Preconditions.checkNotNull(packageName); 140 141 return mWhitelistedPackages == null ? null : mWhitelistedPackages.get(packageName); 142 } 143 144 @Override toString()145 public String toString() { 146 return "WhitelistHelper[" + mWhitelistedPackages + ']'; 147 } 148 149 /** 150 * Dumps it! 151 */ dump(@onNull String prefix, @NonNull String message, @NonNull PrintWriter pw)152 public void dump(@NonNull String prefix, @NonNull String message, @NonNull PrintWriter pw) { 153 if (mWhitelistedPackages == null || mWhitelistedPackages.size() == 0) { 154 pw.print(prefix); pw.print(message); pw.println(": (no whitelisted packages)"); 155 return; 156 } 157 158 final String prefix2 = prefix + " "; 159 final int size = mWhitelistedPackages.size(); 160 pw.print(prefix); pw.print(message); pw.print(": "); pw.print(size); 161 pw.println(" packages"); 162 for (int i = 0; i < mWhitelistedPackages.size(); i++) { 163 final String packageName = mWhitelistedPackages.keyAt(i); 164 final ArraySet<ComponentName> components = mWhitelistedPackages.valueAt(i); 165 pw.print(prefix2); pw.print(i); pw.print("."); pw.print(packageName); pw.print(": "); 166 if (components == null) { 167 pw.println("(whole package)"); 168 continue; 169 } 170 171 pw.print("["); pw.print(components.valueAt(0)); 172 for (int j = 1; j < components.size(); j++) { 173 pw.print(", "); pw.print(components.valueAt(j)); 174 } 175 pw.println("]"); 176 } 177 } 178 } 179