2 * Copyright (C) 2020 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.server.pm.parsing.pkg;
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.PackageParser;
25 import android.content.pm.PackageParser.PackageParserException;
26 import android.content.pm.SharedLibraryInfo;
27 import android.content.pm.VersionedPackage;
28 import android.content.pm.dex.DexMetadataHelper;
29 import android.content.pm.parsing.ParsingPackageRead;
30 import android.content.pm.parsing.component.ParsedActivity;
31 import android.content.pm.parsing.component.ParsedInstrumentation;
32 import android.content.pm.parsing.component.ParsedProvider;
33 import android.content.pm.parsing.component.ParsedService;
34 import android.os.incremental.IncrementalManager;
35 import android.text.TextUtils;
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.PackageSetting;
42 import java.io.IOException;
43 import java.util.ArrayList;
44 import java.util.Collection;
45 import java.util.Collections;
46 import java.util.List;
48 import java.util.Objects;
51 public class AndroidPackageUtils {
53 private AndroidPackageUtils() {
56 public static List<String> getAllCodePathsExcludingResourceOnly(
57 AndroidPackage aPkg) {
58 PackageImpl pkg = (PackageImpl) aPkg;
59 ArrayList<String> paths = new ArrayList<>();
60 if (pkg.isHasCode()) {
61 paths.add(pkg.getBaseCodePath());
63 String[] splitCodePaths = pkg.getSplitCodePaths();
64 if (!ArrayUtils.isEmpty(splitCodePaths)) {
65 for (int i = 0; i < splitCodePaths.length; i++) {
66 if ((pkg.getSplitFlags()[i] & ApplicationInfo.FLAG_HAS_CODE) != 0) {
67 paths.add(splitCodePaths[i]);
75 * @return a list of the base and split code paths.
77 public static List<String> getAllCodePaths(AndroidPackage aPkg) {
78 PackageImpl pkg = (PackageImpl) aPkg;
79 ArrayList<String> paths = new ArrayList<>();
80 paths.add(pkg.getBaseCodePath());
82 String[] splitCodePaths = pkg.getSplitCodePaths();
83 if (!ArrayUtils.isEmpty(splitCodePaths)) {
84 Collections.addAll(paths, splitCodePaths);
89 public static SharedLibraryInfo createSharedLibraryForStatic(AndroidPackage pkg) {
90 return new SharedLibraryInfo(null, pkg.getPackageName(),
91 AndroidPackageUtils.getAllCodePaths(pkg),
92 pkg.getStaticSharedLibName(),
93 pkg.getStaticSharedLibVersion(),
94 SharedLibraryInfo.TYPE_STATIC,
95 new VersionedPackage(pkg.getManifestPackageName(),
96 pkg.getLongVersionCode()),
100 public static SharedLibraryInfo createSharedLibraryForDynamic(AndroidPackage pkg, String name) {
101 return new SharedLibraryInfo(null, pkg.getPackageName(),
102 AndroidPackageUtils.getAllCodePaths(pkg), name,
103 SharedLibraryInfo.VERSION_UNDEFINED,
104 SharedLibraryInfo.TYPE_DYNAMIC, new VersionedPackage(pkg.getPackageName(),
105 pkg.getLongVersionCode()),
110 * Return the dex metadata files for the given package as a map
111 * [code path -> dex metadata path].
113 * NOTE: involves I/O checks.
115 public static Map<String, String> getPackageDexMetadata(AndroidPackage pkg) {
116 return DexMetadataHelper.buildPackageApkToDexMetadataMap
117 (AndroidPackageUtils.getAllCodePaths(pkg));
121 * Validate the dex metadata files installed for the given package.
123 * @throws PackageParserException in case of errors.
125 public static void validatePackageDexMetadata(AndroidPackage pkg)
126 throws PackageParserException {
127 Collection<String> apkToDexMetadataList = getPackageDexMetadata(pkg).values();
128 for (String dexMetadata : apkToDexMetadataList) {
129 DexMetadataHelper.validateDexMetadataFile(dexMetadata);
133 public static NativeLibraryHelper.Handle createNativeLibraryHandle(AndroidPackage pkg)
135 return NativeLibraryHelper.Handle.create(
136 AndroidPackageUtils.getAllCodePaths(pkg),
138 pkg.isExtractNativeLibs(),
144 public static boolean canHaveOatDir(AndroidPackage pkg, boolean isUpdatedSystemApp) {
145 // The following app types CANNOT have oat directory
146 // - non-updated system apps,
147 // - incrementally installed apps.
148 if (pkg.isSystem() && !isUpdatedSystemApp) {
151 if (IncrementalManager.isIncrementalPath(pkg.getCodePath())) {
157 public static boolean hasComponentClassName(AndroidPackage pkg, String className) {
158 List<ParsedActivity> activities = pkg.getActivities();
159 int activitiesSize = activities.size();
160 for (int index = 0; index < activitiesSize; index++) {
161 if (Objects.equals(className, activities.get(index).getName())) {
166 List<ParsedActivity> receivers = pkg.getReceivers();
167 int receiversSize = receivers.size();
168 for (int index = 0; index < receiversSize; index++) {
169 if (Objects.equals(className, receivers.get(index).getName())) {
174 List<ParsedProvider> providers = pkg.getProviders();
175 int providersSize = providers.size();
176 for (int index = 0; index < providersSize; index++) {
177 if (Objects.equals(className, providers.get(index).getName())) {
182 List<ParsedService> services = pkg.getServices();
183 int servicesSize = services.size();
184 for (int index = 0; index < servicesSize; index++) {
185 if (Objects.equals(className, services.get(index).getName())) {
190 List<ParsedInstrumentation> instrumentations = pkg.getInstrumentations();
191 int instrumentationsSize = instrumentations.size();
192 for (int index = 0; index < instrumentationsSize; index++) {
193 if (Objects.equals(className, instrumentations.get(index).getName())) {
201 public static boolean isEncryptionAware(AndroidPackage pkg) {
202 return pkg.isDirectBootAware() || pkg.isPartiallyDirectBootAware();
205 public static boolean isLibrary(AndroidPackage pkg) {
206 // TODO(b/135203078): Can parsing just enforce these always match?
207 return pkg.getStaticSharedLibName() != null || !pkg.getLibraryNames().isEmpty();
210 public static int getHiddenApiEnforcementPolicy(AndroidPackage pkg,
211 @NonNull PackageSetting pkgSetting) {
212 boolean isAllowedToUseHiddenApis;
213 if (pkg.isSignedWithPlatformKey()) {
214 isAllowedToUseHiddenApis = true;
215 } else if (pkg.isSystem() || pkgSetting.getPkgState().isUpdatedSystemApp()) {
216 isAllowedToUseHiddenApis = pkg.isUsesNonSdkApi()
217 || SystemConfig.getInstance().getHiddenApiWhitelistedApps().contains(
218 pkg.getPackageName());
220 isAllowedToUseHiddenApis = false;
223 if (isAllowedToUseHiddenApis) {
224 return ApplicationInfo.HIDDEN_API_ENFORCEMENT_DISABLED;
227 // TODO(b/135203078): Handle maybeUpdateHiddenApiEnforcementPolicy. Right now it's done
228 // entirely through ApplicationInfo and shouldn't touch this specific class, but that
229 // may not always hold true.
230 // if (mHiddenApiPolicy != ApplicationInfo.HIDDEN_API_ENFORCEMENT_DEFAULT) {
231 // return mHiddenApiPolicy;
233 return ApplicationInfo.HIDDEN_API_ENFORCEMENT_ENABLED;
236 public static int getIcon(ParsingPackageRead pkg) {
237 return (PackageParser.sUseRoundIcon && pkg.getRoundIconRes() != 0)
238 ? pkg.getRoundIconRes() : pkg.getIconRes();
241 public static long getLongVersionCode(AndroidPackage pkg) {
242 return PackageInfo.composeLongVersionCode(pkg.getVersionCodeMajor(), pkg.getVersionCode());
246 * Returns false iff the provided flags include the {@link PackageManager#MATCH_SYSTEM_ONLY}
247 * flag and the provided package is not a system package. Otherwise returns {@code true}.
249 public static boolean isMatchForSystemOnly(AndroidPackage pkg, int flags) {
250 if ((flags & PackageManager.MATCH_SYSTEM_ONLY) != 0) {
251 return pkg.isSystem();
256 public static String getPrimaryCpuAbi(AndroidPackage pkg, @Nullable PackageSetting pkgSetting) {
257 if (pkgSetting == null || TextUtils.isEmpty(pkgSetting.primaryCpuAbiString)) {
258 return pkg.getPrimaryCpuAbi();
261 return pkgSetting.primaryCpuAbiString;
264 public static String getSecondaryCpuAbi(AndroidPackage pkg,
265 @Nullable PackageSetting pkgSetting) {
266 if (pkgSetting == null || TextUtils.isEmpty(pkgSetting.secondaryCpuAbiString)) {
267 return pkg.getSecondaryCpuAbi();
270 return pkgSetting.secondaryCpuAbiString;
274 * Returns the primary ABI as parsed from the package. Used only during parsing and derivation.
275 * Otherwise prefer {@link #getPrimaryCpuAbi(AndroidPackage, PackageSetting)}.
277 * TODO(b/135203078): Actually hide the method
278 * Placed in the utility to hide the method on the interface.
280 public static String getRawPrimaryCpuAbi(AndroidPackage pkg) {
281 return pkg.getPrimaryCpuAbi();
285 * Returns the secondary ABI as parsed from the package. Used only during parsing and
286 * derivation. Otherwise prefer {@link #getSecondaryCpuAbi(AndroidPackage, PackageSetting)}.
288 * TODO(b/135203078): Actually hide the method
289 * Placed in the utility to hide the method on the interface.
291 public static String getRawSecondaryCpuAbi(AndroidPackage pkg) {
292 return pkg.getSecondaryCpuAbi();
295 public static String getSeInfo(AndroidPackage pkg, @Nullable PackageSetting pkgSetting) {
296 if (pkgSetting != null) {
297 String overrideSeInfo = pkgSetting.getPkgState().getOverrideSeInfo();
298 if (!TextUtils.isEmpty(overrideSeInfo)) {
299 return overrideSeInfo;
302 return pkg.getSeInfo();