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