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