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