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