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