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