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