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