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.pkg; 18 19 import static android.content.pm.PackageManager.MATCH_DISABLED_COMPONENTS; 20 import static android.content.pm.PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS; 21 import static android.content.pm.PackageManager.MATCH_QUARANTINED_COMPONENTS; 22 23 import android.annotation.NonNull; 24 import android.content.pm.ComponentInfo; 25 import android.content.pm.PackageManager; 26 import android.os.Debug; 27 import android.util.DebugUtils; 28 import android.util.Slog; 29 30 import com.android.internal.pm.pkg.component.ParsedMainComponent; 31 32 /** @hide */ 33 public class PackageUserStateUtils { 34 35 private static final boolean DEBUG = false; 36 private static final String TAG = "PackageUserStateUtils"; 37 isMatch(@onNull PackageUserState state, ComponentInfo componentInfo, long flags)38 public static boolean isMatch(@NonNull PackageUserState state, 39 ComponentInfo componentInfo, long flags) { 40 return isMatch(state, componentInfo.applicationInfo.isSystemApp(), 41 componentInfo.applicationInfo.enabled, componentInfo.enabled, 42 componentInfo.directBootAware, componentInfo.name, flags); 43 } 44 isMatch(@onNull PackageUserState state, boolean isSystem, boolean isPackageEnabled, ParsedMainComponent component, long flags)45 public static boolean isMatch(@NonNull PackageUserState state, boolean isSystem, 46 boolean isPackageEnabled, ParsedMainComponent component, long flags) { 47 return isMatch(state, isSystem, isPackageEnabled, component.isEnabled(), 48 component.isDirectBootAware(), component.getName(), flags); 49 } 50 51 /** 52 * Test if the given component is considered installed, enabled and a match for the given 53 * flags. 54 * 55 * <p> 56 * Expects at least one of {@link PackageManager#MATCH_DIRECT_BOOT_AWARE} and {@link 57 * PackageManager#MATCH_DIRECT_BOOT_UNAWARE} are specified in {@code flags}. 58 * </p> 59 */ isMatch(@onNull PackageUserState state, boolean isSystem, boolean isPackageEnabled, boolean isComponentEnabled, boolean isComponentDirectBootAware, String componentName, long flags)60 public static boolean isMatch(@NonNull PackageUserState state, boolean isSystem, 61 boolean isPackageEnabled, boolean isComponentEnabled, 62 boolean isComponentDirectBootAware, String componentName, long flags) { 63 final boolean matchUninstalled = (flags & PackageManager.MATCH_KNOWN_PACKAGES) != 0; 64 if (!isAvailable(state, flags) && !(isSystem && matchUninstalled)) { 65 return reportIfDebug(false, flags); 66 } 67 68 if (!isEnabled(state, isPackageEnabled, isComponentEnabled, componentName, flags)) { 69 return reportIfDebug(false, flags); 70 } 71 72 if ((flags & PackageManager.MATCH_SYSTEM_ONLY) != 0) { 73 if (!isSystem) { 74 return reportIfDebug(false, flags); 75 } 76 } 77 78 final boolean matchesUnaware = ((flags & PackageManager.MATCH_DIRECT_BOOT_UNAWARE) != 0) 79 && !isComponentDirectBootAware; 80 final boolean matchesAware = ((flags & PackageManager.MATCH_DIRECT_BOOT_AWARE) != 0) 81 && isComponentDirectBootAware; 82 return reportIfDebug(matchesUnaware || matchesAware, flags); 83 } 84 85 /** 86 * @return true if any of the following conditions is met: 87 * <p><ul> 88 * <li> If it is installed and not hidden for this user; 89 * <li> If it is installed but hidden for this user, still return true if 90 * {@link PackageManager#MATCH_UNINSTALLED_PACKAGES} or 91 * {@link PackageManager#MATCH_ARCHIVED_PACKAGES} is requested; 92 * <li> If MATCH_ANY_USER is requested, always return true, because the fact that 93 * this object exists means that the package must be installed or has data on at least one user; 94 * <li> If it is not installed but still has data (i.e., it was previously uninstalled with 95 * {@link PackageManager#DELETE_KEEP_DATA}), return true if the caller requested 96 * {@link PackageManager#MATCH_UNINSTALLED_PACKAGES} or 97 * {@link PackageManager#MATCH_ARCHIVED_PACKAGES}; 98 * </ul><p> 99 */ isAvailable(@onNull PackageUserState state, long flags)100 public static boolean isAvailable(@NonNull PackageUserState state, long flags) { 101 final boolean matchAnyUser = (flags & PackageManager.MATCH_ANY_USER) != 0; 102 final boolean matchUninstalled = (flags & PackageManager.MATCH_UNINSTALLED_PACKAGES) != 0; 103 final boolean matchArchived = (flags & PackageManager.MATCH_ARCHIVED_PACKAGES) != 0; 104 final boolean matchDataExists = matchUninstalled || matchArchived; 105 106 if (matchAnyUser) { 107 return true; 108 } 109 if (state.isInstalled()) { 110 if (!state.isHidden()) { 111 return true; 112 } else return matchDataExists; 113 } else { 114 // not installed 115 return matchDataExists && state.dataExists(); 116 } 117 } 118 reportIfDebug(boolean result, long flags)119 public static boolean reportIfDebug(boolean result, long flags) { 120 if (DEBUG && !result) { 121 Slog.i(TAG, "No match!; flags: " 122 + DebugUtils.flagsToString(PackageManager.class, "MATCH_", flags) + " " 123 + Debug.getCaller()); 124 } 125 return result; 126 } 127 isEnabled(@onNull PackageUserState state, ComponentInfo componentInfo, long flags)128 public static boolean isEnabled(@NonNull PackageUserState state, ComponentInfo componentInfo, 129 long flags) { 130 return isEnabled(state, componentInfo.applicationInfo.enabled, componentInfo.enabled, 131 componentInfo.name, flags); 132 } 133 isEnabled(@onNull PackageUserState state, boolean isPackageEnabled, ParsedMainComponent parsedComponent, long flags)134 public static boolean isEnabled(@NonNull PackageUserState state, boolean isPackageEnabled, 135 ParsedMainComponent parsedComponent, long flags) { 136 return isEnabled(state, isPackageEnabled, parsedComponent.isEnabled(), 137 parsedComponent.getName(), flags); 138 } 139 140 /** 141 * Test if the given component is considered enabled. 142 */ isEnabled(@onNull PackageUserState state, boolean isPackageEnabled, boolean isComponentEnabled, String componentName, long flags)143 public static boolean isEnabled(@NonNull PackageUserState state, 144 boolean isPackageEnabled, boolean isComponentEnabled, String componentName, 145 long flags) { 146 if ((flags & MATCH_DISABLED_COMPONENTS) != 0) { 147 return true; 148 } 149 150 if ((flags & MATCH_QUARANTINED_COMPONENTS) == 0 && state.isQuarantined()) { 151 return false; 152 } 153 154 // First check if the overall package is disabled; if the package is 155 // enabled then fall through to check specific component 156 switch (state.getEnabledState()) { 157 case PackageManager.COMPONENT_ENABLED_STATE_DISABLED: 158 case PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER: 159 return false; 160 case PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED: 161 if ((flags & MATCH_DISABLED_UNTIL_USED_COMPONENTS) == 0) { 162 return false; 163 } 164 // fallthrough 165 case PackageManager.COMPONENT_ENABLED_STATE_DEFAULT: 166 if (!isPackageEnabled) { 167 return false; 168 } 169 // fallthrough 170 case PackageManager.COMPONENT_ENABLED_STATE_ENABLED: 171 break; 172 } 173 174 // Check if component has explicit state before falling through to 175 // the manifest default 176 if (state.isComponentEnabled(componentName)) { 177 return true; 178 } else if (state.isComponentDisabled(componentName)) { 179 return false; 180 } 181 182 return isComponentEnabled; 183 } 184 isPackageEnabled(@onNull PackageUserState state, @NonNull AndroidPackage pkg)185 public static boolean isPackageEnabled(@NonNull PackageUserState state, 186 @NonNull AndroidPackage pkg) { 187 switch (state.getEnabledState()) { 188 case PackageManager.COMPONENT_ENABLED_STATE_ENABLED: 189 return true; 190 case PackageManager.COMPONENT_ENABLED_STATE_DISABLED: 191 case PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER: 192 case PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED: 193 return false; 194 default: 195 case PackageManager.COMPONENT_ENABLED_STATE_DEFAULT: 196 return pkg.isEnabled(); 197 } 198 } 199 } 200