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