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
17package android.content.pm;
18
19import com.android.internal.R;
20import com.android.internal.util.ArrayUtils;
21import com.android.internal.util.XmlUtils;
22
23import org.xmlpull.v1.XmlPullParser;
24import org.xmlpull.v1.XmlPullParserException;
25
26import android.app.ActivityManager;
27import android.content.ComponentName;
28import android.content.Intent;
29import android.content.IntentFilter;
30import android.content.res.AssetManager;
31import android.content.res.Configuration;
32import android.content.res.Resources;
33import android.content.res.TypedArray;
34import android.content.res.XmlResourceParser;
35import android.os.Build;
36import android.os.Bundle;
37import android.os.FileUtils;
38import android.os.PatternMatcher;
39import android.os.Trace;
40import android.os.UserHandle;
41import android.text.TextUtils;
42import android.util.ArrayMap;
43import android.util.ArraySet;
44import android.util.AttributeSet;
45import android.util.Base64;
46import android.util.DisplayMetrics;
47import android.util.Log;
48import android.util.Pair;
49import android.util.Slog;
50import android.util.TypedValue;
51import android.util.apk.ApkSignatureSchemeV2Verifier;
52import android.util.jar.StrictJarFile;
53import android.view.Gravity;
54
55import java.io.File;
56import java.io.IOException;
57import java.io.InputStream;
58import java.io.PrintWriter;
59import java.security.GeneralSecurityException;
60import java.security.KeyFactory;
61import java.security.NoSuchAlgorithmException;
62import java.security.PublicKey;
63import java.security.cert.Certificate;
64import java.security.cert.CertificateEncodingException;
65import java.security.spec.EncodedKeySpec;
66import java.security.spec.InvalidKeySpecException;
67import java.security.spec.X509EncodedKeySpec;
68import java.util.ArrayList;
69import java.util.Arrays;
70import java.util.Collections;
71import java.util.Comparator;
72import java.util.Iterator;
73import java.util.List;
74import java.util.Set;
75import java.util.concurrent.atomic.AtomicReference;
76import java.util.zip.ZipEntry;
77
78import libcore.io.IoUtils;
79
80import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE;
81import static android.content.pm.ActivityInfo.FLAG_IMMERSIVE;
82import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE;
83import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
84import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_AND_PIPABLE;
85import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
86import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
87import static android.content.pm.ApplicationInfo.FLAG_SUSPENDED;
88import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_RESIZEABLE_ACTIVITIES;
89import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST;
90import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME;
91import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING;
92import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
93import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
94import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NOT_APK;
95import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES;
96import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION;
97import 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 */
117public 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
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
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
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
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
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
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
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
424    public PackageParser() {
425        mMetrics = new DisplayMetrics();
426        mMetrics.setToDefaults();
427    }
428
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     */
438    public void setOnlyCoreApps(boolean onlyCoreApps) {
439        mOnlyCoreApps = onlyCoreApps;
440    }
441
442    public void setDisplayMetrics(DisplayMetrics metrics) {
443        mMetrics = metrics;
444    }
445
446    public static final boolean isApkFile(File file) {
447        return isApkPath(file.getName());
448    }
449
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     */
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     */
472    private static boolean checkUseInstalledOrHidden(int flags, PackageUserState state) {
473        return (state.installed && !state.hidden)
474                || (flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0;
475    }
476
477    public static boolean isAvailable(PackageUserState state) {
478        return checkUseInstalledOrHidden(0, state);
479    }
480
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
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
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     */
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
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
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     */
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     */
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
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
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
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
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     */
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
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     */
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     */
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
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
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
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     */
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
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
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
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     */
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     */
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     */
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     */
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
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
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
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
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
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
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
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
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
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
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
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     */
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
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     */
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     */
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
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
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
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
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
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
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
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
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
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
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
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
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
4864        public Package(String packageName) {
4865            this.packageName = packageName;
4866            applicationInfo.packageName = packageName;
4867            applicationInfo.uid = -1;
4868        }
4869
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
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
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
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
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
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
4930        public void setApplicationInfoSplitCodePaths(String[] splitCodePaths) {
4931            this.applicationInfo.setSplitCodePaths(splitCodePaths);
4932            // Children have no splits
4933        }
4934
4935        public void setApplicationInfoSplitResourcePaths(String[] resroucePaths) {
4936            this.applicationInfo.setSplitResourcePaths(resroucePaths);
4937            // Children have no splits
4938        }
4939
4940        public void setSplitCodePaths(String[] codePaths) {
4941            this.splitCodePaths = codePaths;
4942        }
4943
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
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
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
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
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
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
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         */
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
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
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         */
5091        public boolean isForwardLocked() {
5092            return applicationInfo.isForwardLocked();
5093        }
5094
5095        /**
5096         * @hide
5097         */
5098        public boolean isSystemApp() {
5099            return applicationInfo.isSystemApp();
5100        }
5101
5102        /**
5103         * @hide
5104         */
5105        public boolean isPrivilegedApp() {
5106            return applicationInfo.isPrivilegedApp();
5107        }
5108
5109        /**
5110         * @hide
5111         */
5112        public boolean isUpdatedSystemApp() {
5113            return applicationInfo.isUpdatedSystemApp();
5114        }
5115
5116        /**
5117         * @hide
5118         */
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
5127        public boolean isMatch(int flags) {
5128            if ((flags & PackageManager.MATCH_SYSTEM_ONLY) != 0) {
5129                return isSystemApp();
5130            }
5131            return true;
5132        }
5133
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
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
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
5171        public Component(Package _owner) {
5172            owner = _owner;
5173            intents = null;
5174            className = null;
5175        }
5176
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
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
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
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
5269        public void appendComponentShortName(StringBuilder sb) {
5270            ComponentName.appendShortString(sb, owner.applicationInfo.packageName, className);
5271        }
5272
5273        public void printComponentShortName(PrintWriter pw) {
5274            ComponentName.printShortString(pw, owner.applicationInfo.packageName, className);
5275        }
5276
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
5288        public Permission(Package _owner) {
5289            super(_owner);
5290            info = new PermissionInfo();
5291        }
5292
5293        public Permission(Package _owner, PermissionInfo _info) {
5294            super(_owner);
5295            info = _info;
5296        }
5297
5298        public void setPackageName(String packageName) {
5299            super.setPackageName(packageName);
5300            info.packageName = packageName;
5301        }
5302
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
5313        public PermissionGroup(Package _owner) {
5314            super(_owner);
5315            info = new PermissionGroupInfo();
5316        }
5317
5318        public PermissionGroup(Package _owner, PermissionGroupInfo _info) {
5319            super(_owner);
5320            info = _info;
5321        }
5322
5323        public void setPackageName(String packageName) {
5324            super.setPackageName(packageName);
5325            info.packageName = packageName;
5326        }
5327
5328        public String toString() {
5329            return "PermissionGroup{"
5330                + Integer.toHexString(System.identityHashCode(this))
5331                + " " + info.name + "}";
5332        }
5333    }
5334
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
5369    public static ApplicationInfo generateApplicationInfo(Package p, int flags,
5370            PackageUserState state) {
5371        return generateApplicationInfo(p, flags, state, UserHandle.getCallingUserId());
5372    }
5373
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
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
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
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
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
5488        public Activity(final ParseComponentArgs args, final ActivityInfo _info) {
5489            super(args, _info);
5490            info = _info;
5491            info.applicationInfo = args.owner.applicationInfo;
5492        }
5493
5494        public void setPackageName(String packageName) {
5495            super.setPackageName(packageName);
5496            info.packageName = packageName;
5497        }
5498
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
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
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
5542        public Service(final ParseComponentArgs args, final ServiceInfo _info) {
5543            super(args, _info);
5544            info = _info;
5545            info.applicationInfo = args.owner.applicationInfo;
5546        }
5547
5548        public void setPackageName(String packageName) {
5549            super.setPackageName(packageName);
5550            info.packageName = packageName;
5551        }
5552
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
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
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
5591        public Provider(Provider existingProvider) {
5592            super(existingProvider);
5593            this.info = existingProvider.info;
5594            this.syncable = existingProvider.syncable;
5595        }
5596
5597        public void setPackageName(String packageName) {
5598            super.setPackageName(packageName);
5599            info.packageName = packageName;
5600        }
5601
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
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
5637        public Instrumentation(final ParsePackageItemArgs args, final InstrumentationInfo _info) {
5638            super(args, _info);
5639            info = _info;
5640        }
5641
5642        public void setPackageName(String packageName) {
5643            super.setPackageName(packageName);
5644            info.packageName = packageName;
5645        }
5646
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
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
5682        public ActivityIntentInfo(Activity _activity) {
5683            activity = _activity;
5684        }
5685
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
5700        public ServiceIntentInfo(Service _service) {
5701            service = _service;
5702        }
5703
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
5718        public ProviderIntentInfo(Provider provider) {
5719            this.provider = provider;
5720        }
5721
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     */
5736    public static void setCompatibilityModeEnabled(boolean compatibilityModeEnabled) {
5737        sCompatibilityModeEnabled = compatibilityModeEnabled;
5738    }
5739
5740    private static AtomicReference<byte[]> sBuffer = new AtomicReference<byte[]>();
5741
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
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
5770        public PackageParserException(int error, String detailMessage) {
5771            super(detailMessage);
5772            this.error = error;
5773        }
5774
5775        public PackageParserException(int error, String detailMessage, Throwable throwable) {
5776            super(detailMessage, throwable);
5777            this.error = error;
5778        }
5779    }
5780}
5781