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