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 22 import android.annotation.NonNull; 23 import android.content.pm.ComponentInfo; 24 import android.content.pm.PackageManager; 25 import android.os.Debug; 26 import android.util.DebugUtils; 27 import android.util.Slog; 28 29 import com.android.server.pm.pkg.component.ParsedMainComponent; 30 import com.android.server.pm.pkg.parsing.ParsingPackageRead; 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 isAvailable(@onNull PackageUserState state, long flags)85 public static boolean isAvailable(@NonNull PackageUserState state, long flags) { 86 // True if it is installed for this user and it is not hidden. If it is hidden, 87 // still return true if the caller requested MATCH_UNINSTALLED_PACKAGES 88 final boolean matchAnyUser = (flags & PackageManager.MATCH_ANY_USER) != 0; 89 final boolean matchUninstalled = (flags & PackageManager.MATCH_UNINSTALLED_PACKAGES) != 0; 90 return matchAnyUser 91 || (state.isInstalled() 92 && (!state.isHidden() || matchUninstalled)); 93 } 94 reportIfDebug(boolean result, long flags)95 public static boolean reportIfDebug(boolean result, long flags) { 96 if (DEBUG && !result) { 97 Slog.i(TAG, "No match!; flags: " 98 + DebugUtils.flagsToString(PackageManager.class, "MATCH_", flags) + " " 99 + Debug.getCaller()); 100 } 101 return result; 102 } 103 isEnabled(@onNull PackageUserState state, ComponentInfo componentInfo, long flags)104 public static boolean isEnabled(@NonNull PackageUserState state, ComponentInfo componentInfo, 105 long flags) { 106 return isEnabled(state, componentInfo.applicationInfo.enabled, componentInfo.enabled, 107 componentInfo.name, flags); 108 } 109 isEnabled(@onNull PackageUserState state, boolean isPackageEnabled, ParsedMainComponent parsedComponent, long flags)110 public static boolean isEnabled(@NonNull PackageUserState state, boolean isPackageEnabled, 111 ParsedMainComponent parsedComponent, long flags) { 112 return isEnabled(state, isPackageEnabled, parsedComponent.isEnabled(), 113 parsedComponent.getName(), flags); 114 } 115 116 /** 117 * Test if the given component is considered enabled. 118 */ isEnabled(@onNull PackageUserState state, boolean isPackageEnabled, boolean isComponentEnabled, String componentName, long flags)119 public static boolean isEnabled(@NonNull PackageUserState state, 120 boolean isPackageEnabled, boolean isComponentEnabled, String componentName, 121 long flags) { 122 if ((flags & MATCH_DISABLED_COMPONENTS) != 0) { 123 return true; 124 } 125 126 // First check if the overall package is disabled; if the package is 127 // enabled then fall through to check specific component 128 switch (state.getEnabledState()) { 129 case PackageManager.COMPONENT_ENABLED_STATE_DISABLED: 130 case PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER: 131 return false; 132 case PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED: 133 if ((flags & MATCH_DISABLED_UNTIL_USED_COMPONENTS) == 0) { 134 return false; 135 } 136 // fallthrough 137 case PackageManager.COMPONENT_ENABLED_STATE_DEFAULT: 138 if (!isPackageEnabled) { 139 return false; 140 } 141 // fallthrough 142 case PackageManager.COMPONENT_ENABLED_STATE_ENABLED: 143 break; 144 } 145 146 // Check if component has explicit state before falling through to 147 // the manifest default 148 if (state.isComponentEnabled(componentName)) { 149 return true; 150 } else if (state.isComponentDisabled(componentName)) { 151 return false; 152 } 153 154 return isComponentEnabled; 155 } 156 isPackageEnabled(@onNull PackageUserState state, @NonNull ParsingPackageRead pkg)157 public static boolean isPackageEnabled(@NonNull PackageUserState state, 158 @NonNull ParsingPackageRead pkg) { 159 switch (state.getEnabledState()) { 160 case PackageManager.COMPONENT_ENABLED_STATE_ENABLED: 161 return true; 162 case PackageManager.COMPONENT_ENABLED_STATE_DISABLED: 163 case PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER: 164 case PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED: 165 return false; 166 default: 167 case PackageManager.COMPONENT_ENABLED_STATE_DEFAULT: 168 return pkg.isEnabled(); 169 } 170 } 171 } 172