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