• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.PackageParser.PackageParserException;
25 import android.content.pm.SharedLibraryInfo;
26 import android.content.pm.VersionedPackage;
27 import android.content.pm.dex.DexMetadataHelper;
28 import android.content.pm.parsing.ParsingPackageRead;
29 import android.content.pm.parsing.ParsingPackageUtils;
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;
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.PackageSetting;
41 
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;
47 import java.util.Map;
48 import java.util.Objects;
49 
50 /** @hide */
51 public class AndroidPackageUtils {
52 
AndroidPackageUtils()53     private AndroidPackageUtils() {
54     }
55 
getAllCodePathsExcludingResourceOnly( AndroidPackage aPkg)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.getBaseApkPath());
62         }
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]);
68                 }
69             }
70         }
71         return paths;
72     }
73 
74     /**
75      * @return a list of the base and split code paths.
76      */
getAllCodePaths(AndroidPackage aPkg)77     public static List<String> getAllCodePaths(AndroidPackage aPkg) {
78         PackageImpl pkg = (PackageImpl) aPkg;
79         ArrayList<String> paths = new ArrayList<>();
80         paths.add(pkg.getBaseApkPath());
81 
82         String[] splitCodePaths = pkg.getSplitCodePaths();
83         if (!ArrayUtils.isEmpty(splitCodePaths)) {
84             Collections.addAll(paths, splitCodePaths);
85         }
86         return paths;
87     }
88 
createSharedLibraryForStatic(AndroidPackage pkg)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()),
97                 null, null, false /* isNative */);
98     }
99 
createSharedLibraryForDynamic(AndroidPackage pkg, String name)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()),
106                 null, null, false /* isNative */);
107     }
108 
109     /**
110      * Return the dex metadata files for the given package as a map
111      * [code path -> dex metadata path].
112      *
113      * NOTE: involves I/O checks.
114      */
getPackageDexMetadata(AndroidPackage pkg)115     public static Map<String, String> getPackageDexMetadata(AndroidPackage pkg) {
116         return DexMetadataHelper.buildPackageApkToDexMetadataMap
117                 (AndroidPackageUtils.getAllCodePaths(pkg));
118     }
119 
120     /**
121      * Validate the dex metadata files installed for the given package.
122      *
123      * @throws PackageParserException in case of errors.
124      */
validatePackageDexMetadata(AndroidPackage pkg)125     public static void validatePackageDexMetadata(AndroidPackage pkg)
126             throws PackageParserException {
127         Collection<String> apkToDexMetadataList = getPackageDexMetadata(pkg).values();
128         String packageName = pkg.getPackageName();
129         long versionCode = pkg.toAppInfoWithoutState().longVersionCode;
130         for (String dexMetadata : apkToDexMetadataList) {
131             DexMetadataHelper.validateDexMetadataFile(dexMetadata, packageName, versionCode);
132         }
133     }
134 
createNativeLibraryHandle(AndroidPackage pkg)135     public static NativeLibraryHelper.Handle createNativeLibraryHandle(AndroidPackage pkg)
136             throws IOException {
137         return NativeLibraryHelper.Handle.create(
138                 AndroidPackageUtils.getAllCodePaths(pkg),
139                 pkg.isMultiArch(),
140                 pkg.isExtractNativeLibs(),
141                 pkg.isDebuggable()
142         );
143     }
144 
canHaveOatDir(AndroidPackage pkg, boolean isUpdatedSystemApp)145     public static boolean canHaveOatDir(AndroidPackage pkg, boolean isUpdatedSystemApp) {
146         // The following app types CANNOT have oat directory
147         // - non-updated system apps,
148         // - incrementally installed apps.
149         if (pkg.isSystem() && !isUpdatedSystemApp) {
150             return false;
151         }
152         if (IncrementalManager.isIncrementalPath(pkg.getPath())) {
153             return false;
154         }
155         return true;
156     }
157 
hasComponentClassName(AndroidPackage pkg, String className)158     public static boolean hasComponentClassName(AndroidPackage pkg, String className) {
159         List<ParsedActivity> activities = pkg.getActivities();
160         int activitiesSize = activities.size();
161         for (int index = 0; index < activitiesSize; index++) {
162             if (Objects.equals(className, activities.get(index).getName())) {
163                 return true;
164             }
165         }
166 
167         List<ParsedActivity> receivers = pkg.getReceivers();
168         int receiversSize = receivers.size();
169         for (int index = 0; index < receiversSize; index++) {
170             if (Objects.equals(className, receivers.get(index).getName())) {
171                 return true;
172             }
173         }
174 
175         List<ParsedProvider> providers = pkg.getProviders();
176         int providersSize = providers.size();
177         for (int index = 0; index < providersSize; index++) {
178             if (Objects.equals(className, providers.get(index).getName())) {
179                 return true;
180             }
181         }
182 
183         List<ParsedService> services = pkg.getServices();
184         int servicesSize = services.size();
185         for (int index = 0; index < servicesSize; index++) {
186             if (Objects.equals(className, services.get(index).getName())) {
187                 return true;
188             }
189         }
190 
191         List<ParsedInstrumentation> instrumentations = pkg.getInstrumentations();
192         int instrumentationsSize = instrumentations.size();
193         for (int index = 0; index < instrumentationsSize; index++) {
194             if (Objects.equals(className, instrumentations.get(index).getName())) {
195                 return true;
196             }
197         }
198 
199         return false;
200     }
201 
isEncryptionAware(AndroidPackage pkg)202     public static boolean isEncryptionAware(AndroidPackage pkg) {
203         return pkg.isDirectBootAware() || pkg.isPartiallyDirectBootAware();
204     }
205 
isLibrary(AndroidPackage pkg)206     public static boolean isLibrary(AndroidPackage pkg) {
207         // TODO(b/135203078): Can parsing just enforce these always match?
208         return pkg.getStaticSharedLibName() != null || !pkg.getLibraryNames().isEmpty();
209     }
210 
getHiddenApiEnforcementPolicy(AndroidPackage pkg, @NonNull PackageSetting pkgSetting)211     public static int getHiddenApiEnforcementPolicy(AndroidPackage pkg,
212             @NonNull PackageSetting pkgSetting) {
213         boolean isAllowedToUseHiddenApis;
214         if (pkg.isSignedWithPlatformKey()) {
215             isAllowedToUseHiddenApis = true;
216         } else if (pkg.isSystem() || pkgSetting.getPkgState().isUpdatedSystemApp()) {
217             isAllowedToUseHiddenApis = pkg.isUsesNonSdkApi()
218                     || SystemConfig.getInstance().getHiddenApiWhitelistedApps().contains(
219                     pkg.getPackageName());
220         } else {
221             isAllowedToUseHiddenApis = false;
222         }
223 
224         if (isAllowedToUseHiddenApis) {
225             return ApplicationInfo.HIDDEN_API_ENFORCEMENT_DISABLED;
226         }
227 
228         // TODO(b/135203078): Handle maybeUpdateHiddenApiEnforcementPolicy. Right now it's done
229         //  entirely through ApplicationInfo and shouldn't touch this specific class, but that
230         //  may not always hold true.
231 //        if (mHiddenApiPolicy != ApplicationInfo.HIDDEN_API_ENFORCEMENT_DEFAULT) {
232 //            return mHiddenApiPolicy;
233 //        }
234         return ApplicationInfo.HIDDEN_API_ENFORCEMENT_ENABLED;
235     }
236 
getIcon(ParsingPackageRead pkg)237     public static int getIcon(ParsingPackageRead pkg) {
238         return (ParsingPackageUtils.sUseRoundIcon && pkg.getRoundIconRes() != 0)
239                 ? pkg.getRoundIconRes() : pkg.getIconRes();
240     }
241 
getLongVersionCode(AndroidPackage pkg)242     public static long getLongVersionCode(AndroidPackage pkg) {
243         return PackageInfo.composeLongVersionCode(pkg.getVersionCodeMajor(), pkg.getVersionCode());
244     }
245 
246     /**
247      * Returns false iff the provided flags include the {@link PackageManager#MATCH_SYSTEM_ONLY}
248      * flag and the provided package is not a system package. Otherwise returns {@code true}.
249      */
isMatchForSystemOnly(AndroidPackage pkg, int flags)250     public static boolean isMatchForSystemOnly(AndroidPackage pkg, int flags) {
251         if ((flags & PackageManager.MATCH_SYSTEM_ONLY) != 0) {
252             return pkg.isSystem();
253         }
254         return true;
255     }
256 
getPrimaryCpuAbi(AndroidPackage pkg, @Nullable PackageSetting pkgSetting)257     public static String getPrimaryCpuAbi(AndroidPackage pkg, @Nullable PackageSetting pkgSetting) {
258         if (pkgSetting == null || TextUtils.isEmpty(pkgSetting.primaryCpuAbiString)) {
259             return pkg.getPrimaryCpuAbi();
260         }
261 
262         return pkgSetting.primaryCpuAbiString;
263     }
264 
getSecondaryCpuAbi(AndroidPackage pkg, @Nullable PackageSetting pkgSetting)265     public static String getSecondaryCpuAbi(AndroidPackage pkg,
266             @Nullable PackageSetting pkgSetting) {
267         if (pkgSetting == null || TextUtils.isEmpty(pkgSetting.secondaryCpuAbiString)) {
268             return pkg.getSecondaryCpuAbi();
269         }
270 
271         return pkgSetting.secondaryCpuAbiString;
272     }
273 
274     /**
275      * Returns the primary ABI as parsed from the package. Used only during parsing and derivation.
276      * Otherwise prefer {@link #getPrimaryCpuAbi(AndroidPackage, PackageSetting)}.
277      *
278      * TODO(b/135203078): Actually hide the method
279      * Placed in the utility to hide the method on the interface.
280      */
getRawPrimaryCpuAbi(AndroidPackage pkg)281     public static String getRawPrimaryCpuAbi(AndroidPackage pkg) {
282         return 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 #getSecondaryCpuAbi(AndroidPackage, PackageSetting)}.
288      *
289      * TODO(b/135203078): Actually hide the method
290      * Placed in the utility to hide the method on the interface.
291      */
getRawSecondaryCpuAbi(AndroidPackage pkg)292     public static String getRawSecondaryCpuAbi(AndroidPackage pkg) {
293         return pkg.getSecondaryCpuAbi();
294     }
295 
getSeInfo(AndroidPackage pkg, @Nullable PackageSetting pkgSetting)296     public static String getSeInfo(AndroidPackage pkg, @Nullable PackageSetting pkgSetting) {
297         if (pkgSetting != null) {
298             String overrideSeInfo = pkgSetting.getPkgState().getOverrideSeInfo();
299             if (!TextUtils.isEmpty(overrideSeInfo)) {
300                 return overrideSeInfo;
301             }
302         }
303         return pkg.getSeInfo();
304     }
305 }
306