• 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.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