• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007 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 android.content.pm;
18 
19 import com.android.internal.R;
20 import com.android.internal.util.ArrayUtils;
21 import com.android.internal.util.XmlUtils;
22 
23 import org.xmlpull.v1.XmlPullParser;
24 import org.xmlpull.v1.XmlPullParserException;
25 
26 import android.app.ActivityManager;
27 import android.content.ComponentName;
28 import android.content.Intent;
29 import android.content.IntentFilter;
30 import android.content.res.AssetManager;
31 import android.content.res.Configuration;
32 import android.content.res.Resources;
33 import android.content.res.TypedArray;
34 import android.content.res.XmlResourceParser;
35 import android.os.Build;
36 import android.os.Bundle;
37 import android.os.FileUtils;
38 import android.os.PatternMatcher;
39 import android.os.Trace;
40 import android.os.UserHandle;
41 import android.text.TextUtils;
42 import android.util.ArrayMap;
43 import android.util.ArraySet;
44 import android.util.AttributeSet;
45 import android.util.Base64;
46 import android.util.DisplayMetrics;
47 import android.util.Log;
48 import android.util.Pair;
49 import android.util.Slog;
50 import android.util.TypedValue;
51 import android.util.apk.ApkSignatureSchemeV2Verifier;
52 import android.util.jar.StrictJarFile;
53 import android.view.Gravity;
54 
55 import java.io.File;
56 import java.io.IOException;
57 import java.io.InputStream;
58 import java.io.PrintWriter;
59 import java.security.GeneralSecurityException;
60 import java.security.KeyFactory;
61 import java.security.NoSuchAlgorithmException;
62 import java.security.PublicKey;
63 import java.security.cert.Certificate;
64 import java.security.cert.CertificateEncodingException;
65 import java.security.spec.EncodedKeySpec;
66 import java.security.spec.InvalidKeySpecException;
67 import java.security.spec.X509EncodedKeySpec;
68 import java.util.ArrayList;
69 import java.util.Arrays;
70 import java.util.Collections;
71 import java.util.Comparator;
72 import java.util.Iterator;
73 import java.util.List;
74 import java.util.Set;
75 import java.util.concurrent.atomic.AtomicReference;
76 import java.util.zip.ZipEntry;
77 
78 import libcore.io.IoUtils;
79 
80 import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE;
81 import static android.content.pm.ActivityInfo.FLAG_IMMERSIVE;
82 import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE;
83 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
84 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_AND_PIPABLE;
85 import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
86 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
87 import static android.content.pm.ApplicationInfo.FLAG_SUSPENDED;
88 import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_RESIZEABLE_ACTIVITIES;
89 import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST;
90 import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME;
91 import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING;
92 import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
93 import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
94 import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NOT_APK;
95 import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES;
96 import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION;
97 import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
98 
99 /**
100  * Parser for package files (APKs) on disk. This supports apps packaged either
101  * as a single "monolithic" APK, or apps packaged as a "cluster" of multiple
102  * APKs in a single directory.
103  * <p>
104  * Apps packaged as multiple APKs always consist of a single "base" APK (with a
105  * {@code null} split name) and zero or more "split" APKs (with unique split
106  * names). Any subset of those split APKs are a valid install, as long as the
107  * following constraints are met:
108  * <ul>
109  * <li>All APKs must have the exact same package name, version code, and signing
110  * certificates.
111  * <li>All APKs must have unique split names.
112  * <li>All installations must contain a single base APK.
113  * </ul>
114  *
115  * @hide
116  */
117 public class PackageParser {
118     private static final boolean DEBUG_JAR = false;
119     private static final boolean DEBUG_PARSER = false;
120     private static final boolean DEBUG_BACKUP = false;
121 
122     private static final boolean MULTI_PACKAGE_APK_ENABLED = false;
123     private static final int MAX_PACKAGES_PER_APK = 5;
124 
125     public static final int APK_SIGNING_UNKNOWN = 0;
126     public static final int APK_SIGNING_V1 = 1;
127     public static final int APK_SIGNING_V2 = 2;
128 
129     // TODO: switch outError users to PackageParserException
130     // TODO: refactor "codePath" to "apkPath"
131 
132     /** File name in an APK for the Android manifest. */
133     private static final String ANDROID_MANIFEST_FILENAME = "AndroidManifest.xml";
134 
135     /** Path prefix for apps on expanded storage */
136     private static final String MNT_EXPAND = "/mnt/expand/";
137 
138     private static final String TAG_MANIFEST = "manifest";
139     private static final String TAG_APPLICATION = "application";
140     private static final String TAG_OVERLAY = "overlay";
141     private static final String TAG_KEY_SETS = "key-sets";
142     private static final String TAG_PERMISSION_GROUP = "permission-group";
143     private static final String TAG_PERMISSION = "permission";
144     private static final String TAG_PERMISSION_TREE = "permission-tree";
145     private static final String TAG_USES_PERMISSION = "uses-permission";
146     private static final String TAG_USES_PERMISSION_SDK_M = "uses-permission-sdk-m";
147     private static final String TAG_USES_PERMISSION_SDK_23 = "uses-permission-sdk-23";
148     private static final String TAG_USES_CONFIGURATION = "uses-configuration";
149     private static final String TAG_USES_FEATURE = "uses-feature";
150     private static final String TAG_FEATURE_GROUP = "feature-group";
151     private static final String TAG_USES_SDK = "uses-sdk";
152     private static final String TAG_SUPPORT_SCREENS = "supports-screens";
153     private static final String TAG_PROTECTED_BROADCAST = "protected-broadcast";
154     private static final String TAG_INSTRUMENTATION = "instrumentation";
155     private static final String TAG_ORIGINAL_PACKAGE = "original-package";
156     private static final String TAG_ADOPT_PERMISSIONS = "adopt-permissions";
157     private static final String TAG_USES_GL_TEXTURE = "uses-gl-texture";
158     private static final String TAG_COMPATIBLE_SCREENS = "compatible-screens";
159     private static final String TAG_SUPPORTS_INPUT = "supports-input";
160     private static final String TAG_EAT_COMMENT = "eat-comment";
161     private static final String TAG_PACKAGE = "package";
162     private static final String TAG_RESTRICT_UPDATE = "restrict-update";
163 
164     // These are the tags supported by child packages
165     private static final Set<String> CHILD_PACKAGE_TAGS = new ArraySet<>();
166     static {
167         CHILD_PACKAGE_TAGS.add(TAG_APPLICATION);
168         CHILD_PACKAGE_TAGS.add(TAG_USES_PERMISSION);
169         CHILD_PACKAGE_TAGS.add(TAG_USES_PERMISSION_SDK_M);
170         CHILD_PACKAGE_TAGS.add(TAG_USES_PERMISSION_SDK_23);
171         CHILD_PACKAGE_TAGS.add(TAG_USES_CONFIGURATION);
172         CHILD_PACKAGE_TAGS.add(TAG_USES_FEATURE);
173         CHILD_PACKAGE_TAGS.add(TAG_FEATURE_GROUP);
174         CHILD_PACKAGE_TAGS.add(TAG_USES_SDK);
175         CHILD_PACKAGE_TAGS.add(TAG_SUPPORT_SCREENS);
176         CHILD_PACKAGE_TAGS.add(TAG_INSTRUMENTATION);
177         CHILD_PACKAGE_TAGS.add(TAG_USES_GL_TEXTURE);
178         CHILD_PACKAGE_TAGS.add(TAG_COMPATIBLE_SCREENS);
179         CHILD_PACKAGE_TAGS.add(TAG_SUPPORTS_INPUT);
180         CHILD_PACKAGE_TAGS.add(TAG_EAT_COMMENT);
181     }
182 
183     /** @hide */
184     public static class NewPermissionInfo {
185         public final String name;
186         public final int sdkVersion;
187         public final int fileVersion;
188 
NewPermissionInfo(String name, int sdkVersion, int fileVersion)189         public NewPermissionInfo(String name, int sdkVersion, int fileVersion) {
190             this.name = name;
191             this.sdkVersion = sdkVersion;
192             this.fileVersion = fileVersion;
193         }
194     }
195 
196     /** @hide */
197     public static class SplitPermissionInfo {
198         public final String rootPerm;
199         public final String[] newPerms;
200         public final int targetSdk;
201 
SplitPermissionInfo(String rootPerm, String[] newPerms, int targetSdk)202         public SplitPermissionInfo(String rootPerm, String[] newPerms, int targetSdk) {
203             this.rootPerm = rootPerm;
204             this.newPerms = newPerms;
205             this.targetSdk = targetSdk;
206         }
207     }
208 
209     /**
210      * List of new permissions that have been added since 1.0.
211      * NOTE: These must be declared in SDK version order, with permissions
212      * added to older SDKs appearing before those added to newer SDKs.
213      * If sdkVersion is 0, then this is not a permission that we want to
214      * automatically add to older apps, but we do want to allow it to be
215      * granted during a platform update.
216      * @hide
217      */
218     public static final PackageParser.NewPermissionInfo NEW_PERMISSIONS[] =
219         new PackageParser.NewPermissionInfo[] {
220             new PackageParser.NewPermissionInfo(android.Manifest.permission.WRITE_EXTERNAL_STORAGE,
221                     android.os.Build.VERSION_CODES.DONUT, 0),
222             new PackageParser.NewPermissionInfo(android.Manifest.permission.READ_PHONE_STATE,
223                     android.os.Build.VERSION_CODES.DONUT, 0)
224     };
225 
226     /**
227      * List of permissions that have been split into more granular or dependent
228      * permissions.
229      * @hide
230      */
231     public static final PackageParser.SplitPermissionInfo SPLIT_PERMISSIONS[] =
232         new PackageParser.SplitPermissionInfo[] {
233             // READ_EXTERNAL_STORAGE is always required when an app requests
234             // WRITE_EXTERNAL_STORAGE, because we can't have an app that has
235             // write access without read access.  The hack here with the target
236             // target SDK version ensures that this grant is always done.
237             new PackageParser.SplitPermissionInfo(android.Manifest.permission.WRITE_EXTERNAL_STORAGE,
238                     new String[] { android.Manifest.permission.READ_EXTERNAL_STORAGE },
239                     android.os.Build.VERSION_CODES.CUR_DEVELOPMENT+1),
240             new PackageParser.SplitPermissionInfo(android.Manifest.permission.READ_CONTACTS,
241                     new String[] { android.Manifest.permission.READ_CALL_LOG },
242                     android.os.Build.VERSION_CODES.JELLY_BEAN),
243             new PackageParser.SplitPermissionInfo(android.Manifest.permission.WRITE_CONTACTS,
244                     new String[] { android.Manifest.permission.WRITE_CALL_LOG },
245                     android.os.Build.VERSION_CODES.JELLY_BEAN)
246     };
247 
248     /**
249      * @deprecated callers should move to explicitly passing around source path.
250      */
251     @Deprecated
252     private String mArchiveSourcePath;
253 
254     private String[] mSeparateProcesses;
255     private boolean mOnlyCoreApps;
256     private DisplayMetrics mMetrics;
257 
258     private static final int SDK_VERSION = Build.VERSION.SDK_INT;
259     private static final String[] SDK_CODENAMES = Build.VERSION.ACTIVE_CODENAMES;
260 
261     private int mParseError = PackageManager.INSTALL_SUCCEEDED;
262 
263     private static boolean sCompatibilityModeEnabled = true;
264     private static final int PARSE_DEFAULT_INSTALL_LOCATION =
265             PackageInfo.INSTALL_LOCATION_UNSPECIFIED;
266 
267     static class ParsePackageItemArgs {
268         final Package owner;
269         final String[] outError;
270         final int nameRes;
271         final int labelRes;
272         final int iconRes;
273         final int roundIconRes;
274         final int logoRes;
275         final int bannerRes;
276 
277         String tag;
278         TypedArray sa;
279 
ParsePackageItemArgs(Package _owner, String[] _outError, int _nameRes, int _labelRes, int _iconRes, int _roundIconRes, int _logoRes, int _bannerRes)280         ParsePackageItemArgs(Package _owner, String[] _outError,
281                 int _nameRes, int _labelRes, int _iconRes, int _roundIconRes, int _logoRes,
282                 int _bannerRes) {
283             owner = _owner;
284             outError = _outError;
285             nameRes = _nameRes;
286             labelRes = _labelRes;
287             iconRes = _iconRes;
288             logoRes = _logoRes;
289             bannerRes = _bannerRes;
290             roundIconRes = _roundIconRes;
291         }
292     }
293 
294     static class ParseComponentArgs extends ParsePackageItemArgs {
295         final String[] sepProcesses;
296         final int processRes;
297         final int descriptionRes;
298         final int enabledRes;
299         int flags;
300 
ParseComponentArgs(Package _owner, String[] _outError, int _nameRes, int _labelRes, int _iconRes, int _roundIconRes, int _logoRes, int _bannerRes, String[] _sepProcesses, int _processRes, int _descriptionRes, int _enabledRes)301         ParseComponentArgs(Package _owner, String[] _outError,
302                 int _nameRes, int _labelRes, int _iconRes, int _roundIconRes, int _logoRes,
303                 int _bannerRes,
304                 String[] _sepProcesses, int _processRes,
305                 int _descriptionRes, int _enabledRes) {
306             super(_owner, _outError, _nameRes, _labelRes, _iconRes, _roundIconRes, _logoRes,
307                     _bannerRes);
308             sepProcesses = _sepProcesses;
309             processRes = _processRes;
310             descriptionRes = _descriptionRes;
311             enabledRes = _enabledRes;
312         }
313     }
314 
315     /**
316      * Lightweight parsed details about a single package.
317      */
318     public static class PackageLite {
319         public final String packageName;
320         public final int versionCode;
321         public final int installLocation;
322         public final VerifierInfo[] verifiers;
323 
324         /** Names of any split APKs, ordered by parsed splitName */
325         public final String[] splitNames;
326 
327         /**
328          * Path where this package was found on disk. For monolithic packages
329          * this is path to single base APK file; for cluster packages this is
330          * path to the cluster directory.
331          */
332         public final String codePath;
333 
334         /** Path of base APK */
335         public final String baseCodePath;
336         /** Paths of any split APKs, ordered by parsed splitName */
337         public final String[] splitCodePaths;
338 
339         /** Revision code of base APK */
340         public final int baseRevisionCode;
341         /** Revision codes of any split APKs, ordered by parsed splitName */
342         public final int[] splitRevisionCodes;
343 
344         public final boolean coreApp;
345         public final boolean multiArch;
346         public final boolean use32bitAbi;
347         public final boolean extractNativeLibs;
348 
PackageLite(String codePath, ApkLite baseApk, String[] splitNames, String[] splitCodePaths, int[] splitRevisionCodes)349         public PackageLite(String codePath, ApkLite baseApk, String[] splitNames,
350                 String[] splitCodePaths, int[] splitRevisionCodes) {
351             this.packageName = baseApk.packageName;
352             this.versionCode = baseApk.versionCode;
353             this.installLocation = baseApk.installLocation;
354             this.verifiers = baseApk.verifiers;
355             this.splitNames = splitNames;
356             this.codePath = codePath;
357             this.baseCodePath = baseApk.codePath;
358             this.splitCodePaths = splitCodePaths;
359             this.baseRevisionCode = baseApk.revisionCode;
360             this.splitRevisionCodes = splitRevisionCodes;
361             this.coreApp = baseApk.coreApp;
362             this.multiArch = baseApk.multiArch;
363             this.use32bitAbi = baseApk.use32bitAbi;
364             this.extractNativeLibs = baseApk.extractNativeLibs;
365         }
366 
getAllCodePaths()367         public List<String> getAllCodePaths() {
368             ArrayList<String> paths = new ArrayList<>();
369             paths.add(baseCodePath);
370             if (!ArrayUtils.isEmpty(splitCodePaths)) {
371                 Collections.addAll(paths, splitCodePaths);
372             }
373             return paths;
374         }
375     }
376 
377     /**
378      * Lightweight parsed details about a single APK file.
379      */
380     public static class ApkLite {
381         public final String codePath;
382         public final String packageName;
383         public final String splitName;
384         public final int versionCode;
385         public final int revisionCode;
386         public final int installLocation;
387         public final VerifierInfo[] verifiers;
388         public final Signature[] signatures;
389         public final Certificate[][] certificates;
390         public final boolean coreApp;
391         public final boolean multiArch;
392         public final boolean use32bitAbi;
393         public final boolean extractNativeLibs;
394 
ApkLite(String codePath, String packageName, String splitName, int versionCode, int revisionCode, int installLocation, List<VerifierInfo> verifiers, Signature[] signatures, Certificate[][] certificates, boolean coreApp, boolean multiArch, boolean use32bitAbi, boolean extractNativeLibs)395         public ApkLite(String codePath, String packageName, String splitName, int versionCode,
396                 int revisionCode, int installLocation, List<VerifierInfo> verifiers,
397                 Signature[] signatures, Certificate[][] certificates, boolean coreApp,
398                 boolean multiArch, boolean use32bitAbi, boolean extractNativeLibs) {
399             this.codePath = codePath;
400             this.packageName = packageName;
401             this.splitName = splitName;
402             this.versionCode = versionCode;
403             this.revisionCode = revisionCode;
404             this.installLocation = installLocation;
405             this.verifiers = verifiers.toArray(new VerifierInfo[verifiers.size()]);
406             this.signatures = signatures;
407             this.certificates = certificates;
408             this.coreApp = coreApp;
409             this.multiArch = multiArch;
410             this.use32bitAbi = use32bitAbi;
411             this.extractNativeLibs = extractNativeLibs;
412         }
413     }
414 
415     private ParsePackageItemArgs mParseInstrumentationArgs;
416     private ParseComponentArgs mParseActivityArgs;
417     private ParseComponentArgs mParseActivityAliasArgs;
418     private ParseComponentArgs mParseServiceArgs;
419     private ParseComponentArgs mParseProviderArgs;
420 
421     /** If set to true, we will only allow package files that exactly match
422      *  the DTD.  Otherwise, we try to get as much from the package as we
423      *  can without failing.  This should normally be set to false, to
424      *  support extensions to the DTD in future versions. */
425     private static final boolean RIGID_PARSER = false;
426 
427     private static final String TAG = "PackageParser";
428 
PackageParser()429     public PackageParser() {
430         mMetrics = new DisplayMetrics();
431         mMetrics.setToDefaults();
432     }
433 
setSeparateProcesses(String[] procs)434     public void setSeparateProcesses(String[] procs) {
435         mSeparateProcesses = procs;
436     }
437 
438     /**
439      * Flag indicating this parser should only consider apps with
440      * {@code coreApp} manifest attribute to be valid apps. This is useful when
441      * creating a minimalist boot environment.
442      */
setOnlyCoreApps(boolean onlyCoreApps)443     public void setOnlyCoreApps(boolean onlyCoreApps) {
444         mOnlyCoreApps = onlyCoreApps;
445     }
446 
setDisplayMetrics(DisplayMetrics metrics)447     public void setDisplayMetrics(DisplayMetrics metrics) {
448         mMetrics = metrics;
449     }
450 
isApkFile(File file)451     public static final boolean isApkFile(File file) {
452         return isApkPath(file.getName());
453     }
454 
isApkPath(String path)455     private static boolean isApkPath(String path) {
456         return path.endsWith(".apk");
457     }
458 
459     /**
460      * Generate and return the {@link PackageInfo} for a parsed package.
461      *
462      * @param p the parsed package.
463      * @param flags indicating which optional information is included.
464      */
generatePackageInfo(PackageParser.Package p, int gids[], int flags, long firstInstallTime, long lastUpdateTime, Set<String> grantedPermissions, PackageUserState state)465     public static PackageInfo generatePackageInfo(PackageParser.Package p,
466             int gids[], int flags, long firstInstallTime, long lastUpdateTime,
467             Set<String> grantedPermissions, PackageUserState state) {
468 
469         return generatePackageInfo(p, gids, flags, firstInstallTime, lastUpdateTime,
470                 grantedPermissions, state, UserHandle.getCallingUserId());
471     }
472 
473     /**
474      * Returns true if the package is installed and not hidden, or if the caller
475      * explicitly wanted all uninstalled and hidden packages as well.
476      */
checkUseInstalledOrHidden(int flags, PackageUserState state)477     private static boolean checkUseInstalledOrHidden(int flags, PackageUserState state) {
478         return (state.installed && !state.hidden)
479                 || (flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0;
480     }
481 
isAvailable(PackageUserState state)482     public static boolean isAvailable(PackageUserState state) {
483         return checkUseInstalledOrHidden(0, state);
484     }
485 
generatePackageInfo(PackageParser.Package p, int gids[], int flags, long firstInstallTime, long lastUpdateTime, Set<String> grantedPermissions, PackageUserState state, int userId)486     public static PackageInfo generatePackageInfo(PackageParser.Package p,
487             int gids[], int flags, long firstInstallTime, long lastUpdateTime,
488             Set<String> grantedPermissions, PackageUserState state, int userId) {
489         if (!checkUseInstalledOrHidden(flags, state) || !p.isMatch(flags)) {
490             return null;
491         }
492         PackageInfo pi = new PackageInfo();
493         pi.packageName = p.packageName;
494         pi.splitNames = p.splitNames;
495         pi.versionCode = p.mVersionCode;
496         pi.baseRevisionCode = p.baseRevisionCode;
497         pi.splitRevisionCodes = p.splitRevisionCodes;
498         pi.versionName = p.mVersionName;
499         pi.sharedUserId = p.mSharedUserId;
500         pi.sharedUserLabel = p.mSharedUserLabel;
501         pi.applicationInfo = generateApplicationInfo(p, flags, state, userId);
502         pi.installLocation = p.installLocation;
503         pi.coreApp = p.coreApp;
504         if ((pi.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0
505                 || (pi.applicationInfo.flags&ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) {
506             pi.requiredForAllUsers = p.mRequiredForAllUsers;
507         }
508         pi.restrictedAccountType = p.mRestrictedAccountType;
509         pi.requiredAccountType = p.mRequiredAccountType;
510         pi.overlayTarget = p.mOverlayTarget;
511         pi.firstInstallTime = firstInstallTime;
512         pi.lastUpdateTime = lastUpdateTime;
513         if ((flags&PackageManager.GET_GIDS) != 0) {
514             pi.gids = gids;
515         }
516         if ((flags&PackageManager.GET_CONFIGURATIONS) != 0) {
517             int N = p.configPreferences != null ? p.configPreferences.size() : 0;
518             if (N > 0) {
519                 pi.configPreferences = new ConfigurationInfo[N];
520                 p.configPreferences.toArray(pi.configPreferences);
521             }
522             N = p.reqFeatures != null ? p.reqFeatures.size() : 0;
523             if (N > 0) {
524                 pi.reqFeatures = new FeatureInfo[N];
525                 p.reqFeatures.toArray(pi.reqFeatures);
526             }
527             N = p.featureGroups != null ? p.featureGroups.size() : 0;
528             if (N > 0) {
529                 pi.featureGroups = new FeatureGroupInfo[N];
530                 p.featureGroups.toArray(pi.featureGroups);
531             }
532         }
533         if ((flags & PackageManager.GET_ACTIVITIES) != 0) {
534             final int N = p.activities.size();
535             if (N > 0) {
536                 int num = 0;
537                 final ActivityInfo[] res = new ActivityInfo[N];
538                 for (int i = 0; i < N; i++) {
539                     final Activity a = p.activities.get(i);
540                     if (state.isMatch(a.info, flags)) {
541                         res[num++] = generateActivityInfo(a, flags, state, userId);
542                     }
543                 }
544                 pi.activities = ArrayUtils.trimToSize(res, num);
545             }
546         }
547         if ((flags & PackageManager.GET_RECEIVERS) != 0) {
548             final int N = p.receivers.size();
549             if (N > 0) {
550                 int num = 0;
551                 final ActivityInfo[] res = new ActivityInfo[N];
552                 for (int i = 0; i < N; i++) {
553                     final Activity a = p.receivers.get(i);
554                     if (state.isMatch(a.info, flags)) {
555                         res[num++] = generateActivityInfo(a, flags, state, userId);
556                     }
557                 }
558                 pi.receivers = ArrayUtils.trimToSize(res, num);
559             }
560         }
561         if ((flags & PackageManager.GET_SERVICES) != 0) {
562             final int N = p.services.size();
563             if (N > 0) {
564                 int num = 0;
565                 final ServiceInfo[] res = new ServiceInfo[N];
566                 for (int i = 0; i < N; i++) {
567                     final Service s = p.services.get(i);
568                     if (state.isMatch(s.info, flags)) {
569                         res[num++] = generateServiceInfo(s, flags, state, userId);
570                     }
571                 }
572                 pi.services = ArrayUtils.trimToSize(res, num);
573             }
574         }
575         if ((flags & PackageManager.GET_PROVIDERS) != 0) {
576             final int N = p.providers.size();
577             if (N > 0) {
578                 int num = 0;
579                 final ProviderInfo[] res = new ProviderInfo[N];
580                 for (int i = 0; i < N; i++) {
581                     final Provider pr = p.providers.get(i);
582                     if (state.isMatch(pr.info, flags)) {
583                         res[num++] = generateProviderInfo(pr, flags, state, userId);
584                     }
585                 }
586                 pi.providers = ArrayUtils.trimToSize(res, num);
587             }
588         }
589         if ((flags&PackageManager.GET_INSTRUMENTATION) != 0) {
590             int N = p.instrumentation.size();
591             if (N > 0) {
592                 pi.instrumentation = new InstrumentationInfo[N];
593                 for (int i=0; i<N; i++) {
594                     pi.instrumentation[i] = generateInstrumentationInfo(
595                             p.instrumentation.get(i), flags);
596                 }
597             }
598         }
599         if ((flags&PackageManager.GET_PERMISSIONS) != 0) {
600             int N = p.permissions.size();
601             if (N > 0) {
602                 pi.permissions = new PermissionInfo[N];
603                 for (int i=0; i<N; i++) {
604                     pi.permissions[i] = generatePermissionInfo(p.permissions.get(i), flags);
605                 }
606             }
607             N = p.requestedPermissions.size();
608             if (N > 0) {
609                 pi.requestedPermissions = new String[N];
610                 pi.requestedPermissionsFlags = new int[N];
611                 for (int i=0; i<N; i++) {
612                     final String perm = p.requestedPermissions.get(i);
613                     pi.requestedPermissions[i] = perm;
614                     // The notion of required permissions is deprecated but for compatibility.
615                     pi.requestedPermissionsFlags[i] |= PackageInfo.REQUESTED_PERMISSION_REQUIRED;
616                     if (grantedPermissions != null && grantedPermissions.contains(perm)) {
617                         pi.requestedPermissionsFlags[i] |= PackageInfo.REQUESTED_PERMISSION_GRANTED;
618                     }
619                 }
620             }
621         }
622         if ((flags&PackageManager.GET_SIGNATURES) != 0) {
623            int N = (p.mSignatures != null) ? p.mSignatures.length : 0;
624            if (N > 0) {
625                 pi.signatures = new Signature[N];
626                 System.arraycopy(p.mSignatures, 0, pi.signatures, 0, N);
627             }
628         }
629         return pi;
630     }
631 
loadCertificates(StrictJarFile jarFile, ZipEntry entry)632     private static Certificate[][] loadCertificates(StrictJarFile jarFile, ZipEntry entry)
633             throws PackageParserException {
634         InputStream is = null;
635         try {
636             // We must read the stream for the JarEntry to retrieve
637             // its certificates.
638             is = jarFile.getInputStream(entry);
639             readFullyIgnoringContents(is);
640             return jarFile.getCertificateChains(entry);
641         } catch (IOException | RuntimeException e) {
642             throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
643                     "Failed reading " + entry.getName() + " in " + jarFile, e);
644         } finally {
645             IoUtils.closeQuietly(is);
646         }
647     }
648 
649     public final static int PARSE_IS_SYSTEM = 1<<0;
650     public final static int PARSE_CHATTY = 1<<1;
651     public final static int PARSE_MUST_BE_APK = 1<<2;
652     public final static int PARSE_IGNORE_PROCESSES = 1<<3;
653     public final static int PARSE_FORWARD_LOCK = 1<<4;
654     public final static int PARSE_EXTERNAL_STORAGE = 1<<5;
655     public final static int PARSE_IS_SYSTEM_DIR = 1<<6;
656     public final static int PARSE_IS_PRIVILEGED = 1<<7;
657     public final static int PARSE_COLLECT_CERTIFICATES = 1<<8;
658     public final static int PARSE_TRUSTED_OVERLAY = 1<<9;
659     public final static int PARSE_ENFORCE_CODE = 1<<10;
660     public final static int PARSE_IS_EPHEMERAL = 1<<11;
661     public final static int PARSE_FORCE_SDK = 1<<12;
662 
663     private static final Comparator<String> sSplitNameComparator = new SplitNameComparator();
664 
665     /**
666      * Used to sort a set of APKs based on their split names, always placing the
667      * base APK (with {@code null} split name) first.
668      */
669     private static class SplitNameComparator implements Comparator<String> {
670         @Override
compare(String lhs, String rhs)671         public int compare(String lhs, String rhs) {
672             if (lhs == null) {
673                 return -1;
674             } else if (rhs == null) {
675                 return 1;
676             } else {
677                 return lhs.compareTo(rhs);
678             }
679         }
680     }
681 
682     /**
683      * Parse only lightweight details about the package at the given location.
684      * Automatically detects if the package is a monolithic style (single APK
685      * file) or cluster style (directory of APKs).
686      * <p>
687      * This performs sanity checking on cluster style packages, such as
688      * requiring identical package name and version codes, a single base APK,
689      * and unique split names.
690      *
691      * @see PackageParser#parsePackage(File, int)
692      */
parsePackageLite(File packageFile, int flags)693     public static PackageLite parsePackageLite(File packageFile, int flags)
694             throws PackageParserException {
695         if (packageFile.isDirectory()) {
696             return parseClusterPackageLite(packageFile, flags);
697         } else {
698             return parseMonolithicPackageLite(packageFile, flags);
699         }
700     }
701 
parseMonolithicPackageLite(File packageFile, int flags)702     private static PackageLite parseMonolithicPackageLite(File packageFile, int flags)
703             throws PackageParserException {
704         final ApkLite baseApk = parseApkLite(packageFile, flags);
705         final String packagePath = packageFile.getAbsolutePath();
706         return new PackageLite(packagePath, baseApk, null, null, null);
707     }
708 
parseClusterPackageLite(File packageDir, int flags)709     private static PackageLite parseClusterPackageLite(File packageDir, int flags)
710             throws PackageParserException {
711         final File[] files = packageDir.listFiles();
712         if (ArrayUtils.isEmpty(files)) {
713             throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
714                     "No packages found in split");
715         }
716 
717         String packageName = null;
718         int versionCode = 0;
719 
720         final ArrayMap<String, ApkLite> apks = new ArrayMap<>();
721         for (File file : files) {
722             if (isApkFile(file)) {
723                 final ApkLite lite = parseApkLite(file, flags);
724 
725                 // Assert that all package names and version codes are
726                 // consistent with the first one we encounter.
727                 if (packageName == null) {
728                     packageName = lite.packageName;
729                     versionCode = lite.versionCode;
730                 } else {
731                     if (!packageName.equals(lite.packageName)) {
732                         throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
733                                 "Inconsistent package " + lite.packageName + " in " + file
734                                 + "; expected " + packageName);
735                     }
736                     if (versionCode != lite.versionCode) {
737                         throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
738                                 "Inconsistent version " + lite.versionCode + " in " + file
739                                 + "; expected " + versionCode);
740                     }
741                 }
742 
743                 // Assert that each split is defined only once
744                 if (apks.put(lite.splitName, lite) != null) {
745                     throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
746                             "Split name " + lite.splitName
747                             + " defined more than once; most recent was " + file);
748                 }
749             }
750         }
751 
752         final ApkLite baseApk = apks.remove(null);
753         if (baseApk == null) {
754             throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
755                     "Missing base APK in " + packageDir);
756         }
757 
758         // Always apply deterministic ordering based on splitName
759         final int size = apks.size();
760 
761         String[] splitNames = null;
762         String[] splitCodePaths = null;
763         int[] splitRevisionCodes = null;
764         if (size > 0) {
765             splitNames = new String[size];
766             splitCodePaths = new String[size];
767             splitRevisionCodes = new int[size];
768 
769             splitNames = apks.keySet().toArray(splitNames);
770             Arrays.sort(splitNames, sSplitNameComparator);
771 
772             for (int i = 0; i < size; i++) {
773                 splitCodePaths[i] = apks.get(splitNames[i]).codePath;
774                 splitRevisionCodes[i] = apks.get(splitNames[i]).revisionCode;
775             }
776         }
777 
778         final String codePath = packageDir.getAbsolutePath();
779         return new PackageLite(codePath, baseApk, splitNames, splitCodePaths,
780                 splitRevisionCodes);
781     }
782 
783     /**
784      * Parse the package at the given location. Automatically detects if the
785      * package is a monolithic style (single APK file) or cluster style
786      * (directory of APKs).
787      * <p>
788      * This performs sanity checking on cluster style packages, such as
789      * requiring identical package name and version codes, a single base APK,
790      * and unique split names.
791      * <p>
792      * Note that this <em>does not</em> perform signature verification; that
793      * must be done separately in {@link #collectCertificates(Package, int)}.
794      *
795      * @see #parsePackageLite(File, int)
796      */
parsePackage(File packageFile, int flags)797     public Package parsePackage(File packageFile, int flags) throws PackageParserException {
798         if (packageFile.isDirectory()) {
799             return parseClusterPackage(packageFile, flags);
800         } else {
801             return parseMonolithicPackage(packageFile, flags);
802         }
803     }
804 
805     /**
806      * Parse all APKs contained in the given directory, treating them as a
807      * single package. This also performs sanity checking, such as requiring
808      * identical package name and version codes, a single base APK, and unique
809      * split names.
810      * <p>
811      * Note that this <em>does not</em> perform signature verification; that
812      * must be done separately in {@link #collectCertificates(Package, int)}.
813      */
parseClusterPackage(File packageDir, int flags)814     private Package parseClusterPackage(File packageDir, int flags) throws PackageParserException {
815         final PackageLite lite = parseClusterPackageLite(packageDir, 0);
816 
817         if (mOnlyCoreApps && !lite.coreApp) {
818             throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
819                     "Not a coreApp: " + packageDir);
820         }
821 
822         final AssetManager assets = new AssetManager();
823         try {
824             // Load the base and all splits into the AssetManager
825             // so that resources can be overriden when parsing the manifests.
826             loadApkIntoAssetManager(assets, lite.baseCodePath, flags);
827 
828             if (!ArrayUtils.isEmpty(lite.splitCodePaths)) {
829                 for (String path : lite.splitCodePaths) {
830                     loadApkIntoAssetManager(assets, path, flags);
831                 }
832             }
833 
834             final File baseApk = new File(lite.baseCodePath);
835             final Package pkg = parseBaseApk(baseApk, assets, flags);
836             if (pkg == null) {
837                 throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
838                         "Failed to parse base APK: " + baseApk);
839             }
840 
841             if (!ArrayUtils.isEmpty(lite.splitNames)) {
842                 final int num = lite.splitNames.length;
843                 pkg.splitNames = lite.splitNames;
844                 pkg.splitCodePaths = lite.splitCodePaths;
845                 pkg.splitRevisionCodes = lite.splitRevisionCodes;
846                 pkg.splitFlags = new int[num];
847                 pkg.splitPrivateFlags = new int[num];
848 
849                 for (int i = 0; i < num; i++) {
850                     parseSplitApk(pkg, i, assets, flags);
851                 }
852             }
853 
854             pkg.setCodePath(packageDir.getAbsolutePath());
855             pkg.setUse32bitAbi(lite.use32bitAbi);
856             return pkg;
857         } finally {
858             IoUtils.closeQuietly(assets);
859         }
860     }
861 
862     /**
863      * Parse the given APK file, treating it as as a single monolithic package.
864      * <p>
865      * Note that this <em>does not</em> perform signature verification; that
866      * must be done separately in {@link #collectCertificates(Package, int)}.
867      *
868      * @deprecated external callers should move to
869      *             {@link #parsePackage(File, int)}. Eventually this method will
870      *             be marked private.
871      */
872     @Deprecated
parseMonolithicPackage(File apkFile, int flags)873     public Package parseMonolithicPackage(File apkFile, int flags) throws PackageParserException {
874         final PackageLite lite = parseMonolithicPackageLite(apkFile, flags);
875         if (mOnlyCoreApps) {
876             if (!lite.coreApp) {
877                 throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
878                         "Not a coreApp: " + apkFile);
879             }
880         }
881 
882         final AssetManager assets = new AssetManager();
883         try {
884             final Package pkg = parseBaseApk(apkFile, assets, flags);
885             pkg.setCodePath(apkFile.getAbsolutePath());
886             pkg.setUse32bitAbi(lite.use32bitAbi);
887             return pkg;
888         } finally {
889             IoUtils.closeQuietly(assets);
890         }
891     }
892 
loadApkIntoAssetManager(AssetManager assets, String apkPath, int flags)893     private static int loadApkIntoAssetManager(AssetManager assets, String apkPath, int flags)
894             throws PackageParserException {
895         if ((flags & PARSE_MUST_BE_APK) != 0 && !isApkPath(apkPath)) {
896             throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
897                     "Invalid package file: " + apkPath);
898         }
899 
900         // The AssetManager guarantees uniqueness for asset paths, so if this asset path
901         // already exists in the AssetManager, addAssetPath will only return the cookie
902         // assigned to it.
903         int cookie = assets.addAssetPath(apkPath);
904         if (cookie == 0) {
905             throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
906                     "Failed adding asset path: " + apkPath);
907         }
908         return cookie;
909     }
910 
parseBaseApk(File apkFile, AssetManager assets, int flags)911     private Package parseBaseApk(File apkFile, AssetManager assets, int flags)
912             throws PackageParserException {
913         final String apkPath = apkFile.getAbsolutePath();
914 
915         String volumeUuid = null;
916         if (apkPath.startsWith(MNT_EXPAND)) {
917             final int end = apkPath.indexOf('/', MNT_EXPAND.length());
918             volumeUuid = apkPath.substring(MNT_EXPAND.length(), end);
919         }
920 
921         mParseError = PackageManager.INSTALL_SUCCEEDED;
922         mArchiveSourcePath = apkFile.getAbsolutePath();
923 
924         if (DEBUG_JAR) Slog.d(TAG, "Scanning base APK: " + apkPath);
925 
926         final int cookie = loadApkIntoAssetManager(assets, apkPath, flags);
927 
928         Resources res = null;
929         XmlResourceParser parser = null;
930         try {
931             res = new Resources(assets, mMetrics, null);
932             assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
933                     Build.VERSION.RESOURCES_SDK_INT);
934             parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);
935 
936             final String[] outError = new String[1];
937             final Package pkg = parseBaseApk(res, parser, flags, outError);
938             if (pkg == null) {
939                 throw new PackageParserException(mParseError,
940                         apkPath + " (at " + parser.getPositionDescription() + "): " + outError[0]);
941             }
942 
943             pkg.setVolumeUuid(volumeUuid);
944             pkg.setApplicationVolumeUuid(volumeUuid);
945             pkg.setBaseCodePath(apkPath);
946             pkg.setSignatures(null);
947 
948             return pkg;
949 
950         } catch (PackageParserException e) {
951             throw e;
952         } catch (Exception e) {
953             throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
954                     "Failed to read manifest from " + apkPath, e);
955         } finally {
956             IoUtils.closeQuietly(parser);
957         }
958     }
959 
parseSplitApk(Package pkg, int splitIndex, AssetManager assets, int flags)960     private void parseSplitApk(Package pkg, int splitIndex, AssetManager assets, int flags)
961             throws PackageParserException {
962         final String apkPath = pkg.splitCodePaths[splitIndex];
963 
964         mParseError = PackageManager.INSTALL_SUCCEEDED;
965         mArchiveSourcePath = apkPath;
966 
967         if (DEBUG_JAR) Slog.d(TAG, "Scanning split APK: " + apkPath);
968 
969         final int cookie = loadApkIntoAssetManager(assets, apkPath, flags);
970 
971         Resources res = null;
972         XmlResourceParser parser = null;
973         try {
974             res = new Resources(assets, mMetrics, null);
975             assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
976                     Build.VERSION.RESOURCES_SDK_INT);
977             parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);
978 
979             final String[] outError = new String[1];
980             pkg = parseSplitApk(pkg, res, parser, flags, splitIndex, outError);
981             if (pkg == null) {
982                 throw new PackageParserException(mParseError,
983                         apkPath + " (at " + parser.getPositionDescription() + "): " + outError[0]);
984             }
985 
986         } catch (PackageParserException e) {
987             throw e;
988         } catch (Exception e) {
989             throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
990                     "Failed to read manifest from " + apkPath, e);
991         } finally {
992             IoUtils.closeQuietly(parser);
993         }
994     }
995 
996     /**
997      * Parse the manifest of a <em>split APK</em>.
998      * <p>
999      * Note that split APKs have many more restrictions on what they're capable
1000      * of doing, so many valid features of a base APK have been carefully
1001      * omitted here.
1002      */
parseSplitApk(Package pkg, Resources res, XmlResourceParser parser, int flags, int splitIndex, String[] outError)1003     private Package parseSplitApk(Package pkg, Resources res, XmlResourceParser parser, int flags,
1004             int splitIndex, String[] outError) throws XmlPullParserException, IOException,
1005             PackageParserException {
1006         AttributeSet attrs = parser;
1007 
1008         // We parsed manifest tag earlier; just skip past it
1009         parsePackageSplitNames(parser, attrs);
1010 
1011         mParseInstrumentationArgs = null;
1012         mParseActivityArgs = null;
1013         mParseServiceArgs = null;
1014         mParseProviderArgs = null;
1015 
1016         int type;
1017 
1018         boolean foundApp = false;
1019 
1020         int outerDepth = parser.getDepth();
1021         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
1022                 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
1023             if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
1024                 continue;
1025             }
1026 
1027             String tagName = parser.getName();
1028             if (tagName.equals("application")) {
1029                 if (foundApp) {
1030                     if (RIGID_PARSER) {
1031                         outError[0] = "<manifest> has more than one <application>";
1032                         mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1033                         return null;
1034                     } else {
1035                         Slog.w(TAG, "<manifest> has more than one <application>");
1036                         XmlUtils.skipCurrentTag(parser);
1037                         continue;
1038                     }
1039                 }
1040 
1041                 foundApp = true;
1042                 if (!parseSplitApplication(pkg, res, parser, flags, splitIndex, outError)) {
1043                     return null;
1044                 }
1045 
1046             } else if (RIGID_PARSER) {
1047                 outError[0] = "Bad element under <manifest>: "
1048                     + parser.getName();
1049                 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1050                 return null;
1051 
1052             } else {
1053                 Slog.w(TAG, "Unknown element under <manifest>: " + parser.getName()
1054                         + " at " + mArchiveSourcePath + " "
1055                         + parser.getPositionDescription());
1056                 XmlUtils.skipCurrentTag(parser);
1057                 continue;
1058             }
1059         }
1060 
1061         if (!foundApp) {
1062             outError[0] = "<manifest> does not contain an <application>";
1063             mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_EMPTY;
1064         }
1065 
1066         return pkg;
1067     }
1068 
getApkSigningVersion(Package pkg)1069     public static int getApkSigningVersion(Package pkg) {
1070         try {
1071             if (ApkSignatureSchemeV2Verifier.hasSignature(pkg.baseCodePath)) {
1072                 return APK_SIGNING_V2;
1073             }
1074             return APK_SIGNING_V1;
1075         } catch (IOException e) {
1076         }
1077         return APK_SIGNING_UNKNOWN;
1078     }
1079 
1080     /**
1081      * Populates the correct packages fields with the given certificates.
1082      * <p>
1083      * This is useful when we've already processed the certificates [such as during package
1084      * installation through an installer session]. We don't re-process the archive and
1085      * simply populate the correct fields.
1086      */
populateCertificates(Package pkg, Certificate[][] certificates)1087     public static void populateCertificates(Package pkg, Certificate[][] certificates)
1088             throws PackageParserException {
1089         pkg.mCertificates = null;
1090         pkg.mSignatures = null;
1091         pkg.mSigningKeys = null;
1092 
1093         pkg.mCertificates = certificates;
1094         try {
1095             pkg.mSignatures = convertToSignatures(certificates);
1096         } catch (CertificateEncodingException e) {
1097             // certificates weren't encoded properly; something went wrong
1098             throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
1099                     "Failed to collect certificates from " + pkg.baseCodePath, e);
1100         }
1101         pkg.mSigningKeys = new ArraySet<>(certificates.length);
1102         for (int i = 0; i < certificates.length; i++) {
1103             Certificate[] signerCerts = certificates[i];
1104             Certificate signerCert = signerCerts[0];
1105             pkg.mSigningKeys.add(signerCert.getPublicKey());
1106         }
1107         // add signatures to child packages
1108         final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
1109         for (int i = 0; i < childCount; i++) {
1110             Package childPkg = pkg.childPackages.get(i);
1111             childPkg.mCertificates = pkg.mCertificates;
1112             childPkg.mSignatures = pkg.mSignatures;
1113             childPkg.mSigningKeys = pkg.mSigningKeys;
1114         }
1115     }
1116 
1117     /**
1118      * Collect certificates from all the APKs described in the given package,
1119      * populating {@link Package#mSignatures}. Also asserts that all APK
1120      * contents are signed correctly and consistently.
1121      */
collectCertificates(Package pkg, int parseFlags)1122     public static void collectCertificates(Package pkg, int parseFlags)
1123             throws PackageParserException {
1124         collectCertificatesInternal(pkg, parseFlags);
1125         final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
1126         for (int i = 0; i < childCount; i++) {
1127             Package childPkg = pkg.childPackages.get(i);
1128             childPkg.mCertificates = pkg.mCertificates;
1129             childPkg.mSignatures = pkg.mSignatures;
1130             childPkg.mSigningKeys = pkg.mSigningKeys;
1131         }
1132     }
1133 
collectCertificatesInternal(Package pkg, int parseFlags)1134     private static void collectCertificatesInternal(Package pkg, int parseFlags)
1135             throws PackageParserException {
1136         pkg.mCertificates = null;
1137         pkg.mSignatures = null;
1138         pkg.mSigningKeys = null;
1139 
1140         Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates");
1141         try {
1142             collectCertificates(pkg, new File(pkg.baseCodePath), parseFlags);
1143 
1144             if (!ArrayUtils.isEmpty(pkg.splitCodePaths)) {
1145                 for (int i = 0; i < pkg.splitCodePaths.length; i++) {
1146                     collectCertificates(pkg, new File(pkg.splitCodePaths[i]), parseFlags);
1147                 }
1148             }
1149         } finally {
1150             Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
1151         }
1152     }
1153 
collectCertificates(Package pkg, File apkFile, int parseFlags)1154     private static void collectCertificates(Package pkg, File apkFile, int parseFlags)
1155             throws PackageParserException {
1156         final String apkPath = apkFile.getAbsolutePath();
1157 
1158         // Try to verify the APK using APK Signature Scheme v2.
1159         boolean verified = false;
1160         {
1161             Certificate[][] allSignersCerts = null;
1162             Signature[] signatures = null;
1163             try {
1164                 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "verifyV2");
1165                 allSignersCerts = ApkSignatureSchemeV2Verifier.verify(apkPath);
1166                 signatures = convertToSignatures(allSignersCerts);
1167                 // APK verified using APK Signature Scheme v2.
1168                 verified = true;
1169             } catch (ApkSignatureSchemeV2Verifier.SignatureNotFoundException e) {
1170                 // No APK Signature Scheme v2 signature found
1171             } catch (Exception e) {
1172                 // APK Signature Scheme v2 signature was found but did not verify
1173                 throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
1174                         "Failed to collect certificates from " + apkPath
1175                                 + " using APK Signature Scheme v2",
1176                         e);
1177             } finally {
1178                 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
1179             }
1180 
1181             if (verified) {
1182                 if (pkg.mCertificates == null) {
1183                     pkg.mCertificates = allSignersCerts;
1184                     pkg.mSignatures = signatures;
1185                     pkg.mSigningKeys = new ArraySet<>(allSignersCerts.length);
1186                     for (int i = 0; i < allSignersCerts.length; i++) {
1187                         Certificate[] signerCerts = allSignersCerts[i];
1188                         Certificate signerCert = signerCerts[0];
1189                         pkg.mSigningKeys.add(signerCert.getPublicKey());
1190                     }
1191                 } else {
1192                     if (!Signature.areExactMatch(pkg.mSignatures, signatures)) {
1193                         throw new PackageParserException(
1194                                 INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES,
1195                                 apkPath + " has mismatched certificates");
1196                     }
1197                 }
1198                 // Not yet done, because we need to confirm that AndroidManifest.xml exists and,
1199                 // if requested, that classes.dex exists.
1200             }
1201         }
1202 
1203         StrictJarFile jarFile = null;
1204         try {
1205             Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "strictJarFileCtor");
1206             // Ignore signature stripping protections when verifying APKs from system partition.
1207             // For those APKs we only care about extracting signer certificates, and don't care
1208             // about verifying integrity.
1209             boolean signatureSchemeRollbackProtectionsEnforced =
1210                     (parseFlags & PARSE_IS_SYSTEM_DIR) == 0;
1211             jarFile = new StrictJarFile(
1212                     apkPath,
1213                     !verified, // whether to verify JAR signature
1214                     signatureSchemeRollbackProtectionsEnforced);
1215             Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
1216 
1217             // Always verify manifest, regardless of source
1218             final ZipEntry manifestEntry = jarFile.findEntry(ANDROID_MANIFEST_FILENAME);
1219             if (manifestEntry == null) {
1220                 throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
1221                         "Package " + apkPath + " has no manifest");
1222             }
1223 
1224             // Optimization: early termination when APK already verified
1225             if (verified) {
1226                 return;
1227             }
1228 
1229             // APK's integrity needs to be verified using JAR signature scheme.
1230             Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "verifyV1");
1231             final List<ZipEntry> toVerify = new ArrayList<>();
1232             toVerify.add(manifestEntry);
1233 
1234             // If we're parsing an untrusted package, verify all contents
1235             if ((parseFlags & PARSE_IS_SYSTEM_DIR) == 0) {
1236                 final Iterator<ZipEntry> i = jarFile.iterator();
1237                 while (i.hasNext()) {
1238                     final ZipEntry entry = i.next();
1239 
1240                     if (entry.isDirectory()) continue;
1241 
1242                     final String entryName = entry.getName();
1243                     if (entryName.startsWith("META-INF/")) continue;
1244                     if (entryName.equals(ANDROID_MANIFEST_FILENAME)) continue;
1245 
1246                     toVerify.add(entry);
1247                 }
1248             }
1249 
1250             // Verify that entries are signed consistently with the first entry
1251             // we encountered. Note that for splits, certificates may have
1252             // already been populated during an earlier parse of a base APK.
1253             for (ZipEntry entry : toVerify) {
1254                 final Certificate[][] entryCerts = loadCertificates(jarFile, entry);
1255                 if (ArrayUtils.isEmpty(entryCerts)) {
1256                     throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
1257                             "Package " + apkPath + " has no certificates at entry "
1258                             + entry.getName());
1259                 }
1260                 final Signature[] entrySignatures = convertToSignatures(entryCerts);
1261 
1262                 if (pkg.mCertificates == null) {
1263                     pkg.mCertificates = entryCerts;
1264                     pkg.mSignatures = entrySignatures;
1265                     pkg.mSigningKeys = new ArraySet<PublicKey>();
1266                     for (int i=0; i < entryCerts.length; i++) {
1267                         pkg.mSigningKeys.add(entryCerts[i][0].getPublicKey());
1268                     }
1269                 } else {
1270                     if (!Signature.areExactMatch(pkg.mSignatures, entrySignatures)) {
1271                         throw new PackageParserException(
1272                                 INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES, "Package " + apkPath
1273                                         + " has mismatched certificates at entry "
1274                                         + entry.getName());
1275                     }
1276                 }
1277             }
1278             Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
1279         } catch (GeneralSecurityException e) {
1280             throw new PackageParserException(INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING,
1281                     "Failed to collect certificates from " + apkPath, e);
1282         } catch (IOException | RuntimeException e) {
1283             throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
1284                     "Failed to collect certificates from " + apkPath, e);
1285         } finally {
1286             closeQuietly(jarFile);
1287         }
1288     }
1289 
convertToSignatures(Certificate[][] certs)1290     private static Signature[] convertToSignatures(Certificate[][] certs)
1291             throws CertificateEncodingException {
1292         final Signature[] res = new Signature[certs.length];
1293         for (int i = 0; i < certs.length; i++) {
1294             res[i] = new Signature(certs[i]);
1295         }
1296         return res;
1297     }
1298 
1299     /**
1300      * Utility method that retrieves lightweight details about a single APK
1301      * file, including package name, split name, and install location.
1302      *
1303      * @param apkFile path to a single APK
1304      * @param flags optional parse flags, such as
1305      *            {@link #PARSE_COLLECT_CERTIFICATES}
1306      */
parseApkLite(File apkFile, int flags)1307     public static ApkLite parseApkLite(File apkFile, int flags)
1308             throws PackageParserException {
1309         final String apkPath = apkFile.getAbsolutePath();
1310 
1311         AssetManager assets = null;
1312         XmlResourceParser parser = null;
1313         try {
1314             assets = new AssetManager();
1315             assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1316                     Build.VERSION.RESOURCES_SDK_INT);
1317 
1318             int cookie = assets.addAssetPath(apkPath);
1319             if (cookie == 0) {
1320                 throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
1321                         "Failed to parse " + apkPath);
1322             }
1323 
1324             final DisplayMetrics metrics = new DisplayMetrics();
1325             metrics.setToDefaults();
1326 
1327             final Resources res = new Resources(assets, metrics, null);
1328             parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);
1329 
1330             final Signature[] signatures;
1331             final Certificate[][] certificates;
1332             if ((flags & PARSE_COLLECT_CERTIFICATES) != 0) {
1333                 // TODO: factor signature related items out of Package object
1334                 final Package tempPkg = new Package(null);
1335                 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates");
1336                 try {
1337                     collectCertificates(tempPkg, apkFile, 0 /*parseFlags*/);
1338                 } finally {
1339                     Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
1340                 }
1341                 signatures = tempPkg.mSignatures;
1342                 certificates = tempPkg.mCertificates;
1343             } else {
1344                 signatures = null;
1345                 certificates = null;
1346             }
1347 
1348             final AttributeSet attrs = parser;
1349             return parseApkLite(apkPath, res, parser, attrs, flags, signatures, certificates);
1350 
1351         } catch (XmlPullParserException | IOException | RuntimeException e) {
1352             throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
1353                     "Failed to parse " + apkPath, e);
1354         } finally {
1355             IoUtils.closeQuietly(parser);
1356             IoUtils.closeQuietly(assets);
1357         }
1358     }
1359 
validateName(String name, boolean requireSeparator, boolean requireFilename)1360     private static String validateName(String name, boolean requireSeparator,
1361             boolean requireFilename) {
1362         final int N = name.length();
1363         boolean hasSep = false;
1364         boolean front = true;
1365         for (int i=0; i<N; i++) {
1366             final char c = name.charAt(i);
1367             if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
1368                 front = false;
1369                 continue;
1370             }
1371             if (!front) {
1372                 if ((c >= '0' && c <= '9') || c == '_') {
1373                     continue;
1374                 }
1375             }
1376             if (c == '.') {
1377                 hasSep = true;
1378                 front = true;
1379                 continue;
1380             }
1381             return "bad character '" + c + "'";
1382         }
1383         if (requireFilename && !FileUtils.isValidExtFilename(name)) {
1384             return "Invalid filename";
1385         }
1386         return hasSep || !requireSeparator
1387                 ? null : "must have at least one '.' separator";
1388     }
1389 
parsePackageSplitNames(XmlPullParser parser, AttributeSet attrs)1390     private static Pair<String, String> parsePackageSplitNames(XmlPullParser parser,
1391             AttributeSet attrs) throws IOException, XmlPullParserException,
1392             PackageParserException {
1393 
1394         int type;
1395         while ((type = parser.next()) != XmlPullParser.START_TAG
1396                 && type != XmlPullParser.END_DOCUMENT) {
1397         }
1398 
1399         if (type != XmlPullParser.START_TAG) {
1400             throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
1401                     "No start tag found");
1402         }
1403         if (!parser.getName().equals(TAG_MANIFEST)) {
1404             throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
1405                     "No <manifest> tag");
1406         }
1407 
1408         final String packageName = attrs.getAttributeValue(null, "package");
1409         if (!"android".equals(packageName)) {
1410             final String error = validateName(packageName, true, true);
1411             if (error != null) {
1412                 throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
1413                         "Invalid manifest package: " + error);
1414             }
1415         }
1416 
1417         String splitName = attrs.getAttributeValue(null, "split");
1418         if (splitName != null) {
1419             if (splitName.length() == 0) {
1420                 splitName = null;
1421             } else {
1422                 final String error = validateName(splitName, false, false);
1423                 if (error != null) {
1424                     throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
1425                             "Invalid manifest split: " + error);
1426                 }
1427             }
1428         }
1429 
1430         return Pair.create(packageName.intern(),
1431                 (splitName != null) ? splitName.intern() : splitName);
1432     }
1433 
parseApkLite(String codePath, Resources res, XmlPullParser parser, AttributeSet attrs, int flags, Signature[] signatures, Certificate[][] certificates)1434     private static ApkLite parseApkLite(String codePath, Resources res, XmlPullParser parser,
1435             AttributeSet attrs, int flags, Signature[] signatures, Certificate[][] certificates)
1436                     throws IOException, XmlPullParserException, PackageParserException {
1437         final Pair<String, String> packageSplit = parsePackageSplitNames(parser, attrs);
1438 
1439         int installLocation = PARSE_DEFAULT_INSTALL_LOCATION;
1440         int versionCode = 0;
1441         int revisionCode = 0;
1442         boolean coreApp = false;
1443         boolean multiArch = false;
1444         boolean use32bitAbi = false;
1445         boolean extractNativeLibs = true;
1446 
1447         for (int i = 0; i < attrs.getAttributeCount(); i++) {
1448             final String attr = attrs.getAttributeName(i);
1449             if (attr.equals("installLocation")) {
1450                 installLocation = attrs.getAttributeIntValue(i,
1451                         PARSE_DEFAULT_INSTALL_LOCATION);
1452             } else if (attr.equals("versionCode")) {
1453                 versionCode = attrs.getAttributeIntValue(i, 0);
1454             } else if (attr.equals("revisionCode")) {
1455                 revisionCode = attrs.getAttributeIntValue(i, 0);
1456             } else if (attr.equals("coreApp")) {
1457                 coreApp = attrs.getAttributeBooleanValue(i, false);
1458             }
1459         }
1460 
1461         // Only search the tree when the tag is directly below <manifest>
1462         int type;
1463         final int searchDepth = parser.getDepth() + 1;
1464 
1465         final List<VerifierInfo> verifiers = new ArrayList<VerifierInfo>();
1466         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
1467                 && (type != XmlPullParser.END_TAG || parser.getDepth() >= searchDepth)) {
1468             if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
1469                 continue;
1470             }
1471 
1472             if (parser.getDepth() == searchDepth && "package-verifier".equals(parser.getName())) {
1473                 final VerifierInfo verifier = parseVerifier(res, parser, attrs, flags);
1474                 if (verifier != null) {
1475                     verifiers.add(verifier);
1476                 }
1477             }
1478 
1479             if (parser.getDepth() == searchDepth && "application".equals(parser.getName())) {
1480                 for (int i = 0; i < attrs.getAttributeCount(); ++i) {
1481                     final String attr = attrs.getAttributeName(i);
1482                     if ("multiArch".equals(attr)) {
1483                         multiArch = attrs.getAttributeBooleanValue(i, false);
1484                     }
1485                     if ("use32bitAbi".equals(attr)) {
1486                         use32bitAbi = attrs.getAttributeBooleanValue(i, false);
1487                     }
1488                     if ("extractNativeLibs".equals(attr)) {
1489                         extractNativeLibs = attrs.getAttributeBooleanValue(i, true);
1490                     }
1491                 }
1492             }
1493         }
1494 
1495         return new ApkLite(codePath, packageSplit.first, packageSplit.second, versionCode,
1496                 revisionCode, installLocation, verifiers, signatures, certificates, coreApp,
1497                 multiArch, use32bitAbi, extractNativeLibs);
1498     }
1499 
1500     /**
1501      * Temporary.
1502      */
stringToSignature(String str)1503     static public Signature stringToSignature(String str) {
1504         final int N = str.length();
1505         byte[] sig = new byte[N];
1506         for (int i=0; i<N; i++) {
1507             sig[i] = (byte)str.charAt(i);
1508         }
1509         return new Signature(sig);
1510     }
1511 
1512     /**
1513      * Parses a child package and adds it to the parent if successful. If you add
1514      * new tags that need to be supported by child packages make sure to add them
1515      * to {@link #CHILD_PACKAGE_TAGS}.
1516      *
1517      * @param parentPkg The parent that contains the child
1518      * @param res Resources against which to resolve values
1519      * @param parser Parser of the manifest
1520      * @param flags Flags about how to parse
1521      * @param outError Human readable error if parsing fails
1522      * @return True of parsing succeeded.
1523      *
1524      * @throws XmlPullParserException
1525      * @throws IOException
1526      */
parseBaseApkChild(Package parentPkg, Resources res, XmlResourceParser parser, int flags, String[] outError)1527     private boolean parseBaseApkChild(Package parentPkg, Resources res, XmlResourceParser parser,
1528             int flags, String[] outError) throws XmlPullParserException, IOException {
1529         // Let ppl not abuse this mechanism by limiting the packages per APK
1530         if (parentPkg.childPackages != null && parentPkg.childPackages.size() + 2
1531                 > MAX_PACKAGES_PER_APK) {
1532             outError[0] = "Maximum number of packages per APK is: " + MAX_PACKAGES_PER_APK;
1533             mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1534             return false;
1535         }
1536 
1537         // Make sure we have a valid child package name
1538         String childPackageName = parser.getAttributeValue(null, "package");
1539         if (validateName(childPackageName, true, false) != null) {
1540             mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME;
1541             return false;
1542         }
1543 
1544         // Child packages must be unique
1545         if (childPackageName.equals(parentPkg.packageName)) {
1546             String message = "Child package name cannot be equal to parent package name: "
1547                     + parentPkg.packageName;
1548             Slog.w(TAG, message);
1549             outError[0] = message;
1550             mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1551             return false;
1552         }
1553 
1554         // Child packages must be unique
1555         if (parentPkg.hasChildPackage(childPackageName)) {
1556             String message = "Duplicate child package:" + childPackageName;
1557             Slog.w(TAG, message);
1558             outError[0] = message;
1559             mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1560             return false;
1561         }
1562 
1563         // Go ahead and parse the child
1564         Package childPkg = new Package(childPackageName);
1565 
1566         // Child package inherits parent version code/name/target SDK
1567         childPkg.mVersionCode = parentPkg.mVersionCode;
1568         childPkg.baseRevisionCode = parentPkg.baseRevisionCode;
1569         childPkg.mVersionName = parentPkg.mVersionName;
1570         childPkg.applicationInfo.targetSdkVersion = parentPkg.applicationInfo.targetSdkVersion;
1571         childPkg.applicationInfo.minSdkVersion = parentPkg.applicationInfo.minSdkVersion;
1572 
1573         childPkg = parseBaseApkCommon(childPkg, CHILD_PACKAGE_TAGS, res, parser, flags, outError);
1574         if (childPkg == null) {
1575             // If we got null then error was set during child parsing
1576             return false;
1577         }
1578 
1579         // Set the parent-child relation
1580         if (parentPkg.childPackages == null) {
1581             parentPkg.childPackages = new ArrayList<>();
1582         }
1583         parentPkg.childPackages.add(childPkg);
1584         childPkg.parentPackage = parentPkg;
1585 
1586         return true;
1587     }
1588 
1589     /**
1590      * Parse the manifest of a <em>base APK</em>. When adding new features you
1591      * need to consider whether they should be supported by split APKs and child
1592      * packages.
1593      *
1594      * @param res The resources from which to resolve values
1595      * @param parser The manifest parser
1596      * @param flags Flags how to parse
1597      * @param outError Human readable error message
1598      * @return Parsed package or null on error.
1599      *
1600      * @throws XmlPullParserException
1601      * @throws IOException
1602      */
parseBaseApk(Resources res, XmlResourceParser parser, int flags, String[] outError)1603     private Package parseBaseApk(Resources res, XmlResourceParser parser, int flags,
1604             String[] outError) throws XmlPullParserException, IOException {
1605         final String splitName;
1606         final String pkgName;
1607 
1608         try {
1609             Pair<String, String> packageSplit = parsePackageSplitNames(parser, parser);
1610             pkgName = packageSplit.first;
1611             splitName = packageSplit.second;
1612 
1613             if (!TextUtils.isEmpty(splitName)) {
1614                 outError[0] = "Expected base APK, but found split " + splitName;
1615                 mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME;
1616                 return null;
1617             }
1618         } catch (PackageParserException e) {
1619             mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME;
1620             return null;
1621         }
1622 
1623         final Package pkg = new Package(pkgName);
1624 
1625         TypedArray sa = res.obtainAttributes(parser,
1626                 com.android.internal.R.styleable.AndroidManifest);
1627 
1628         pkg.mVersionCode = pkg.applicationInfo.versionCode = sa.getInteger(
1629                 com.android.internal.R.styleable.AndroidManifest_versionCode, 0);
1630         pkg.baseRevisionCode = sa.getInteger(
1631                 com.android.internal.R.styleable.AndroidManifest_revisionCode, 0);
1632         pkg.mVersionName = sa.getNonConfigurationString(
1633                 com.android.internal.R.styleable.AndroidManifest_versionName, 0);
1634         if (pkg.mVersionName != null) {
1635             pkg.mVersionName = pkg.mVersionName.intern();
1636         }
1637 
1638         pkg.coreApp = parser.getAttributeBooleanValue(null, "coreApp", false);
1639 
1640         sa.recycle();
1641 
1642         return parseBaseApkCommon(pkg, null, res, parser, flags, outError);
1643     }
1644 
1645     /**
1646      * This is the common parsing routing for handling parent and child
1647      * packages in a base APK. The difference between parent and child
1648      * parsing is that some tags are not supported by child packages as
1649      * well as some manifest attributes are ignored. The implementation
1650      * assumes the calling code has already handled the manifest tag if needed
1651      * (this applies to the parent only).
1652      *
1653      * @param pkg The package which to populate
1654      * @param acceptedTags Which tags to handle, null to handle all
1655      * @param res Resources against which to resolve values
1656      * @param parser Parser of the manifest
1657      * @param flags Flags about how to parse
1658      * @param outError Human readable error if parsing fails
1659      * @return The package if parsing succeeded or null.
1660      *
1661      * @throws XmlPullParserException
1662      * @throws IOException
1663      */
parseBaseApkCommon(Package pkg, Set<String> acceptedTags, Resources res, XmlResourceParser parser, int flags, String[] outError)1664     private Package parseBaseApkCommon(Package pkg, Set<String> acceptedTags, Resources res,
1665             XmlResourceParser parser, int flags, String[] outError) throws XmlPullParserException,
1666             IOException {
1667         mParseInstrumentationArgs = null;
1668         mParseActivityArgs = null;
1669         mParseServiceArgs = null;
1670         mParseProviderArgs = null;
1671 
1672         int type;
1673         boolean foundApp = false;
1674 
1675         TypedArray sa = res.obtainAttributes(parser,
1676                 com.android.internal.R.styleable.AndroidManifest);
1677 
1678         String str = sa.getNonConfigurationString(
1679                 com.android.internal.R.styleable.AndroidManifest_sharedUserId, 0);
1680         if (str != null && str.length() > 0) {
1681             String nameError = validateName(str, true, false);
1682             if (nameError != null && !"android".equals(pkg.packageName)) {
1683                 outError[0] = "<manifest> specifies bad sharedUserId name \""
1684                     + str + "\": " + nameError;
1685                 mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID;
1686                 return null;
1687             }
1688             pkg.mSharedUserId = str.intern();
1689             pkg.mSharedUserLabel = sa.getResourceId(
1690                     com.android.internal.R.styleable.AndroidManifest_sharedUserLabel, 0);
1691         }
1692 
1693         pkg.installLocation = sa.getInteger(
1694                 com.android.internal.R.styleable.AndroidManifest_installLocation,
1695                 PARSE_DEFAULT_INSTALL_LOCATION);
1696         pkg.applicationInfo.installLocation = pkg.installLocation;
1697 
1698 
1699         /* Set the global "forward lock" flag */
1700         if ((flags & PARSE_FORWARD_LOCK) != 0) {
1701             pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK;
1702         }
1703 
1704         /* Set the global "on SD card" flag */
1705         if ((flags & PARSE_EXTERNAL_STORAGE) != 0) {
1706             pkg.applicationInfo.flags |= ApplicationInfo.FLAG_EXTERNAL_STORAGE;
1707         }
1708 
1709         if ((flags & PARSE_IS_EPHEMERAL) != 0) {
1710             pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_EPHEMERAL;
1711         }
1712 
1713         // Resource boolean are -1, so 1 means we don't know the value.
1714         int supportsSmallScreens = 1;
1715         int supportsNormalScreens = 1;
1716         int supportsLargeScreens = 1;
1717         int supportsXLargeScreens = 1;
1718         int resizeable = 1;
1719         int anyDensity = 1;
1720 
1721         int outerDepth = parser.getDepth();
1722         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
1723                 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
1724             if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
1725                 continue;
1726             }
1727 
1728             String tagName = parser.getName();
1729 
1730             if (acceptedTags != null && !acceptedTags.contains(tagName)) {
1731                 Slog.w(TAG, "Skipping unsupported element under <manifest>: "
1732                         + tagName + " at " + mArchiveSourcePath + " "
1733                         + parser.getPositionDescription());
1734                 XmlUtils.skipCurrentTag(parser);
1735                 continue;
1736             }
1737 
1738             if (tagName.equals(TAG_APPLICATION)) {
1739                 if (foundApp) {
1740                     if (RIGID_PARSER) {
1741                         outError[0] = "<manifest> has more than one <application>";
1742                         mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1743                         return null;
1744                     } else {
1745                         Slog.w(TAG, "<manifest> has more than one <application>");
1746                         XmlUtils.skipCurrentTag(parser);
1747                         continue;
1748                     }
1749                 }
1750 
1751                 foundApp = true;
1752                 if (!parseBaseApplication(pkg, res, parser, flags, outError)) {
1753                     return null;
1754                 }
1755             } else if (tagName.equals(TAG_OVERLAY)) {
1756                 sa = res.obtainAttributes(parser,
1757                         com.android.internal.R.styleable.AndroidManifestResourceOverlay);
1758                 pkg.mOverlayTarget = sa.getString(
1759                         com.android.internal.R.styleable.AndroidManifestResourceOverlay_targetPackage);
1760                 pkg.mOverlayPriority = sa.getInt(
1761                         com.android.internal.R.styleable.AndroidManifestResourceOverlay_priority,
1762                         -1);
1763                 sa.recycle();
1764 
1765                 if (pkg.mOverlayTarget == null) {
1766                     outError[0] = "<overlay> does not specify a target package";
1767                     mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1768                     return null;
1769                 }
1770                 if (pkg.mOverlayPriority < 0 || pkg.mOverlayPriority > 9999) {
1771                     outError[0] = "<overlay> priority must be between 0 and 9999";
1772                     mParseError =
1773                         PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1774                     return null;
1775                 }
1776                 XmlUtils.skipCurrentTag(parser);
1777 
1778             } else if (tagName.equals(TAG_KEY_SETS)) {
1779                 if (!parseKeySets(pkg, res, parser, outError)) {
1780                     return null;
1781                 }
1782             } else if (tagName.equals(TAG_PERMISSION_GROUP)) {
1783                 if (parsePermissionGroup(pkg, flags, res, parser, outError) == null) {
1784                     return null;
1785                 }
1786             } else if (tagName.equals(TAG_PERMISSION)) {
1787                 if (parsePermission(pkg, res, parser, outError) == null) {
1788                     return null;
1789                 }
1790             } else if (tagName.equals(TAG_PERMISSION_TREE)) {
1791                 if (parsePermissionTree(pkg, res, parser, outError) == null) {
1792                     return null;
1793                 }
1794             } else if (tagName.equals(TAG_USES_PERMISSION)) {
1795                 if (!parseUsesPermission(pkg, res, parser)) {
1796                     return null;
1797                 }
1798             } else if (tagName.equals(TAG_USES_PERMISSION_SDK_M)
1799                     || tagName.equals(TAG_USES_PERMISSION_SDK_23)) {
1800                 if (!parseUsesPermission(pkg, res, parser)) {
1801                     return null;
1802                 }
1803             } else if (tagName.equals(TAG_USES_CONFIGURATION)) {
1804                 ConfigurationInfo cPref = new ConfigurationInfo();
1805                 sa = res.obtainAttributes(parser,
1806                         com.android.internal.R.styleable.AndroidManifestUsesConfiguration);
1807                 cPref.reqTouchScreen = sa.getInt(
1808                         com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqTouchScreen,
1809                         Configuration.TOUCHSCREEN_UNDEFINED);
1810                 cPref.reqKeyboardType = sa.getInt(
1811                         com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqKeyboardType,
1812                         Configuration.KEYBOARD_UNDEFINED);
1813                 if (sa.getBoolean(
1814                         com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqHardKeyboard,
1815                         false)) {
1816                     cPref.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
1817                 }
1818                 cPref.reqNavigation = sa.getInt(
1819                         com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqNavigation,
1820                         Configuration.NAVIGATION_UNDEFINED);
1821                 if (sa.getBoolean(
1822                         com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqFiveWayNav,
1823                         false)) {
1824                     cPref.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
1825                 }
1826                 sa.recycle();
1827                 pkg.configPreferences = ArrayUtils.add(pkg.configPreferences, cPref);
1828 
1829                 XmlUtils.skipCurrentTag(parser);
1830 
1831             } else if (tagName.equals(TAG_USES_FEATURE)) {
1832                 FeatureInfo fi = parseUsesFeature(res, parser);
1833                 pkg.reqFeatures = ArrayUtils.add(pkg.reqFeatures, fi);
1834 
1835                 if (fi.name == null) {
1836                     ConfigurationInfo cPref = new ConfigurationInfo();
1837                     cPref.reqGlEsVersion = fi.reqGlEsVersion;
1838                     pkg.configPreferences = ArrayUtils.add(pkg.configPreferences, cPref);
1839                 }
1840 
1841                 XmlUtils.skipCurrentTag(parser);
1842 
1843             } else if (tagName.equals(TAG_FEATURE_GROUP)) {
1844                 FeatureGroupInfo group = new FeatureGroupInfo();
1845                 ArrayList<FeatureInfo> features = null;
1846                 final int innerDepth = parser.getDepth();
1847                 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
1848                         && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
1849                     if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
1850                         continue;
1851                     }
1852 
1853                     final String innerTagName = parser.getName();
1854                     if (innerTagName.equals("uses-feature")) {
1855                         FeatureInfo featureInfo = parseUsesFeature(res, parser);
1856                         // FeatureGroups are stricter and mandate that
1857                         // any <uses-feature> declared are mandatory.
1858                         featureInfo.flags |= FeatureInfo.FLAG_REQUIRED;
1859                         features = ArrayUtils.add(features, featureInfo);
1860                     } else {
1861                         Slog.w(TAG, "Unknown element under <feature-group>: " + innerTagName +
1862                                 " at " + mArchiveSourcePath + " " +
1863                                 parser.getPositionDescription());
1864                     }
1865                     XmlUtils.skipCurrentTag(parser);
1866                 }
1867 
1868                 if (features != null) {
1869                     group.features = new FeatureInfo[features.size()];
1870                     group.features = features.toArray(group.features);
1871                 }
1872                 pkg.featureGroups = ArrayUtils.add(pkg.featureGroups, group);
1873 
1874             } else if (tagName.equals(TAG_USES_SDK)) {
1875                 if (SDK_VERSION > 0) {
1876                     sa = res.obtainAttributes(parser,
1877                             com.android.internal.R.styleable.AndroidManifestUsesSdk);
1878 
1879                     int minVers = 1;
1880                     String minCode = null;
1881                     int targetVers = 0;
1882                     String targetCode = null;
1883 
1884                     TypedValue val = sa.peekValue(
1885                             com.android.internal.R.styleable.AndroidManifestUsesSdk_minSdkVersion);
1886                     if (val != null) {
1887                         if (val.type == TypedValue.TYPE_STRING && val.string != null) {
1888                             targetCode = minCode = val.string.toString();
1889                         } else {
1890                             // If it's not a string, it's an integer.
1891                             targetVers = minVers = val.data;
1892                         }
1893                     }
1894 
1895                     val = sa.peekValue(
1896                             com.android.internal.R.styleable.AndroidManifestUsesSdk_targetSdkVersion);
1897                     if (val != null) {
1898                         if (val.type == TypedValue.TYPE_STRING && val.string != null) {
1899                             targetCode = val.string.toString();
1900                             if (minCode == null) {
1901                                 minCode = targetCode;
1902                             }
1903                         } else {
1904                             // If it's not a string, it's an integer.
1905                             targetVers = val.data;
1906                         }
1907                     }
1908 
1909                     sa.recycle();
1910 
1911                     if (minCode != null) {
1912                         boolean allowedCodename = false;
1913                         for (String codename : SDK_CODENAMES) {
1914                             if (minCode.equals(codename)) {
1915                                 allowedCodename = true;
1916                                 break;
1917                             }
1918                         }
1919                         if (!allowedCodename) {
1920                             if (SDK_CODENAMES.length > 0) {
1921                                 outError[0] = "Requires development platform " + minCode
1922                                         + " (current platform is any of "
1923                                         + Arrays.toString(SDK_CODENAMES) + ")";
1924                             } else {
1925                                 outError[0] = "Requires development platform " + minCode
1926                                         + " but this is a release platform.";
1927                             }
1928                             mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK;
1929                             return null;
1930                         }
1931                         pkg.applicationInfo.minSdkVersion =
1932                                 android.os.Build.VERSION_CODES.CUR_DEVELOPMENT;
1933                     } else if (minVers > SDK_VERSION) {
1934                         outError[0] = "Requires newer sdk version #" + minVers
1935                                 + " (current version is #" + SDK_VERSION + ")";
1936                         mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK;
1937                         return null;
1938                     } else {
1939                         pkg.applicationInfo.minSdkVersion = minVers;
1940                     }
1941 
1942                     if (targetCode != null) {
1943                         boolean allowedCodename = false;
1944                         for (String codename : SDK_CODENAMES) {
1945                             if (targetCode.equals(codename)) {
1946                                 allowedCodename = true;
1947                                 break;
1948                             }
1949                         }
1950                         if (!allowedCodename) {
1951                             if (SDK_CODENAMES.length > 0) {
1952                                 outError[0] = "Requires development platform " + targetCode
1953                                         + " (current platform is any of "
1954                                         + Arrays.toString(SDK_CODENAMES) + ")";
1955                             } else {
1956                                 outError[0] = "Requires development platform " + targetCode
1957                                         + " but this is a release platform.";
1958                             }
1959                             mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK;
1960                             return null;
1961                         }
1962                         // If the code matches, it definitely targets this SDK.
1963                         pkg.applicationInfo.targetSdkVersion
1964                                 = android.os.Build.VERSION_CODES.CUR_DEVELOPMENT;
1965                     } else {
1966                         pkg.applicationInfo.targetSdkVersion = targetVers;
1967                     }
1968                 }
1969 
1970                 XmlUtils.skipCurrentTag(parser);
1971 
1972             } else if (tagName.equals(TAG_SUPPORT_SCREENS)) {
1973                 sa = res.obtainAttributes(parser,
1974                         com.android.internal.R.styleable.AndroidManifestSupportsScreens);
1975 
1976                 pkg.applicationInfo.requiresSmallestWidthDp = sa.getInteger(
1977                         com.android.internal.R.styleable.AndroidManifestSupportsScreens_requiresSmallestWidthDp,
1978                         0);
1979                 pkg.applicationInfo.compatibleWidthLimitDp = sa.getInteger(
1980                         com.android.internal.R.styleable.AndroidManifestSupportsScreens_compatibleWidthLimitDp,
1981                         0);
1982                 pkg.applicationInfo.largestWidthLimitDp = sa.getInteger(
1983                         com.android.internal.R.styleable.AndroidManifestSupportsScreens_largestWidthLimitDp,
1984                         0);
1985 
1986                 // This is a trick to get a boolean and still able to detect
1987                 // if a value was actually set.
1988                 supportsSmallScreens = sa.getInteger(
1989                         com.android.internal.R.styleable.AndroidManifestSupportsScreens_smallScreens,
1990                         supportsSmallScreens);
1991                 supportsNormalScreens = sa.getInteger(
1992                         com.android.internal.R.styleable.AndroidManifestSupportsScreens_normalScreens,
1993                         supportsNormalScreens);
1994                 supportsLargeScreens = sa.getInteger(
1995                         com.android.internal.R.styleable.AndroidManifestSupportsScreens_largeScreens,
1996                         supportsLargeScreens);
1997                 supportsXLargeScreens = sa.getInteger(
1998                         com.android.internal.R.styleable.AndroidManifestSupportsScreens_xlargeScreens,
1999                         supportsXLargeScreens);
2000                 resizeable = sa.getInteger(
2001                         com.android.internal.R.styleable.AndroidManifestSupportsScreens_resizeable,
2002                         resizeable);
2003                 anyDensity = sa.getInteger(
2004                         com.android.internal.R.styleable.AndroidManifestSupportsScreens_anyDensity,
2005                         anyDensity);
2006 
2007                 sa.recycle();
2008 
2009                 XmlUtils.skipCurrentTag(parser);
2010 
2011             } else if (tagName.equals(TAG_PROTECTED_BROADCAST)) {
2012                 sa = res.obtainAttributes(parser,
2013                         com.android.internal.R.styleable.AndroidManifestProtectedBroadcast);
2014 
2015                 // Note: don't allow this value to be a reference to a resource
2016                 // that may change.
2017                 String name = sa.getNonResourceString(
2018                         com.android.internal.R.styleable.AndroidManifestProtectedBroadcast_name);
2019 
2020                 sa.recycle();
2021 
2022                 if (name != null && (flags&PARSE_IS_SYSTEM) != 0) {
2023                     if (pkg.protectedBroadcasts == null) {
2024                         pkg.protectedBroadcasts = new ArrayList<String>();
2025                     }
2026                     if (!pkg.protectedBroadcasts.contains(name)) {
2027                         pkg.protectedBroadcasts.add(name.intern());
2028                     }
2029                 }
2030 
2031                 XmlUtils.skipCurrentTag(parser);
2032 
2033             } else if (tagName.equals(TAG_INSTRUMENTATION)) {
2034                 if (parseInstrumentation(pkg, res, parser, outError) == null) {
2035                     return null;
2036                 }
2037             } else if (tagName.equals(TAG_ORIGINAL_PACKAGE)) {
2038                 sa = res.obtainAttributes(parser,
2039                         com.android.internal.R.styleable.AndroidManifestOriginalPackage);
2040 
2041                 String orig =sa.getNonConfigurationString(
2042                         com.android.internal.R.styleable.AndroidManifestOriginalPackage_name, 0);
2043                 if (!pkg.packageName.equals(orig)) {
2044                     if (pkg.mOriginalPackages == null) {
2045                         pkg.mOriginalPackages = new ArrayList<String>();
2046                         pkg.mRealPackage = pkg.packageName;
2047                     }
2048                     pkg.mOriginalPackages.add(orig);
2049                 }
2050 
2051                 sa.recycle();
2052 
2053                 XmlUtils.skipCurrentTag(parser);
2054 
2055             } else if (tagName.equals(TAG_ADOPT_PERMISSIONS)) {
2056                 sa = res.obtainAttributes(parser,
2057                         com.android.internal.R.styleable.AndroidManifestOriginalPackage);
2058 
2059                 String name = sa.getNonConfigurationString(
2060                         com.android.internal.R.styleable.AndroidManifestOriginalPackage_name, 0);
2061 
2062                 sa.recycle();
2063 
2064                 if (name != null) {
2065                     if (pkg.mAdoptPermissions == null) {
2066                         pkg.mAdoptPermissions = new ArrayList<String>();
2067                     }
2068                     pkg.mAdoptPermissions.add(name);
2069                 }
2070 
2071                 XmlUtils.skipCurrentTag(parser);
2072 
2073             } else if (tagName.equals(TAG_USES_GL_TEXTURE)) {
2074                 // Just skip this tag
2075                 XmlUtils.skipCurrentTag(parser);
2076                 continue;
2077 
2078             } else if (tagName.equals(TAG_COMPATIBLE_SCREENS)) {
2079                 // Just skip this tag
2080                 XmlUtils.skipCurrentTag(parser);
2081                 continue;
2082             } else if (tagName.equals(TAG_SUPPORTS_INPUT)) {//
2083                 XmlUtils.skipCurrentTag(parser);
2084                 continue;
2085 
2086             } else if (tagName.equals(TAG_EAT_COMMENT)) {
2087                 // Just skip this tag
2088                 XmlUtils.skipCurrentTag(parser);
2089                 continue;
2090 
2091             } else if (tagName.equals(TAG_PACKAGE)) {
2092                 if (!MULTI_PACKAGE_APK_ENABLED) {
2093                     XmlUtils.skipCurrentTag(parser);
2094                     continue;
2095                 }
2096                 if (!parseBaseApkChild(pkg, res, parser, flags, outError)) {
2097                     // If parsing a child failed the error is already set
2098                     return null;
2099                 }
2100 
2101             } else if (tagName.equals(TAG_RESTRICT_UPDATE)) {
2102                 if ((flags & PARSE_IS_SYSTEM_DIR) != 0) {
2103                     sa = res.obtainAttributes(parser,
2104                             com.android.internal.R.styleable.AndroidManifestRestrictUpdate);
2105                     final String hash = sa.getNonConfigurationString(
2106                             com.android.internal.R.styleable.AndroidManifestRestrictUpdate_hash, 0);
2107                     sa.recycle();
2108 
2109                     pkg.restrictUpdateHash = null;
2110                     if (hash != null) {
2111                         final int hashLength = hash.length();
2112                         final byte[] hashBytes = new byte[hashLength / 2];
2113                         for (int i = 0; i < hashLength; i += 2){
2114                             hashBytes[i/2] = (byte) ((Character.digit(hash.charAt(i), 16) << 4)
2115                                     + Character.digit(hash.charAt(i + 1), 16));
2116                         }
2117                         pkg.restrictUpdateHash = hashBytes;
2118                     }
2119                 }
2120 
2121                 XmlUtils.skipCurrentTag(parser);
2122 
2123             } else if (RIGID_PARSER) {
2124                 outError[0] = "Bad element under <manifest>: "
2125                     + parser.getName();
2126                 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2127                 return null;
2128 
2129             } else {
2130                 Slog.w(TAG, "Unknown element under <manifest>: " + parser.getName()
2131                         + " at " + mArchiveSourcePath + " "
2132                         + parser.getPositionDescription());
2133                 XmlUtils.skipCurrentTag(parser);
2134                 continue;
2135             }
2136         }
2137 
2138         if (!foundApp && pkg.instrumentation.size() == 0) {
2139             outError[0] = "<manifest> does not contain an <application> or <instrumentation>";
2140             mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_EMPTY;
2141         }
2142 
2143         final int NP = PackageParser.NEW_PERMISSIONS.length;
2144         StringBuilder implicitPerms = null;
2145         for (int ip=0; ip<NP; ip++) {
2146             final PackageParser.NewPermissionInfo npi
2147                     = PackageParser.NEW_PERMISSIONS[ip];
2148             if (pkg.applicationInfo.targetSdkVersion >= npi.sdkVersion) {
2149                 break;
2150             }
2151             if (!pkg.requestedPermissions.contains(npi.name)) {
2152                 if (implicitPerms == null) {
2153                     implicitPerms = new StringBuilder(128);
2154                     implicitPerms.append(pkg.packageName);
2155                     implicitPerms.append(": compat added ");
2156                 } else {
2157                     implicitPerms.append(' ');
2158                 }
2159                 implicitPerms.append(npi.name);
2160                 pkg.requestedPermissions.add(npi.name);
2161             }
2162         }
2163         if (implicitPerms != null) {
2164             Slog.i(TAG, implicitPerms.toString());
2165         }
2166 
2167         final int NS = PackageParser.SPLIT_PERMISSIONS.length;
2168         for (int is=0; is<NS; is++) {
2169             final PackageParser.SplitPermissionInfo spi
2170                     = PackageParser.SPLIT_PERMISSIONS[is];
2171             if (pkg.applicationInfo.targetSdkVersion >= spi.targetSdk
2172                     || !pkg.requestedPermissions.contains(spi.rootPerm)) {
2173                 continue;
2174             }
2175             for (int in=0; in<spi.newPerms.length; in++) {
2176                 final String perm = spi.newPerms[in];
2177                 if (!pkg.requestedPermissions.contains(perm)) {
2178                     pkg.requestedPermissions.add(perm);
2179                 }
2180             }
2181         }
2182 
2183         if (supportsSmallScreens < 0 || (supportsSmallScreens > 0
2184                 && pkg.applicationInfo.targetSdkVersion
2185                         >= android.os.Build.VERSION_CODES.DONUT)) {
2186             pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS;
2187         }
2188         if (supportsNormalScreens != 0) {
2189             pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS;
2190         }
2191         if (supportsLargeScreens < 0 || (supportsLargeScreens > 0
2192                 && pkg.applicationInfo.targetSdkVersion
2193                         >= android.os.Build.VERSION_CODES.DONUT)) {
2194             pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS;
2195         }
2196         if (supportsXLargeScreens < 0 || (supportsXLargeScreens > 0
2197                 && pkg.applicationInfo.targetSdkVersion
2198                         >= android.os.Build.VERSION_CODES.GINGERBREAD)) {
2199             pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS;
2200         }
2201         if (resizeable < 0 || (resizeable > 0
2202                 && pkg.applicationInfo.targetSdkVersion
2203                         >= android.os.Build.VERSION_CODES.DONUT)) {
2204             pkg.applicationInfo.flags |= ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS;
2205         }
2206         if (anyDensity < 0 || (anyDensity > 0
2207                 && pkg.applicationInfo.targetSdkVersion
2208                         >= android.os.Build.VERSION_CODES.DONUT)) {
2209             pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES;
2210         }
2211 
2212         return pkg;
2213     }
2214 
parseUsesFeature(Resources res, AttributeSet attrs)2215     private FeatureInfo parseUsesFeature(Resources res, AttributeSet attrs) {
2216         FeatureInfo fi = new FeatureInfo();
2217         TypedArray sa = res.obtainAttributes(attrs,
2218                 com.android.internal.R.styleable.AndroidManifestUsesFeature);
2219         // Note: don't allow this value to be a reference to a resource
2220         // that may change.
2221         fi.name = sa.getNonResourceString(
2222                 com.android.internal.R.styleable.AndroidManifestUsesFeature_name);
2223         fi.version = sa.getInt(
2224                 com.android.internal.R.styleable.AndroidManifestUsesFeature_version, 0);
2225         if (fi.name == null) {
2226             fi.reqGlEsVersion = sa.getInt(
2227                         com.android.internal.R.styleable.AndroidManifestUsesFeature_glEsVersion,
2228                         FeatureInfo.GL_ES_VERSION_UNDEFINED);
2229         }
2230         if (sa.getBoolean(
2231                 com.android.internal.R.styleable.AndroidManifestUsesFeature_required, true)) {
2232             fi.flags |= FeatureInfo.FLAG_REQUIRED;
2233         }
2234         sa.recycle();
2235         return fi;
2236     }
2237 
parseUsesPermission(Package pkg, Resources res, XmlResourceParser parser)2238     private boolean parseUsesPermission(Package pkg, Resources res, XmlResourceParser parser)
2239             throws XmlPullParserException, IOException {
2240         TypedArray sa = res.obtainAttributes(parser,
2241                 com.android.internal.R.styleable.AndroidManifestUsesPermission);
2242 
2243         // Note: don't allow this value to be a reference to a resource
2244         // that may change.
2245         String name = sa.getNonResourceString(
2246                 com.android.internal.R.styleable.AndroidManifestUsesPermission_name);
2247 
2248         int maxSdkVersion = 0;
2249         TypedValue val = sa.peekValue(
2250                 com.android.internal.R.styleable.AndroidManifestUsesPermission_maxSdkVersion);
2251         if (val != null) {
2252             if (val.type >= TypedValue.TYPE_FIRST_INT && val.type <= TypedValue.TYPE_LAST_INT) {
2253                 maxSdkVersion = val.data;
2254             }
2255         }
2256 
2257         sa.recycle();
2258 
2259         if ((maxSdkVersion == 0) || (maxSdkVersion >= Build.VERSION.RESOURCES_SDK_INT)) {
2260             if (name != null) {
2261                 int index = pkg.requestedPermissions.indexOf(name);
2262                 if (index == -1) {
2263                     pkg.requestedPermissions.add(name.intern());
2264                 } else {
2265                     Slog.w(TAG, "Ignoring duplicate uses-permissions/uses-permissions-sdk-m: "
2266                             + name + " in package: " + pkg.packageName + " at: "
2267                             + parser.getPositionDescription());
2268                 }
2269             }
2270         }
2271 
2272         XmlUtils.skipCurrentTag(parser);
2273         return true;
2274     }
2275 
buildClassName(String pkg, CharSequence clsSeq, String[] outError)2276     private static String buildClassName(String pkg, CharSequence clsSeq,
2277             String[] outError) {
2278         if (clsSeq == null || clsSeq.length() <= 0) {
2279             outError[0] = "Empty class name in package " + pkg;
2280             return null;
2281         }
2282         String cls = clsSeq.toString();
2283         char c = cls.charAt(0);
2284         if (c == '.') {
2285             return (pkg + cls).intern();
2286         }
2287         if (cls.indexOf('.') < 0) {
2288             StringBuilder b = new StringBuilder(pkg);
2289             b.append('.');
2290             b.append(cls);
2291             return b.toString().intern();
2292         }
2293         return cls.intern();
2294     }
2295 
buildCompoundName(String pkg, CharSequence procSeq, String type, String[] outError)2296     private static String buildCompoundName(String pkg,
2297             CharSequence procSeq, String type, String[] outError) {
2298         String proc = procSeq.toString();
2299         char c = proc.charAt(0);
2300         if (pkg != null && c == ':') {
2301             if (proc.length() < 2) {
2302                 outError[0] = "Bad " + type + " name " + proc + " in package " + pkg
2303                         + ": must be at least two characters";
2304                 return null;
2305             }
2306             String subName = proc.substring(1);
2307             String nameError = validateName(subName, false, false);
2308             if (nameError != null) {
2309                 outError[0] = "Invalid " + type + " name " + proc + " in package "
2310                         + pkg + ": " + nameError;
2311                 return null;
2312             }
2313             return (pkg + proc).intern();
2314         }
2315         String nameError = validateName(proc, true, false);
2316         if (nameError != null && !"system".equals(proc)) {
2317             outError[0] = "Invalid " + type + " name " + proc + " in package "
2318                     + pkg + ": " + nameError;
2319             return null;
2320         }
2321         return proc.intern();
2322     }
2323 
buildProcessName(String pkg, String defProc, CharSequence procSeq, int flags, String[] separateProcesses, String[] outError)2324     private static String buildProcessName(String pkg, String defProc,
2325             CharSequence procSeq, int flags, String[] separateProcesses,
2326             String[] outError) {
2327         if ((flags&PARSE_IGNORE_PROCESSES) != 0 && !"system".equals(procSeq)) {
2328             return defProc != null ? defProc : pkg;
2329         }
2330         if (separateProcesses != null) {
2331             for (int i=separateProcesses.length-1; i>=0; i--) {
2332                 String sp = separateProcesses[i];
2333                 if (sp.equals(pkg) || sp.equals(defProc) || sp.equals(procSeq)) {
2334                     return pkg;
2335                 }
2336             }
2337         }
2338         if (procSeq == null || procSeq.length() <= 0) {
2339             return defProc;
2340         }
2341         return buildCompoundName(pkg, procSeq, "process", outError);
2342     }
2343 
buildTaskAffinityName(String pkg, String defProc, CharSequence procSeq, String[] outError)2344     private static String buildTaskAffinityName(String pkg, String defProc,
2345             CharSequence procSeq, String[] outError) {
2346         if (procSeq == null) {
2347             return defProc;
2348         }
2349         if (procSeq.length() <= 0) {
2350             return null;
2351         }
2352         return buildCompoundName(pkg, procSeq, "taskAffinity", outError);
2353     }
2354 
parseKeySets(Package owner, Resources res, XmlResourceParser parser, String[] outError)2355     private boolean parseKeySets(Package owner, Resources res,
2356             XmlResourceParser parser, String[] outError)
2357             throws XmlPullParserException, IOException {
2358         // we've encountered the 'key-sets' tag
2359         // all the keys and keysets that we want must be defined here
2360         // so we're going to iterate over the parser and pull out the things we want
2361         int outerDepth = parser.getDepth();
2362         int currentKeySetDepth = -1;
2363         int type;
2364         String currentKeySet = null;
2365         ArrayMap<String, PublicKey> publicKeys = new ArrayMap<String, PublicKey>();
2366         ArraySet<String> upgradeKeySets = new ArraySet<String>();
2367         ArrayMap<String, ArraySet<String>> definedKeySets = new ArrayMap<String, ArraySet<String>>();
2368         ArraySet<String> improperKeySets = new ArraySet<String>();
2369         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
2370                 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
2371             if (type == XmlPullParser.END_TAG) {
2372                 if (parser.getDepth() == currentKeySetDepth) {
2373                     currentKeySet = null;
2374                     currentKeySetDepth = -1;
2375                 }
2376                 continue;
2377             }
2378             String tagName = parser.getName();
2379             if (tagName.equals("key-set")) {
2380                 if (currentKeySet != null) {
2381                     outError[0] = "Improperly nested 'key-set' tag at "
2382                             + parser.getPositionDescription();
2383                     mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2384                     return false;
2385                 }
2386                 final TypedArray sa = res.obtainAttributes(parser,
2387                         com.android.internal.R.styleable.AndroidManifestKeySet);
2388                 final String keysetName = sa.getNonResourceString(
2389                     com.android.internal.R.styleable.AndroidManifestKeySet_name);
2390                 definedKeySets.put(keysetName, new ArraySet<String>());
2391                 currentKeySet = keysetName;
2392                 currentKeySetDepth = parser.getDepth();
2393                 sa.recycle();
2394             } else if (tagName.equals("public-key")) {
2395                 if (currentKeySet == null) {
2396                     outError[0] = "Improperly nested 'key-set' tag at "
2397                             + parser.getPositionDescription();
2398                     mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2399                     return false;
2400                 }
2401                 final TypedArray sa = res.obtainAttributes(parser,
2402                         com.android.internal.R.styleable.AndroidManifestPublicKey);
2403                 final String publicKeyName = sa.getNonResourceString(
2404                         com.android.internal.R.styleable.AndroidManifestPublicKey_name);
2405                 final String encodedKey = sa.getNonResourceString(
2406                             com.android.internal.R.styleable.AndroidManifestPublicKey_value);
2407                 if (encodedKey == null && publicKeys.get(publicKeyName) == null) {
2408                     outError[0] = "'public-key' " + publicKeyName + " must define a public-key value"
2409                             + " on first use at " + parser.getPositionDescription();
2410                     mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2411                     sa.recycle();
2412                     return false;
2413                 } else if (encodedKey != null) {
2414                     PublicKey currentKey = parsePublicKey(encodedKey);
2415                     if (currentKey == null) {
2416                         Slog.w(TAG, "No recognized valid key in 'public-key' tag at "
2417                                 + parser.getPositionDescription() + " key-set " + currentKeySet
2418                                 + " will not be added to the package's defined key-sets.");
2419                         sa.recycle();
2420                         improperKeySets.add(currentKeySet);
2421                         XmlUtils.skipCurrentTag(parser);
2422                         continue;
2423                     }
2424                     if (publicKeys.get(publicKeyName) == null
2425                             || publicKeys.get(publicKeyName).equals(currentKey)) {
2426 
2427                         /* public-key first definition, or matches old definition */
2428                         publicKeys.put(publicKeyName, currentKey);
2429                     } else {
2430                         outError[0] = "Value of 'public-key' " + publicKeyName
2431                                + " conflicts with previously defined value at "
2432                                + parser.getPositionDescription();
2433                         mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2434                         sa.recycle();
2435                         return false;
2436                     }
2437                 }
2438                 definedKeySets.get(currentKeySet).add(publicKeyName);
2439                 sa.recycle();
2440                 XmlUtils.skipCurrentTag(parser);
2441             } else if (tagName.equals("upgrade-key-set")) {
2442                 final TypedArray sa = res.obtainAttributes(parser,
2443                         com.android.internal.R.styleable.AndroidManifestUpgradeKeySet);
2444                 String name = sa.getNonResourceString(
2445                         com.android.internal.R.styleable.AndroidManifestUpgradeKeySet_name);
2446                 upgradeKeySets.add(name);
2447                 sa.recycle();
2448                 XmlUtils.skipCurrentTag(parser);
2449             } else if (RIGID_PARSER) {
2450                 outError[0] = "Bad element under <key-sets>: " + parser.getName()
2451                         + " at " + mArchiveSourcePath + " "
2452                         + parser.getPositionDescription();
2453                 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2454                 return false;
2455             } else {
2456                 Slog.w(TAG, "Unknown element under <key-sets>: " + parser.getName()
2457                         + " at " + mArchiveSourcePath + " "
2458                         + parser.getPositionDescription());
2459                 XmlUtils.skipCurrentTag(parser);
2460                 continue;
2461             }
2462         }
2463         Set<String> publicKeyNames = publicKeys.keySet();
2464         if (publicKeyNames.removeAll(definedKeySets.keySet())) {
2465             outError[0] = "Package" + owner.packageName + " AndroidManifext.xml "
2466                     + "'key-set' and 'public-key' names must be distinct.";
2467             mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2468             return false;
2469         }
2470         owner.mKeySetMapping = new ArrayMap<String, ArraySet<PublicKey>>();
2471         for (ArrayMap.Entry<String, ArraySet<String>> e: definedKeySets.entrySet()) {
2472             final String keySetName = e.getKey();
2473             if (e.getValue().size() == 0) {
2474                 Slog.w(TAG, "Package" + owner.packageName + " AndroidManifext.xml "
2475                         + "'key-set' " + keySetName + " has no valid associated 'public-key'."
2476                         + " Not including in package's defined key-sets.");
2477                 continue;
2478             } else if (improperKeySets.contains(keySetName)) {
2479                 Slog.w(TAG, "Package" + owner.packageName + " AndroidManifext.xml "
2480                         + "'key-set' " + keySetName + " contained improper 'public-key'"
2481                         + " tags. Not including in package's defined key-sets.");
2482                 continue;
2483             }
2484             owner.mKeySetMapping.put(keySetName, new ArraySet<PublicKey>());
2485             for (String s : e.getValue()) {
2486                 owner.mKeySetMapping.get(keySetName).add(publicKeys.get(s));
2487             }
2488         }
2489         if (owner.mKeySetMapping.keySet().containsAll(upgradeKeySets)) {
2490             owner.mUpgradeKeySets = upgradeKeySets;
2491         } else {
2492             outError[0] ="Package" + owner.packageName + " AndroidManifext.xml "
2493                    + "does not define all 'upgrade-key-set's .";
2494             mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2495             return false;
2496         }
2497         return true;
2498     }
2499 
parsePermissionGroup(Package owner, int flags, Resources res, XmlResourceParser parser, String[] outError)2500     private PermissionGroup parsePermissionGroup(Package owner, int flags, Resources res,
2501             XmlResourceParser parser, String[] outError)
2502             throws XmlPullParserException, IOException {
2503         PermissionGroup perm = new PermissionGroup(owner);
2504 
2505         TypedArray sa = res.obtainAttributes(parser,
2506                 com.android.internal.R.styleable.AndroidManifestPermissionGroup);
2507         if (!parsePackageItemInfo(owner, perm.info, outError,
2508                 "<permission-group>", sa, true /*nameRequired*/,
2509                 com.android.internal.R.styleable.AndroidManifestPermissionGroup_name,
2510                 com.android.internal.R.styleable.AndroidManifestPermissionGroup_label,
2511                 com.android.internal.R.styleable.AndroidManifestPermissionGroup_icon,
2512                 com.android.internal.R.styleable.AndroidManifestPermissionGroup_roundIcon,
2513                 com.android.internal.R.styleable.AndroidManifestPermissionGroup_logo,
2514                 com.android.internal.R.styleable.AndroidManifestPermissionGroup_banner)) {
2515             sa.recycle();
2516             mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2517             return null;
2518         }
2519 
2520         perm.info.descriptionRes = sa.getResourceId(
2521                 com.android.internal.R.styleable.AndroidManifestPermissionGroup_description,
2522                 0);
2523         perm.info.flags = sa.getInt(
2524                 com.android.internal.R.styleable.AndroidManifestPermissionGroup_permissionGroupFlags, 0);
2525         perm.info.priority = sa.getInt(
2526                 com.android.internal.R.styleable.AndroidManifestPermissionGroup_priority, 0);
2527         if (perm.info.priority > 0 && (flags&PARSE_IS_SYSTEM) == 0) {
2528             perm.info.priority = 0;
2529         }
2530 
2531         sa.recycle();
2532 
2533         if (!parseAllMetaData(res, parser, "<permission-group>", perm,
2534                 outError)) {
2535             mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2536             return null;
2537         }
2538 
2539         owner.permissionGroups.add(perm);
2540 
2541         return perm;
2542     }
2543 
parsePermission(Package owner, Resources res, XmlResourceParser parser, String[] outError)2544     private Permission parsePermission(Package owner, Resources res,
2545             XmlResourceParser parser, String[] outError)
2546         throws XmlPullParserException, IOException {
2547         Permission perm = new Permission(owner);
2548 
2549         TypedArray sa = res.obtainAttributes(parser,
2550                 com.android.internal.R.styleable.AndroidManifestPermission);
2551 
2552         if (!parsePackageItemInfo(owner, perm.info, outError,
2553                 "<permission>", sa, true /*nameRequired*/,
2554                 com.android.internal.R.styleable.AndroidManifestPermission_name,
2555                 com.android.internal.R.styleable.AndroidManifestPermission_label,
2556                 com.android.internal.R.styleable.AndroidManifestPermission_icon,
2557                 com.android.internal.R.styleable.AndroidManifestPermission_roundIcon,
2558                 com.android.internal.R.styleable.AndroidManifestPermission_logo,
2559                 com.android.internal.R.styleable.AndroidManifestPermission_banner)) {
2560             sa.recycle();
2561             mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2562             return null;
2563         }
2564 
2565         // Note: don't allow this value to be a reference to a resource
2566         // that may change.
2567         perm.info.group = sa.getNonResourceString(
2568                 com.android.internal.R.styleable.AndroidManifestPermission_permissionGroup);
2569         if (perm.info.group != null) {
2570             perm.info.group = perm.info.group.intern();
2571         }
2572 
2573         perm.info.descriptionRes = sa.getResourceId(
2574                 com.android.internal.R.styleable.AndroidManifestPermission_description,
2575                 0);
2576 
2577         perm.info.protectionLevel = sa.getInt(
2578                 com.android.internal.R.styleable.AndroidManifestPermission_protectionLevel,
2579                 PermissionInfo.PROTECTION_NORMAL);
2580 
2581         perm.info.flags = sa.getInt(
2582                 com.android.internal.R.styleable.AndroidManifestPermission_permissionFlags, 0);
2583 
2584         sa.recycle();
2585 
2586         if (perm.info.protectionLevel == -1) {
2587             outError[0] = "<permission> does not specify protectionLevel";
2588             mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2589             return null;
2590         }
2591 
2592         perm.info.protectionLevel = PermissionInfo.fixProtectionLevel(perm.info.protectionLevel);
2593 
2594         if ((perm.info.protectionLevel&PermissionInfo.PROTECTION_MASK_FLAGS) != 0) {
2595             if ((perm.info.protectionLevel&PermissionInfo.PROTECTION_MASK_BASE) !=
2596                     PermissionInfo.PROTECTION_SIGNATURE) {
2597                 outError[0] = "<permission>  protectionLevel specifies a flag but is "
2598                         + "not based on signature type";
2599                 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2600                 return null;
2601             }
2602         }
2603 
2604         if (!parseAllMetaData(res, parser, "<permission>", perm, outError)) {
2605             mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2606             return null;
2607         }
2608 
2609         owner.permissions.add(perm);
2610 
2611         return perm;
2612     }
2613 
parsePermissionTree(Package owner, Resources res, XmlResourceParser parser, String[] outError)2614     private Permission parsePermissionTree(Package owner, Resources res,
2615             XmlResourceParser parser, String[] outError)
2616         throws XmlPullParserException, IOException {
2617         Permission perm = new Permission(owner);
2618 
2619         TypedArray sa = res.obtainAttributes(parser,
2620                 com.android.internal.R.styleable.AndroidManifestPermissionTree);
2621 
2622         if (!parsePackageItemInfo(owner, perm.info, outError,
2623                 "<permission-tree>", sa, true /*nameRequired*/,
2624                 com.android.internal.R.styleable.AndroidManifestPermissionTree_name,
2625                 com.android.internal.R.styleable.AndroidManifestPermissionTree_label,
2626                 com.android.internal.R.styleable.AndroidManifestPermissionTree_icon,
2627                 com.android.internal.R.styleable.AndroidManifestPermissionTree_roundIcon,
2628                 com.android.internal.R.styleable.AndroidManifestPermissionTree_logo,
2629                 com.android.internal.R.styleable.AndroidManifestPermissionTree_banner)) {
2630             sa.recycle();
2631             mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2632             return null;
2633         }
2634 
2635         sa.recycle();
2636 
2637         int index = perm.info.name.indexOf('.');
2638         if (index > 0) {
2639             index = perm.info.name.indexOf('.', index+1);
2640         }
2641         if (index < 0) {
2642             outError[0] = "<permission-tree> name has less than three segments: "
2643                 + perm.info.name;
2644             mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2645             return null;
2646         }
2647 
2648         perm.info.descriptionRes = 0;
2649         perm.info.protectionLevel = PermissionInfo.PROTECTION_NORMAL;
2650         perm.tree = true;
2651 
2652         if (!parseAllMetaData(res, parser, "<permission-tree>", perm,
2653                 outError)) {
2654             mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2655             return null;
2656         }
2657 
2658         owner.permissions.add(perm);
2659 
2660         return perm;
2661     }
2662 
parseInstrumentation(Package owner, Resources res, XmlResourceParser parser, String[] outError)2663     private Instrumentation parseInstrumentation(Package owner, Resources res,
2664             XmlResourceParser parser, String[] outError)
2665             throws XmlPullParserException, IOException {
2666         TypedArray sa = res.obtainAttributes(parser,
2667                 com.android.internal.R.styleable.AndroidManifestInstrumentation);
2668 
2669         if (mParseInstrumentationArgs == null) {
2670             mParseInstrumentationArgs = new ParsePackageItemArgs(owner, outError,
2671                     com.android.internal.R.styleable.AndroidManifestInstrumentation_name,
2672                     com.android.internal.R.styleable.AndroidManifestInstrumentation_label,
2673                     com.android.internal.R.styleable.AndroidManifestInstrumentation_icon,
2674                     com.android.internal.R.styleable.AndroidManifestInstrumentation_roundIcon,
2675                     com.android.internal.R.styleable.AndroidManifestInstrumentation_logo,
2676                     com.android.internal.R.styleable.AndroidManifestInstrumentation_banner);
2677             mParseInstrumentationArgs.tag = "<instrumentation>";
2678         }
2679 
2680         mParseInstrumentationArgs.sa = sa;
2681 
2682         Instrumentation a = new Instrumentation(mParseInstrumentationArgs,
2683                 new InstrumentationInfo());
2684         if (outError[0] != null) {
2685             sa.recycle();
2686             mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2687             return null;
2688         }
2689 
2690         String str;
2691         // Note: don't allow this value to be a reference to a resource
2692         // that may change.
2693         str = sa.getNonResourceString(
2694                 com.android.internal.R.styleable.AndroidManifestInstrumentation_targetPackage);
2695         a.info.targetPackage = str != null ? str.intern() : null;
2696 
2697         a.info.handleProfiling = sa.getBoolean(
2698                 com.android.internal.R.styleable.AndroidManifestInstrumentation_handleProfiling,
2699                 false);
2700 
2701         a.info.functionalTest = sa.getBoolean(
2702                 com.android.internal.R.styleable.AndroidManifestInstrumentation_functionalTest,
2703                 false);
2704 
2705         sa.recycle();
2706 
2707         if (a.info.targetPackage == null) {
2708             outError[0] = "<instrumentation> does not specify targetPackage";
2709             mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2710             return null;
2711         }
2712 
2713         if (!parseAllMetaData(res, parser, "<instrumentation>", a,
2714                 outError)) {
2715             mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2716             return null;
2717         }
2718 
2719         owner.instrumentation.add(a);
2720 
2721         return a;
2722     }
2723 
2724     /**
2725      * Parse the {@code application} XML tree at the current parse location in a
2726      * <em>base APK</em> manifest.
2727      * <p>
2728      * When adding new features, carefully consider if they should also be
2729      * supported by split APKs.
2730      */
parseBaseApplication(Package owner, Resources res, XmlResourceParser parser, int flags, String[] outError)2731     private boolean parseBaseApplication(Package owner, Resources res,
2732             XmlResourceParser parser, int flags, String[] outError)
2733         throws XmlPullParserException, IOException {
2734         final ApplicationInfo ai = owner.applicationInfo;
2735         final String pkgName = owner.applicationInfo.packageName;
2736 
2737         TypedArray sa = res.obtainAttributes(parser,
2738                 com.android.internal.R.styleable.AndroidManifestApplication);
2739 
2740         if (!parsePackageItemInfo(owner, ai, outError,
2741                 "<application>", sa, false /*nameRequired*/,
2742                 com.android.internal.R.styleable.AndroidManifestApplication_name,
2743                 com.android.internal.R.styleable.AndroidManifestApplication_label,
2744                 com.android.internal.R.styleable.AndroidManifestApplication_icon,
2745                 com.android.internal.R.styleable.AndroidManifestApplication_roundIcon,
2746                 com.android.internal.R.styleable.AndroidManifestApplication_logo,
2747                 com.android.internal.R.styleable.AndroidManifestApplication_banner)) {
2748             sa.recycle();
2749             mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2750             return false;
2751         }
2752 
2753         if (ai.name != null) {
2754             ai.className = ai.name;
2755         }
2756 
2757         String manageSpaceActivity = sa.getNonConfigurationString(
2758                 com.android.internal.R.styleable.AndroidManifestApplication_manageSpaceActivity,
2759                 Configuration.NATIVE_CONFIG_VERSION);
2760         if (manageSpaceActivity != null) {
2761             ai.manageSpaceActivityName = buildClassName(pkgName, manageSpaceActivity,
2762                     outError);
2763         }
2764 
2765         boolean allowBackup = sa.getBoolean(
2766                 com.android.internal.R.styleable.AndroidManifestApplication_allowBackup, true);
2767         if (allowBackup) {
2768             ai.flags |= ApplicationInfo.FLAG_ALLOW_BACKUP;
2769 
2770             // backupAgent, killAfterRestore, fullBackupContent, backupInForeground,
2771             // and restoreAnyVersion are only relevant if backup is possible for the
2772             // given application.
2773             String backupAgent = sa.getNonConfigurationString(
2774                     com.android.internal.R.styleable.AndroidManifestApplication_backupAgent,
2775                     Configuration.NATIVE_CONFIG_VERSION);
2776             if (backupAgent != null) {
2777                 ai.backupAgentName = buildClassName(pkgName, backupAgent, outError);
2778                 if (DEBUG_BACKUP) {
2779                     Slog.v(TAG, "android:backupAgent = " + ai.backupAgentName
2780                             + " from " + pkgName + "+" + backupAgent);
2781                 }
2782 
2783                 if (sa.getBoolean(
2784                         com.android.internal.R.styleable.AndroidManifestApplication_killAfterRestore,
2785                         true)) {
2786                     ai.flags |= ApplicationInfo.FLAG_KILL_AFTER_RESTORE;
2787                 }
2788                 if (sa.getBoolean(
2789                         com.android.internal.R.styleable.AndroidManifestApplication_restoreAnyVersion,
2790                         false)) {
2791                     ai.flags |= ApplicationInfo.FLAG_RESTORE_ANY_VERSION;
2792                 }
2793                 if (sa.getBoolean(
2794                         com.android.internal.R.styleable.AndroidManifestApplication_fullBackupOnly,
2795                         false)) {
2796                     ai.flags |= ApplicationInfo.FLAG_FULL_BACKUP_ONLY;
2797                 }
2798                 if (sa.getBoolean(
2799                         com.android.internal.R.styleable.AndroidManifestApplication_backupInForeground,
2800                         false)) {
2801                     ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_BACKUP_IN_FOREGROUND;
2802                 }
2803             }
2804 
2805             TypedValue v = sa.peekValue(
2806                     com.android.internal.R.styleable.AndroidManifestApplication_fullBackupContent);
2807             if (v != null && (ai.fullBackupContent = v.resourceId) == 0) {
2808                 if (DEBUG_BACKUP) {
2809                     Slog.v(TAG, "fullBackupContent specified as boolean=" +
2810                             (v.data == 0 ? "false" : "true"));
2811                 }
2812                 // "false" => -1, "true" => 0
2813                 ai.fullBackupContent = (v.data == 0 ? -1 : 0);
2814             }
2815             if (DEBUG_BACKUP) {
2816                 Slog.v(TAG, "fullBackupContent=" + ai.fullBackupContent + " for " + pkgName);
2817             }
2818         }
2819 
2820         ai.theme = sa.getResourceId(
2821                 com.android.internal.R.styleable.AndroidManifestApplication_theme, 0);
2822         ai.descriptionRes = sa.getResourceId(
2823                 com.android.internal.R.styleable.AndroidManifestApplication_description, 0);
2824 
2825         if ((flags&PARSE_IS_SYSTEM) != 0) {
2826             if (sa.getBoolean(
2827                     com.android.internal.R.styleable.AndroidManifestApplication_persistent,
2828                     false)) {
2829                 ai.flags |= ApplicationInfo.FLAG_PERSISTENT;
2830             }
2831         }
2832 
2833         if (sa.getBoolean(
2834                 com.android.internal.R.styleable.AndroidManifestApplication_requiredForAllUsers,
2835                 false)) {
2836             owner.mRequiredForAllUsers = true;
2837         }
2838 
2839         String restrictedAccountType = sa.getString(com.android.internal.R.styleable
2840                 .AndroidManifestApplication_restrictedAccountType);
2841         if (restrictedAccountType != null && restrictedAccountType.length() > 0) {
2842             owner.mRestrictedAccountType = restrictedAccountType;
2843         }
2844 
2845         String requiredAccountType = sa.getString(com.android.internal.R.styleable
2846                 .AndroidManifestApplication_requiredAccountType);
2847         if (requiredAccountType != null && requiredAccountType.length() > 0) {
2848             owner.mRequiredAccountType = requiredAccountType;
2849         }
2850 
2851         if (sa.getBoolean(
2852                 com.android.internal.R.styleable.AndroidManifestApplication_debuggable,
2853                 false)) {
2854             ai.flags |= ApplicationInfo.FLAG_DEBUGGABLE;
2855         }
2856 
2857         if (sa.getBoolean(
2858                 com.android.internal.R.styleable.AndroidManifestApplication_vmSafeMode,
2859                 false)) {
2860             ai.flags |= ApplicationInfo.FLAG_VM_SAFE_MODE;
2861         }
2862 
2863         owner.baseHardwareAccelerated = sa.getBoolean(
2864                 com.android.internal.R.styleable.AndroidManifestApplication_hardwareAccelerated,
2865                 owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.ICE_CREAM_SANDWICH);
2866         if (owner.baseHardwareAccelerated) {
2867             ai.flags |= ApplicationInfo.FLAG_HARDWARE_ACCELERATED;
2868         }
2869 
2870         if (sa.getBoolean(
2871                 com.android.internal.R.styleable.AndroidManifestApplication_hasCode,
2872                 true)) {
2873             ai.flags |= ApplicationInfo.FLAG_HAS_CODE;
2874         }
2875 
2876         if (sa.getBoolean(
2877                 com.android.internal.R.styleable.AndroidManifestApplication_allowTaskReparenting,
2878                 false)) {
2879             ai.flags |= ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING;
2880         }
2881 
2882         if (sa.getBoolean(
2883                 com.android.internal.R.styleable.AndroidManifestApplication_allowClearUserData,
2884                 true)) {
2885             ai.flags |= ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA;
2886         }
2887 
2888         // The parent package controls installation, hence specify test only installs.
2889         if (owner.parentPackage == null) {
2890             if (sa.getBoolean(
2891                     com.android.internal.R.styleable.AndroidManifestApplication_testOnly,
2892                     false)) {
2893                 ai.flags |= ApplicationInfo.FLAG_TEST_ONLY;
2894             }
2895         }
2896 
2897         if (sa.getBoolean(
2898                 com.android.internal.R.styleable.AndroidManifestApplication_largeHeap,
2899                 false)) {
2900             ai.flags |= ApplicationInfo.FLAG_LARGE_HEAP;
2901         }
2902 
2903         if (sa.getBoolean(
2904                 com.android.internal.R.styleable.AndroidManifestApplication_usesCleartextTraffic,
2905                 true)) {
2906             ai.flags |= ApplicationInfo.FLAG_USES_CLEARTEXT_TRAFFIC;
2907         }
2908 
2909         if (sa.getBoolean(
2910                 com.android.internal.R.styleable.AndroidManifestApplication_supportsRtl,
2911                 false /* default is no RTL support*/)) {
2912             ai.flags |= ApplicationInfo.FLAG_SUPPORTS_RTL;
2913         }
2914 
2915         if (sa.getBoolean(
2916                 com.android.internal.R.styleable.AndroidManifestApplication_multiArch,
2917                 false)) {
2918             ai.flags |= ApplicationInfo.FLAG_MULTIARCH;
2919         }
2920 
2921         if (sa.getBoolean(
2922                 com.android.internal.R.styleable.AndroidManifestApplication_extractNativeLibs,
2923                 true)) {
2924             ai.flags |= ApplicationInfo.FLAG_EXTRACT_NATIVE_LIBS;
2925         }
2926 
2927         if (sa.getBoolean(
2928                 R.styleable.AndroidManifestApplication_defaultToDeviceProtectedStorage,
2929                 false)) {
2930             ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE;
2931         }
2932         if (sa.getBoolean(
2933                 R.styleable.AndroidManifestApplication_directBootAware,
2934                 false)) {
2935             ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE;
2936         }
2937 
2938         if (sa.getBoolean(R.styleable.AndroidManifestApplication_resizeableActivity,
2939                 owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.N)) {
2940             ai.privateFlags |= PRIVATE_FLAG_RESIZEABLE_ACTIVITIES;
2941         }
2942 
2943         ai.networkSecurityConfigRes = sa.getResourceId(
2944                 com.android.internal.R.styleable.AndroidManifestApplication_networkSecurityConfig,
2945                 0);
2946 
2947         String str;
2948         str = sa.getNonConfigurationString(
2949                 com.android.internal.R.styleable.AndroidManifestApplication_permission, 0);
2950         ai.permission = (str != null && str.length() > 0) ? str.intern() : null;
2951 
2952         if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.FROYO) {
2953             str = sa.getNonConfigurationString(
2954                     com.android.internal.R.styleable.AndroidManifestApplication_taskAffinity,
2955                     Configuration.NATIVE_CONFIG_VERSION);
2956         } else {
2957             // Some older apps have been seen to use a resource reference
2958             // here that on older builds was ignored (with a warning).  We
2959             // need to continue to do this for them so they don't break.
2960             str = sa.getNonResourceString(
2961                     com.android.internal.R.styleable.AndroidManifestApplication_taskAffinity);
2962         }
2963         ai.taskAffinity = buildTaskAffinityName(ai.packageName, ai.packageName,
2964                 str, outError);
2965 
2966         if (outError[0] == null) {
2967             CharSequence pname;
2968             if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.FROYO) {
2969                 pname = sa.getNonConfigurationString(
2970                         com.android.internal.R.styleable.AndroidManifestApplication_process,
2971                         Configuration.NATIVE_CONFIG_VERSION);
2972             } else {
2973                 // Some older apps have been seen to use a resource reference
2974                 // here that on older builds was ignored (with a warning).  We
2975                 // need to continue to do this for them so they don't break.
2976                 pname = sa.getNonResourceString(
2977                         com.android.internal.R.styleable.AndroidManifestApplication_process);
2978             }
2979             ai.processName = buildProcessName(ai.packageName, null, pname,
2980                     flags, mSeparateProcesses, outError);
2981 
2982             ai.enabled = sa.getBoolean(
2983                     com.android.internal.R.styleable.AndroidManifestApplication_enabled, true);
2984 
2985             if (sa.getBoolean(
2986                     com.android.internal.R.styleable.AndroidManifestApplication_isGame, false)) {
2987                 ai.flags |= ApplicationInfo.FLAG_IS_GAME;
2988             }
2989 
2990             if (false) {
2991                 if (sa.getBoolean(
2992                         com.android.internal.R.styleable.AndroidManifestApplication_cantSaveState,
2993                         false)) {
2994                     ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE;
2995 
2996                     // A heavy-weight application can not be in a custom process.
2997                     // We can do direct compare because we intern all strings.
2998                     if (ai.processName != null && ai.processName != ai.packageName) {
2999                         outError[0] = "cantSaveState applications can not use custom processes";
3000                     }
3001                 }
3002             }
3003         }
3004 
3005         ai.uiOptions = sa.getInt(
3006                 com.android.internal.R.styleable.AndroidManifestApplication_uiOptions, 0);
3007 
3008         sa.recycle();
3009 
3010         if (outError[0] != null) {
3011             mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3012             return false;
3013         }
3014 
3015         final int innerDepth = parser.getDepth();
3016         int type;
3017         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
3018                 && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
3019             if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
3020                 continue;
3021             }
3022 
3023             String tagName = parser.getName();
3024             if (tagName.equals("activity")) {
3025                 Activity a = parseActivity(owner, res, parser, flags, outError, false,
3026                         owner.baseHardwareAccelerated);
3027                 if (a == null) {
3028                     mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3029                     return false;
3030                 }
3031 
3032                 owner.activities.add(a);
3033 
3034             } else if (tagName.equals("receiver")) {
3035                 Activity a = parseActivity(owner, res, parser, flags, outError, true, false);
3036                 if (a == null) {
3037                     mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3038                     return false;
3039                 }
3040 
3041                 owner.receivers.add(a);
3042 
3043             } else if (tagName.equals("service")) {
3044                 Service s = parseService(owner, res, parser, flags, outError);
3045                 if (s == null) {
3046                     mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3047                     return false;
3048                 }
3049 
3050                 owner.services.add(s);
3051 
3052             } else if (tagName.equals("provider")) {
3053                 Provider p = parseProvider(owner, res, parser, flags, outError);
3054                 if (p == null) {
3055                     mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3056                     return false;
3057                 }
3058 
3059                 owner.providers.add(p);
3060 
3061             } else if (tagName.equals("activity-alias")) {
3062                 Activity a = parseActivityAlias(owner, res, parser, flags, outError);
3063                 if (a == null) {
3064                     mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3065                     return false;
3066                 }
3067 
3068                 owner.activities.add(a);
3069 
3070             } else if (parser.getName().equals("meta-data")) {
3071                 // note: application meta-data is stored off to the side, so it can
3072                 // remain null in the primary copy (we like to avoid extra copies because
3073                 // it can be large)
3074                 if ((owner.mAppMetaData = parseMetaData(res, parser, owner.mAppMetaData,
3075                         outError)) == null) {
3076                     mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3077                     return false;
3078                 }
3079 
3080             } else if (tagName.equals("library")) {
3081                 sa = res.obtainAttributes(parser,
3082                         com.android.internal.R.styleable.AndroidManifestLibrary);
3083 
3084                 // Note: don't allow this value to be a reference to a resource
3085                 // that may change.
3086                 String lname = sa.getNonResourceString(
3087                         com.android.internal.R.styleable.AndroidManifestLibrary_name);
3088 
3089                 sa.recycle();
3090 
3091                 if (lname != null) {
3092                     lname = lname.intern();
3093                     if (!ArrayUtils.contains(owner.libraryNames, lname)) {
3094                         owner.libraryNames = ArrayUtils.add(owner.libraryNames, lname);
3095                     }
3096                 }
3097 
3098                 XmlUtils.skipCurrentTag(parser);
3099 
3100             } else if (tagName.equals("uses-library")) {
3101                 sa = res.obtainAttributes(parser,
3102                         com.android.internal.R.styleable.AndroidManifestUsesLibrary);
3103 
3104                 // Note: don't allow this value to be a reference to a resource
3105                 // that may change.
3106                 String lname = sa.getNonResourceString(
3107                         com.android.internal.R.styleable.AndroidManifestUsesLibrary_name);
3108                 boolean req = sa.getBoolean(
3109                         com.android.internal.R.styleable.AndroidManifestUsesLibrary_required,
3110                         true);
3111 
3112                 sa.recycle();
3113 
3114                 if (lname != null) {
3115                     lname = lname.intern();
3116                     if (req) {
3117                         owner.usesLibraries = ArrayUtils.add(owner.usesLibraries, lname);
3118                     } else {
3119                         owner.usesOptionalLibraries = ArrayUtils.add(
3120                                 owner.usesOptionalLibraries, lname);
3121                     }
3122                 }
3123 
3124                 XmlUtils.skipCurrentTag(parser);
3125 
3126             } else if (tagName.equals("uses-package")) {
3127                 // Dependencies for app installers; we don't currently try to
3128                 // enforce this.
3129                 XmlUtils.skipCurrentTag(parser);
3130 
3131             } else {
3132                 if (!RIGID_PARSER) {
3133                     Slog.w(TAG, "Unknown element under <application>: " + tagName
3134                             + " at " + mArchiveSourcePath + " "
3135                             + parser.getPositionDescription());
3136                     XmlUtils.skipCurrentTag(parser);
3137                     continue;
3138                 } else {
3139                     outError[0] = "Bad element under <application>: " + tagName;
3140                     mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3141                     return false;
3142                 }
3143             }
3144         }
3145 
3146         modifySharedLibrariesForBackwardCompatibility(owner);
3147 
3148         if (hasDomainURLs(owner)) {
3149             owner.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS;
3150         } else {
3151             owner.applicationInfo.privateFlags &= ~ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS;
3152         }
3153 
3154         return true;
3155     }
3156 
modifySharedLibrariesForBackwardCompatibility(Package owner)3157     private static void modifySharedLibrariesForBackwardCompatibility(Package owner) {
3158         // "org.apache.http.legacy" is now a part of the boot classpath so it doesn't need
3159         // to be an explicit dependency.
3160         //
3161         // A future change will remove this library from the boot classpath, at which point
3162         // all apps that target SDK 21 and earlier will have it automatically added to their
3163         // dependency lists.
3164         owner.usesLibraries = ArrayUtils.remove(owner.usesLibraries, "org.apache.http.legacy");
3165         owner.usesOptionalLibraries = ArrayUtils.remove(owner.usesOptionalLibraries,
3166                 "org.apache.http.legacy");
3167     }
3168 
3169     /**
3170      * Check if one of the IntentFilter as both actions DEFAULT / VIEW and a HTTP/HTTPS data URI
3171      */
hasDomainURLs(Package pkg)3172     private static boolean hasDomainURLs(Package pkg) {
3173         if (pkg == null || pkg.activities == null) return false;
3174         final ArrayList<Activity> activities = pkg.activities;
3175         final int countActivities = activities.size();
3176         for (int n=0; n<countActivities; n++) {
3177             Activity activity = activities.get(n);
3178             ArrayList<ActivityIntentInfo> filters = activity.intents;
3179             if (filters == null) continue;
3180             final int countFilters = filters.size();
3181             for (int m=0; m<countFilters; m++) {
3182                 ActivityIntentInfo aii = filters.get(m);
3183                 if (!aii.hasAction(Intent.ACTION_VIEW)) continue;
3184                 if (!aii.hasAction(Intent.ACTION_DEFAULT)) continue;
3185                 if (aii.hasDataScheme(IntentFilter.SCHEME_HTTP) ||
3186                         aii.hasDataScheme(IntentFilter.SCHEME_HTTPS)) {
3187                     return true;
3188                 }
3189             }
3190         }
3191         return false;
3192     }
3193 
3194     /**
3195      * Parse the {@code application} XML tree at the current parse location in a
3196      * <em>split APK</em> manifest.
3197      * <p>
3198      * Note that split APKs have many more restrictions on what they're capable
3199      * of doing, so many valid features of a base APK have been carefully
3200      * omitted here.
3201      */
parseSplitApplication(Package owner, Resources res, XmlResourceParser parser, int flags, int splitIndex, String[] outError)3202     private boolean parseSplitApplication(Package owner, Resources res, XmlResourceParser parser,
3203             int flags, int splitIndex, String[] outError)
3204             throws XmlPullParserException, IOException {
3205         TypedArray sa = res.obtainAttributes(parser,
3206                 com.android.internal.R.styleable.AndroidManifestApplication);
3207 
3208         if (sa.getBoolean(
3209                 com.android.internal.R.styleable.AndroidManifestApplication_hasCode, true)) {
3210             owner.splitFlags[splitIndex] |= ApplicationInfo.FLAG_HAS_CODE;
3211         }
3212 
3213         final int innerDepth = parser.getDepth();
3214         int type;
3215         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
3216                 && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
3217             if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
3218                 continue;
3219             }
3220 
3221             String tagName = parser.getName();
3222             if (tagName.equals("activity")) {
3223                 Activity a = parseActivity(owner, res, parser, flags, outError, false,
3224                         owner.baseHardwareAccelerated);
3225                 if (a == null) {
3226                     mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3227                     return false;
3228                 }
3229 
3230                 owner.activities.add(a);
3231 
3232             } else if (tagName.equals("receiver")) {
3233                 Activity a = parseActivity(owner, res, parser, flags, outError, true, false);
3234                 if (a == null) {
3235                     mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3236                     return false;
3237                 }
3238 
3239                 owner.receivers.add(a);
3240 
3241             } else if (tagName.equals("service")) {
3242                 Service s = parseService(owner, res, parser, flags, outError);
3243                 if (s == null) {
3244                     mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3245                     return false;
3246                 }
3247 
3248                 owner.services.add(s);
3249 
3250             } else if (tagName.equals("provider")) {
3251                 Provider p = parseProvider(owner, res, parser, flags, outError);
3252                 if (p == null) {
3253                     mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3254                     return false;
3255                 }
3256 
3257                 owner.providers.add(p);
3258 
3259             } else if (tagName.equals("activity-alias")) {
3260                 Activity a = parseActivityAlias(owner, res, parser, flags, outError);
3261                 if (a == null) {
3262                     mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3263                     return false;
3264                 }
3265 
3266                 owner.activities.add(a);
3267 
3268             } else if (parser.getName().equals("meta-data")) {
3269                 // note: application meta-data is stored off to the side, so it can
3270                 // remain null in the primary copy (we like to avoid extra copies because
3271                 // it can be large)
3272                 if ((owner.mAppMetaData = parseMetaData(res, parser, owner.mAppMetaData,
3273                         outError)) == null) {
3274                     mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3275                     return false;
3276                 }
3277 
3278             } else if (tagName.equals("uses-library")) {
3279                 sa = res.obtainAttributes(parser,
3280                         com.android.internal.R.styleable.AndroidManifestUsesLibrary);
3281 
3282                 // Note: don't allow this value to be a reference to a resource
3283                 // that may change.
3284                 String lname = sa.getNonResourceString(
3285                         com.android.internal.R.styleable.AndroidManifestUsesLibrary_name);
3286                 boolean req = sa.getBoolean(
3287                         com.android.internal.R.styleable.AndroidManifestUsesLibrary_required,
3288                         true);
3289 
3290                 sa.recycle();
3291 
3292                 if (lname != null) {
3293                     lname = lname.intern();
3294                     if (req) {
3295                         // Upgrade to treat as stronger constraint
3296                         owner.usesLibraries = ArrayUtils.add(owner.usesLibraries, lname);
3297                         owner.usesOptionalLibraries = ArrayUtils.remove(
3298                                 owner.usesOptionalLibraries, lname);
3299                     } else {
3300                         // Ignore if someone already defined as required
3301                         if (!ArrayUtils.contains(owner.usesLibraries, lname)) {
3302                             owner.usesOptionalLibraries = ArrayUtils.add(
3303                                     owner.usesOptionalLibraries, lname);
3304                         }
3305                     }
3306                 }
3307 
3308                 XmlUtils.skipCurrentTag(parser);
3309 
3310             } else if (tagName.equals("uses-package")) {
3311                 // Dependencies for app installers; we don't currently try to
3312                 // enforce this.
3313                 XmlUtils.skipCurrentTag(parser);
3314 
3315             } else {
3316                 if (!RIGID_PARSER) {
3317                     Slog.w(TAG, "Unknown element under <application>: " + tagName
3318                             + " at " + mArchiveSourcePath + " "
3319                             + parser.getPositionDescription());
3320                     XmlUtils.skipCurrentTag(parser);
3321                     continue;
3322                 } else {
3323                     outError[0] = "Bad element under <application>: " + tagName;
3324                     mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
3325                     return false;
3326                 }
3327             }
3328         }
3329 
3330         return true;
3331     }
3332 
parsePackageItemInfo(Package owner, PackageItemInfo outInfo, String[] outError, String tag, TypedArray sa, boolean nameRequired, int nameRes, int labelRes, int iconRes, int roundIconRes, int logoRes, int bannerRes)3333     private static boolean parsePackageItemInfo(Package owner, PackageItemInfo outInfo,
3334             String[] outError, String tag, TypedArray sa, boolean nameRequired,
3335             int nameRes, int labelRes, int iconRes, int roundIconRes, int logoRes, int bannerRes) {
3336         String name = sa.getNonConfigurationString(nameRes, 0);
3337         if (name == null) {
3338             if (nameRequired) {
3339                 outError[0] = tag + " does not specify android:name";
3340                 return false;
3341             }
3342         } else {
3343             outInfo.name
3344                 = buildClassName(owner.applicationInfo.packageName, name, outError);
3345             if (outInfo.name == null) {
3346                 return false;
3347             }
3348         }
3349 
3350         final boolean useRoundIcon =
3351                 Resources.getSystem().getBoolean(com.android.internal.R.bool.config_useRoundIcon);
3352         int roundIconVal = useRoundIcon ? sa.getResourceId(roundIconRes, 0) : 0;
3353         if (roundIconVal != 0) {
3354             outInfo.icon = roundIconVal;
3355             outInfo.nonLocalizedLabel = null;
3356         } else {
3357             int iconVal = sa.getResourceId(iconRes, 0);
3358             if (iconVal != 0) {
3359                 outInfo.icon = iconVal;
3360                 outInfo.nonLocalizedLabel = null;
3361             }
3362         }
3363 
3364         int logoVal = sa.getResourceId(logoRes, 0);
3365         if (logoVal != 0) {
3366             outInfo.logo = logoVal;
3367         }
3368 
3369         int bannerVal = sa.getResourceId(bannerRes, 0);
3370         if (bannerVal != 0) {
3371             outInfo.banner = bannerVal;
3372         }
3373 
3374         TypedValue v = sa.peekValue(labelRes);
3375         if (v != null && (outInfo.labelRes=v.resourceId) == 0) {
3376             outInfo.nonLocalizedLabel = v.coerceToString();
3377         }
3378 
3379         outInfo.packageName = owner.packageName;
3380 
3381         return true;
3382     }
3383 
parseActivity(Package owner, Resources res, XmlResourceParser parser, int flags, String[] outError, boolean receiver, boolean hardwareAccelerated)3384     private Activity parseActivity(Package owner, Resources res,
3385             XmlResourceParser parser, int flags, String[] outError,
3386             boolean receiver, boolean hardwareAccelerated)
3387             throws XmlPullParserException, IOException {
3388         TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestActivity);
3389 
3390         if (mParseActivityArgs == null) {
3391             mParseActivityArgs = new ParseComponentArgs(owner, outError,
3392                     R.styleable.AndroidManifestActivity_name,
3393                     R.styleable.AndroidManifestActivity_label,
3394                     R.styleable.AndroidManifestActivity_icon,
3395                     R.styleable.AndroidManifestActivity_roundIcon,
3396                     R.styleable.AndroidManifestActivity_logo,
3397                     R.styleable.AndroidManifestActivity_banner,
3398                     mSeparateProcesses,
3399                     R.styleable.AndroidManifestActivity_process,
3400                     R.styleable.AndroidManifestActivity_description,
3401                     R.styleable.AndroidManifestActivity_enabled);
3402         }
3403 
3404         mParseActivityArgs.tag = receiver ? "<receiver>" : "<activity>";
3405         mParseActivityArgs.sa = sa;
3406         mParseActivityArgs.flags = flags;
3407 
3408         Activity a = new Activity(mParseActivityArgs, new ActivityInfo());
3409         if (outError[0] != null) {
3410             sa.recycle();
3411             return null;
3412         }
3413 
3414         boolean setExported = sa.hasValue(R.styleable.AndroidManifestActivity_exported);
3415         if (setExported) {
3416             a.info.exported = sa.getBoolean(R.styleable.AndroidManifestActivity_exported, false);
3417         }
3418 
3419         a.info.theme = sa.getResourceId(R.styleable.AndroidManifestActivity_theme, 0);
3420 
3421         a.info.uiOptions = sa.getInt(R.styleable.AndroidManifestActivity_uiOptions,
3422                 a.info.applicationInfo.uiOptions);
3423 
3424         String parentName = sa.getNonConfigurationString(
3425                 R.styleable.AndroidManifestActivity_parentActivityName,
3426                 Configuration.NATIVE_CONFIG_VERSION);
3427         if (parentName != null) {
3428             String parentClassName = buildClassName(a.info.packageName, parentName, outError);
3429             if (outError[0] == null) {
3430                 a.info.parentActivityName = parentClassName;
3431             } else {
3432                 Log.e(TAG, "Activity " + a.info.name + " specified invalid parentActivityName " +
3433                         parentName);
3434                 outError[0] = null;
3435             }
3436         }
3437 
3438         String str;
3439         str = sa.getNonConfigurationString(R.styleable.AndroidManifestActivity_permission, 0);
3440         if (str == null) {
3441             a.info.permission = owner.applicationInfo.permission;
3442         } else {
3443             a.info.permission = str.length() > 0 ? str.toString().intern() : null;
3444         }
3445 
3446         str = sa.getNonConfigurationString(
3447                 R.styleable.AndroidManifestActivity_taskAffinity,
3448                 Configuration.NATIVE_CONFIG_VERSION);
3449         a.info.taskAffinity = buildTaskAffinityName(owner.applicationInfo.packageName,
3450                 owner.applicationInfo.taskAffinity, str, outError);
3451 
3452         a.info.flags = 0;
3453         if (sa.getBoolean(
3454                 R.styleable.AndroidManifestActivity_multiprocess, false)) {
3455             a.info.flags |= ActivityInfo.FLAG_MULTIPROCESS;
3456         }
3457 
3458         if (sa.getBoolean(R.styleable.AndroidManifestActivity_finishOnTaskLaunch, false)) {
3459             a.info.flags |= ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH;
3460         }
3461 
3462         if (sa.getBoolean(R.styleable.AndroidManifestActivity_clearTaskOnLaunch, false)) {
3463             a.info.flags |= ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH;
3464         }
3465 
3466         if (sa.getBoolean(R.styleable.AndroidManifestActivity_noHistory, false)) {
3467             a.info.flags |= ActivityInfo.FLAG_NO_HISTORY;
3468         }
3469 
3470         if (sa.getBoolean(R.styleable.AndroidManifestActivity_alwaysRetainTaskState, false)) {
3471             a.info.flags |= ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE;
3472         }
3473 
3474         if (sa.getBoolean(R.styleable.AndroidManifestActivity_stateNotNeeded, false)) {
3475             a.info.flags |= ActivityInfo.FLAG_STATE_NOT_NEEDED;
3476         }
3477 
3478         if (sa.getBoolean(R.styleable.AndroidManifestActivity_excludeFromRecents, false)) {
3479             a.info.flags |= ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS;
3480         }
3481 
3482         if (sa.getBoolean(R.styleable.AndroidManifestActivity_allowTaskReparenting,
3483                 (owner.applicationInfo.flags&ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING) != 0)) {
3484             a.info.flags |= ActivityInfo.FLAG_ALLOW_TASK_REPARENTING;
3485         }
3486 
3487         if (sa.getBoolean(R.styleable.AndroidManifestActivity_finishOnCloseSystemDialogs, false)) {
3488             a.info.flags |= ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS;
3489         }
3490 
3491         if (sa.getBoolean(R.styleable.AndroidManifestActivity_showOnLockScreen, false)
3492                 || sa.getBoolean(R.styleable.AndroidManifestActivity_showForAllUsers, false)) {
3493             a.info.flags |= ActivityInfo.FLAG_SHOW_FOR_ALL_USERS;
3494         }
3495 
3496         if (sa.getBoolean(R.styleable.AndroidManifestActivity_immersive, false)) {
3497             a.info.flags |= ActivityInfo.FLAG_IMMERSIVE;
3498         }
3499 
3500         if (sa.getBoolean(R.styleable.AndroidManifestActivity_systemUserOnly, false)) {
3501             a.info.flags |= ActivityInfo.FLAG_SYSTEM_USER_ONLY;
3502         }
3503 
3504         if (!receiver) {
3505             if (sa.getBoolean(R.styleable.AndroidManifestActivity_hardwareAccelerated,
3506                     hardwareAccelerated)) {
3507                 a.info.flags |= ActivityInfo.FLAG_HARDWARE_ACCELERATED;
3508             }
3509 
3510             a.info.launchMode = sa.getInt(
3511                     R.styleable.AndroidManifestActivity_launchMode, ActivityInfo.LAUNCH_MULTIPLE);
3512             a.info.documentLaunchMode = sa.getInt(
3513                     R.styleable.AndroidManifestActivity_documentLaunchMode,
3514                     ActivityInfo.DOCUMENT_LAUNCH_NONE);
3515             a.info.maxRecents = sa.getInt(
3516                     R.styleable.AndroidManifestActivity_maxRecents,
3517                     ActivityManager.getDefaultAppRecentsLimitStatic());
3518             a.info.configChanges = sa.getInt(R.styleable.AndroidManifestActivity_configChanges, 0);
3519             a.info.softInputMode = sa.getInt(
3520                     R.styleable.AndroidManifestActivity_windowSoftInputMode, 0);
3521 
3522             a.info.persistableMode = sa.getInteger(
3523                     R.styleable.AndroidManifestActivity_persistableMode,
3524                     ActivityInfo.PERSIST_ROOT_ONLY);
3525 
3526             if (sa.getBoolean(R.styleable.AndroidManifestActivity_allowEmbedded, false)) {
3527                 a.info.flags |= ActivityInfo.FLAG_ALLOW_EMBEDDED;
3528             }
3529 
3530             if (sa.getBoolean(R.styleable.AndroidManifestActivity_autoRemoveFromRecents, false)) {
3531                 a.info.flags |= ActivityInfo.FLAG_AUTO_REMOVE_FROM_RECENTS;
3532             }
3533 
3534             if (sa.getBoolean(R.styleable.AndroidManifestActivity_relinquishTaskIdentity, false)) {
3535                 a.info.flags |= ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY;
3536             }
3537 
3538             if (sa.getBoolean(R.styleable.AndroidManifestActivity_resumeWhilePausing, false)) {
3539                 a.info.flags |= ActivityInfo.FLAG_RESUME_WHILE_PAUSING;
3540             }
3541 
3542             a.info.screenOrientation = sa.getInt(
3543                     R.styleable.AndroidManifestActivity_screenOrientation,
3544                     SCREEN_ORIENTATION_UNSPECIFIED);
3545 
3546             a.info.resizeMode = RESIZE_MODE_UNRESIZEABLE;
3547             final boolean appDefault = (owner.applicationInfo.privateFlags
3548                     & PRIVATE_FLAG_RESIZEABLE_ACTIVITIES) != 0;
3549             // This flag is used to workaround the issue with ignored resizeableActivity param when
3550             // either targetSdkVersion is not set at all or <uses-sdk> tag is below <application>
3551             // tag in AndroidManifest. If this param was explicitly set to 'false' we need to set
3552             // corresponding resizeMode regardless of targetSdkVersion value at this point in time.
3553             final boolean resizeableSetExplicitly
3554                     = sa.hasValue(R.styleable.AndroidManifestActivity_resizeableActivity);
3555             final boolean resizeable = sa.getBoolean(
3556                     R.styleable.AndroidManifestActivity_resizeableActivity, appDefault);
3557 
3558             if (resizeable) {
3559                 if (sa.getBoolean(R.styleable.AndroidManifestActivity_supportsPictureInPicture,
3560                         false)) {
3561                     a.info.resizeMode = RESIZE_MODE_RESIZEABLE_AND_PIPABLE;
3562                 } else {
3563                     a.info.resizeMode = RESIZE_MODE_RESIZEABLE;
3564                 }
3565             } else if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.N
3566                     || resizeableSetExplicitly) {
3567                 a.info.resizeMode = RESIZE_MODE_UNRESIZEABLE;
3568             } else if (!a.info.isFixedOrientation() && (a.info.flags & FLAG_IMMERSIVE) == 0) {
3569                 a.info.resizeMode = RESIZE_MODE_FORCE_RESIZEABLE;
3570             }
3571 
3572             if (sa.getBoolean(R.styleable.AndroidManifestActivity_alwaysFocusable, false)) {
3573                 a.info.flags |= FLAG_ALWAYS_FOCUSABLE;
3574             }
3575 
3576             a.info.lockTaskLaunchMode =
3577                     sa.getInt(R.styleable.AndroidManifestActivity_lockTaskMode, 0);
3578 
3579             a.info.encryptionAware = a.info.directBootAware = sa.getBoolean(
3580                     R.styleable.AndroidManifestActivity_directBootAware,
3581                     false);
3582 
3583             a.info.requestedVrComponent =
3584                 sa.getString(R.styleable.AndroidManifestActivity_enableVrMode);
3585         } else {
3586             a.info.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
3587             a.info.configChanges = 0;
3588 
3589             if (sa.getBoolean(R.styleable.AndroidManifestActivity_singleUser, false)) {
3590                 a.info.flags |= ActivityInfo.FLAG_SINGLE_USER;
3591                 if (a.info.exported && (flags & PARSE_IS_PRIVILEGED) == 0) {
3592                     Slog.w(TAG, "Activity exported request ignored due to singleUser: "
3593                             + a.className + " at " + mArchiveSourcePath + " "
3594                             + parser.getPositionDescription());
3595                     a.info.exported = false;
3596                     setExported = true;
3597                 }
3598             }
3599 
3600             a.info.encryptionAware = a.info.directBootAware = sa.getBoolean(
3601                     R.styleable.AndroidManifestActivity_directBootAware,
3602                     false);
3603         }
3604 
3605         if (a.info.directBootAware) {
3606             owner.applicationInfo.privateFlags |=
3607                     ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE;
3608         }
3609 
3610         sa.recycle();
3611 
3612         if (receiver && (owner.applicationInfo.privateFlags
3613                 &ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0) {
3614             // A heavy-weight application can not have receives in its main process
3615             // We can do direct compare because we intern all strings.
3616             if (a.info.processName == owner.packageName) {
3617                 outError[0] = "Heavy-weight applications can not have receivers in main process";
3618             }
3619         }
3620 
3621         if (outError[0] != null) {
3622             return null;
3623         }
3624 
3625         int outerDepth = parser.getDepth();
3626         int type;
3627         while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
3628                && (type != XmlPullParser.END_TAG
3629                        || parser.getDepth() > outerDepth)) {
3630             if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
3631                 continue;
3632             }
3633 
3634             if (parser.getName().equals("intent-filter")) {
3635                 ActivityIntentInfo intent = new ActivityIntentInfo(a);
3636                 if (!parseIntent(res, parser, true, true, intent, outError)) {
3637                     return null;
3638                 }
3639                 if (intent.countActions() == 0) {
3640                     Slog.w(TAG, "No actions in intent filter at "
3641                             + mArchiveSourcePath + " "
3642                             + parser.getPositionDescription());
3643                 } else {
3644                     a.intents.add(intent);
3645                 }
3646             } else if (!receiver && parser.getName().equals("preferred")) {
3647                 ActivityIntentInfo intent = new ActivityIntentInfo(a);
3648                 if (!parseIntent(res, parser, false, false, intent, outError)) {
3649                     return null;
3650                 }
3651                 if (intent.countActions() == 0) {
3652                     Slog.w(TAG, "No actions in preferred at "
3653                             + mArchiveSourcePath + " "
3654                             + parser.getPositionDescription());
3655                 } else {
3656                     if (owner.preferredActivityFilters == null) {
3657                         owner.preferredActivityFilters = new ArrayList<ActivityIntentInfo>();
3658                     }
3659                     owner.preferredActivityFilters.add(intent);
3660                 }
3661             } else if (parser.getName().equals("meta-data")) {
3662                 if ((a.metaData = parseMetaData(res, parser, a.metaData,
3663                         outError)) == null) {
3664                     return null;
3665                 }
3666             } else if (!receiver && parser.getName().equals("layout")) {
3667                 parseLayout(res, parser, a);
3668             } else {
3669                 if (!RIGID_PARSER) {
3670                     Slog.w(TAG, "Problem in package " + mArchiveSourcePath + ":");
3671                     if (receiver) {
3672                         Slog.w(TAG, "Unknown element under <receiver>: " + parser.getName()
3673                                 + " at " + mArchiveSourcePath + " "
3674                                 + parser.getPositionDescription());
3675                     } else {
3676                         Slog.w(TAG, "Unknown element under <activity>: " + parser.getName()
3677                                 + " at " + mArchiveSourcePath + " "
3678                                 + parser.getPositionDescription());
3679                     }
3680                     XmlUtils.skipCurrentTag(parser);
3681                     continue;
3682                 } else {
3683                     if (receiver) {
3684                         outError[0] = "Bad element under <receiver>: " + parser.getName();
3685                     } else {
3686                         outError[0] = "Bad element under <activity>: " + parser.getName();
3687                     }
3688                     return null;
3689                 }
3690             }
3691         }
3692 
3693         if (!setExported) {
3694             a.info.exported = a.intents.size() > 0;
3695         }
3696 
3697         return a;
3698     }
3699 
parseLayout(Resources res, AttributeSet attrs, Activity a)3700     private void parseLayout(Resources res, AttributeSet attrs, Activity a) {
3701         TypedArray sw = res.obtainAttributes(attrs,
3702                 com.android.internal.R.styleable.AndroidManifestLayout);
3703         int width = -1;
3704         float widthFraction = -1f;
3705         int height = -1;
3706         float heightFraction = -1f;
3707         final int widthType = sw.getType(
3708                 com.android.internal.R.styleable.AndroidManifestLayout_defaultWidth);
3709         if (widthType == TypedValue.TYPE_FRACTION) {
3710             widthFraction = sw.getFraction(
3711                     com.android.internal.R.styleable.AndroidManifestLayout_defaultWidth,
3712                     1, 1, -1);
3713         } else if (widthType == TypedValue.TYPE_DIMENSION) {
3714             width = sw.getDimensionPixelSize(
3715                     com.android.internal.R.styleable.AndroidManifestLayout_defaultWidth,
3716                     -1);
3717         }
3718         final int heightType = sw.getType(
3719                 com.android.internal.R.styleable.AndroidManifestLayout_defaultHeight);
3720         if (heightType == TypedValue.TYPE_FRACTION) {
3721             heightFraction = sw.getFraction(
3722                     com.android.internal.R.styleable.AndroidManifestLayout_defaultHeight,
3723                     1, 1, -1);
3724         } else if (heightType == TypedValue.TYPE_DIMENSION) {
3725             height = sw.getDimensionPixelSize(
3726                     com.android.internal.R.styleable.AndroidManifestLayout_defaultHeight,
3727                     -1);
3728         }
3729         int gravity = sw.getInt(
3730                 com.android.internal.R.styleable.AndroidManifestLayout_gravity,
3731                 Gravity.CENTER);
3732         int minWidth = sw.getDimensionPixelSize(
3733                 com.android.internal.R.styleable.AndroidManifestLayout_minWidth,
3734                 -1);
3735         int minHeight = sw.getDimensionPixelSize(
3736                 com.android.internal.R.styleable.AndroidManifestLayout_minHeight,
3737                 -1);
3738         sw.recycle();
3739         a.info.windowLayout = new ActivityInfo.WindowLayout(width, widthFraction,
3740                 height, heightFraction, gravity, minWidth, minHeight);
3741     }
3742 
parseActivityAlias(Package owner, Resources res, XmlResourceParser parser, int flags, String[] outError)3743     private Activity parseActivityAlias(Package owner, Resources res,
3744             XmlResourceParser parser, int flags, String[] outError)
3745             throws XmlPullParserException, IOException {
3746         TypedArray sa = res.obtainAttributes(parser,
3747                 com.android.internal.R.styleable.AndroidManifestActivityAlias);
3748 
3749         String targetActivity = sa.getNonConfigurationString(
3750                 com.android.internal.R.styleable.AndroidManifestActivityAlias_targetActivity,
3751                 Configuration.NATIVE_CONFIG_VERSION);
3752         if (targetActivity == null) {
3753             outError[0] = "<activity-alias> does not specify android:targetActivity";
3754             sa.recycle();
3755             return null;
3756         }
3757 
3758         targetActivity = buildClassName(owner.applicationInfo.packageName,
3759                 targetActivity, outError);
3760         if (targetActivity == null) {
3761             sa.recycle();
3762             return null;
3763         }
3764 
3765         if (mParseActivityAliasArgs == null) {
3766             mParseActivityAliasArgs = new ParseComponentArgs(owner, outError,
3767                     com.android.internal.R.styleable.AndroidManifestActivityAlias_name,
3768                     com.android.internal.R.styleable.AndroidManifestActivityAlias_label,
3769                     com.android.internal.R.styleable.AndroidManifestActivityAlias_icon,
3770                     com.android.internal.R.styleable.AndroidManifestActivityAlias_roundIcon,
3771                     com.android.internal.R.styleable.AndroidManifestActivityAlias_logo,
3772                     com.android.internal.R.styleable.AndroidManifestActivityAlias_banner,
3773                     mSeparateProcesses,
3774                     0,
3775                     com.android.internal.R.styleable.AndroidManifestActivityAlias_description,
3776                     com.android.internal.R.styleable.AndroidManifestActivityAlias_enabled);
3777             mParseActivityAliasArgs.tag = "<activity-alias>";
3778         }
3779 
3780         mParseActivityAliasArgs.sa = sa;
3781         mParseActivityAliasArgs.flags = flags;
3782 
3783         Activity target = null;
3784 
3785         final int NA = owner.activities.size();
3786         for (int i=0; i<NA; i++) {
3787             Activity t = owner.activities.get(i);
3788             if (targetActivity.equals(t.info.name)) {
3789                 target = t;
3790                 break;
3791             }
3792         }
3793 
3794         if (target == null) {
3795             outError[0] = "<activity-alias> target activity " + targetActivity
3796                     + " not found in manifest";
3797             sa.recycle();
3798             return null;
3799         }
3800 
3801         ActivityInfo info = new ActivityInfo();
3802         info.targetActivity = targetActivity;
3803         info.configChanges = target.info.configChanges;
3804         info.flags = target.info.flags;
3805         info.icon = target.info.icon;
3806         info.logo = target.info.logo;
3807         info.banner = target.info.banner;
3808         info.labelRes = target.info.labelRes;
3809         info.nonLocalizedLabel = target.info.nonLocalizedLabel;
3810         info.launchMode = target.info.launchMode;
3811         info.lockTaskLaunchMode = target.info.lockTaskLaunchMode;
3812         info.processName = target.info.processName;
3813         if (info.descriptionRes == 0) {
3814             info.descriptionRes = target.info.descriptionRes;
3815         }
3816         info.screenOrientation = target.info.screenOrientation;
3817         info.taskAffinity = target.info.taskAffinity;
3818         info.theme = target.info.theme;
3819         info.softInputMode = target.info.softInputMode;
3820         info.uiOptions = target.info.uiOptions;
3821         info.parentActivityName = target.info.parentActivityName;
3822         info.maxRecents = target.info.maxRecents;
3823         info.windowLayout = target.info.windowLayout;
3824         info.resizeMode = target.info.resizeMode;
3825         info.encryptionAware = info.directBootAware = target.info.directBootAware;
3826 
3827         Activity a = new Activity(mParseActivityAliasArgs, info);
3828         if (outError[0] != null) {
3829             sa.recycle();
3830             return null;
3831         }
3832 
3833         final boolean setExported = sa.hasValue(
3834                 com.android.internal.R.styleable.AndroidManifestActivityAlias_exported);
3835         if (setExported) {
3836             a.info.exported = sa.getBoolean(
3837                     com.android.internal.R.styleable.AndroidManifestActivityAlias_exported, false);
3838         }
3839 
3840         String str;
3841         str = sa.getNonConfigurationString(
3842                 com.android.internal.R.styleable.AndroidManifestActivityAlias_permission, 0);
3843         if (str != null) {
3844             a.info.permission = str.length() > 0 ? str.toString().intern() : null;
3845         }
3846 
3847         String parentName = sa.getNonConfigurationString(
3848                 com.android.internal.R.styleable.AndroidManifestActivityAlias_parentActivityName,
3849                 Configuration.NATIVE_CONFIG_VERSION);
3850         if (parentName != null) {
3851             String parentClassName = buildClassName(a.info.packageName, parentName, outError);
3852             if (outError[0] == null) {
3853                 a.info.parentActivityName = parentClassName;
3854             } else {
3855                 Log.e(TAG, "Activity alias " + a.info.name +
3856                         " specified invalid parentActivityName " + parentName);
3857                 outError[0] = null;
3858             }
3859         }
3860 
3861         sa.recycle();
3862 
3863         if (outError[0] != null) {
3864             return null;
3865         }
3866 
3867         int outerDepth = parser.getDepth();
3868         int type;
3869         while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
3870                && (type != XmlPullParser.END_TAG
3871                        || parser.getDepth() > outerDepth)) {
3872             if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
3873                 continue;
3874             }
3875 
3876             if (parser.getName().equals("intent-filter")) {
3877                 ActivityIntentInfo intent = new ActivityIntentInfo(a);
3878                 if (!parseIntent(res, parser, true, true, intent, outError)) {
3879                     return null;
3880                 }
3881                 if (intent.countActions() == 0) {
3882                     Slog.w(TAG, "No actions in intent filter at "
3883                             + mArchiveSourcePath + " "
3884                             + parser.getPositionDescription());
3885                 } else {
3886                     a.intents.add(intent);
3887                 }
3888             } else if (parser.getName().equals("meta-data")) {
3889                 if ((a.metaData=parseMetaData(res, parser, a.metaData,
3890                         outError)) == null) {
3891                     return null;
3892                 }
3893             } else {
3894                 if (!RIGID_PARSER) {
3895                     Slog.w(TAG, "Unknown element under <activity-alias>: " + parser.getName()
3896                             + " at " + mArchiveSourcePath + " "
3897                             + parser.getPositionDescription());
3898                     XmlUtils.skipCurrentTag(parser);
3899                     continue;
3900                 } else {
3901                     outError[0] = "Bad element under <activity-alias>: " + parser.getName();
3902                     return null;
3903                 }
3904             }
3905         }
3906 
3907         if (!setExported) {
3908             a.info.exported = a.intents.size() > 0;
3909         }
3910 
3911         return a;
3912     }
3913 
parseProvider(Package owner, Resources res, XmlResourceParser parser, int flags, String[] outError)3914     private Provider parseProvider(Package owner, Resources res,
3915             XmlResourceParser parser, int flags, String[] outError)
3916             throws XmlPullParserException, IOException {
3917         TypedArray sa = res.obtainAttributes(parser,
3918                 com.android.internal.R.styleable.AndroidManifestProvider);
3919 
3920         if (mParseProviderArgs == null) {
3921             mParseProviderArgs = new ParseComponentArgs(owner, outError,
3922                     com.android.internal.R.styleable.AndroidManifestProvider_name,
3923                     com.android.internal.R.styleable.AndroidManifestProvider_label,
3924                     com.android.internal.R.styleable.AndroidManifestProvider_icon,
3925                     com.android.internal.R.styleable.AndroidManifestProvider_roundIcon,
3926                     com.android.internal.R.styleable.AndroidManifestProvider_logo,
3927                     com.android.internal.R.styleable.AndroidManifestProvider_banner,
3928                     mSeparateProcesses,
3929                     com.android.internal.R.styleable.AndroidManifestProvider_process,
3930                     com.android.internal.R.styleable.AndroidManifestProvider_description,
3931                     com.android.internal.R.styleable.AndroidManifestProvider_enabled);
3932             mParseProviderArgs.tag = "<provider>";
3933         }
3934 
3935         mParseProviderArgs.sa = sa;
3936         mParseProviderArgs.flags = flags;
3937 
3938         Provider p = new Provider(mParseProviderArgs, new ProviderInfo());
3939         if (outError[0] != null) {
3940             sa.recycle();
3941             return null;
3942         }
3943 
3944         boolean providerExportedDefault = false;
3945 
3946         if (owner.applicationInfo.targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR1) {
3947             // For compatibility, applications targeting API level 16 or lower
3948             // should have their content providers exported by default, unless they
3949             // specify otherwise.
3950             providerExportedDefault = true;
3951         }
3952 
3953         p.info.exported = sa.getBoolean(
3954                 com.android.internal.R.styleable.AndroidManifestProvider_exported,
3955                 providerExportedDefault);
3956 
3957         String cpname = sa.getNonConfigurationString(
3958                 com.android.internal.R.styleable.AndroidManifestProvider_authorities, 0);
3959 
3960         p.info.isSyncable = sa.getBoolean(
3961                 com.android.internal.R.styleable.AndroidManifestProvider_syncable,
3962                 false);
3963 
3964         String permission = sa.getNonConfigurationString(
3965                 com.android.internal.R.styleable.AndroidManifestProvider_permission, 0);
3966         String str = sa.getNonConfigurationString(
3967                 com.android.internal.R.styleable.AndroidManifestProvider_readPermission, 0);
3968         if (str == null) {
3969             str = permission;
3970         }
3971         if (str == null) {
3972             p.info.readPermission = owner.applicationInfo.permission;
3973         } else {
3974             p.info.readPermission =
3975                 str.length() > 0 ? str.toString().intern() : null;
3976         }
3977         str = sa.getNonConfigurationString(
3978                 com.android.internal.R.styleable.AndroidManifestProvider_writePermission, 0);
3979         if (str == null) {
3980             str = permission;
3981         }
3982         if (str == null) {
3983             p.info.writePermission = owner.applicationInfo.permission;
3984         } else {
3985             p.info.writePermission =
3986                 str.length() > 0 ? str.toString().intern() : null;
3987         }
3988 
3989         p.info.grantUriPermissions = sa.getBoolean(
3990                 com.android.internal.R.styleable.AndroidManifestProvider_grantUriPermissions,
3991                 false);
3992 
3993         p.info.multiprocess = sa.getBoolean(
3994                 com.android.internal.R.styleable.AndroidManifestProvider_multiprocess,
3995                 false);
3996 
3997         p.info.initOrder = sa.getInt(
3998                 com.android.internal.R.styleable.AndroidManifestProvider_initOrder,
3999                 0);
4000 
4001         p.info.flags = 0;
4002 
4003         if (sa.getBoolean(
4004                 com.android.internal.R.styleable.AndroidManifestProvider_singleUser,
4005                 false)) {
4006             p.info.flags |= ProviderInfo.FLAG_SINGLE_USER;
4007             if (p.info.exported && (flags & PARSE_IS_PRIVILEGED) == 0) {
4008                 Slog.w(TAG, "Provider exported request ignored due to singleUser: "
4009                         + p.className + " at " + mArchiveSourcePath + " "
4010                         + parser.getPositionDescription());
4011                 p.info.exported = false;
4012             }
4013         }
4014 
4015         p.info.encryptionAware = p.info.directBootAware = sa.getBoolean(
4016                 R.styleable.AndroidManifestProvider_directBootAware,
4017                 false);
4018         if (p.info.directBootAware) {
4019             owner.applicationInfo.privateFlags |=
4020                     ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE;
4021         }
4022 
4023         sa.recycle();
4024 
4025         if ((owner.applicationInfo.privateFlags&ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE)
4026                 != 0) {
4027             // A heavy-weight application can not have providers in its main process
4028             // We can do direct compare because we intern all strings.
4029             if (p.info.processName == owner.packageName) {
4030                 outError[0] = "Heavy-weight applications can not have providers in main process";
4031                 return null;
4032             }
4033         }
4034 
4035         if (cpname == null) {
4036             outError[0] = "<provider> does not include authorities attribute";
4037             return null;
4038         }
4039         if (cpname.length() <= 0) {
4040             outError[0] = "<provider> has empty authorities attribute";
4041             return null;
4042         }
4043         p.info.authority = cpname.intern();
4044 
4045         if (!parseProviderTags(res, parser, p, outError)) {
4046             return null;
4047         }
4048 
4049         return p;
4050     }
4051 
parseProviderTags(Resources res, XmlResourceParser parser, Provider outInfo, String[] outError)4052     private boolean parseProviderTags(Resources res,
4053             XmlResourceParser parser, Provider outInfo, String[] outError)
4054             throws XmlPullParserException, IOException {
4055         int outerDepth = parser.getDepth();
4056         int type;
4057         while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
4058                && (type != XmlPullParser.END_TAG
4059                        || parser.getDepth() > outerDepth)) {
4060             if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
4061                 continue;
4062             }
4063 
4064             if (parser.getName().equals("intent-filter")) {
4065                 ProviderIntentInfo intent = new ProviderIntentInfo(outInfo);
4066                 if (!parseIntent(res, parser, true, false, intent, outError)) {
4067                     return false;
4068                 }
4069                 outInfo.intents.add(intent);
4070 
4071             } else if (parser.getName().equals("meta-data")) {
4072                 if ((outInfo.metaData=parseMetaData(res, parser,
4073                         outInfo.metaData, outError)) == null) {
4074                     return false;
4075                 }
4076 
4077             } else if (parser.getName().equals("grant-uri-permission")) {
4078                 TypedArray sa = res.obtainAttributes(parser,
4079                         com.android.internal.R.styleable.AndroidManifestGrantUriPermission);
4080 
4081                 PatternMatcher pa = null;
4082 
4083                 String str = sa.getNonConfigurationString(
4084                         com.android.internal.R.styleable.AndroidManifestGrantUriPermission_path, 0);
4085                 if (str != null) {
4086                     pa = new PatternMatcher(str, PatternMatcher.PATTERN_LITERAL);
4087                 }
4088 
4089                 str = sa.getNonConfigurationString(
4090                         com.android.internal.R.styleable.AndroidManifestGrantUriPermission_pathPrefix, 0);
4091                 if (str != null) {
4092                     pa = new PatternMatcher(str, PatternMatcher.PATTERN_PREFIX);
4093                 }
4094 
4095                 str = sa.getNonConfigurationString(
4096                         com.android.internal.R.styleable.AndroidManifestGrantUriPermission_pathPattern, 0);
4097                 if (str != null) {
4098                     pa = new PatternMatcher(str, PatternMatcher.PATTERN_SIMPLE_GLOB);
4099                 }
4100 
4101                 sa.recycle();
4102 
4103                 if (pa != null) {
4104                     if (outInfo.info.uriPermissionPatterns == null) {
4105                         outInfo.info.uriPermissionPatterns = new PatternMatcher[1];
4106                         outInfo.info.uriPermissionPatterns[0] = pa;
4107                     } else {
4108                         final int N = outInfo.info.uriPermissionPatterns.length;
4109                         PatternMatcher[] newp = new PatternMatcher[N+1];
4110                         System.arraycopy(outInfo.info.uriPermissionPatterns, 0, newp, 0, N);
4111                         newp[N] = pa;
4112                         outInfo.info.uriPermissionPatterns = newp;
4113                     }
4114                     outInfo.info.grantUriPermissions = true;
4115                 } else {
4116                     if (!RIGID_PARSER) {
4117                         Slog.w(TAG, "Unknown element under <path-permission>: "
4118                                 + parser.getName() + " at " + mArchiveSourcePath + " "
4119                                 + parser.getPositionDescription());
4120                         XmlUtils.skipCurrentTag(parser);
4121                         continue;
4122                     } else {
4123                         outError[0] = "No path, pathPrefix, or pathPattern for <path-permission>";
4124                         return false;
4125                     }
4126                 }
4127                 XmlUtils.skipCurrentTag(parser);
4128 
4129             } else if (parser.getName().equals("path-permission")) {
4130                 TypedArray sa = res.obtainAttributes(parser,
4131                         com.android.internal.R.styleable.AndroidManifestPathPermission);
4132 
4133                 PathPermission pa = null;
4134 
4135                 String permission = sa.getNonConfigurationString(
4136                         com.android.internal.R.styleable.AndroidManifestPathPermission_permission, 0);
4137                 String readPermission = sa.getNonConfigurationString(
4138                         com.android.internal.R.styleable.AndroidManifestPathPermission_readPermission, 0);
4139                 if (readPermission == null) {
4140                     readPermission = permission;
4141                 }
4142                 String writePermission = sa.getNonConfigurationString(
4143                         com.android.internal.R.styleable.AndroidManifestPathPermission_writePermission, 0);
4144                 if (writePermission == null) {
4145                     writePermission = permission;
4146                 }
4147 
4148                 boolean havePerm = false;
4149                 if (readPermission != null) {
4150                     readPermission = readPermission.intern();
4151                     havePerm = true;
4152                 }
4153                 if (writePermission != null) {
4154                     writePermission = writePermission.intern();
4155                     havePerm = true;
4156                 }
4157 
4158                 if (!havePerm) {
4159                     if (!RIGID_PARSER) {
4160                         Slog.w(TAG, "No readPermission or writePermssion for <path-permission>: "
4161                                 + parser.getName() + " at " + mArchiveSourcePath + " "
4162                                 + parser.getPositionDescription());
4163                         XmlUtils.skipCurrentTag(parser);
4164                         continue;
4165                     } else {
4166                         outError[0] = "No readPermission or writePermssion for <path-permission>";
4167                         return false;
4168                     }
4169                 }
4170 
4171                 String path = sa.getNonConfigurationString(
4172                         com.android.internal.R.styleable.AndroidManifestPathPermission_path, 0);
4173                 if (path != null) {
4174                     pa = new PathPermission(path,
4175                             PatternMatcher.PATTERN_LITERAL, readPermission, writePermission);
4176                 }
4177 
4178                 path = sa.getNonConfigurationString(
4179                         com.android.internal.R.styleable.AndroidManifestPathPermission_pathPrefix, 0);
4180                 if (path != null) {
4181                     pa = new PathPermission(path,
4182                             PatternMatcher.PATTERN_PREFIX, readPermission, writePermission);
4183                 }
4184 
4185                 path = sa.getNonConfigurationString(
4186                         com.android.internal.R.styleable.AndroidManifestPathPermission_pathPattern, 0);
4187                 if (path != null) {
4188                     pa = new PathPermission(path,
4189                             PatternMatcher.PATTERN_SIMPLE_GLOB, readPermission, writePermission);
4190                 }
4191 
4192                 sa.recycle();
4193 
4194                 if (pa != null) {
4195                     if (outInfo.info.pathPermissions == null) {
4196                         outInfo.info.pathPermissions = new PathPermission[1];
4197                         outInfo.info.pathPermissions[0] = pa;
4198                     } else {
4199                         final int N = outInfo.info.pathPermissions.length;
4200                         PathPermission[] newp = new PathPermission[N+1];
4201                         System.arraycopy(outInfo.info.pathPermissions, 0, newp, 0, N);
4202                         newp[N] = pa;
4203                         outInfo.info.pathPermissions = newp;
4204                     }
4205                 } else {
4206                     if (!RIGID_PARSER) {
4207                         Slog.w(TAG, "No path, pathPrefix, or pathPattern for <path-permission>: "
4208                                 + parser.getName() + " at " + mArchiveSourcePath + " "
4209                                 + parser.getPositionDescription());
4210                         XmlUtils.skipCurrentTag(parser);
4211                         continue;
4212                     }
4213                     outError[0] = "No path, pathPrefix, or pathPattern for <path-permission>";
4214                     return false;
4215                 }
4216                 XmlUtils.skipCurrentTag(parser);
4217 
4218             } else {
4219                 if (!RIGID_PARSER) {
4220                     Slog.w(TAG, "Unknown element under <provider>: "
4221                             + parser.getName() + " at " + mArchiveSourcePath + " "
4222                             + parser.getPositionDescription());
4223                     XmlUtils.skipCurrentTag(parser);
4224                     continue;
4225                 } else {
4226                     outError[0] = "Bad element under <provider>: " + parser.getName();
4227                     return false;
4228                 }
4229             }
4230         }
4231         return true;
4232     }
4233 
parseService(Package owner, Resources res, XmlResourceParser parser, int flags, String[] outError)4234     private Service parseService(Package owner, Resources res,
4235             XmlResourceParser parser, int flags, String[] outError)
4236             throws XmlPullParserException, IOException {
4237         TypedArray sa = res.obtainAttributes(parser,
4238                 com.android.internal.R.styleable.AndroidManifestService);
4239 
4240         if (mParseServiceArgs == null) {
4241             mParseServiceArgs = new ParseComponentArgs(owner, outError,
4242                     com.android.internal.R.styleable.AndroidManifestService_name,
4243                     com.android.internal.R.styleable.AndroidManifestService_label,
4244                     com.android.internal.R.styleable.AndroidManifestService_icon,
4245                     com.android.internal.R.styleable.AndroidManifestService_roundIcon,
4246                     com.android.internal.R.styleable.AndroidManifestService_logo,
4247                     com.android.internal.R.styleable.AndroidManifestService_banner,
4248                     mSeparateProcesses,
4249                     com.android.internal.R.styleable.AndroidManifestService_process,
4250                     com.android.internal.R.styleable.AndroidManifestService_description,
4251                     com.android.internal.R.styleable.AndroidManifestService_enabled);
4252             mParseServiceArgs.tag = "<service>";
4253         }
4254 
4255         mParseServiceArgs.sa = sa;
4256         mParseServiceArgs.flags = flags;
4257 
4258         Service s = new Service(mParseServiceArgs, new ServiceInfo());
4259         if (outError[0] != null) {
4260             sa.recycle();
4261             return null;
4262         }
4263 
4264         boolean setExported = sa.hasValue(
4265                 com.android.internal.R.styleable.AndroidManifestService_exported);
4266         if (setExported) {
4267             s.info.exported = sa.getBoolean(
4268                     com.android.internal.R.styleable.AndroidManifestService_exported, false);
4269         }
4270 
4271         String str = sa.getNonConfigurationString(
4272                 com.android.internal.R.styleable.AndroidManifestService_permission, 0);
4273         if (str == null) {
4274             s.info.permission = owner.applicationInfo.permission;
4275         } else {
4276             s.info.permission = str.length() > 0 ? str.toString().intern() : null;
4277         }
4278 
4279         s.info.flags = 0;
4280         if (sa.getBoolean(
4281                 com.android.internal.R.styleable.AndroidManifestService_stopWithTask,
4282                 false)) {
4283             s.info.flags |= ServiceInfo.FLAG_STOP_WITH_TASK;
4284         }
4285         if (sa.getBoolean(
4286                 com.android.internal.R.styleable.AndroidManifestService_isolatedProcess,
4287                 false)) {
4288             s.info.flags |= ServiceInfo.FLAG_ISOLATED_PROCESS;
4289         }
4290         if (sa.getBoolean(
4291                 com.android.internal.R.styleable.AndroidManifestService_externalService,
4292                 false)) {
4293             s.info.flags |= ServiceInfo.FLAG_EXTERNAL_SERVICE;
4294         }
4295         if (sa.getBoolean(
4296                 com.android.internal.R.styleable.AndroidManifestService_singleUser,
4297                 false)) {
4298             s.info.flags |= ServiceInfo.FLAG_SINGLE_USER;
4299             if (s.info.exported && (flags & PARSE_IS_PRIVILEGED) == 0) {
4300                 Slog.w(TAG, "Service exported request ignored due to singleUser: "
4301                         + s.className + " at " + mArchiveSourcePath + " "
4302                         + parser.getPositionDescription());
4303                 s.info.exported = false;
4304                 setExported = true;
4305             }
4306         }
4307 
4308         s.info.encryptionAware = s.info.directBootAware = sa.getBoolean(
4309                 R.styleable.AndroidManifestService_directBootAware,
4310                 false);
4311         if (s.info.directBootAware) {
4312             owner.applicationInfo.privateFlags |=
4313                     ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE;
4314         }
4315 
4316         sa.recycle();
4317 
4318         if ((owner.applicationInfo.privateFlags&ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE)
4319                 != 0) {
4320             // A heavy-weight application can not have services in its main process
4321             // We can do direct compare because we intern all strings.
4322             if (s.info.processName == owner.packageName) {
4323                 outError[0] = "Heavy-weight applications can not have services in main process";
4324                 return null;
4325             }
4326         }
4327 
4328         int outerDepth = parser.getDepth();
4329         int type;
4330         while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
4331                && (type != XmlPullParser.END_TAG
4332                        || parser.getDepth() > outerDepth)) {
4333             if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
4334                 continue;
4335             }
4336 
4337             if (parser.getName().equals("intent-filter")) {
4338                 ServiceIntentInfo intent = new ServiceIntentInfo(s);
4339                 if (!parseIntent(res, parser, true, false, intent, outError)) {
4340                     return null;
4341                 }
4342 
4343                 s.intents.add(intent);
4344             } else if (parser.getName().equals("meta-data")) {
4345                 if ((s.metaData=parseMetaData(res, parser, s.metaData,
4346                         outError)) == null) {
4347                     return null;
4348                 }
4349             } else {
4350                 if (!RIGID_PARSER) {
4351                     Slog.w(TAG, "Unknown element under <service>: "
4352                             + parser.getName() + " at " + mArchiveSourcePath + " "
4353                             + parser.getPositionDescription());
4354                     XmlUtils.skipCurrentTag(parser);
4355                     continue;
4356                 } else {
4357                     outError[0] = "Bad element under <service>: " + parser.getName();
4358                     return null;
4359                 }
4360             }
4361         }
4362 
4363         if (!setExported) {
4364             s.info.exported = s.intents.size() > 0;
4365         }
4366 
4367         return s;
4368     }
4369 
parseAllMetaData(Resources res, XmlResourceParser parser, String tag, Component<?> outInfo, String[] outError)4370     private boolean parseAllMetaData(Resources res, XmlResourceParser parser, String tag,
4371             Component<?> outInfo, String[] outError) throws XmlPullParserException, IOException {
4372         int outerDepth = parser.getDepth();
4373         int type;
4374         while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
4375                && (type != XmlPullParser.END_TAG
4376                        || parser.getDepth() > outerDepth)) {
4377             if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
4378                 continue;
4379             }
4380 
4381             if (parser.getName().equals("meta-data")) {
4382                 if ((outInfo.metaData=parseMetaData(res, parser,
4383                         outInfo.metaData, outError)) == null) {
4384                     return false;
4385                 }
4386             } else {
4387                 if (!RIGID_PARSER) {
4388                     Slog.w(TAG, "Unknown element under " + tag + ": "
4389                             + parser.getName() + " at " + mArchiveSourcePath + " "
4390                             + parser.getPositionDescription());
4391                     XmlUtils.skipCurrentTag(parser);
4392                     continue;
4393                 } else {
4394                     outError[0] = "Bad element under " + tag + ": " + parser.getName();
4395                     return false;
4396                 }
4397             }
4398         }
4399         return true;
4400     }
4401 
parseMetaData(Resources res, XmlResourceParser parser, Bundle data, String[] outError)4402     private Bundle parseMetaData(Resources res,
4403             XmlResourceParser parser, Bundle data, String[] outError)
4404             throws XmlPullParserException, IOException {
4405 
4406         TypedArray sa = res.obtainAttributes(parser,
4407                 com.android.internal.R.styleable.AndroidManifestMetaData);
4408 
4409         if (data == null) {
4410             data = new Bundle();
4411         }
4412 
4413         String name = sa.getNonConfigurationString(
4414                 com.android.internal.R.styleable.AndroidManifestMetaData_name, 0);
4415         if (name == null) {
4416             outError[0] = "<meta-data> requires an android:name attribute";
4417             sa.recycle();
4418             return null;
4419         }
4420 
4421         name = name.intern();
4422 
4423         TypedValue v = sa.peekValue(
4424                 com.android.internal.R.styleable.AndroidManifestMetaData_resource);
4425         if (v != null && v.resourceId != 0) {
4426             //Slog.i(TAG, "Meta data ref " + name + ": " + v);
4427             data.putInt(name, v.resourceId);
4428         } else {
4429             v = sa.peekValue(
4430                     com.android.internal.R.styleable.AndroidManifestMetaData_value);
4431             //Slog.i(TAG, "Meta data " + name + ": " + v);
4432             if (v != null) {
4433                 if (v.type == TypedValue.TYPE_STRING) {
4434                     CharSequence cs = v.coerceToString();
4435                     data.putString(name, cs != null ? cs.toString().intern() : null);
4436                 } else if (v.type == TypedValue.TYPE_INT_BOOLEAN) {
4437                     data.putBoolean(name, v.data != 0);
4438                 } else if (v.type >= TypedValue.TYPE_FIRST_INT
4439                         && v.type <= TypedValue.TYPE_LAST_INT) {
4440                     data.putInt(name, v.data);
4441                 } else if (v.type == TypedValue.TYPE_FLOAT) {
4442                     data.putFloat(name, v.getFloat());
4443                 } else {
4444                     if (!RIGID_PARSER) {
4445                         Slog.w(TAG, "<meta-data> only supports string, integer, float, color, boolean, and resource reference types: "
4446                                 + parser.getName() + " at " + mArchiveSourcePath + " "
4447                                 + parser.getPositionDescription());
4448                     } else {
4449                         outError[0] = "<meta-data> only supports string, integer, float, color, boolean, and resource reference types";
4450                         data = null;
4451                     }
4452                 }
4453             } else {
4454                 outError[0] = "<meta-data> requires an android:value or android:resource attribute";
4455                 data = null;
4456             }
4457         }
4458 
4459         sa.recycle();
4460 
4461         XmlUtils.skipCurrentTag(parser);
4462 
4463         return data;
4464     }
4465 
parseVerifier(Resources res, XmlPullParser parser, AttributeSet attrs, int flags)4466     private static VerifierInfo parseVerifier(Resources res, XmlPullParser parser,
4467             AttributeSet attrs, int flags) {
4468         final TypedArray sa = res.obtainAttributes(attrs,
4469                 com.android.internal.R.styleable.AndroidManifestPackageVerifier);
4470 
4471         final String packageName = sa.getNonResourceString(
4472                 com.android.internal.R.styleable.AndroidManifestPackageVerifier_name);
4473 
4474         final String encodedPublicKey = sa.getNonResourceString(
4475                 com.android.internal.R.styleable.AndroidManifestPackageVerifier_publicKey);
4476 
4477         sa.recycle();
4478 
4479         if (packageName == null || packageName.length() == 0) {
4480             Slog.i(TAG, "verifier package name was null; skipping");
4481             return null;
4482         }
4483 
4484         final PublicKey publicKey = parsePublicKey(encodedPublicKey);
4485         if (publicKey == null) {
4486             Slog.i(TAG, "Unable to parse verifier public key for " + packageName);
4487             return null;
4488         }
4489 
4490         return new VerifierInfo(packageName, publicKey);
4491     }
4492 
parsePublicKey(final String encodedPublicKey)4493     public static final PublicKey parsePublicKey(final String encodedPublicKey) {
4494         if (encodedPublicKey == null) {
4495             Slog.w(TAG, "Could not parse null public key");
4496             return null;
4497         }
4498 
4499         EncodedKeySpec keySpec;
4500         try {
4501             final byte[] encoded = Base64.decode(encodedPublicKey, Base64.DEFAULT);
4502             keySpec = new X509EncodedKeySpec(encoded);
4503         } catch (IllegalArgumentException e) {
4504             Slog.w(TAG, "Could not parse verifier public key; invalid Base64");
4505             return null;
4506         }
4507 
4508         /* First try the key as an RSA key. */
4509         try {
4510             final KeyFactory keyFactory = KeyFactory.getInstance("RSA");
4511             return keyFactory.generatePublic(keySpec);
4512         } catch (NoSuchAlgorithmException e) {
4513             Slog.wtf(TAG, "Could not parse public key: RSA KeyFactory not included in build");
4514         } catch (InvalidKeySpecException e) {
4515             // Not a RSA public key.
4516         }
4517 
4518         /* Now try it as a ECDSA key. */
4519         try {
4520             final KeyFactory keyFactory = KeyFactory.getInstance("EC");
4521             return keyFactory.generatePublic(keySpec);
4522         } catch (NoSuchAlgorithmException e) {
4523             Slog.wtf(TAG, "Could not parse public key: EC KeyFactory not included in build");
4524         } catch (InvalidKeySpecException e) {
4525             // Not a ECDSA public key.
4526         }
4527 
4528         /* Now try it as a DSA key. */
4529         try {
4530             final KeyFactory keyFactory = KeyFactory.getInstance("DSA");
4531             return keyFactory.generatePublic(keySpec);
4532         } catch (NoSuchAlgorithmException e) {
4533             Slog.wtf(TAG, "Could not parse public key: DSA KeyFactory not included in build");
4534         } catch (InvalidKeySpecException e) {
4535             // Not a DSA public key.
4536         }
4537 
4538         /* Not a supported key type */
4539         return null;
4540     }
4541 
4542     private static final String ANDROID_RESOURCES
4543             = "http://schemas.android.com/apk/res/android";
4544 
parseIntent(Resources res, XmlResourceParser parser, boolean allowGlobs, boolean allowAutoVerify, IntentInfo outInfo, String[] outError)4545     private boolean parseIntent(Resources res, XmlResourceParser parser,
4546             boolean allowGlobs, boolean allowAutoVerify, IntentInfo outInfo, String[] outError)
4547             throws XmlPullParserException, IOException {
4548 
4549         TypedArray sa = res.obtainAttributes(parser,
4550                 com.android.internal.R.styleable.AndroidManifestIntentFilter);
4551 
4552         int priority = sa.getInt(
4553                 com.android.internal.R.styleable.AndroidManifestIntentFilter_priority, 0);
4554         outInfo.setPriority(priority);
4555 
4556         TypedValue v = sa.peekValue(
4557                 com.android.internal.R.styleable.AndroidManifestIntentFilter_label);
4558         if (v != null && (outInfo.labelRes=v.resourceId) == 0) {
4559             outInfo.nonLocalizedLabel = v.coerceToString();
4560         }
4561 
4562         final boolean useRoundIcon =
4563                 Resources.getSystem().getBoolean(com.android.internal.R.bool.config_useRoundIcon);
4564         int roundIconVal = useRoundIcon ? sa.getResourceId(
4565                 com.android.internal.R.styleable.AndroidManifestIntentFilter_roundIcon, 0) : 0;
4566         if (roundIconVal != 0) {
4567             outInfo.icon = roundIconVal;
4568         } else {
4569             outInfo.icon = sa.getResourceId(
4570                     com.android.internal.R.styleable.AndroidManifestIntentFilter_icon, 0);
4571         }
4572 
4573         outInfo.logo = sa.getResourceId(
4574                 com.android.internal.R.styleable.AndroidManifestIntentFilter_logo, 0);
4575 
4576         outInfo.banner = sa.getResourceId(
4577                 com.android.internal.R.styleable.AndroidManifestIntentFilter_banner, 0);
4578 
4579         if (allowAutoVerify) {
4580             outInfo.setAutoVerify(sa.getBoolean(
4581                     com.android.internal.R.styleable.AndroidManifestIntentFilter_autoVerify,
4582                     false));
4583         }
4584 
4585         sa.recycle();
4586 
4587         int outerDepth = parser.getDepth();
4588         int type;
4589         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
4590                 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
4591             if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
4592                 continue;
4593             }
4594 
4595             String nodeName = parser.getName();
4596             if (nodeName.equals("action")) {
4597                 String value = parser.getAttributeValue(
4598                         ANDROID_RESOURCES, "name");
4599                 if (value == null || value == "") {
4600                     outError[0] = "No value supplied for <android:name>";
4601                     return false;
4602                 }
4603                 XmlUtils.skipCurrentTag(parser);
4604 
4605                 outInfo.addAction(value);
4606             } else if (nodeName.equals("category")) {
4607                 String value = parser.getAttributeValue(
4608                         ANDROID_RESOURCES, "name");
4609                 if (value == null || value == "") {
4610                     outError[0] = "No value supplied for <android:name>";
4611                     return false;
4612                 }
4613                 XmlUtils.skipCurrentTag(parser);
4614 
4615                 outInfo.addCategory(value);
4616 
4617             } else if (nodeName.equals("data")) {
4618                 sa = res.obtainAttributes(parser,
4619                         com.android.internal.R.styleable.AndroidManifestData);
4620 
4621                 String str = sa.getNonConfigurationString(
4622                         com.android.internal.R.styleable.AndroidManifestData_mimeType, 0);
4623                 if (str != null) {
4624                     try {
4625                         outInfo.addDataType(str);
4626                     } catch (IntentFilter.MalformedMimeTypeException e) {
4627                         outError[0] = e.toString();
4628                         sa.recycle();
4629                         return false;
4630                     }
4631                 }
4632 
4633                 str = sa.getNonConfigurationString(
4634                         com.android.internal.R.styleable.AndroidManifestData_scheme, 0);
4635                 if (str != null) {
4636                     outInfo.addDataScheme(str);
4637                 }
4638 
4639                 str = sa.getNonConfigurationString(
4640                         com.android.internal.R.styleable.AndroidManifestData_ssp, 0);
4641                 if (str != null) {
4642                     outInfo.addDataSchemeSpecificPart(str, PatternMatcher.PATTERN_LITERAL);
4643                 }
4644 
4645                 str = sa.getNonConfigurationString(
4646                         com.android.internal.R.styleable.AndroidManifestData_sspPrefix, 0);
4647                 if (str != null) {
4648                     outInfo.addDataSchemeSpecificPart(str, PatternMatcher.PATTERN_PREFIX);
4649                 }
4650 
4651                 str = sa.getNonConfigurationString(
4652                         com.android.internal.R.styleable.AndroidManifestData_sspPattern, 0);
4653                 if (str != null) {
4654                     if (!allowGlobs) {
4655                         outError[0] = "sspPattern not allowed here; ssp must be literal";
4656                         return false;
4657                     }
4658                     outInfo.addDataSchemeSpecificPart(str, PatternMatcher.PATTERN_SIMPLE_GLOB);
4659                 }
4660 
4661                 String host = sa.getNonConfigurationString(
4662                         com.android.internal.R.styleable.AndroidManifestData_host, 0);
4663                 String port = sa.getNonConfigurationString(
4664                         com.android.internal.R.styleable.AndroidManifestData_port, 0);
4665                 if (host != null) {
4666                     outInfo.addDataAuthority(host, port);
4667                 }
4668 
4669                 str = sa.getNonConfigurationString(
4670                         com.android.internal.R.styleable.AndroidManifestData_path, 0);
4671                 if (str != null) {
4672                     outInfo.addDataPath(str, PatternMatcher.PATTERN_LITERAL);
4673                 }
4674 
4675                 str = sa.getNonConfigurationString(
4676                         com.android.internal.R.styleable.AndroidManifestData_pathPrefix, 0);
4677                 if (str != null) {
4678                     outInfo.addDataPath(str, PatternMatcher.PATTERN_PREFIX);
4679                 }
4680 
4681                 str = sa.getNonConfigurationString(
4682                         com.android.internal.R.styleable.AndroidManifestData_pathPattern, 0);
4683                 if (str != null) {
4684                     if (!allowGlobs) {
4685                         outError[0] = "pathPattern not allowed here; path must be literal";
4686                         return false;
4687                     }
4688                     outInfo.addDataPath(str, PatternMatcher.PATTERN_SIMPLE_GLOB);
4689                 }
4690 
4691                 sa.recycle();
4692                 XmlUtils.skipCurrentTag(parser);
4693             } else if (!RIGID_PARSER) {
4694                 Slog.w(TAG, "Unknown element under <intent-filter>: "
4695                         + parser.getName() + " at " + mArchiveSourcePath + " "
4696                         + parser.getPositionDescription());
4697                 XmlUtils.skipCurrentTag(parser);
4698             } else {
4699                 outError[0] = "Bad element under <intent-filter>: " + parser.getName();
4700                 return false;
4701             }
4702         }
4703 
4704         outInfo.hasDefault = outInfo.hasCategory(Intent.CATEGORY_DEFAULT);
4705 
4706         if (DEBUG_PARSER) {
4707             final StringBuilder cats = new StringBuilder("Intent d=");
4708             cats.append(outInfo.hasDefault);
4709             cats.append(", cat=");
4710 
4711             final Iterator<String> it = outInfo.categoriesIterator();
4712             if (it != null) {
4713                 while (it.hasNext()) {
4714                     cats.append(' ');
4715                     cats.append(it.next());
4716                 }
4717             }
4718             Slog.d(TAG, cats.toString());
4719         }
4720 
4721         return true;
4722     }
4723 
4724     /**
4725      * Representation of a full package parsed from APK files on disk. A package
4726      * consists of a single base APK, and zero or more split APKs.
4727      */
4728     public final static class Package {
4729 
4730         public String packageName;
4731 
4732         /** Names of any split APKs, ordered by parsed splitName */
4733         public String[] splitNames;
4734 
4735         // TODO: work towards making these paths invariant
4736 
4737         public String volumeUuid;
4738 
4739         /**
4740          * Path where this package was found on disk. For monolithic packages
4741          * this is path to single base APK file; for cluster packages this is
4742          * path to the cluster directory.
4743          */
4744         public String codePath;
4745 
4746         /** Path of base APK */
4747         public String baseCodePath;
4748         /** Paths of any split APKs, ordered by parsed splitName */
4749         public String[] splitCodePaths;
4750 
4751         /** Revision code of base APK */
4752         public int baseRevisionCode;
4753         /** Revision codes of any split APKs, ordered by parsed splitName */
4754         public int[] splitRevisionCodes;
4755 
4756         /** Flags of any split APKs; ordered by parsed splitName */
4757         public int[] splitFlags;
4758 
4759         /**
4760          * Private flags of any split APKs; ordered by parsed splitName.
4761          *
4762          * {@hide}
4763          */
4764         public int[] splitPrivateFlags;
4765 
4766         public boolean baseHardwareAccelerated;
4767 
4768         // For now we only support one application per package.
4769         public final ApplicationInfo applicationInfo = new ApplicationInfo();
4770 
4771         public final ArrayList<Permission> permissions = new ArrayList<Permission>(0);
4772         public final ArrayList<PermissionGroup> permissionGroups = new ArrayList<PermissionGroup>(0);
4773         public final ArrayList<Activity> activities = new ArrayList<Activity>(0);
4774         public final ArrayList<Activity> receivers = new ArrayList<Activity>(0);
4775         public final ArrayList<Provider> providers = new ArrayList<Provider>(0);
4776         public final ArrayList<Service> services = new ArrayList<Service>(0);
4777         public final ArrayList<Instrumentation> instrumentation = new ArrayList<Instrumentation>(0);
4778 
4779         public final ArrayList<String> requestedPermissions = new ArrayList<String>();
4780 
4781         public ArrayList<String> protectedBroadcasts;
4782 
4783         public Package parentPackage;
4784         public ArrayList<Package> childPackages;
4785 
4786         public ArrayList<String> libraryNames = null;
4787         public ArrayList<String> usesLibraries = null;
4788         public ArrayList<String> usesOptionalLibraries = null;
4789         public String[] usesLibraryFiles = null;
4790 
4791         public ArrayList<ActivityIntentInfo> preferredActivityFilters = null;
4792 
4793         public ArrayList<String> mOriginalPackages = null;
4794         public String mRealPackage = null;
4795         public ArrayList<String> mAdoptPermissions = null;
4796 
4797         // We store the application meta-data independently to avoid multiple unwanted references
4798         public Bundle mAppMetaData = null;
4799 
4800         // The version code declared for this package.
4801         public int mVersionCode;
4802 
4803         // The version name declared for this package.
4804         public String mVersionName;
4805 
4806         // The shared user id that this package wants to use.
4807         public String mSharedUserId;
4808 
4809         // The shared user label that this package wants to use.
4810         public int mSharedUserLabel;
4811 
4812         // Signatures that were read from the package.
4813         public Signature[] mSignatures;
4814         public Certificate[][] mCertificates;
4815 
4816         // For use by package manager service for quick lookup of
4817         // preferred up order.
4818         public int mPreferredOrder = 0;
4819 
4820         // For use by package manager to keep track of when a package was last used.
4821         public long[] mLastPackageUsageTimeInMills =
4822                 new long[PackageManager.NOTIFY_PACKAGE_USE_REASONS_COUNT];
4823 
4824         // // User set enabled state.
4825         // public int mSetEnabled = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
4826         //
4827         // // Whether the package has been stopped.
4828         // public boolean mSetStopped = false;
4829 
4830         // Additional data supplied by callers.
4831         public Object mExtras;
4832 
4833         // Applications hardware preferences
4834         public ArrayList<ConfigurationInfo> configPreferences = null;
4835 
4836         // Applications requested features
4837         public ArrayList<FeatureInfo> reqFeatures = null;
4838 
4839         // Applications requested feature groups
4840         public ArrayList<FeatureGroupInfo> featureGroups = null;
4841 
4842         public int installLocation;
4843 
4844         public boolean coreApp;
4845 
4846         /* An app that's required for all users and cannot be uninstalled for a user */
4847         public boolean mRequiredForAllUsers;
4848 
4849         /* The restricted account authenticator type that is used by this application */
4850         public String mRestrictedAccountType;
4851 
4852         /* The required account type without which this application will not function */
4853         public String mRequiredAccountType;
4854 
4855         public String mOverlayTarget;
4856         public int mOverlayPriority;
4857         public boolean mTrustedOverlay;
4858 
4859         /**
4860          * Data used to feed the KeySetManagerService
4861          */
4862         public ArraySet<PublicKey> mSigningKeys;
4863         public ArraySet<String> mUpgradeKeySets;
4864         public ArrayMap<String, ArraySet<PublicKey>> mKeySetMapping;
4865 
4866         /**
4867          * The install time abi override for this package, if any.
4868          *
4869          * TODO: This seems like a horrible place to put the abiOverride because
4870          * this isn't something the packageParser parsers. However, this fits in with
4871          * the rest of the PackageManager where package scanning randomly pushes
4872          * and prods fields out of {@code this.applicationInfo}.
4873          */
4874         public String cpuAbiOverride;
4875         /**
4876          * The install time abi override to choose 32bit abi's when multiple abi's
4877          * are present. This is only meaningfull for multiarch applications.
4878          * The use32bitAbi attribute is ignored if cpuAbiOverride is also set.
4879          */
4880         public boolean use32bitAbi;
4881 
4882         public byte[] restrictUpdateHash;
4883 
Package(String packageName)4884         public Package(String packageName) {
4885             this.packageName = packageName;
4886             applicationInfo.packageName = packageName;
4887             applicationInfo.uid = -1;
4888         }
4889 
setApplicationVolumeUuid(String volumeUuid)4890         public void setApplicationVolumeUuid(String volumeUuid) {
4891             this.applicationInfo.volumeUuid = volumeUuid;
4892             if (childPackages != null) {
4893                 final int packageCount = childPackages.size();
4894                 for (int i = 0; i < packageCount; i++) {
4895                     childPackages.get(i).applicationInfo.volumeUuid = volumeUuid;
4896                 }
4897             }
4898         }
4899 
setApplicationInfoCodePath(String codePath)4900         public void setApplicationInfoCodePath(String codePath) {
4901             this.applicationInfo.setCodePath(codePath);
4902             if (childPackages != null) {
4903                 final int packageCount = childPackages.size();
4904                 for (int i = 0; i < packageCount; i++) {
4905                     childPackages.get(i).applicationInfo.setCodePath(codePath);
4906                 }
4907             }
4908         }
4909 
setApplicationInfoResourcePath(String resourcePath)4910         public void setApplicationInfoResourcePath(String resourcePath) {
4911             this.applicationInfo.setResourcePath(resourcePath);
4912             if (childPackages != null) {
4913                 final int packageCount = childPackages.size();
4914                 for (int i = 0; i < packageCount; i++) {
4915                     childPackages.get(i).applicationInfo.setResourcePath(resourcePath);
4916                 }
4917             }
4918         }
4919 
setApplicationInfoBaseResourcePath(String resourcePath)4920         public void setApplicationInfoBaseResourcePath(String resourcePath) {
4921             this.applicationInfo.setBaseResourcePath(resourcePath);
4922             if (childPackages != null) {
4923                 final int packageCount = childPackages.size();
4924                 for (int i = 0; i < packageCount; i++) {
4925                     childPackages.get(i).applicationInfo.setBaseResourcePath(resourcePath);
4926                 }
4927             }
4928         }
4929 
setApplicationInfoBaseCodePath(String baseCodePath)4930         public void setApplicationInfoBaseCodePath(String baseCodePath) {
4931             this.applicationInfo.setBaseCodePath(baseCodePath);
4932             if (childPackages != null) {
4933                 final int packageCount = childPackages.size();
4934                 for (int i = 0; i < packageCount; i++) {
4935                     childPackages.get(i).applicationInfo.setBaseCodePath(baseCodePath);
4936                 }
4937             }
4938         }
4939 
hasChildPackage(String packageName)4940         public boolean hasChildPackage(String packageName) {
4941             final int childCount = (childPackages != null) ? childPackages.size() : 0;
4942             for (int i = 0; i < childCount; i++) {
4943                 if (childPackages.get(i).packageName.equals(packageName)) {
4944                     return true;
4945                 }
4946             }
4947             return false;
4948         }
4949 
setApplicationInfoSplitCodePaths(String[] splitCodePaths)4950         public void setApplicationInfoSplitCodePaths(String[] splitCodePaths) {
4951             this.applicationInfo.setSplitCodePaths(splitCodePaths);
4952             // Children have no splits
4953         }
4954 
setApplicationInfoSplitResourcePaths(String[] resroucePaths)4955         public void setApplicationInfoSplitResourcePaths(String[] resroucePaths) {
4956             this.applicationInfo.setSplitResourcePaths(resroucePaths);
4957             // Children have no splits
4958         }
4959 
setSplitCodePaths(String[] codePaths)4960         public void setSplitCodePaths(String[] codePaths) {
4961             this.splitCodePaths = codePaths;
4962         }
4963 
setCodePath(String codePath)4964         public void setCodePath(String codePath) {
4965             this.codePath = codePath;
4966             if (childPackages != null) {
4967                 final int packageCount = childPackages.size();
4968                 for (int i = 0; i < packageCount; i++) {
4969                     childPackages.get(i).codePath = codePath;
4970                 }
4971             }
4972         }
4973 
setBaseCodePath(String baseCodePath)4974         public void setBaseCodePath(String baseCodePath) {
4975             this.baseCodePath = baseCodePath;
4976             if (childPackages != null) {
4977                 final int packageCount = childPackages.size();
4978                 for (int i = 0; i < packageCount; i++) {
4979                     childPackages.get(i).baseCodePath = baseCodePath;
4980                 }
4981             }
4982         }
4983 
setSignatures(Signature[] signatures)4984         public void setSignatures(Signature[] signatures) {
4985             this.mSignatures = signatures;
4986             if (childPackages != null) {
4987                 final int packageCount = childPackages.size();
4988                 for (int i = 0; i < packageCount; i++) {
4989                     childPackages.get(i).mSignatures = signatures;
4990                 }
4991             }
4992         }
4993 
setVolumeUuid(String volumeUuid)4994         public void setVolumeUuid(String volumeUuid) {
4995             this.volumeUuid = volumeUuid;
4996             if (childPackages != null) {
4997                 final int packageCount = childPackages.size();
4998                 for (int i = 0; i < packageCount; i++) {
4999                     childPackages.get(i).volumeUuid = volumeUuid;
5000                 }
5001             }
5002         }
5003 
setApplicationInfoFlags(int mask, int flags)5004         public void setApplicationInfoFlags(int mask, int flags) {
5005             applicationInfo.flags = (applicationInfo.flags & ~mask) | (mask & flags);
5006             if (childPackages != null) {
5007                 final int packageCount = childPackages.size();
5008                 for (int i = 0; i < packageCount; i++) {
5009                     childPackages.get(i).applicationInfo.flags =
5010                             (applicationInfo.flags & ~mask) | (mask & flags);
5011                 }
5012             }
5013         }
5014 
setUse32bitAbi(boolean use32bitAbi)5015         public void setUse32bitAbi(boolean use32bitAbi) {
5016             this.use32bitAbi = use32bitAbi;
5017             if (childPackages != null) {
5018                 final int packageCount = childPackages.size();
5019                 for (int i = 0; i < packageCount; i++) {
5020                     childPackages.get(i).use32bitAbi = use32bitAbi;
5021                 }
5022             }
5023         }
5024 
getAllCodePaths()5025         public List<String> getAllCodePaths() {
5026             ArrayList<String> paths = new ArrayList<>();
5027             paths.add(baseCodePath);
5028             if (!ArrayUtils.isEmpty(splitCodePaths)) {
5029                 Collections.addAll(paths, splitCodePaths);
5030             }
5031             return paths;
5032         }
5033 
5034         /**
5035          * Filtered set of {@link #getAllCodePaths()} that excludes
5036          * resource-only APKs.
5037          */
getAllCodePathsExcludingResourceOnly()5038         public List<String> getAllCodePathsExcludingResourceOnly() {
5039             ArrayList<String> paths = new ArrayList<>();
5040             if ((applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) != 0) {
5041                 paths.add(baseCodePath);
5042             }
5043             if (!ArrayUtils.isEmpty(splitCodePaths)) {
5044                 for (int i = 0; i < splitCodePaths.length; i++) {
5045                     if ((splitFlags[i] & ApplicationInfo.FLAG_HAS_CODE) != 0) {
5046                         paths.add(splitCodePaths[i]);
5047                     }
5048                 }
5049             }
5050             return paths;
5051         }
5052 
setPackageName(String newName)5053         public void setPackageName(String newName) {
5054             packageName = newName;
5055             applicationInfo.packageName = newName;
5056             for (int i=permissions.size()-1; i>=0; i--) {
5057                 permissions.get(i).setPackageName(newName);
5058             }
5059             for (int i=permissionGroups.size()-1; i>=0; i--) {
5060                 permissionGroups.get(i).setPackageName(newName);
5061             }
5062             for (int i=activities.size()-1; i>=0; i--) {
5063                 activities.get(i).setPackageName(newName);
5064             }
5065             for (int i=receivers.size()-1; i>=0; i--) {
5066                 receivers.get(i).setPackageName(newName);
5067             }
5068             for (int i=providers.size()-1; i>=0; i--) {
5069                 providers.get(i).setPackageName(newName);
5070             }
5071             for (int i=services.size()-1; i>=0; i--) {
5072                 services.get(i).setPackageName(newName);
5073             }
5074             for (int i=instrumentation.size()-1; i>=0; i--) {
5075                 instrumentation.get(i).setPackageName(newName);
5076             }
5077         }
5078 
hasComponentClassName(String name)5079         public boolean hasComponentClassName(String name) {
5080             for (int i=activities.size()-1; i>=0; i--) {
5081                 if (name.equals(activities.get(i).className)) {
5082                     return true;
5083                 }
5084             }
5085             for (int i=receivers.size()-1; i>=0; i--) {
5086                 if (name.equals(receivers.get(i).className)) {
5087                     return true;
5088                 }
5089             }
5090             for (int i=providers.size()-1; i>=0; i--) {
5091                 if (name.equals(providers.get(i).className)) {
5092                     return true;
5093                 }
5094             }
5095             for (int i=services.size()-1; i>=0; i--) {
5096                 if (name.equals(services.get(i).className)) {
5097                     return true;
5098                 }
5099             }
5100             for (int i=instrumentation.size()-1; i>=0; i--) {
5101                 if (name.equals(instrumentation.get(i).className)) {
5102                     return true;
5103                 }
5104             }
5105             return false;
5106         }
5107 
5108         /**
5109          * @hide
5110          */
isForwardLocked()5111         public boolean isForwardLocked() {
5112             return applicationInfo.isForwardLocked();
5113         }
5114 
5115         /**
5116          * @hide
5117          */
isSystemApp()5118         public boolean isSystemApp() {
5119             return applicationInfo.isSystemApp();
5120         }
5121 
5122         /**
5123          * @hide
5124          */
isPrivilegedApp()5125         public boolean isPrivilegedApp() {
5126             return applicationInfo.isPrivilegedApp();
5127         }
5128 
5129         /**
5130          * @hide
5131          */
isUpdatedSystemApp()5132         public boolean isUpdatedSystemApp() {
5133             return applicationInfo.isUpdatedSystemApp();
5134         }
5135 
5136         /**
5137          * @hide
5138          */
canHaveOatDir()5139         public boolean canHaveOatDir() {
5140             // The following app types CANNOT have oat directory
5141             // - non-updated system apps
5142             // - forward-locked apps or apps installed in ASEC containers
5143             return (!isSystemApp() || isUpdatedSystemApp())
5144                     && !isForwardLocked() && !applicationInfo.isExternalAsec();
5145         }
5146 
isMatch(int flags)5147         public boolean isMatch(int flags) {
5148             if ((flags & PackageManager.MATCH_SYSTEM_ONLY) != 0) {
5149                 return isSystemApp();
5150             }
5151             return true;
5152         }
5153 
getLatestPackageUseTimeInMills()5154         public long getLatestPackageUseTimeInMills() {
5155             long latestUse = 0L;
5156             for (long use : mLastPackageUsageTimeInMills) {
5157                 latestUse = Math.max(latestUse, use);
5158             }
5159             return latestUse;
5160         }
5161 
getLatestForegroundPackageUseTimeInMills()5162         public long getLatestForegroundPackageUseTimeInMills() {
5163             int[] foregroundReasons = {
5164                 PackageManager.NOTIFY_PACKAGE_USE_ACTIVITY,
5165                 PackageManager.NOTIFY_PACKAGE_USE_FOREGROUND_SERVICE
5166             };
5167 
5168             long latestUse = 0L;
5169             for (int reason : foregroundReasons) {
5170                 latestUse = Math.max(latestUse, mLastPackageUsageTimeInMills[reason]);
5171             }
5172             return latestUse;
5173         }
5174 
toString()5175         public String toString() {
5176             return "Package{"
5177                 + Integer.toHexString(System.identityHashCode(this))
5178                 + " " + packageName + "}";
5179         }
5180     }
5181 
5182     public static class Component<II extends IntentInfo> {
5183         public final Package owner;
5184         public final ArrayList<II> intents;
5185         public final String className;
5186         public Bundle metaData;
5187 
5188         ComponentName componentName;
5189         String componentShortName;
5190 
Component(Package _owner)5191         public Component(Package _owner) {
5192             owner = _owner;
5193             intents = null;
5194             className = null;
5195         }
5196 
Component(final ParsePackageItemArgs args, final PackageItemInfo outInfo)5197         public Component(final ParsePackageItemArgs args, final PackageItemInfo outInfo) {
5198             owner = args.owner;
5199             intents = new ArrayList<II>(0);
5200             if (parsePackageItemInfo(args.owner, outInfo, args.outError, args.tag, args.sa,
5201                     true /*nameRequired*/, args.nameRes, args.labelRes, args.iconRes,
5202                     args.roundIconRes, args.logoRes, args.bannerRes)) {
5203                 className = outInfo.name;
5204             } else {
5205                 className = null;
5206             }
5207         }
5208 
Component(final ParseComponentArgs args, final ComponentInfo outInfo)5209         public Component(final ParseComponentArgs args, final ComponentInfo outInfo) {
5210             this(args, (PackageItemInfo)outInfo);
5211             if (args.outError[0] != null) {
5212                 return;
5213             }
5214 
5215             if (args.processRes != 0) {
5216                 CharSequence pname;
5217                 if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.FROYO) {
5218                     pname = args.sa.getNonConfigurationString(args.processRes,
5219                             Configuration.NATIVE_CONFIG_VERSION);
5220                 } else {
5221                     // Some older apps have been seen to use a resource reference
5222                     // here that on older builds was ignored (with a warning).  We
5223                     // need to continue to do this for them so they don't break.
5224                     pname = args.sa.getNonResourceString(args.processRes);
5225                 }
5226                 outInfo.processName = buildProcessName(owner.applicationInfo.packageName,
5227                         owner.applicationInfo.processName, pname,
5228                         args.flags, args.sepProcesses, args.outError);
5229             }
5230 
5231             if (args.descriptionRes != 0) {
5232                 outInfo.descriptionRes = args.sa.getResourceId(args.descriptionRes, 0);
5233             }
5234 
5235             outInfo.enabled = args.sa.getBoolean(args.enabledRes, true);
5236         }
5237 
Component(Component<II> clone)5238         public Component(Component<II> clone) {
5239             owner = clone.owner;
5240             intents = clone.intents;
5241             className = clone.className;
5242             componentName = clone.componentName;
5243             componentShortName = clone.componentShortName;
5244         }
5245 
getComponentName()5246         public ComponentName getComponentName() {
5247             if (componentName != null) {
5248                 return componentName;
5249             }
5250             if (className != null) {
5251                 componentName = new ComponentName(owner.applicationInfo.packageName,
5252                         className);
5253             }
5254             return componentName;
5255         }
5256 
appendComponentShortName(StringBuilder sb)5257         public void appendComponentShortName(StringBuilder sb) {
5258             ComponentName.appendShortString(sb, owner.applicationInfo.packageName, className);
5259         }
5260 
printComponentShortName(PrintWriter pw)5261         public void printComponentShortName(PrintWriter pw) {
5262             ComponentName.printShortString(pw, owner.applicationInfo.packageName, className);
5263         }
5264 
setPackageName(String packageName)5265         public void setPackageName(String packageName) {
5266             componentName = null;
5267             componentShortName = null;
5268         }
5269     }
5270 
5271     public final static class Permission extends Component<IntentInfo> {
5272         public final PermissionInfo info;
5273         public boolean tree;
5274         public PermissionGroup group;
5275 
Permission(Package _owner)5276         public Permission(Package _owner) {
5277             super(_owner);
5278             info = new PermissionInfo();
5279         }
5280 
Permission(Package _owner, PermissionInfo _info)5281         public Permission(Package _owner, PermissionInfo _info) {
5282             super(_owner);
5283             info = _info;
5284         }
5285 
setPackageName(String packageName)5286         public void setPackageName(String packageName) {
5287             super.setPackageName(packageName);
5288             info.packageName = packageName;
5289         }
5290 
toString()5291         public String toString() {
5292             return "Permission{"
5293                 + Integer.toHexString(System.identityHashCode(this))
5294                 + " " + info.name + "}";
5295         }
5296     }
5297 
5298     public final static class PermissionGroup extends Component<IntentInfo> {
5299         public final PermissionGroupInfo info;
5300 
PermissionGroup(Package _owner)5301         public PermissionGroup(Package _owner) {
5302             super(_owner);
5303             info = new PermissionGroupInfo();
5304         }
5305 
PermissionGroup(Package _owner, PermissionGroupInfo _info)5306         public PermissionGroup(Package _owner, PermissionGroupInfo _info) {
5307             super(_owner);
5308             info = _info;
5309         }
5310 
setPackageName(String packageName)5311         public void setPackageName(String packageName) {
5312             super.setPackageName(packageName);
5313             info.packageName = packageName;
5314         }
5315 
toString()5316         public String toString() {
5317             return "PermissionGroup{"
5318                 + Integer.toHexString(System.identityHashCode(this))
5319                 + " " + info.name + "}";
5320         }
5321     }
5322 
copyNeeded(int flags, Package p, PackageUserState state, Bundle metaData, int userId)5323     private static boolean copyNeeded(int flags, Package p,
5324             PackageUserState state, Bundle metaData, int userId) {
5325         if (userId != UserHandle.USER_SYSTEM) {
5326             // We always need to copy for other users, since we need
5327             // to fix up the uid.
5328             return true;
5329         }
5330         if (state.enabled != PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
5331             boolean enabled = state.enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
5332             if (p.applicationInfo.enabled != enabled) {
5333                 return true;
5334             }
5335         }
5336         boolean suspended = (p.applicationInfo.flags & FLAG_SUSPENDED) != 0;
5337         if (state.suspended != suspended) {
5338             return true;
5339         }
5340         if (!state.installed || state.hidden) {
5341             return true;
5342         }
5343         if (state.stopped) {
5344             return true;
5345         }
5346         if ((flags & PackageManager.GET_META_DATA) != 0
5347                 && (metaData != null || p.mAppMetaData != null)) {
5348             return true;
5349         }
5350         if ((flags & PackageManager.GET_SHARED_LIBRARY_FILES) != 0
5351                 && p.usesLibraryFiles != null) {
5352             return true;
5353         }
5354         return false;
5355     }
5356 
generateApplicationInfo(Package p, int flags, PackageUserState state)5357     public static ApplicationInfo generateApplicationInfo(Package p, int flags,
5358             PackageUserState state) {
5359         return generateApplicationInfo(p, flags, state, UserHandle.getCallingUserId());
5360     }
5361 
updateApplicationInfo(ApplicationInfo ai, int flags, PackageUserState state)5362     private static void updateApplicationInfo(ApplicationInfo ai, int flags,
5363             PackageUserState state) {
5364         // CompatibilityMode is global state.
5365         if (!sCompatibilityModeEnabled) {
5366             ai.disableCompatibilityMode();
5367         }
5368         if (state.installed) {
5369             ai.flags |= ApplicationInfo.FLAG_INSTALLED;
5370         } else {
5371             ai.flags &= ~ApplicationInfo.FLAG_INSTALLED;
5372         }
5373         if (state.suspended) {
5374             ai.flags |= ApplicationInfo.FLAG_SUSPENDED;
5375         } else {
5376             ai.flags &= ~ApplicationInfo.FLAG_SUSPENDED;
5377         }
5378         if (state.hidden) {
5379             ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_HIDDEN;
5380         } else {
5381             ai.privateFlags &= ~ApplicationInfo.PRIVATE_FLAG_HIDDEN;
5382         }
5383         if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
5384             ai.enabled = true;
5385         } else if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
5386             ai.enabled = (flags&PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS) != 0;
5387         } else if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED
5388                 || state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) {
5389             ai.enabled = false;
5390         }
5391         ai.enabledSetting = state.enabled;
5392     }
5393 
generateApplicationInfo(Package p, int flags, PackageUserState state, int userId)5394     public static ApplicationInfo generateApplicationInfo(Package p, int flags,
5395             PackageUserState state, int userId) {
5396         if (p == null) return null;
5397         if (!checkUseInstalledOrHidden(flags, state) || !p.isMatch(flags)) {
5398             return null;
5399         }
5400         if (!copyNeeded(flags, p, state, null, userId)
5401                 && ((flags&PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS) == 0
5402                         || state.enabled != PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED)) {
5403             // In this case it is safe to directly modify the internal ApplicationInfo state:
5404             // - CompatibilityMode is global state, so will be the same for every call.
5405             // - We only come in to here if the app should reported as installed; this is the
5406             // default state, and we will do a copy otherwise.
5407             // - The enable state will always be reported the same for the application across
5408             // calls; the only exception is for the UNTIL_USED mode, and in that case we will
5409             // be doing a copy.
5410             updateApplicationInfo(p.applicationInfo, flags, state);
5411             return p.applicationInfo;
5412         }
5413 
5414         // Make shallow copy so we can store the metadata/libraries safely
5415         ApplicationInfo ai = new ApplicationInfo(p.applicationInfo);
5416         ai.initForUser(userId);
5417         if ((flags & PackageManager.GET_META_DATA) != 0) {
5418             ai.metaData = p.mAppMetaData;
5419         }
5420         if ((flags & PackageManager.GET_SHARED_LIBRARY_FILES) != 0) {
5421             ai.sharedLibraryFiles = p.usesLibraryFiles;
5422         }
5423         if (state.stopped) {
5424             ai.flags |= ApplicationInfo.FLAG_STOPPED;
5425         } else {
5426             ai.flags &= ~ApplicationInfo.FLAG_STOPPED;
5427         }
5428         updateApplicationInfo(ai, flags, state);
5429         return ai;
5430     }
5431 
generateApplicationInfo(ApplicationInfo ai, int flags, PackageUserState state, int userId)5432     public static ApplicationInfo generateApplicationInfo(ApplicationInfo ai, int flags,
5433             PackageUserState state, int userId) {
5434         if (ai == null) return null;
5435         if (!checkUseInstalledOrHidden(flags, state)) {
5436             return null;
5437         }
5438         // This is only used to return the ResolverActivity; we will just always
5439         // make a copy.
5440         ai = new ApplicationInfo(ai);
5441         ai.initForUser(userId);
5442         if (state.stopped) {
5443             ai.flags |= ApplicationInfo.FLAG_STOPPED;
5444         } else {
5445             ai.flags &= ~ApplicationInfo.FLAG_STOPPED;
5446         }
5447         updateApplicationInfo(ai, flags, state);
5448         return ai;
5449     }
5450 
generatePermissionInfo( Permission p, int flags)5451     public static final PermissionInfo generatePermissionInfo(
5452             Permission p, int flags) {
5453         if (p == null) return null;
5454         if ((flags&PackageManager.GET_META_DATA) == 0) {
5455             return p.info;
5456         }
5457         PermissionInfo pi = new PermissionInfo(p.info);
5458         pi.metaData = p.metaData;
5459         return pi;
5460     }
5461 
generatePermissionGroupInfo( PermissionGroup pg, int flags)5462     public static final PermissionGroupInfo generatePermissionGroupInfo(
5463             PermissionGroup pg, int flags) {
5464         if (pg == null) return null;
5465         if ((flags&PackageManager.GET_META_DATA) == 0) {
5466             return pg.info;
5467         }
5468         PermissionGroupInfo pgi = new PermissionGroupInfo(pg.info);
5469         pgi.metaData = pg.metaData;
5470         return pgi;
5471     }
5472 
5473     public final static class Activity extends Component<ActivityIntentInfo> {
5474         public final ActivityInfo info;
5475 
Activity(final ParseComponentArgs args, final ActivityInfo _info)5476         public Activity(final ParseComponentArgs args, final ActivityInfo _info) {
5477             super(args, _info);
5478             info = _info;
5479             info.applicationInfo = args.owner.applicationInfo;
5480         }
5481 
setPackageName(String packageName)5482         public void setPackageName(String packageName) {
5483             super.setPackageName(packageName);
5484             info.packageName = packageName;
5485         }
5486 
toString()5487         public String toString() {
5488             StringBuilder sb = new StringBuilder(128);
5489             sb.append("Activity{");
5490             sb.append(Integer.toHexString(System.identityHashCode(this)));
5491             sb.append(' ');
5492             appendComponentShortName(sb);
5493             sb.append('}');
5494             return sb.toString();
5495         }
5496     }
5497 
generateActivityInfo(Activity a, int flags, PackageUserState state, int userId)5498     public static final ActivityInfo generateActivityInfo(Activity a, int flags,
5499             PackageUserState state, int userId) {
5500         if (a == null) return null;
5501         if (!checkUseInstalledOrHidden(flags, state)) {
5502             return null;
5503         }
5504         if (!copyNeeded(flags, a.owner, state, a.metaData, userId)) {
5505             return a.info;
5506         }
5507         // Make shallow copies so we can store the metadata safely
5508         ActivityInfo ai = new ActivityInfo(a.info);
5509         ai.metaData = a.metaData;
5510         ai.applicationInfo = generateApplicationInfo(a.owner, flags, state, userId);
5511         return ai;
5512     }
5513 
generateActivityInfo(ActivityInfo ai, int flags, PackageUserState state, int userId)5514     public static final ActivityInfo generateActivityInfo(ActivityInfo ai, int flags,
5515             PackageUserState state, int userId) {
5516         if (ai == null) return null;
5517         if (!checkUseInstalledOrHidden(flags, state)) {
5518             return null;
5519         }
5520         // This is only used to return the ResolverActivity; we will just always
5521         // make a copy.
5522         ai = new ActivityInfo(ai);
5523         ai.applicationInfo = generateApplicationInfo(ai.applicationInfo, flags, state, userId);
5524         return ai;
5525     }
5526 
5527     public final static class Service extends Component<ServiceIntentInfo> {
5528         public final ServiceInfo info;
5529 
Service(final ParseComponentArgs args, final ServiceInfo _info)5530         public Service(final ParseComponentArgs args, final ServiceInfo _info) {
5531             super(args, _info);
5532             info = _info;
5533             info.applicationInfo = args.owner.applicationInfo;
5534         }
5535 
setPackageName(String packageName)5536         public void setPackageName(String packageName) {
5537             super.setPackageName(packageName);
5538             info.packageName = packageName;
5539         }
5540 
toString()5541         public String toString() {
5542             StringBuilder sb = new StringBuilder(128);
5543             sb.append("Service{");
5544             sb.append(Integer.toHexString(System.identityHashCode(this)));
5545             sb.append(' ');
5546             appendComponentShortName(sb);
5547             sb.append('}');
5548             return sb.toString();
5549         }
5550     }
5551 
generateServiceInfo(Service s, int flags, PackageUserState state, int userId)5552     public static final ServiceInfo generateServiceInfo(Service s, int flags,
5553             PackageUserState state, int userId) {
5554         if (s == null) return null;
5555         if (!checkUseInstalledOrHidden(flags, state)) {
5556             return null;
5557         }
5558         if (!copyNeeded(flags, s.owner, state, s.metaData, userId)) {
5559             return s.info;
5560         }
5561         // Make shallow copies so we can store the metadata safely
5562         ServiceInfo si = new ServiceInfo(s.info);
5563         si.metaData = s.metaData;
5564         si.applicationInfo = generateApplicationInfo(s.owner, flags, state, userId);
5565         return si;
5566     }
5567 
5568     public final static class Provider extends Component<ProviderIntentInfo> {
5569         public final ProviderInfo info;
5570         public boolean syncable;
5571 
Provider(final ParseComponentArgs args, final ProviderInfo _info)5572         public Provider(final ParseComponentArgs args, final ProviderInfo _info) {
5573             super(args, _info);
5574             info = _info;
5575             info.applicationInfo = args.owner.applicationInfo;
5576             syncable = false;
5577         }
5578 
Provider(Provider existingProvider)5579         public Provider(Provider existingProvider) {
5580             super(existingProvider);
5581             this.info = existingProvider.info;
5582             this.syncable = existingProvider.syncable;
5583         }
5584 
setPackageName(String packageName)5585         public void setPackageName(String packageName) {
5586             super.setPackageName(packageName);
5587             info.packageName = packageName;
5588         }
5589 
toString()5590         public String toString() {
5591             StringBuilder sb = new StringBuilder(128);
5592             sb.append("Provider{");
5593             sb.append(Integer.toHexString(System.identityHashCode(this)));
5594             sb.append(' ');
5595             appendComponentShortName(sb);
5596             sb.append('}');
5597             return sb.toString();
5598         }
5599     }
5600 
generateProviderInfo(Provider p, int flags, PackageUserState state, int userId)5601     public static final ProviderInfo generateProviderInfo(Provider p, int flags,
5602             PackageUserState state, int userId) {
5603         if (p == null) return null;
5604         if (!checkUseInstalledOrHidden(flags, state)) {
5605             return null;
5606         }
5607         if (!copyNeeded(flags, p.owner, state, p.metaData, userId)
5608                 && ((flags & PackageManager.GET_URI_PERMISSION_PATTERNS) != 0
5609                         || p.info.uriPermissionPatterns == null)) {
5610             return p.info;
5611         }
5612         // Make shallow copies so we can store the metadata safely
5613         ProviderInfo pi = new ProviderInfo(p.info);
5614         pi.metaData = p.metaData;
5615         if ((flags & PackageManager.GET_URI_PERMISSION_PATTERNS) == 0) {
5616             pi.uriPermissionPatterns = null;
5617         }
5618         pi.applicationInfo = generateApplicationInfo(p.owner, flags, state, userId);
5619         return pi;
5620     }
5621 
5622     public final static class Instrumentation extends Component<IntentInfo> {
5623         public final InstrumentationInfo info;
5624 
Instrumentation(final ParsePackageItemArgs args, final InstrumentationInfo _info)5625         public Instrumentation(final ParsePackageItemArgs args, final InstrumentationInfo _info) {
5626             super(args, _info);
5627             info = _info;
5628         }
5629 
setPackageName(String packageName)5630         public void setPackageName(String packageName) {
5631             super.setPackageName(packageName);
5632             info.packageName = packageName;
5633         }
5634 
toString()5635         public String toString() {
5636             StringBuilder sb = new StringBuilder(128);
5637             sb.append("Instrumentation{");
5638             sb.append(Integer.toHexString(System.identityHashCode(this)));
5639             sb.append(' ');
5640             appendComponentShortName(sb);
5641             sb.append('}');
5642             return sb.toString();
5643         }
5644     }
5645 
generateInstrumentationInfo( Instrumentation i, int flags)5646     public static final InstrumentationInfo generateInstrumentationInfo(
5647             Instrumentation i, int flags) {
5648         if (i == null) return null;
5649         if ((flags&PackageManager.GET_META_DATA) == 0) {
5650             return i.info;
5651         }
5652         InstrumentationInfo ii = new InstrumentationInfo(i.info);
5653         ii.metaData = i.metaData;
5654         return ii;
5655     }
5656 
5657     public static class IntentInfo extends IntentFilter {
5658         public boolean hasDefault;
5659         public int labelRes;
5660         public CharSequence nonLocalizedLabel;
5661         public int icon;
5662         public int logo;
5663         public int banner;
5664         public int preferred;
5665     }
5666 
5667     public final static class ActivityIntentInfo extends IntentInfo {
5668         public final Activity activity;
5669 
ActivityIntentInfo(Activity _activity)5670         public ActivityIntentInfo(Activity _activity) {
5671             activity = _activity;
5672         }
5673 
toString()5674         public String toString() {
5675             StringBuilder sb = new StringBuilder(128);
5676             sb.append("ActivityIntentInfo{");
5677             sb.append(Integer.toHexString(System.identityHashCode(this)));
5678             sb.append(' ');
5679             activity.appendComponentShortName(sb);
5680             sb.append('}');
5681             return sb.toString();
5682         }
5683     }
5684 
5685     public final static class ServiceIntentInfo extends IntentInfo {
5686         public final Service service;
5687 
ServiceIntentInfo(Service _service)5688         public ServiceIntentInfo(Service _service) {
5689             service = _service;
5690         }
5691 
toString()5692         public String toString() {
5693             StringBuilder sb = new StringBuilder(128);
5694             sb.append("ServiceIntentInfo{");
5695             sb.append(Integer.toHexString(System.identityHashCode(this)));
5696             sb.append(' ');
5697             service.appendComponentShortName(sb);
5698             sb.append('}');
5699             return sb.toString();
5700         }
5701     }
5702 
5703     public static final class ProviderIntentInfo extends IntentInfo {
5704         public final Provider provider;
5705 
ProviderIntentInfo(Provider provider)5706         public ProviderIntentInfo(Provider provider) {
5707             this.provider = provider;
5708         }
5709 
toString()5710         public String toString() {
5711             StringBuilder sb = new StringBuilder(128);
5712             sb.append("ProviderIntentInfo{");
5713             sb.append(Integer.toHexString(System.identityHashCode(this)));
5714             sb.append(' ');
5715             provider.appendComponentShortName(sb);
5716             sb.append('}');
5717             return sb.toString();
5718         }
5719     }
5720 
5721     /**
5722      * @hide
5723      */
setCompatibilityModeEnabled(boolean compatibilityModeEnabled)5724     public static void setCompatibilityModeEnabled(boolean compatibilityModeEnabled) {
5725         sCompatibilityModeEnabled = compatibilityModeEnabled;
5726     }
5727 
5728     private static AtomicReference<byte[]> sBuffer = new AtomicReference<byte[]>();
5729 
readFullyIgnoringContents(InputStream in)5730     public static long readFullyIgnoringContents(InputStream in) throws IOException {
5731         byte[] buffer = sBuffer.getAndSet(null);
5732         if (buffer == null) {
5733             buffer = new byte[4096];
5734         }
5735 
5736         int n = 0;
5737         int count = 0;
5738         while ((n = in.read(buffer, 0, buffer.length)) != -1) {
5739             count += n;
5740         }
5741 
5742         sBuffer.set(buffer);
5743         return count;
5744     }
5745 
closeQuietly(StrictJarFile jarFile)5746     public static void closeQuietly(StrictJarFile jarFile) {
5747         if (jarFile != null) {
5748             try {
5749                 jarFile.close();
5750             } catch (Exception ignored) {
5751             }
5752         }
5753     }
5754 
5755     public static class PackageParserException extends Exception {
5756         public final int error;
5757 
PackageParserException(int error, String detailMessage)5758         public PackageParserException(int error, String detailMessage) {
5759             super(detailMessage);
5760             this.error = error;
5761         }
5762 
PackageParserException(int error, String detailMessage, Throwable throwable)5763         public PackageParserException(int error, String detailMessage, Throwable throwable) {
5764             super(detailMessage, throwable);
5765             this.error = error;
5766         }
5767     }
5768 }
5769