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