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 31 /** @hide */ 32 public class PackageUserStateUtils { 33 34 private static final boolean DEBUG = false; 35 private static final String TAG = "PackageUserStateUtils"; 36 isMatch(@onNull PackageUserState state, ComponentInfo componentInfo, long flags)37 public static boolean isMatch(@NonNull PackageUserState state, 38 ComponentInfo componentInfo, long flags) { 39 return isMatch(state, componentInfo.applicationInfo.isSystemApp(), 40 componentInfo.applicationInfo.enabled, componentInfo.enabled, 41 componentInfo.directBootAware, componentInfo.name, flags); 42 } 43 isMatch(@onNull PackageUserState state, boolean isSystem, boolean isPackageEnabled, ParsedMainComponent component, long flags)44 public static boolean isMatch(@NonNull PackageUserState state, boolean isSystem, 45 boolean isPackageEnabled, ParsedMainComponent component, long flags) { 46 return isMatch(state, isSystem, isPackageEnabled, component.isEnabled(), 47 component.isDirectBootAware(), component.getName(), flags); 48 } 49 50 /** 51 * Test if the given component is considered installed, enabled and a match for the given 52 * flags. 53 * 54 * <p> 55 * Expects at least one of {@link PackageManager#MATCH_DIRECT_BOOT_AWARE} and {@link 56 * PackageManager#MATCH_DIRECT_BOOT_UNAWARE} are specified in {@code flags}. 57 * </p> 58 */ isMatch(@onNull PackageUserState state, boolean isSystem, boolean isPackageEnabled, boolean isComponentEnabled, boolean isComponentDirectBootAware, String componentName, long flags)59 public static boolean isMatch(@NonNull PackageUserState state, boolean isSystem, 60 boolean isPackageEnabled, boolean isComponentEnabled, 61 boolean isComponentDirectBootAware, String componentName, long flags) { 62 final boolean matchUninstalled = (flags & PackageManager.MATCH_KNOWN_PACKAGES) != 0; 63 if (!isAvailable(state, flags) && !(isSystem && matchUninstalled)) { 64 return reportIfDebug(false, flags); 65 } 66 67 if (!isEnabled(state, isPackageEnabled, isComponentEnabled, componentName, flags)) { 68 return reportIfDebug(false, flags); 69 } 70 71 if ((flags & PackageManager.MATCH_SYSTEM_ONLY) != 0) { 72 if (!isSystem) { 73 return reportIfDebug(false, flags); 74 } 75 } 76 77 final boolean matchesUnaware = ((flags & PackageManager.MATCH_DIRECT_BOOT_UNAWARE) != 0) 78 && !isComponentDirectBootAware; 79 final boolean matchesAware = ((flags & PackageManager.MATCH_DIRECT_BOOT_AWARE) != 0) 80 && isComponentDirectBootAware; 81 return reportIfDebug(matchesUnaware || matchesAware, flags); 82 } 83 isAvailable(@onNull PackageUserState state, long flags)84 public static boolean isAvailable(@NonNull PackageUserState state, long flags) { 85 // True if it is installed for this user and it is not hidden. If it is hidden, 86 // still return true if the caller requested MATCH_UNINSTALLED_PACKAGES 87 final boolean matchAnyUser = (flags & PackageManager.MATCH_ANY_USER) != 0; 88 final boolean matchUninstalled = (flags & PackageManager.MATCH_UNINSTALLED_PACKAGES) != 0; 89 return matchAnyUser 90 || (state.isInstalled() 91 && (!state.isHidden() || matchUninstalled)); 92 } 93 reportIfDebug(boolean result, long flags)94 public static boolean reportIfDebug(boolean result, long flags) { 95 if (DEBUG && !result) { 96 Slog.i(TAG, "No match!; flags: " 97 + DebugUtils.flagsToString(PackageManager.class, "MATCH_", flags) + " " 98 + Debug.getCaller()); 99 } 100 return result; 101 } 102 isEnabled(@onNull PackageUserState state, ComponentInfo componentInfo, long flags)103 public static boolean isEnabled(@NonNull PackageUserState state, ComponentInfo componentInfo, 104 long flags) { 105 return isEnabled(state, componentInfo.applicationInfo.enabled, componentInfo.enabled, 106 componentInfo.name, flags); 107 } 108 isEnabled(@onNull PackageUserState state, boolean isPackageEnabled, ParsedMainComponent parsedComponent, long flags)109 public static boolean isEnabled(@NonNull PackageUserState state, boolean isPackageEnabled, 110 ParsedMainComponent parsedComponent, long flags) { 111 return isEnabled(state, isPackageEnabled, parsedComponent.isEnabled(), 112 parsedComponent.getName(), flags); 113 } 114 115 /** 116 * Test if the given component is considered enabled. 117 */ isEnabled(@onNull PackageUserState state, boolean isPackageEnabled, boolean isComponentEnabled, String componentName, long flags)118 public static boolean isEnabled(@NonNull PackageUserState state, 119 boolean isPackageEnabled, boolean isComponentEnabled, String componentName, 120 long flags) { 121 if ((flags & MATCH_DISABLED_COMPONENTS) != 0) { 122 return true; 123 } 124 125 // First check if the overall package is disabled; if the package is 126 // enabled then fall through to check specific component 127 switch (state.getEnabledState()) { 128 case PackageManager.COMPONENT_ENABLED_STATE_DISABLED: 129 case PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER: 130 return false; 131 case PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED: 132 if ((flags & MATCH_DISABLED_UNTIL_USED_COMPONENTS) == 0) { 133 return false; 134 } 135 // fallthrough 136 case PackageManager.COMPONENT_ENABLED_STATE_DEFAULT: 137 if (!isPackageEnabled) { 138 return false; 139 } 140 // fallthrough 141 case PackageManager.COMPONENT_ENABLED_STATE_ENABLED: 142 break; 143 } 144 145 // Check if component has explicit state before falling through to 146 // the manifest default 147 if (state.isComponentEnabled(componentName)) { 148 return true; 149 } else if (state.isComponentDisabled(componentName)) { 150 return false; 151 } 152 153 return isComponentEnabled; 154 } 155 isPackageEnabled(@onNull PackageUserState state, @NonNull AndroidPackage pkg)156 public static boolean isPackageEnabled(@NonNull PackageUserState state, 157 @NonNull AndroidPackage pkg) { 158 switch (state.getEnabledState()) { 159 case PackageManager.COMPONENT_ENABLED_STATE_ENABLED: 160 return true; 161 case PackageManager.COMPONENT_ENABLED_STATE_DISABLED: 162 case PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER: 163 case PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED: 164 return false; 165 default: 166 case PackageManager.COMPONENT_ENABLED_STATE_DEFAULT: 167 return pkg.isEnabled(); 168 } 169 } 170 } 171