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