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