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