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