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