1 /* 2 * Copyright (C) 2020 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.parsing.pkg; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.content.pm.ApplicationInfo; 22 import android.content.pm.PackageInfo; 23 import android.content.pm.PackageManager; 24 import android.content.pm.SharedLibraryInfo; 25 import android.content.pm.VersionedPackage; 26 import android.content.pm.dex.DexMetadataHelper; 27 import android.content.pm.parsing.result.ParseResult; 28 import android.content.pm.parsing.result.ParseTypeImpl; 29 import android.os.incremental.IncrementalManager; 30 31 import com.android.internal.content.NativeLibraryHelper; 32 import com.android.internal.pm.parsing.PackageParserException; 33 import com.android.internal.pm.parsing.pkg.AndroidPackageHidden; 34 import com.android.internal.pm.parsing.pkg.PackageImpl; 35 import com.android.internal.pm.pkg.component.ParsedActivity; 36 import com.android.internal.pm.pkg.component.ParsedInstrumentation; 37 import com.android.internal.pm.pkg.component.ParsedProvider; 38 import com.android.internal.pm.pkg.component.ParsedService; 39 import com.android.internal.pm.pkg.parsing.ParsingPackageHidden; 40 import com.android.internal.util.ArrayUtils; 41 import com.android.server.SystemConfig; 42 import com.android.server.pm.pkg.AndroidPackage; 43 import com.android.server.pm.pkg.PackageState; 44 import com.android.server.pm.pkg.PackageStateInternal; 45 46 import java.io.IOException; 47 import java.util.ArrayList; 48 import java.util.Collection; 49 import java.util.Collections; 50 import java.util.List; 51 import java.util.Map; 52 import java.util.Objects; 53 54 /** @hide */ 55 public class AndroidPackageUtils { 56 AndroidPackageUtils()57 private AndroidPackageUtils() { 58 } 59 getAllCodePathsExcludingResourceOnly( AndroidPackage aPkg)60 public static List<String> getAllCodePathsExcludingResourceOnly( 61 AndroidPackage aPkg) { 62 PackageImpl pkg = (PackageImpl) aPkg; 63 ArrayList<String> paths = new ArrayList<>(); 64 if (pkg.isDeclaredHavingCode()) { 65 paths.add(pkg.getBaseApkPath()); 66 } 67 String[] splitCodePaths = pkg.getSplitCodePaths(); 68 if (!ArrayUtils.isEmpty(splitCodePaths)) { 69 for (int i = 0; i < splitCodePaths.length; i++) { 70 if ((pkg.getSplitFlags()[i] & ApplicationInfo.FLAG_HAS_CODE) != 0) { 71 paths.add(splitCodePaths[i]); 72 } 73 } 74 } 75 return paths; 76 } 77 78 /** 79 * @return a list of the base and split code paths. 80 */ getAllCodePaths(AndroidPackage aPkg)81 public static List<String> getAllCodePaths(AndroidPackage aPkg) { 82 PackageImpl pkg = (PackageImpl) aPkg; 83 ArrayList<String> paths = new ArrayList<>(); 84 paths.add(pkg.getBaseApkPath()); 85 86 String[] splitCodePaths = pkg.getSplitCodePaths(); 87 if (!ArrayUtils.isEmpty(splitCodePaths)) { 88 Collections.addAll(paths, splitCodePaths); 89 } 90 return paths; 91 } 92 createSharedLibraryForSdk(AndroidPackage pkg)93 public static SharedLibraryInfo createSharedLibraryForSdk(AndroidPackage pkg) { 94 return new SharedLibraryInfo(null, pkg.getPackageName(), 95 AndroidPackageUtils.getAllCodePaths(pkg), 96 pkg.getSdkLibraryName(), 97 pkg.getSdkLibVersionMajor(), 98 SharedLibraryInfo.TYPE_SDK_PACKAGE, 99 new VersionedPackage(pkg.getManifestPackageName(), 100 pkg.getLongVersionCode()), 101 null, null, false /* isNative */); 102 } 103 createSharedLibraryForStatic(AndroidPackage pkg)104 public static SharedLibraryInfo createSharedLibraryForStatic(AndroidPackage pkg) { 105 return new SharedLibraryInfo(null, pkg.getPackageName(), 106 AndroidPackageUtils.getAllCodePaths(pkg), 107 pkg.getStaticSharedLibraryName(), 108 pkg.getStaticSharedLibraryVersion(), 109 SharedLibraryInfo.TYPE_STATIC, 110 new VersionedPackage(pkg.getManifestPackageName(), 111 pkg.getLongVersionCode()), 112 null, null, false /* isNative */); 113 } 114 createSharedLibraryForDynamic(AndroidPackage pkg, String name)115 public static SharedLibraryInfo createSharedLibraryForDynamic(AndroidPackage pkg, String name) { 116 return new SharedLibraryInfo(null, pkg.getPackageName(), 117 AndroidPackageUtils.getAllCodePaths(pkg), name, 118 SharedLibraryInfo.VERSION_UNDEFINED, 119 SharedLibraryInfo.TYPE_DYNAMIC, new VersionedPackage(pkg.getPackageName(), 120 pkg.getLongVersionCode()), 121 null, null, false /* isNative */); 122 } 123 124 /** 125 * Return the dex metadata files for the given package as a map 126 * [code path -> dex metadata path]. 127 * 128 * NOTE: involves I/O checks. 129 */ getPackageDexMetadata(AndroidPackage pkg)130 public static Map<String, String> getPackageDexMetadata(AndroidPackage pkg) { 131 return DexMetadataHelper.buildPackageApkToDexMetadataMap 132 (AndroidPackageUtils.getAllCodePaths(pkg)); 133 } 134 135 /** 136 * Validate the dex metadata files installed for the given package. 137 * 138 * @throws PackageParserException in case of errors. 139 */ validatePackageDexMetadata(AndroidPackage pkg)140 public static void validatePackageDexMetadata(AndroidPackage pkg) 141 throws PackageParserException { 142 Collection<String> apkToDexMetadataList = getPackageDexMetadata(pkg).values(); 143 String packageName = pkg.getPackageName(); 144 long versionCode = pkg.getLongVersionCode(); 145 final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing(); 146 for (String dexMetadata : apkToDexMetadataList) { 147 final ParseResult result = DexMetadataHelper.validateDexMetadataFile( 148 input.reset(), dexMetadata, packageName, versionCode); 149 if (result.isError()) { 150 throw new PackageParserException( 151 result.getErrorCode(), result.getErrorMessage(), result.getException()); 152 } 153 } 154 } 155 createNativeLibraryHandle(AndroidPackage pkg)156 public static NativeLibraryHelper.Handle createNativeLibraryHandle(AndroidPackage pkg) 157 throws IOException { 158 boolean pageSizeCompatDisabled = pkg.getPageSizeAppCompatFlags() 159 == ApplicationInfo.PAGE_SIZE_APP_COMPAT_FLAG_MANIFEST_OVERRIDE_DISABLED; 160 return NativeLibraryHelper.Handle.create( 161 AndroidPackageUtils.getAllCodePaths(pkg), 162 pkg.isMultiArch(), 163 pkg.isExtractNativeLibrariesRequested(), 164 pkg.isDebuggable(), 165 pageSizeCompatDisabled 166 ); 167 } 168 canHaveOatDir(@onNull PackageState packageState, @NonNull AndroidPackage pkg)169 public static boolean canHaveOatDir(@NonNull PackageState packageState, 170 @NonNull AndroidPackage pkg) { 171 // The following app types CANNOT have oat directory 172 // - non-updated system apps, 173 // - incrementally installed apps. 174 if (packageState.isSystem() && !packageState.isUpdatedSystemApp()) { 175 return false; 176 } 177 if (IncrementalManager.isIncrementalPath(pkg.getPath())) { 178 return false; 179 } 180 return true; 181 } 182 hasComponentClassName(AndroidPackage pkg, String className)183 public static boolean hasComponentClassName(AndroidPackage pkg, String className) { 184 List<ParsedActivity> activities = pkg.getActivities(); 185 int activitiesSize = activities.size(); 186 for (int index = 0; index < activitiesSize; index++) { 187 if (Objects.equals(className, activities.get(index).getName())) { 188 return true; 189 } 190 } 191 192 List<ParsedActivity> receivers = pkg.getReceivers(); 193 int receiversSize = receivers.size(); 194 for (int index = 0; index < receiversSize; index++) { 195 if (Objects.equals(className, receivers.get(index).getName())) { 196 return true; 197 } 198 } 199 200 List<ParsedProvider> providers = pkg.getProviders(); 201 int providersSize = providers.size(); 202 for (int index = 0; index < providersSize; index++) { 203 if (Objects.equals(className, providers.get(index).getName())) { 204 return true; 205 } 206 } 207 208 List<ParsedService> services = pkg.getServices(); 209 int servicesSize = services.size(); 210 for (int index = 0; index < servicesSize; index++) { 211 if (Objects.equals(className, services.get(index).getName())) { 212 return true; 213 } 214 } 215 216 List<ParsedInstrumentation> instrumentations = pkg.getInstrumentations(); 217 int instrumentationsSize = instrumentations.size(); 218 for (int index = 0; index < instrumentationsSize; index++) { 219 if (Objects.equals(className, instrumentations.get(index).getName())) { 220 return true; 221 } 222 } 223 224 if (pkg.getBackupAgentName() != null) { 225 if (Objects.equals(className, pkg.getBackupAgentName())) { 226 return true; 227 } 228 } 229 230 return false; 231 } 232 isEncryptionAware(AndroidPackage pkg)233 public static boolean isEncryptionAware(AndroidPackage pkg) { 234 return pkg.isDirectBootAware() || pkg.isPartiallyDirectBootAware(); 235 } 236 isLibrary(AndroidPackage pkg)237 public static boolean isLibrary(AndroidPackage pkg) { 238 // TODO(b/135203078): Can parsing just enforce these always match? 239 return pkg.getSdkLibraryName() != null || pkg.getStaticSharedLibraryName() != null 240 || !pkg.getLibraryNames().isEmpty(); 241 } 242 getHiddenApiEnforcementPolicy(@onNull AndroidPackage pkg, @NonNull PackageStateInternal packageState)243 public static int getHiddenApiEnforcementPolicy(@NonNull AndroidPackage pkg, 244 @NonNull PackageStateInternal packageState) { 245 boolean isAllowedToUseHiddenApis; 246 if (pkg == null) { 247 isAllowedToUseHiddenApis = false; 248 } else if (pkg.isSignedWithPlatformKey()) { 249 isAllowedToUseHiddenApis = true; 250 } else if (packageState.isSystem()) { 251 isAllowedToUseHiddenApis = pkg.isNonSdkApiRequested() 252 || SystemConfig.getInstance().getHiddenApiWhitelistedApps().contains( 253 pkg.getPackageName()); 254 } else { 255 isAllowedToUseHiddenApis = false; 256 } 257 258 if (isAllowedToUseHiddenApis) { 259 return ApplicationInfo.HIDDEN_API_ENFORCEMENT_DISABLED; 260 } 261 262 // TODO(b/135203078): Handle maybeUpdateHiddenApiEnforcementPolicy. Right now it's done 263 // entirely through ApplicationInfo and shouldn't touch this specific class, but that 264 // may not always hold true. 265 // if (mHiddenApiPolicy != ApplicationInfo.HIDDEN_API_ENFORCEMENT_DEFAULT) { 266 // return mHiddenApiPolicy; 267 // } 268 return ApplicationInfo.HIDDEN_API_ENFORCEMENT_ENABLED; 269 } 270 271 /** 272 * Returns false iff the provided flags include the {@link PackageManager#MATCH_SYSTEM_ONLY} 273 * flag and the provided package is not a system package. Otherwise returns {@code true}. 274 */ isMatchForSystemOnly(@onNull PackageState packageState, long flags)275 public static boolean isMatchForSystemOnly(@NonNull PackageState packageState, long flags) { 276 if ((flags & PackageManager.MATCH_SYSTEM_ONLY) != 0) { 277 return packageState.isSystem(); 278 } 279 return true; 280 } 281 282 /** 283 * Returns the primary ABI as parsed from the package. Used only during parsing and derivation. 284 * Otherwise prefer {@link PackageState#getPrimaryCpuAbi()}. 285 */ getRawPrimaryCpuAbi(AndroidPackage pkg)286 public static String getRawPrimaryCpuAbi(AndroidPackage pkg) { 287 return ((AndroidPackageHidden) pkg).getPrimaryCpuAbi(); 288 } 289 290 /** 291 * Returns the secondary ABI as parsed from the package. Used only during parsing and 292 * derivation. Otherwise prefer {@link PackageState#getSecondaryCpuAbi()}. 293 */ getRawSecondaryCpuAbi(@onNull AndroidPackage pkg)294 public static String getRawSecondaryCpuAbi(@NonNull AndroidPackage pkg) { 295 return ((AndroidPackageHidden) pkg).getSecondaryCpuAbi(); 296 } 297 298 @Deprecated 299 @NonNull generateAppInfoWithoutState(AndroidPackage pkg)300 public static ApplicationInfo generateAppInfoWithoutState(AndroidPackage pkg) { 301 return ((AndroidPackageHidden) pkg).toAppInfoWithoutState(); 302 } 303 304 /** 305 * Replacement of unnecessary legacy getRealPackage. Only returns a value if the package was 306 * actually renamed. 307 */ 308 @Nullable getRealPackageOrNull(@onNull AndroidPackage pkg, boolean isSystem)309 public static String getRealPackageOrNull(@NonNull AndroidPackage pkg, boolean isSystem) { 310 if (pkg.getOriginalPackages().isEmpty() || !isSystem) { 311 return null; 312 } 313 314 return pkg.getManifestPackageName(); 315 } 316 fillVersionCodes(@onNull AndroidPackage pkg, @NonNull PackageInfo info)317 public static void fillVersionCodes(@NonNull AndroidPackage pkg, @NonNull PackageInfo info) { 318 info.versionCode = ((ParsingPackageHidden) pkg).getVersionCode(); 319 info.versionCodeMajor = ((ParsingPackageHidden) pkg).getVersionCodeMajor(); 320 } 321 } 322