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