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