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 return NativeLibraryHelper.Handle.create( 159 AndroidPackageUtils.getAllCodePaths(pkg), 160 pkg.isMultiArch(), 161 pkg.isExtractNativeLibrariesRequested(), 162 pkg.isDebuggable() 163 ); 164 } 165 canHaveOatDir(@onNull PackageState packageState, @NonNull AndroidPackage pkg)166 public static boolean canHaveOatDir(@NonNull PackageState packageState, 167 @NonNull AndroidPackage pkg) { 168 // The following app types CANNOT have oat directory 169 // - non-updated system apps, 170 // - incrementally installed apps. 171 if (packageState.isSystem() && !packageState.isUpdatedSystemApp()) { 172 return false; 173 } 174 if (IncrementalManager.isIncrementalPath(pkg.getPath())) { 175 return false; 176 } 177 return true; 178 } 179 hasComponentClassName(AndroidPackage pkg, String className)180 public static boolean hasComponentClassName(AndroidPackage pkg, String className) { 181 List<ParsedActivity> activities = pkg.getActivities(); 182 int activitiesSize = activities.size(); 183 for (int index = 0; index < activitiesSize; index++) { 184 if (Objects.equals(className, activities.get(index).getName())) { 185 return true; 186 } 187 } 188 189 List<ParsedActivity> receivers = pkg.getReceivers(); 190 int receiversSize = receivers.size(); 191 for (int index = 0; index < receiversSize; index++) { 192 if (Objects.equals(className, receivers.get(index).getName())) { 193 return true; 194 } 195 } 196 197 List<ParsedProvider> providers = pkg.getProviders(); 198 int providersSize = providers.size(); 199 for (int index = 0; index < providersSize; index++) { 200 if (Objects.equals(className, providers.get(index).getName())) { 201 return true; 202 } 203 } 204 205 List<ParsedService> services = pkg.getServices(); 206 int servicesSize = services.size(); 207 for (int index = 0; index < servicesSize; index++) { 208 if (Objects.equals(className, services.get(index).getName())) { 209 return true; 210 } 211 } 212 213 List<ParsedInstrumentation> instrumentations = pkg.getInstrumentations(); 214 int instrumentationsSize = instrumentations.size(); 215 for (int index = 0; index < instrumentationsSize; index++) { 216 if (Objects.equals(className, instrumentations.get(index).getName())) { 217 return true; 218 } 219 } 220 221 if (pkg.getBackupAgentName() != null) { 222 if (Objects.equals(className, pkg.getBackupAgentName())) { 223 return true; 224 } 225 } 226 227 return false; 228 } 229 isEncryptionAware(AndroidPackage pkg)230 public static boolean isEncryptionAware(AndroidPackage pkg) { 231 return pkg.isDirectBootAware() || pkg.isPartiallyDirectBootAware(); 232 } 233 isLibrary(AndroidPackage pkg)234 public static boolean isLibrary(AndroidPackage pkg) { 235 // TODO(b/135203078): Can parsing just enforce these always match? 236 return pkg.getSdkLibraryName() != null || pkg.getStaticSharedLibraryName() != null 237 || !pkg.getLibraryNames().isEmpty(); 238 } 239 getHiddenApiEnforcementPolicy(@onNull AndroidPackage pkg, @NonNull PackageStateInternal packageState)240 public static int getHiddenApiEnforcementPolicy(@NonNull AndroidPackage pkg, 241 @NonNull PackageStateInternal packageState) { 242 boolean isAllowedToUseHiddenApis; 243 if (pkg == null) { 244 isAllowedToUseHiddenApis = false; 245 } else if (pkg.isSignedWithPlatformKey()) { 246 isAllowedToUseHiddenApis = true; 247 } else if (packageState.isSystem()) { 248 isAllowedToUseHiddenApis = pkg.isNonSdkApiRequested() 249 || SystemConfig.getInstance().getHiddenApiWhitelistedApps().contains( 250 pkg.getPackageName()); 251 } else { 252 isAllowedToUseHiddenApis = false; 253 } 254 255 if (isAllowedToUseHiddenApis) { 256 return ApplicationInfo.HIDDEN_API_ENFORCEMENT_DISABLED; 257 } 258 259 // TODO(b/135203078): Handle maybeUpdateHiddenApiEnforcementPolicy. Right now it's done 260 // entirely through ApplicationInfo and shouldn't touch this specific class, but that 261 // may not always hold true. 262 // if (mHiddenApiPolicy != ApplicationInfo.HIDDEN_API_ENFORCEMENT_DEFAULT) { 263 // return mHiddenApiPolicy; 264 // } 265 return ApplicationInfo.HIDDEN_API_ENFORCEMENT_ENABLED; 266 } 267 268 /** 269 * Returns false iff the provided flags include the {@link PackageManager#MATCH_SYSTEM_ONLY} 270 * flag and the provided package is not a system package. Otherwise returns {@code true}. 271 */ isMatchForSystemOnly(@onNull PackageState packageState, long flags)272 public static boolean isMatchForSystemOnly(@NonNull PackageState packageState, long flags) { 273 if ((flags & PackageManager.MATCH_SYSTEM_ONLY) != 0) { 274 return packageState.isSystem(); 275 } 276 return true; 277 } 278 279 /** 280 * Returns the primary ABI as parsed from the package. Used only during parsing and derivation. 281 * Otherwise prefer {@link PackageState#getPrimaryCpuAbi()}. 282 */ getRawPrimaryCpuAbi(AndroidPackage pkg)283 public static String getRawPrimaryCpuAbi(AndroidPackage pkg) { 284 return ((AndroidPackageHidden) pkg).getPrimaryCpuAbi(); 285 } 286 287 /** 288 * Returns the secondary ABI as parsed from the package. Used only during parsing and 289 * derivation. Otherwise prefer {@link PackageState#getSecondaryCpuAbi()}. 290 */ getRawSecondaryCpuAbi(@onNull AndroidPackage pkg)291 public static String getRawSecondaryCpuAbi(@NonNull AndroidPackage pkg) { 292 return ((AndroidPackageHidden) pkg).getSecondaryCpuAbi(); 293 } 294 295 @Deprecated 296 @NonNull generateAppInfoWithoutState(AndroidPackage pkg)297 public static ApplicationInfo generateAppInfoWithoutState(AndroidPackage pkg) { 298 return ((AndroidPackageHidden) pkg).toAppInfoWithoutState(); 299 } 300 301 /** 302 * Replacement of unnecessary legacy getRealPackage. Only returns a value if the package was 303 * actually renamed. 304 */ 305 @Nullable getRealPackageOrNull(@onNull AndroidPackage pkg, boolean isSystem)306 public static String getRealPackageOrNull(@NonNull AndroidPackage pkg, boolean isSystem) { 307 if (pkg.getOriginalPackages().isEmpty() || !isSystem) { 308 return null; 309 } 310 311 return pkg.getManifestPackageName(); 312 } 313 fillVersionCodes(@onNull AndroidPackage pkg, @NonNull PackageInfo info)314 public static void fillVersionCodes(@NonNull AndroidPackage pkg, @NonNull PackageInfo info) { 315 info.versionCode = ((ParsingPackageHidden) pkg).getVersionCode(); 316 info.versionCodeMajor = ((ParsingPackageHidden) pkg).getVersionCodeMajor(); 317 } 318 } 319