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