blob: 4d9445df250ac0fa23186b38fe01844163a729af [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.content.pm;
18
Jeff Sharkey275e0852014-06-17 18:18:49 -070019import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070020import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME;
Jeff Sharkey275e0852014-06-17 18:18:49 -070021import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING;
22import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070023import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
Jeff Sharkeyc4858a22014-06-16 10:51:20 -070024import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NOT_APK;
Jeff Sharkey275e0852014-06-17 18:18:49 -070025import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES;
26import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070027
Dianne Hackborn852975d2014-08-22 17:42:43 -070028import android.app.ActivityManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080029import android.content.ComponentName;
30import android.content.Intent;
31import android.content.IntentFilter;
32import android.content.res.AssetManager;
33import android.content.res.Configuration;
34import android.content.res.Resources;
35import android.content.res.TypedArray;
36import android.content.res.XmlResourceParser;
Suchi Amalapurapu8d5ae982009-10-06 09:26:09 -070037import android.os.Build;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080038import android.os.Bundle;
39import android.os.PatternMatcher;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -070040import android.os.UserHandle;
Jeff Sharkeyc4858a22014-06-16 10:51:20 -070041import android.text.TextUtils;
Jeff Sharkey275e0852014-06-17 18:18:49 -070042import android.util.ArrayMap;
43import android.util.ArraySet;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080044import android.util.AttributeSet;
Kenny Root05ca4c92011-09-15 10:36:25 -070045import android.util.Base64;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080046import android.util.DisplayMetrics;
Kenny Root05ca4c92011-09-15 10:36:25 -070047import android.util.Log;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070048import android.util.Pair;
Kenny Rootd2d29252011-08-08 11:27:57 -070049import android.util.Slog;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080050import android.util.TypedValue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080051
Jeff Sharkey275e0852014-06-17 18:18:49 -070052import com.android.internal.util.ArrayUtils;
53import com.android.internal.util.XmlUtils;
54
55import libcore.io.IoUtils;
56
57import org.xmlpull.v1.XmlPullParser;
58import org.xmlpull.v1.XmlPullParserException;
59
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080060import java.io.File;
61import java.io.IOException;
62import java.io.InputStream;
Dianne Hackborn6d8dfbd2013-09-23 17:38:51 -070063import java.io.PrintWriter;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070064import java.security.GeneralSecurityException;
Kenny Root05ca4c92011-09-15 10:36:25 -070065import java.security.KeyFactory;
66import java.security.NoSuchAlgorithmException;
67import java.security.PublicKey;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080068import java.security.cert.Certificate;
69import java.security.cert.CertificateEncodingException;
Kenny Root05ca4c92011-09-15 10:36:25 -070070import java.security.spec.EncodedKeySpec;
71import java.security.spec.InvalidKeySpecException;
72import java.security.spec.X509EncodedKeySpec;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080073import java.util.ArrayList;
Dianne Hackbornffcda102014-04-24 13:06:27 -070074import java.util.Arrays;
Jeff Sharkey275e0852014-06-17 18:18:49 -070075import java.util.Collections;
76import java.util.Comparator;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080077import java.util.Iterator;
Kenny Root05ca4c92011-09-15 10:36:25 -070078import java.util.List;
Geremy Condraf1bcca82013-01-07 22:35:24 -080079import java.util.Set;
Jeff Sharkey275e0852014-06-17 18:18:49 -070080import java.util.concurrent.atomic.AtomicReference;
Narayan Kamatheb565dc2013-12-12 16:54:33 +000081import java.util.jar.StrictJarFile;
Kenny Root6c918ce2013-04-02 14:04:24 -070082import java.util.zip.ZipEntry;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080083
84/**
Jeff Sharkeyda96e132014-07-15 14:54:09 -070085 * Parser for package files (APKs) on disk. This supports apps packaged either
86 * as a single "monolithic" APK, or apps packaged as a "cluster" of multiple
87 * APKs in a single directory.
88 * <p>
89 * Apps packaged as multiple APKs always consist of a single "base" APK (with a
90 * {@code null} split name) and zero or more "split" APKs (with unique split
91 * names). Any subset of those split APKs are a valid install, as long as the
92 * following constraints are met:
93 * <ul>
94 * <li>All APKs must have the exact same package name, version code, and signing
95 * certificates.
96 * <li>All APKs must have unique split names.
97 * <li>All installations must contain a single base APK.
98 * </ul>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080099 *
Jeff Sharkeyda96e132014-07-15 14:54:09 -0700100 * @hide
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800101 */
102public class PackageParser {
Kenny Rootd2d29252011-08-08 11:27:57 -0700103 private static final boolean DEBUG_JAR = false;
104 private static final boolean DEBUG_PARSER = false;
105 private static final boolean DEBUG_BACKUP = false;
106
Jeff Sharkeyc4858a22014-06-16 10:51:20 -0700107 // TODO: switch outError users to PackageParserException
Jeff Sharkeyda96e132014-07-15 14:54:09 -0700108 // TODO: refactor "codePath" to "apkPath"
Jeff Sharkeyc4858a22014-06-16 10:51:20 -0700109
Kenny Rootbcc954d2011-08-08 16:19:08 -0700110 /** File name in an APK for the Android manifest. */
111 private static final String ANDROID_MANIFEST_FILENAME = "AndroidManifest.xml";
112
Dianne Hackborna96cbb42009-05-13 15:06:13 -0700113 /** @hide */
114 public static class NewPermissionInfo {
115 public final String name;
116 public final int sdkVersion;
117 public final int fileVersion;
118
119 public NewPermissionInfo(String name, int sdkVersion, int fileVersion) {
120 this.name = name;
121 this.sdkVersion = sdkVersion;
122 this.fileVersion = fileVersion;
123 }
124 }
Dianne Hackborn79245122012-03-12 10:51:26 -0700125
126 /** @hide */
127 public static class SplitPermissionInfo {
128 public final String rootPerm;
129 public final String[] newPerms;
Dianne Hackborn31b0e0e2012-04-05 19:33:30 -0700130 public final int targetSdk;
Dianne Hackborn79245122012-03-12 10:51:26 -0700131
Dianne Hackborn31b0e0e2012-04-05 19:33:30 -0700132 public SplitPermissionInfo(String rootPerm, String[] newPerms, int targetSdk) {
Dianne Hackborn79245122012-03-12 10:51:26 -0700133 this.rootPerm = rootPerm;
134 this.newPerms = newPerms;
Dianne Hackborn31b0e0e2012-04-05 19:33:30 -0700135 this.targetSdk = targetSdk;
Dianne Hackborn79245122012-03-12 10:51:26 -0700136 }
137 }
138
Dianne Hackborna96cbb42009-05-13 15:06:13 -0700139 /**
140 * List of new permissions that have been added since 1.0.
141 * NOTE: These must be declared in SDK version order, with permissions
142 * added to older SDKs appearing before those added to newer SDKs.
Dianne Hackborn79245122012-03-12 10:51:26 -0700143 * If sdkVersion is 0, then this is not a permission that we want to
144 * automatically add to older apps, but we do want to allow it to be
145 * granted during a platform update.
Dianne Hackborna96cbb42009-05-13 15:06:13 -0700146 * @hide
147 */
Jaikumar Ganesh45515652009-04-23 15:20:21 -0700148 public static final PackageParser.NewPermissionInfo NEW_PERMISSIONS[] =
149 new PackageParser.NewPermissionInfo[] {
San Mehat5a3a77d2009-06-01 09:25:28 -0700150 new PackageParser.NewPermissionInfo(android.Manifest.permission.WRITE_EXTERNAL_STORAGE,
Jaikumar Ganesh45515652009-04-23 15:20:21 -0700151 android.os.Build.VERSION_CODES.DONUT, 0),
152 new PackageParser.NewPermissionInfo(android.Manifest.permission.READ_PHONE_STATE,
153 android.os.Build.VERSION_CODES.DONUT, 0)
Dianne Hackborna96cbb42009-05-13 15:06:13 -0700154 };
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800155
Dianne Hackborn79245122012-03-12 10:51:26 -0700156 /**
157 * List of permissions that have been split into more granular or dependent
158 * permissions.
159 * @hide
160 */
161 public static final PackageParser.SplitPermissionInfo SPLIT_PERMISSIONS[] =
162 new PackageParser.SplitPermissionInfo[] {
Dianne Hackborn2bd8d042012-06-11 12:27:05 -0700163 // READ_EXTERNAL_STORAGE is always required when an app requests
164 // WRITE_EXTERNAL_STORAGE, because we can't have an app that has
165 // write access without read access. The hack here with the target
166 // target SDK version ensures that this grant is always done.
Dianne Hackborn79245122012-03-12 10:51:26 -0700167 new PackageParser.SplitPermissionInfo(android.Manifest.permission.WRITE_EXTERNAL_STORAGE,
Dianne Hackborn31b0e0e2012-04-05 19:33:30 -0700168 new String[] { android.Manifest.permission.READ_EXTERNAL_STORAGE },
Dianne Hackborn2bd8d042012-06-11 12:27:05 -0700169 android.os.Build.VERSION_CODES.CUR_DEVELOPMENT+1),
Dianne Hackborn31b0e0e2012-04-05 19:33:30 -0700170 new PackageParser.SplitPermissionInfo(android.Manifest.permission.READ_CONTACTS,
171 new String[] { android.Manifest.permission.READ_CALL_LOG },
172 android.os.Build.VERSION_CODES.JELLY_BEAN),
173 new PackageParser.SplitPermissionInfo(android.Manifest.permission.WRITE_CONTACTS,
174 new String[] { android.Manifest.permission.WRITE_CALL_LOG },
175 android.os.Build.VERSION_CODES.JELLY_BEAN)
Dianne Hackborn79245122012-03-12 10:51:26 -0700176 };
177
Jeff Sharkey275e0852014-06-17 18:18:49 -0700178 /**
179 * @deprecated callers should move to explicitly passing around source path.
180 */
181 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800182 private String mArchiveSourcePath;
Jeff Sharkey275e0852014-06-17 18:18:49 -0700183
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800184 private String[] mSeparateProcesses;
Dianne Hackbornd2509fd2011-09-12 12:29:43 -0700185 private boolean mOnlyCoreApps;
Jeff Sharkey275e0852014-06-17 18:18:49 -0700186 private DisplayMetrics mMetrics;
187
Suchi Amalapurapu8d5ae982009-10-06 09:26:09 -0700188 private static final int SDK_VERSION = Build.VERSION.SDK_INT;
Dianne Hackbornffcda102014-04-24 13:06:27 -0700189 private static final String[] SDK_CODENAMES = Build.VERSION.ACTIVE_CODENAMES;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800190
191 private int mParseError = PackageManager.INSTALL_SUCCEEDED;
192
Suchi Amalapurapu90d8ee62010-03-18 11:38:35 -0700193 private static boolean sCompatibilityModeEnabled = true;
Amith Yamasani655d0e22013-06-12 14:19:10 -0700194 private static final int PARSE_DEFAULT_INSTALL_LOCATION =
195 PackageInfo.INSTALL_LOCATION_UNSPECIFIED;
Mitsuru Oshima69fff4a2009-07-21 09:51:05 -0700196
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700197 static class ParsePackageItemArgs {
198 final Package owner;
199 final String[] outError;
200 final int nameRes;
201 final int labelRes;
202 final int iconRes;
Adam Powell81cd2e92010-04-21 16:35:18 -0700203 final int logoRes;
Jose Limaf78e3122014-03-06 12:13:15 -0800204 final int bannerRes;
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700205
206 String tag;
207 TypedArray sa;
208
209 ParsePackageItemArgs(Package _owner, String[] _outError,
Jose Limaf78e3122014-03-06 12:13:15 -0800210 int _nameRes, int _labelRes, int _iconRes, int _logoRes, int _bannerRes) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700211 owner = _owner;
212 outError = _outError;
213 nameRes = _nameRes;
214 labelRes = _labelRes;
215 iconRes = _iconRes;
Adam Powell81cd2e92010-04-21 16:35:18 -0700216 logoRes = _logoRes;
Jose Limaf78e3122014-03-06 12:13:15 -0800217 bannerRes = _bannerRes;
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700218 }
219 }
220
221 static class ParseComponentArgs extends ParsePackageItemArgs {
222 final String[] sepProcesses;
223 final int processRes;
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800224 final int descriptionRes;
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700225 final int enabledRes;
226 int flags;
227
228 ParseComponentArgs(Package _owner, String[] _outError,
Jose Limaf78e3122014-03-06 12:13:15 -0800229 int _nameRes, int _labelRes, int _iconRes, int _logoRes, int _bannerRes,
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800230 String[] _sepProcesses, int _processRes,
231 int _descriptionRes, int _enabledRes) {
Jose Limaf78e3122014-03-06 12:13:15 -0800232 super(_owner, _outError, _nameRes, _labelRes, _iconRes, _logoRes, _bannerRes);
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700233 sepProcesses = _sepProcesses;
234 processRes = _processRes;
Dianne Hackborn8aa2e892010-01-22 11:31:30 -0800235 descriptionRes = _descriptionRes;
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700236 enabledRes = _enabledRes;
237 }
238 }
Suchi Amalapurapua2b6c372010-03-05 17:40:11 -0800239
Jeff Sharkeyc4858a22014-06-16 10:51:20 -0700240 /**
Jeff Sharkey73767b92014-07-04 20:18:13 -0700241 * Lightweight parsed details about a single package.
242 */
243 public static class PackageLite {
244 public final String packageName;
245 public final int versionCode;
Jeff Sharkeybe520fb2014-07-04 18:23:17 -0700246 public final int installLocation;
247 public final VerifierInfo[] verifiers;
Jeff Sharkey73767b92014-07-04 20:18:13 -0700248
249 /** Names of any split APKs, ordered by parsed splitName */
250 public final String[] splitNames;
251
252 /**
253 * Path where this package was found on disk. For monolithic packages
254 * this is path to single base APK file; for cluster packages this is
255 * path to the cluster directory.
256 */
257 public final String codePath;
258
259 /** Path of base APK */
260 public final String baseCodePath;
261 /** Paths of any split APKs, ordered by parsed splitName */
262 public final String[] splitCodePaths;
263
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -0800264 /** Revision code of base APK */
265 public final int baseRevisionCode;
266 /** Revision codes of any split APKs, ordered by parsed splitName */
267 public final int[] splitRevisionCodes;
268
Jeff Sharkeyda96e132014-07-15 14:54:09 -0700269 public final boolean coreApp;
Narayan Kamathff110bd2014-07-04 18:30:45 +0100270 public final boolean multiArch;
271
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700272 public PackageLite(String codePath, ApkLite baseApk, String[] splitNames,
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -0800273 String[] splitCodePaths, int[] splitRevisionCodes) {
Jeff Sharkeybe520fb2014-07-04 18:23:17 -0700274 this.packageName = baseApk.packageName;
275 this.versionCode = baseApk.versionCode;
276 this.installLocation = baseApk.installLocation;
277 this.verifiers = baseApk.verifiers;
Jeff Sharkey73767b92014-07-04 20:18:13 -0700278 this.splitNames = splitNames;
279 this.codePath = codePath;
Jeff Sharkeybe520fb2014-07-04 18:23:17 -0700280 this.baseCodePath = baseApk.codePath;
Jeff Sharkey73767b92014-07-04 20:18:13 -0700281 this.splitCodePaths = splitCodePaths;
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -0800282 this.baseRevisionCode = baseApk.revisionCode;
283 this.splitRevisionCodes = splitRevisionCodes;
Jeff Sharkeyda96e132014-07-15 14:54:09 -0700284 this.coreApp = baseApk.coreApp;
Narayan Kamathff110bd2014-07-04 18:30:45 +0100285 this.multiArch = baseApk.multiArch;
Jeff Sharkey73767b92014-07-04 20:18:13 -0700286 }
287
288 public List<String> getAllCodePaths() {
289 ArrayList<String> paths = new ArrayList<>();
290 paths.add(baseCodePath);
291 if (!ArrayUtils.isEmpty(splitCodePaths)) {
292 Collections.addAll(paths, splitCodePaths);
293 }
294 return paths;
295 }
296 }
297
298 /**
Jeff Sharkeyc4858a22014-06-16 10:51:20 -0700299 * Lightweight parsed details about a single APK file.
Suchi Amalapurapua2b6c372010-03-05 17:40:11 -0800300 */
Jeff Sharkeyc4858a22014-06-16 10:51:20 -0700301 public static class ApkLite {
Jeff Sharkeybe520fb2014-07-04 18:23:17 -0700302 public final String codePath;
Kenny Root05ca4c92011-09-15 10:36:25 -0700303 public final String packageName;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700304 public final String splitName;
Dianne Hackborn7767eac2012-08-23 18:25:40 -0700305 public final int versionCode;
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -0800306 public final int revisionCode;
Kenny Root05ca4c92011-09-15 10:36:25 -0700307 public final int installLocation;
308 public final VerifierInfo[] verifiers;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700309 public final Signature[] signatures;
Jeff Sharkeyda96e132014-07-15 14:54:09 -0700310 public final boolean coreApp;
Narayan Kamathff110bd2014-07-04 18:30:45 +0100311 public final boolean multiArch;
Kenny Root05ca4c92011-09-15 10:36:25 -0700312
Jeff Sharkeybe520fb2014-07-04 18:23:17 -0700313 public ApkLite(String codePath, String packageName, String splitName, int versionCode,
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -0800314 int revisionCode, int installLocation, List<VerifierInfo> verifiers,
315 Signature[] signatures, boolean coreApp, boolean multiArch) {
Jeff Sharkeybe520fb2014-07-04 18:23:17 -0700316 this.codePath = codePath;
Suchi Amalapurapua2b6c372010-03-05 17:40:11 -0800317 this.packageName = packageName;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700318 this.splitName = splitName;
Dianne Hackborn7767eac2012-08-23 18:25:40 -0700319 this.versionCode = versionCode;
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -0800320 this.revisionCode = revisionCode;
Suchi Amalapurapua2b6c372010-03-05 17:40:11 -0800321 this.installLocation = installLocation;
Kenny Root05ca4c92011-09-15 10:36:25 -0700322 this.verifiers = verifiers.toArray(new VerifierInfo[verifiers.size()]);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700323 this.signatures = signatures;
Jeff Sharkeyda96e132014-07-15 14:54:09 -0700324 this.coreApp = coreApp;
Narayan Kamathff110bd2014-07-04 18:30:45 +0100325 this.multiArch = multiArch;
Suchi Amalapurapua2b6c372010-03-05 17:40:11 -0800326 }
327 }
328
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700329 private ParsePackageItemArgs mParseInstrumentationArgs;
330 private ParseComponentArgs mParseActivityArgs;
331 private ParseComponentArgs mParseActivityAliasArgs;
332 private ParseComponentArgs mParseServiceArgs;
333 private ParseComponentArgs mParseProviderArgs;
334
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800335 /** If set to true, we will only allow package files that exactly match
336 * the DTD. Otherwise, we try to get as much from the package as we
337 * can without failing. This should normally be set to false, to
338 * support extensions to the DTD in future versions. */
339 private static final boolean RIGID_PARSER = false;
340
341 private static final String TAG = "PackageParser";
342
Jeff Sharkey275e0852014-06-17 18:18:49 -0700343 public PackageParser() {
344 mMetrics = new DisplayMetrics();
345 mMetrics.setToDefaults();
Jeff Sharkeyc4858a22014-06-16 10:51:20 -0700346 }
347
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800348 public void setSeparateProcesses(String[] procs) {
349 mSeparateProcesses = procs;
350 }
351
Jeff Sharkeyda96e132014-07-15 14:54:09 -0700352 /**
353 * Flag indicating this parser should only consider apps with
354 * {@code coreApp} manifest attribute to be valid apps. This is useful when
355 * creating a minimalist boot environment.
356 */
Dianne Hackbornd2509fd2011-09-12 12:29:43 -0700357 public void setOnlyCoreApps(boolean onlyCoreApps) {
358 mOnlyCoreApps = onlyCoreApps;
359 }
360
Jeff Sharkey275e0852014-06-17 18:18:49 -0700361 public void setDisplayMetrics(DisplayMetrics metrics) {
362 mMetrics = metrics;
363 }
364
Jeff Sharkey73767b92014-07-04 20:18:13 -0700365 public static final boolean isApkFile(File file) {
Adam Lesinski3bcbd902014-08-22 17:01:04 -0700366 return isApkPath(file.getName());
367 }
368
369 private static boolean isApkPath(String path) {
370 return path.endsWith(".apk");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800371 }
372
Dianne Hackborn7767eac2012-08-23 18:25:40 -0700373 /*
Amith Yamasani13593602012-03-22 16:16:17 -0700374 public static PackageInfo generatePackageInfo(PackageParser.Package p,
375 int gids[], int flags, long firstInstallTime, long lastUpdateTime,
376 HashSet<String> grantedPermissions) {
Dianne Hackborn7767eac2012-08-23 18:25:40 -0700377 PackageUserState state = new PackageUserState();
Amith Yamasani13593602012-03-22 16:16:17 -0700378 return generatePackageInfo(p, gids, flags, firstInstallTime, lastUpdateTime,
Dianne Hackborn7767eac2012-08-23 18:25:40 -0700379 grantedPermissions, state, UserHandle.getCallingUserId());
Amith Yamasani13593602012-03-22 16:16:17 -0700380 }
Dianne Hackborn7767eac2012-08-23 18:25:40 -0700381 */
Amith Yamasani13593602012-03-22 16:16:17 -0700382
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800383 /**
384 * Generate and return the {@link PackageInfo} for a parsed package.
385 *
386 * @param p the parsed package.
387 * @param flags indicating which optional information is included.
388 */
389 public static PackageInfo generatePackageInfo(PackageParser.Package p,
Dianne Hackborne639da72012-02-21 15:11:13 -0800390 int gids[], int flags, long firstInstallTime, long lastUpdateTime,
Jeff Sharkey9f837a92014-10-24 12:07:24 -0700391 ArraySet<String> grantedPermissions, PackageUserState state) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800392
Amith Yamasani483f3b02012-03-13 16:08:00 -0700393 return generatePackageInfo(p, gids, flags, firstInstallTime, lastUpdateTime,
Dianne Hackborn7767eac2012-08-23 18:25:40 -0700394 grantedPermissions, state, UserHandle.getCallingUserId());
395 }
396
Amith Yamasani655d0e22013-06-12 14:19:10 -0700397 /**
Amith Yamasanie5bcff62014-07-19 15:44:09 -0700398 * Returns true if the package is installed and not hidden, or if the caller
399 * explicitly wanted all uninstalled and hidden packages as well.
Amith Yamasani655d0e22013-06-12 14:19:10 -0700400 */
Amith Yamasanie5bcff62014-07-19 15:44:09 -0700401 private static boolean checkUseInstalledOrHidden(int flags, PackageUserState state) {
402 return (state.installed && !state.hidden)
Amith Yamasani655d0e22013-06-12 14:19:10 -0700403 || (flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0;
Amith Yamasani483f3b02012-03-13 16:08:00 -0700404 }
405
Christopher Tateba629da2013-11-13 17:42:28 -0800406 public static boolean isAvailable(PackageUserState state) {
Amith Yamasanie5bcff62014-07-19 15:44:09 -0700407 return checkUseInstalledOrHidden(0, state);
Christopher Tateba629da2013-11-13 17:42:28 -0800408 }
409
Amith Yamasani13593602012-03-22 16:16:17 -0700410 public static PackageInfo generatePackageInfo(PackageParser.Package p,
Amith Yamasani483f3b02012-03-13 16:08:00 -0700411 int gids[], int flags, long firstInstallTime, long lastUpdateTime,
Jeff Sharkey9f837a92014-10-24 12:07:24 -0700412 ArraySet<String> grantedPermissions, PackageUserState state, int userId) {
Amith Yamasani742a6712011-05-04 14:49:28 -0700413
Amith Yamasanie5bcff62014-07-19 15:44:09 -0700414 if (!checkUseInstalledOrHidden(flags, state)) {
Dianne Hackborn7767eac2012-08-23 18:25:40 -0700415 return null;
416 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800417 PackageInfo pi = new PackageInfo();
418 pi.packageName = p.packageName;
Jeff Sharkey6c833e02014-07-14 22:44:30 -0700419 pi.splitNames = p.splitNames;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800420 pi.versionCode = p.mVersionCode;
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -0800421 pi.baseRevisionCode = p.baseRevisionCode;
422 pi.splitRevisionCodes = p.splitRevisionCodes;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800423 pi.versionName = p.mVersionName;
424 pi.sharedUserId = p.mSharedUserId;
425 pi.sharedUserLabel = p.mSharedUserLabel;
Dianne Hackborn7767eac2012-08-23 18:25:40 -0700426 pi.applicationInfo = generateApplicationInfo(p, flags, state, userId);
Suchi Amalapurapu117818e2010-02-09 03:45:40 -0800427 pi.installLocation = p.installLocation;
Jeff Hao272bf3a2014-10-08 13:34:43 -0700428 pi.coreApp = p.coreApp;
Amith Yamasani0d8750d2013-05-01 15:25:28 -0700429 if ((pi.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0
430 || (pi.applicationInfo.flags&ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) {
431 pi.requiredForAllUsers = p.mRequiredForAllUsers;
432 }
Amith Yamasani0ac1fc92013-03-27 18:56:08 -0700433 pi.restrictedAccountType = p.mRestrictedAccountType;
Amith Yamasaniccbe3892013-04-12 17:52:42 -0700434 pi.requiredAccountType = p.mRequiredAccountType;
MÃ¥rten Kongstad48d22322014-01-31 14:43:27 +0100435 pi.overlayTarget = p.mOverlayTarget;
Dianne Hackborn78d6883692010-10-07 01:12:46 -0700436 pi.firstInstallTime = firstInstallTime;
437 pi.lastUpdateTime = lastUpdateTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800438 if ((flags&PackageManager.GET_GIDS) != 0) {
439 pi.gids = gids;
440 }
441 if ((flags&PackageManager.GET_CONFIGURATIONS) != 0) {
Jeff Sharkeyda96e132014-07-15 14:54:09 -0700442 int N = p.configPreferences != null ? p.configPreferences.size() : 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800443 if (N > 0) {
444 pi.configPreferences = new ConfigurationInfo[N];
Dianne Hackborn49237342009-08-27 20:08:01 -0700445 p.configPreferences.toArray(pi.configPreferences);
446 }
447 N = p.reqFeatures != null ? p.reqFeatures.size() : 0;
448 if (N > 0) {
449 pi.reqFeatures = new FeatureInfo[N];
450 p.reqFeatures.toArray(pi.reqFeatures);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800451 }
Adam Lesinskid3edfde2014-08-08 17:32:44 -0700452 N = p.featureGroups != null ? p.featureGroups.size() : 0;
453 if (N > 0) {
454 pi.featureGroups = new FeatureGroupInfo[N];
455 p.featureGroups.toArray(pi.featureGroups);
456 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800457 }
458 if ((flags&PackageManager.GET_ACTIVITIES) != 0) {
459 int N = p.activities.size();
460 if (N > 0) {
Dianne Hackborn7eca6872009-09-28 23:57:05 -0700461 if ((flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) {
462 pi.activities = new ActivityInfo[N];
463 } else {
464 int num = 0;
465 for (int i=0; i<N; i++) {
466 if (p.activities.get(i).info.enabled) num++;
467 }
468 pi.activities = new ActivityInfo[num];
469 }
Suchi Amalapurapud83006c2009-10-28 23:39:46 -0700470 for (int i=0, j=0; i<N; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800471 final Activity activity = p.activities.get(i);
472 if (activity.info.enabled
473 || (flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) {
Amith Yamasani742a6712011-05-04 14:49:28 -0700474 pi.activities[j++] = generateActivityInfo(p.activities.get(i), flags,
Dianne Hackborn7767eac2012-08-23 18:25:40 -0700475 state, userId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800476 }
477 }
478 }
479 }
480 if ((flags&PackageManager.GET_RECEIVERS) != 0) {
481 int N = p.receivers.size();
482 if (N > 0) {
Dianne Hackborn7eca6872009-09-28 23:57:05 -0700483 if ((flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) {
484 pi.receivers = new ActivityInfo[N];
485 } else {
486 int num = 0;
487 for (int i=0; i<N; i++) {
488 if (p.receivers.get(i).info.enabled) num++;
489 }
490 pi.receivers = new ActivityInfo[num];
491 }
Suchi Amalapurapud83006c2009-10-28 23:39:46 -0700492 for (int i=0, j=0; i<N; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800493 final Activity activity = p.receivers.get(i);
494 if (activity.info.enabled
495 || (flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) {
Amith Yamasani13593602012-03-22 16:16:17 -0700496 pi.receivers[j++] = generateActivityInfo(p.receivers.get(i), flags,
Dianne Hackborn7767eac2012-08-23 18:25:40 -0700497 state, userId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800498 }
499 }
500 }
501 }
502 if ((flags&PackageManager.GET_SERVICES) != 0) {
503 int N = p.services.size();
504 if (N > 0) {
Dianne Hackborn7eca6872009-09-28 23:57:05 -0700505 if ((flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) {
506 pi.services = new ServiceInfo[N];
507 } else {
508 int num = 0;
509 for (int i=0; i<N; i++) {
510 if (p.services.get(i).info.enabled) num++;
511 }
512 pi.services = new ServiceInfo[num];
513 }
Suchi Amalapurapud83006c2009-10-28 23:39:46 -0700514 for (int i=0, j=0; i<N; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800515 final Service service = p.services.get(i);
516 if (service.info.enabled
517 || (flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) {
Dianne Hackborn7767eac2012-08-23 18:25:40 -0700518 pi.services[j++] = generateServiceInfo(p.services.get(i), flags,
519 state, userId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800520 }
521 }
522 }
523 }
524 if ((flags&PackageManager.GET_PROVIDERS) != 0) {
525 int N = p.providers.size();
526 if (N > 0) {
Dianne Hackborn7eca6872009-09-28 23:57:05 -0700527 if ((flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) {
528 pi.providers = new ProviderInfo[N];
529 } else {
530 int num = 0;
531 for (int i=0; i<N; i++) {
532 if (p.providers.get(i).info.enabled) num++;
533 }
534 pi.providers = new ProviderInfo[num];
535 }
Suchi Amalapurapud83006c2009-10-28 23:39:46 -0700536 for (int i=0, j=0; i<N; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800537 final Provider provider = p.providers.get(i);
538 if (provider.info.enabled
539 || (flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) {
Dianne Hackborn7767eac2012-08-23 18:25:40 -0700540 pi.providers[j++] = generateProviderInfo(p.providers.get(i), flags,
541 state, userId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800542 }
543 }
544 }
545 }
546 if ((flags&PackageManager.GET_INSTRUMENTATION) != 0) {
547 int N = p.instrumentation.size();
548 if (N > 0) {
549 pi.instrumentation = new InstrumentationInfo[N];
550 for (int i=0; i<N; i++) {
551 pi.instrumentation[i] = generateInstrumentationInfo(
552 p.instrumentation.get(i), flags);
553 }
554 }
555 }
556 if ((flags&PackageManager.GET_PERMISSIONS) != 0) {
557 int N = p.permissions.size();
558 if (N > 0) {
559 pi.permissions = new PermissionInfo[N];
560 for (int i=0; i<N; i++) {
561 pi.permissions[i] = generatePermissionInfo(p.permissions.get(i), flags);
562 }
563 }
564 N = p.requestedPermissions.size();
565 if (N > 0) {
566 pi.requestedPermissions = new String[N];
Dianne Hackborne639da72012-02-21 15:11:13 -0800567 pi.requestedPermissionsFlags = new int[N];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800568 for (int i=0; i<N; i++) {
Dianne Hackborne639da72012-02-21 15:11:13 -0800569 final String perm = p.requestedPermissions.get(i);
570 pi.requestedPermissions[i] = perm;
571 if (p.requestedPermissionsRequired.get(i)) {
572 pi.requestedPermissionsFlags[i] |= PackageInfo.REQUESTED_PERMISSION_REQUIRED;
573 }
574 if (grantedPermissions != null && grantedPermissions.contains(perm)) {
575 pi.requestedPermissionsFlags[i] |= PackageInfo.REQUESTED_PERMISSION_GRANTED;
576 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800577 }
578 }
579 }
580 if ((flags&PackageManager.GET_SIGNATURES) != 0) {
Suchi Amalapurapud83006c2009-10-28 23:39:46 -0700581 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);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800585 }
586 }
587 return pi;
588 }
589
Jeff Sharkey275e0852014-06-17 18:18:49 -0700590 private static Certificate[][] loadCertificates(StrictJarFile jarFile, ZipEntry entry)
591 throws PackageParserException {
592 InputStream is = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800593 try {
594 // We must read the stream for the JarEntry to retrieve
595 // its certificates.
Jeff Sharkey275e0852014-06-17 18:18:49 -0700596 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);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800604 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800605 }
606
Suchi Amalapurapuaf8e9f42010-01-12 10:17:28 -0800607 public final static int PARSE_IS_SYSTEM = 1<<0;
608 public final static int PARSE_CHATTY = 1<<1;
609 public final static int PARSE_MUST_BE_APK = 1<<2;
610 public final static int PARSE_IGNORE_PROCESSES = 1<<3;
611 public final static int PARSE_FORWARD_LOCK = 1<<4;
612 public final static int PARSE_ON_SDCARD = 1<<5;
Dianne Hackborn806da1d2010-03-18 16:50:07 -0700613 public final static int PARSE_IS_SYSTEM_DIR = 1<<6;
Christopher Tateccbf84f2013-05-08 15:25:41 -0700614 public final static int PARSE_IS_PRIVILEGED = 1<<7;
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700615 public final static int PARSE_COLLECT_CERTIFICATES = 1<<8;
Jeff Sharkey275e0852014-06-17 18:18:49 -0700616 public final static int PARSE_TRUSTED_OVERLAY = 1<<9;
617
618 private static final Comparator<String> sSplitNameComparator = new SplitNameComparator();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800619
Jeff Sharkeyc4858a22014-06-16 10:51:20 -0700620 /**
Jeff Sharkey275e0852014-06-17 18:18:49 -0700621 * Used to sort a set of APKs based on their split names, always placing the
622 * base APK (with {@code null} split name) first.
Jeff Sharkeyc4858a22014-06-16 10:51:20 -0700623 */
Jeff Sharkey275e0852014-06-17 18:18:49 -0700624 private static class SplitNameComparator implements Comparator<String> {
625 @Override
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
Jeff Sharkeyda96e132014-07-15 14:54:09 -0700637 /**
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 */
Jeff Sharkey73767b92014-07-04 20:18:13 -0700648 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
657 private static PackageLite parseMonolithicPackageLite(File packageFile, int flags)
658 throws PackageParserException {
Jeff Sharkeybe520fb2014-07-04 18:23:17 -0700659 final ApkLite baseApk = parseApkLite(packageFile, flags);
Jeff Sharkey73767b92014-07-04 20:18:13 -0700660 final String packagePath = packageFile.getAbsolutePath();
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -0800661 return new PackageLite(packagePath, baseApk, null, null, null);
Jeff Sharkey73767b92014-07-04 20:18:13 -0700662 }
663
664 private static PackageLite parseClusterPackageLite(File packageDir, int flags)
665 throws PackageParserException {
666 final File[] files = packageDir.listFiles();
Jeff Sharkeyc4858a22014-06-16 10:51:20 -0700667 if (ArrayUtils.isEmpty(files)) {
668 throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
669 "No packages found in split");
670 }
671
Jeff Sharkey275e0852014-06-17 18:18:49 -0700672 String packageName = null;
673 int versionCode = 0;
674
Jeff Sharkeybe520fb2014-07-04 18:23:17 -0700675 final ArrayMap<String, ApkLite> apks = new ArrayMap<>();
Jeff Sharkeyc4858a22014-06-16 10:51:20 -0700676 for (File file : files) {
Jeff Sharkey73767b92014-07-04 20:18:13 -0700677 if (isApkFile(file)) {
678 final ApkLite lite = parseApkLite(file, flags);
Jeff Sharkey275e0852014-06-17 18:18:49 -0700679
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 }
Jeff Sharkeyc4858a22014-06-16 10:51:20 -0700696 }
697
Jeff Sharkey275e0852014-06-17 18:18:49 -0700698 // Assert that each split is defined only once
Jeff Sharkeybe520fb2014-07-04 18:23:17 -0700699 if (apks.put(lite.splitName, lite) != null) {
Jeff Sharkey275e0852014-06-17 18:18:49 -0700700 throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
701 "Split name " + lite.splitName
702 + " defined more than once; most recent was " + file);
Jeff Sharkeyc4858a22014-06-16 10:51:20 -0700703 }
704 }
705 }
706
Jeff Sharkeybe520fb2014-07-04 18:23:17 -0700707 final ApkLite baseApk = apks.remove(null);
Jeff Sharkey73767b92014-07-04 20:18:13 -0700708 if (baseApk == null) {
Jeff Sharkey275e0852014-06-17 18:18:49 -0700709 throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
Jeff Sharkey73767b92014-07-04 20:18:13 -0700710 "Missing base APK in " + packageDir);
Jeff Sharkeyc4858a22014-06-16 10:51:20 -0700711 }
712
Jeff Sharkey57dcf5b2014-06-18 17:46:05 -0700713 // Always apply deterministic ordering based on splitName
714 final int size = apks.size();
Jeff Sharkey57dcf5b2014-06-18 17:46:05 -0700715
Jeff Sharkey73767b92014-07-04 20:18:13 -0700716 String[] splitNames = null;
717 String[] splitCodePaths = null;
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -0800718 int[] splitRevisionCodes = null;
Jeff Sharkey73767b92014-07-04 20:18:13 -0700719 if (size > 0) {
720 splitNames = new String[size];
721 splitCodePaths = new String[size];
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -0800722 splitRevisionCodes = new int[size];
Jeff Sharkey73767b92014-07-04 20:18:13 -0700723
724 splitNames = apks.keySet().toArray(splitNames);
725 Arrays.sort(splitNames, sSplitNameComparator);
726
727 for (int i = 0; i < size; i++) {
Jeff Sharkeybe520fb2014-07-04 18:23:17 -0700728 splitCodePaths[i] = apks.get(splitNames[i]).codePath;
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -0800729 splitRevisionCodes[i] = apks.get(splitNames[i]).revisionCode;
Jeff Sharkey73767b92014-07-04 20:18:13 -0700730 }
Jeff Sharkeyc4858a22014-06-16 10:51:20 -0700731 }
732
Jeff Sharkey73767b92014-07-04 20:18:13 -0700733 final String codePath = packageDir.getAbsolutePath();
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -0800734 return new PackageLite(codePath, baseApk, splitNames, splitCodePaths,
735 splitRevisionCodes);
Jeff Sharkey73767b92014-07-04 20:18:13 -0700736 }
737
Jeff Sharkeyda96e132014-07-15 14:54:09 -0700738 /**
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 */
Jeff Sharkey73767b92014-07-04 20:18:13 -0700752 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 */
769 private Package parseClusterPackage(File packageDir, int flags) throws PackageParserException {
770 final PackageLite lite = parseClusterPackageLite(packageDir, 0);
771
Jeff Sharkeyda96e132014-07-15 14:54:09 -0700772 if (mOnlyCoreApps && !lite.coreApp) {
773 throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
774 "Not a coreApp: " + packageDir);
775 }
776
Adam Lesinski3bcbd902014-08-22 17:01:04 -0700777 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);
Jeff Sharkey73767b92014-07-04 20:18:13 -0700782
Adam Lesinski3bcbd902014-08-22 17:01:04 -0700783 if (!ArrayUtils.isEmpty(lite.splitCodePaths)) {
784 for (String path : lite.splitCodePaths) {
785 loadApkIntoAssetManager(assets, path, flags);
786 }
Jeff Sharkey73767b92014-07-04 20:18:13 -0700787 }
Jeff Sharkey73767b92014-07-04 20:18:13 -0700788
Adam Lesinski3bcbd902014-08-22 17:01:04 -0700789 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;
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -0800800 pkg.splitRevisionCodes = lite.splitRevisionCodes;
Adam Lesinski3bcbd902014-08-22 17:01:04 -0700801 pkg.splitFlags = new int[num];
Alex Klyubinb9f8a522015-02-03 11:12:59 -0800802 pkg.splitPrivateFlags = new int[num];
Adam Lesinski3bcbd902014-08-22 17:01:04 -0700803
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 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800814 }
815
Jeff Sharkey275e0852014-06-17 18:18:49 -0700816 /**
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)}.
Jeff Sharkeyd7460572014-07-06 20:44:55 -0700821 *
822 * @deprecated external callers should move to
823 * {@link #parsePackage(File, int)}. Eventually this method will
824 * be marked private.
Jeff Sharkey275e0852014-06-17 18:18:49 -0700825 */
Jeff Sharkeyd7460572014-07-06 20:44:55 -0700826 @Deprecated
Jeff Sharkey275e0852014-06-17 18:18:49 -0700827 public Package parseMonolithicPackage(File apkFile, int flags) throws PackageParserException {
Jeff Sharkeyda96e132014-07-15 14:54:09 -0700828 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 }
Jeff Sharkeyc4858a22014-06-16 10:51:20 -0700834 }
Jeff Sharkey57dcf5b2014-06-18 17:46:05 -0700835
Adam Lesinski3bcbd902014-08-22 17:01:04 -0700836 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 }
Jeff Sharkeyc4858a22014-06-16 10:51:20 -0700844 }
845
Adam Lesinski3bcbd902014-08-22 17:01:04 -0700846 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
864 private Package parseBaseApk(File apkFile, AssetManager assets, int flags)
865 throws PackageParserException {
Jeff Sharkeyda96e132014-07-15 14:54:09 -0700866 final String apkPath = apkFile.getAbsolutePath();
Jeff Sharkey275e0852014-06-17 18:18:49 -0700867
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800868 mParseError = PackageManager.INSTALL_SUCCEEDED;
Jeff Sharkeyc4858a22014-06-16 10:51:20 -0700869 mArchiveSourcePath = apkFile.getAbsolutePath();
Jeff Sharkeyda96e132014-07-15 14:54:09 -0700870
Jeff Sharkeyda96e132014-07-15 14:54:09 -0700871 if (DEBUG_JAR) Slog.d(TAG, "Scanning base APK: " + apkPath);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800872
Adam Lesinski3bcbd902014-08-22 17:01:04 -0700873 final int cookie = loadApkIntoAssetManager(assets, apkPath, flags);
874
Dianne Hackborn3b81bc12011-01-15 11:50:52 -0800875 Resources res = null;
Jeff Sharkeyda96e132014-07-15 14:54:09 -0700876 XmlResourceParser parser = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800877 try {
Jeff Sharkeyda96e132014-07-15 14:54:09 -0700878 res = new Resources(assets, mMetrics, null);
879 assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
880 Build.VERSION.RESOURCES_SDK_INT);
881 parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);
882
883 final String[] outError = new String[1];
884 final Package pkg = parseBaseApk(res, parser, flags, outError);
885 if (pkg == null) {
886 throw new PackageParserException(mParseError,
887 apkPath + " (at " + parser.getPositionDescription() + "): " + outError[0]);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800888 }
Jeff Sharkeyda96e132014-07-15 14:54:09 -0700889
890 pkg.baseCodePath = apkPath;
891 pkg.mSignatures = null;
892
Jeff Sharkeyda96e132014-07-15 14:54:09 -0700893 return pkg;
894
895 } catch (PackageParserException e) {
896 throw e;
897 } catch (Exception e) {
898 throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
Jeff Sharkey78a13012014-07-15 20:18:34 -0700899 "Failed to read manifest from " + apkPath, e);
Jeff Sharkeyda96e132014-07-15 14:54:09 -0700900 } finally {
901 IoUtils.closeQuietly(parser);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800902 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800903 }
904
Adam Lesinski3bcbd902014-08-22 17:01:04 -0700905 private void parseSplitApk(Package pkg, int splitIndex, AssetManager assets, int flags)
Jeff Sharkeyda96e132014-07-15 14:54:09 -0700906 throws PackageParserException {
907 final String apkPath = pkg.splitCodePaths[splitIndex];
908 final File apkFile = new File(apkPath);
Jeff Sharkey275e0852014-06-17 18:18:49 -0700909
Jeff Sharkeyda96e132014-07-15 14:54:09 -0700910 mParseError = PackageManager.INSTALL_SUCCEEDED;
911 mArchiveSourcePath = apkPath;
912
Jeff Sharkeyda96e132014-07-15 14:54:09 -0700913 if (DEBUG_JAR) Slog.d(TAG, "Scanning split APK: " + apkPath);
914
Adam Lesinski3bcbd902014-08-22 17:01:04 -0700915 final int cookie = loadApkIntoAssetManager(assets, apkPath, flags);
916
Jeff Sharkeyda96e132014-07-15 14:54:09 -0700917 Resources res = null;
918 XmlResourceParser parser = null;
919 try {
Jeff Sharkeyda96e132014-07-15 14:54:09 -0700920 res = new Resources(assets, mMetrics, null);
921 assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
922 Build.VERSION.RESOURCES_SDK_INT);
923 parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);
924
925 final String[] outError = new String[1];
926 pkg = parseSplitApk(pkg, res, parser, flags, splitIndex, outError);
927 if (pkg == null) {
928 throw new PackageParserException(mParseError,
929 apkPath + " (at " + parser.getPositionDescription() + "): " + outError[0]);
930 }
931
932 } catch (PackageParserException e) {
933 throw e;
934 } catch (Exception e) {
935 throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
Jeff Sharkey78a13012014-07-15 20:18:34 -0700936 "Failed to read manifest from " + apkPath, e);
Jeff Sharkeyda96e132014-07-15 14:54:09 -0700937 } finally {
938 IoUtils.closeQuietly(parser);
Jeff Sharkeyda96e132014-07-15 14:54:09 -0700939 }
940 }
941
942 /**
943 * Parse the manifest of a <em>split APK</em>.
944 * <p>
945 * Note that split APKs have many more restrictions on what they're capable
946 * of doing, so many valid features of a base APK have been carefully
947 * omitted here.
948 */
949 private Package parseSplitApk(Package pkg, Resources res, XmlResourceParser parser, int flags,
Jeff Sharkey78a13012014-07-15 20:18:34 -0700950 int splitIndex, String[] outError) throws XmlPullParserException, IOException,
951 PackageParserException {
Jeff Sharkeyda96e132014-07-15 14:54:09 -0700952 AttributeSet attrs = parser;
953
Jeff Sharkey78a13012014-07-15 20:18:34 -0700954 // We parsed manifest tag earlier; just skip past it
955 parsePackageSplitNames(parser, attrs, flags);
956
Jeff Sharkeyda96e132014-07-15 14:54:09 -0700957 mParseInstrumentationArgs = null;
958 mParseActivityArgs = null;
959 mParseServiceArgs = null;
960 mParseProviderArgs = null;
961
962 int type;
963
964 boolean foundApp = false;
965
966 int outerDepth = parser.getDepth();
967 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
968 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
969 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
970 continue;
971 }
972
973 String tagName = parser.getName();
974 if (tagName.equals("application")) {
975 if (foundApp) {
976 if (RIGID_PARSER) {
977 outError[0] = "<manifest> has more than one <application>";
978 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
979 return null;
980 } else {
981 Slog.w(TAG, "<manifest> has more than one <application>");
982 XmlUtils.skipCurrentTag(parser);
983 continue;
984 }
985 }
986
987 foundApp = true;
988 if (!parseSplitApplication(pkg, res, parser, attrs, flags, splitIndex, outError)) {
989 return null;
990 }
991
992 } else if (RIGID_PARSER) {
993 outError[0] = "Bad element under <manifest>: "
994 + parser.getName();
995 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
996 return null;
997
998 } else {
999 Slog.w(TAG, "Unknown element under <manifest>: " + parser.getName()
1000 + " at " + mArchiveSourcePath + " "
1001 + parser.getPositionDescription());
1002 XmlUtils.skipCurrentTag(parser);
1003 continue;
1004 }
1005 }
1006
1007 if (!foundApp) {
1008 outError[0] = "<manifest> does not contain an <application>";
1009 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_EMPTY;
1010 }
1011
1012 return pkg;
Jeff Sharkeyc4858a22014-06-16 10:51:20 -07001013 }
1014
Kenny Root6c918ce2013-04-02 14:04:24 -07001015 /**
1016 * Gathers the {@link ManifestDigest} for {@code pkg} if it exists in the
1017 * APK. If it successfully scanned the package and found the
1018 * {@code AndroidManifest.xml}, {@code true} is returned.
1019 */
Jeff Sharkeyc4858a22014-06-16 10:51:20 -07001020 public void collectManifestDigest(Package pkg) throws PackageParserException {
Jeff Sharkey032f2b22014-06-19 15:48:47 -07001021 pkg.manifestDigest = null;
1022
Jeff Sharkey275e0852014-06-17 18:18:49 -07001023 // TODO: extend to gather digest for split APKs
Kenny Root6c918ce2013-04-02 14:04:24 -07001024 try {
Jeff Sharkey57dcf5b2014-06-18 17:46:05 -07001025 final StrictJarFile jarFile = new StrictJarFile(pkg.baseCodePath);
Kenny Root6c918ce2013-04-02 14:04:24 -07001026 try {
Narayan Kamatheb565dc2013-12-12 16:54:33 +00001027 final ZipEntry je = jarFile.findEntry(ANDROID_MANIFEST_FILENAME);
Kenny Root6c918ce2013-04-02 14:04:24 -07001028 if (je != null) {
1029 pkg.manifestDigest = ManifestDigest.fromInputStream(jarFile.getInputStream(je));
1030 }
1031 } finally {
1032 jarFile.close();
1033 }
Jeff Sharkey275e0852014-06-17 18:18:49 -07001034 } catch (IOException | RuntimeException e) {
Jeff Sharkeyc4858a22014-06-16 10:51:20 -07001035 throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
1036 "Failed to collect manifest digest");
Kenny Root6c918ce2013-04-02 14:04:24 -07001037 }
1038 }
1039
Jeff Sharkey275e0852014-06-17 18:18:49 -07001040 /**
1041 * Collect certificates from all the APKs described in the given package,
1042 * populating {@link Package#mSignatures}. This also asserts that all APK
1043 * contents are signed correctly and consistently.
1044 */
Jeff Sharkeyc4858a22014-06-16 10:51:20 -07001045 public void collectCertificates(Package pkg, int flags) throws PackageParserException {
Jeff Sharkey275e0852014-06-17 18:18:49 -07001046 pkg.mCertificates = null;
1047 pkg.mSignatures = null;
1048 pkg.mSigningKeys = null;
1049
Jeff Sharkey57dcf5b2014-06-18 17:46:05 -07001050 collectCertificates(pkg, new File(pkg.baseCodePath), flags);
Jeff Sharkey275e0852014-06-17 18:18:49 -07001051
1052 if (!ArrayUtils.isEmpty(pkg.splitCodePaths)) {
1053 for (String splitCodePath : pkg.splitCodePaths) {
1054 collectCertificates(pkg, new File(splitCodePath), flags);
1055 }
Jeff Sharkeyc4858a22014-06-16 10:51:20 -07001056 }
1057 }
1058
Jeff Sharkey275e0852014-06-17 18:18:49 -07001059 private static void collectCertificates(Package pkg, File apkFile, int flags)
1060 throws PackageParserException {
1061 final String apkPath = apkFile.getAbsolutePath();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001062
Jeff Sharkey275e0852014-06-17 18:18:49 -07001063 StrictJarFile jarFile = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001064 try {
Jeff Sharkey275e0852014-06-17 18:18:49 -07001065 jarFile = new StrictJarFile(apkPath);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001066
Jeff Sharkey275e0852014-06-17 18:18:49 -07001067 // Always verify manifest, regardless of source
1068 final ZipEntry manifestEntry = jarFile.findEntry(ANDROID_MANIFEST_FILENAME);
1069 if (manifestEntry == null) {
1070 throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
1071 "Package " + apkPath + " has no manifest");
1072 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001073
Jeff Sharkey275e0852014-06-17 18:18:49 -07001074 final List<ZipEntry> toVerify = new ArrayList<>();
1075 toVerify.add(manifestEntry);
1076
1077 // If we're parsing an untrusted package, verify all contents
1078 if ((flags & PARSE_IS_SYSTEM) == 0) {
1079 final Iterator<ZipEntry> i = jarFile.iterator();
1080 while (i.hasNext()) {
1081 final ZipEntry entry = i.next();
1082
1083 if (entry.isDirectory()) continue;
1084 if (entry.getName().startsWith("META-INF/")) continue;
1085 if (entry.getName().equals(ANDROID_MANIFEST_FILENAME)) continue;
1086
1087 toVerify.add(entry);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001088 }
Jeff Sharkey275e0852014-06-17 18:18:49 -07001089 }
1090
1091 // Verify that entries are signed consistently with the first entry
1092 // we encountered. Note that for splits, certificates may have
1093 // already been populated during an earlier parse of a base APK.
1094 for (ZipEntry entry : toVerify) {
1095 final Certificate[][] entryCerts = loadCertificates(jarFile, entry);
1096 if (ArrayUtils.isEmpty(entryCerts)) {
1097 throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
1098 "Package " + apkPath + " has no certificates at entry "
1099 + entry.getName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001100 }
Jeff Sharkeyec55ef02014-07-08 11:28:00 -07001101 final Signature[] entrySignatures = convertToSignatures(entryCerts);
Kenny Rootd2d29252011-08-08 11:27:57 -07001102
Jeff Sharkey275e0852014-06-17 18:18:49 -07001103 if (pkg.mCertificates == null) {
1104 pkg.mCertificates = entryCerts;
Jeff Sharkeyec55ef02014-07-08 11:28:00 -07001105 pkg.mSignatures = entrySignatures;
dcashman55b10782014-04-09 14:20:38 -07001106 pkg.mSigningKeys = new ArraySet<PublicKey>();
1107 for (int i=0; i < entryCerts.length; i++) {
Jeff Sharkey275e0852014-06-17 18:18:49 -07001108 pkg.mSigningKeys.add(entryCerts[i][0].getPublicKey());
Kenny Rootbcc954d2011-08-08 16:19:08 -07001109 }
Jeff Sharkey275e0852014-06-17 18:18:49 -07001110 } else {
Jeff Sharkeyec55ef02014-07-08 11:28:00 -07001111 if (!Signature.areExactMatch(pkg.mSignatures, entrySignatures)) {
Jeff Sharkey275e0852014-06-17 18:18:49 -07001112 throw new PackageParserException(
1113 INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES, "Package " + apkPath
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001114 + " has mismatched certificates at entry "
Jeff Sharkey275e0852014-06-17 18:18:49 -07001115 + entry.getName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001116 }
1117 }
1118 }
Jeff Sharkeybc097552014-09-09 14:57:26 -07001119 } catch (GeneralSecurityException e) {
Jeff Sharkey275e0852014-06-17 18:18:49 -07001120 throw new PackageParserException(INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING,
1121 "Failed to collect certificates from " + apkPath, e);
Jeff Sharkeybc097552014-09-09 14:57:26 -07001122 } catch (IOException | RuntimeException e) {
1123 throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
1124 "Failed to collect certificates from " + apkPath, e);
Jeff Sharkey275e0852014-06-17 18:18:49 -07001125 } finally {
1126 closeQuietly(jarFile);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001127 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001128 }
1129
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001130 private static Signature[] convertToSignatures(Certificate[][] certs)
1131 throws CertificateEncodingException {
1132 final Signature[] res = new Signature[certs.length];
1133 for (int i = 0; i < certs.length; i++) {
1134 res[i] = new Signature(certs[i]);
1135 }
1136 return res;
1137 }
1138
Jeff Sharkey275e0852014-06-17 18:18:49 -07001139 /**
1140 * Utility method that retrieves lightweight details about a single APK
1141 * file, including package name, split name, and install location.
1142 *
1143 * @param apkFile path to a single APK
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -07001144 * @param flags optional parse flags, such as
1145 * {@link #PARSE_COLLECT_CERTIFICATES}
Suchi Amalapurapua2b6c372010-03-05 17:40:11 -08001146 */
Jeff Sharkey275e0852014-06-17 18:18:49 -07001147 public static ApkLite parseApkLite(File apkFile, int flags)
1148 throws PackageParserException {
1149 final String apkPath = apkFile.getAbsolutePath();
1150
Jeff Sharkeyda96e132014-07-15 14:54:09 -07001151 AssetManager assets = null;
Jeff Sharkey275e0852014-06-17 18:18:49 -07001152 XmlResourceParser parser = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001153 try {
Jeff Sharkeyda96e132014-07-15 14:54:09 -07001154 assets = new AssetManager();
1155 assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
Dianne Hackborn3b81bc12011-01-15 11:50:52 -08001156 Build.VERSION.RESOURCES_SDK_INT);
Kenny Root1ebd74a2011-08-03 15:09:44 -07001157
Jeff Sharkeyda96e132014-07-15 14:54:09 -07001158 int cookie = assets.addAssetPath(apkPath);
Kenny Root1ebd74a2011-08-03 15:09:44 -07001159 if (cookie == 0) {
Jeff Sharkey275e0852014-06-17 18:18:49 -07001160 throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
1161 "Failed to parse " + apkPath);
Kenny Root1ebd74a2011-08-03 15:09:44 -07001162 }
1163
Kenny Root05ca4c92011-09-15 10:36:25 -07001164 final DisplayMetrics metrics = new DisplayMetrics();
1165 metrics.setToDefaults();
Jeff Sharkey275e0852014-06-17 18:18:49 -07001166
Jeff Sharkeyda96e132014-07-15 14:54:09 -07001167 final Resources res = new Resources(assets, metrics, null);
1168 parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);
Kenny Root05ca4c92011-09-15 10:36:25 -07001169
Jeff Sharkey275e0852014-06-17 18:18:49 -07001170 final Signature[] signatures;
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -07001171 if ((flags & PARSE_COLLECT_CERTIFICATES) != 0) {
1172 // TODO: factor signature related items out of Package object
1173 final Package tempPkg = new Package(null);
1174 collectCertificates(tempPkg, apkFile, 0);
1175 signatures = tempPkg.mSignatures;
Jeff Sharkey275e0852014-06-17 18:18:49 -07001176 } else {
1177 signatures = null;
1178 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001179
Jeff Sharkey275e0852014-06-17 18:18:49 -07001180 final AttributeSet attrs = parser;
Jeff Sharkeybe520fb2014-07-04 18:23:17 -07001181 return parseApkLite(apkPath, res, parser, attrs, flags, signatures);
Jeff Sharkey275e0852014-06-17 18:18:49 -07001182
1183 } catch (XmlPullParserException | IOException | RuntimeException e) {
1184 throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
1185 "Failed to parse " + apkPath, e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001186 } finally {
Jeff Sharkeyda96e132014-07-15 14:54:09 -07001187 IoUtils.closeQuietly(parser);
1188 IoUtils.closeQuietly(assets);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001189 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001190 }
1191
1192 private static String validateName(String name, boolean requiresSeparator) {
1193 final int N = name.length();
1194 boolean hasSep = false;
1195 boolean front = true;
1196 for (int i=0; i<N; i++) {
1197 final char c = name.charAt(i);
1198 if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
1199 front = false;
1200 continue;
1201 }
1202 if (!front) {
1203 if ((c >= '0' && c <= '9') || c == '_') {
1204 continue;
1205 }
1206 }
1207 if (c == '.') {
1208 hasSep = true;
1209 front = true;
1210 continue;
1211 }
1212 return "bad character '" + c + "'";
1213 }
1214 return hasSep || !requiresSeparator
1215 ? null : "must have at least one '.' separator";
1216 }
1217
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001218 private static Pair<String, String> parsePackageSplitNames(XmlPullParser parser,
1219 AttributeSet attrs, int flags) throws IOException, XmlPullParserException,
1220 PackageParserException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001221
1222 int type;
Kenny Rootd2d29252011-08-08 11:27:57 -07001223 while ((type = parser.next()) != XmlPullParser.START_TAG
1224 && type != XmlPullParser.END_DOCUMENT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001225 }
1226
Kenny Rootd2d29252011-08-08 11:27:57 -07001227 if (type != XmlPullParser.START_TAG) {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001228 throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
1229 "No start tag found");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001230 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001231 if (!parser.getName().equals("manifest")) {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001232 throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
1233 "No <manifest> tag");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001234 }
1235
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001236 final String packageName = attrs.getAttributeValue(null, "package");
1237 if (!"android".equals(packageName)) {
1238 final String error = validateName(packageName, true);
1239 if (error != null) {
1240 throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
1241 "Invalid manifest package: " + error);
1242 }
1243 }
1244
Jeff Sharkey275e0852014-06-17 18:18:49 -07001245 String splitName = attrs.getAttributeValue(null, "split");
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001246 if (splitName != null) {
Jeff Sharkey275e0852014-06-17 18:18:49 -07001247 if (splitName.length() == 0) {
1248 splitName = null;
1249 } else {
Jeff Sharkeyec55ef02014-07-08 11:28:00 -07001250 final String error = validateName(splitName, false);
Jeff Sharkey275e0852014-06-17 18:18:49 -07001251 if (error != null) {
1252 throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
1253 "Invalid manifest split: " + error);
1254 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001255 }
1256 }
1257
1258 return Pair.create(packageName.intern(),
1259 (splitName != null) ? splitName.intern() : splitName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001260 }
1261
Jeff Sharkeybe520fb2014-07-04 18:23:17 -07001262 private static ApkLite parseApkLite(String codePath, Resources res, XmlPullParser parser,
Jeff Sharkey275e0852014-06-17 18:18:49 -07001263 AttributeSet attrs, int flags, Signature[] signatures) throws IOException,
1264 XmlPullParserException, PackageParserException {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001265 final Pair<String, String> packageSplit = parsePackageSplitNames(parser, attrs, flags);
Suchi Amalapurapua2b6c372010-03-05 17:40:11 -08001266
Suchi Amalapurapu90d8ee62010-03-18 11:38:35 -07001267 int installLocation = PARSE_DEFAULT_INSTALL_LOCATION;
Dianne Hackborn7767eac2012-08-23 18:25:40 -07001268 int versionCode = 0;
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -08001269 int revisionCode = 0;
Jeff Sharkeyda96e132014-07-15 14:54:09 -07001270 boolean coreApp = false;
Narayan Kamathff110bd2014-07-04 18:30:45 +01001271 boolean multiArch = false;
Jeff Sharkeyda96e132014-07-15 14:54:09 -07001272
Suchi Amalapurapua2b6c372010-03-05 17:40:11 -08001273 for (int i = 0; i < attrs.getAttributeCount(); i++) {
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -08001274 final String attr = attrs.getAttributeName(i);
Suchi Amalapurapua2b6c372010-03-05 17:40:11 -08001275 if (attr.equals("installLocation")) {
1276 installLocation = attrs.getAttributeIntValue(i,
Suchi Amalapurapu90d8ee62010-03-18 11:38:35 -07001277 PARSE_DEFAULT_INSTALL_LOCATION);
Dianne Hackborn7767eac2012-08-23 18:25:40 -07001278 } else if (attr.equals("versionCode")) {
1279 versionCode = attrs.getAttributeIntValue(i, 0);
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -08001280 } else if (attr.equals("revisionCode")) {
1281 revisionCode = attrs.getAttributeIntValue(i, 0);
Jeff Sharkeyda96e132014-07-15 14:54:09 -07001282 } else if (attr.equals("coreApp")) {
1283 coreApp = attrs.getAttributeBooleanValue(i, false);
Suchi Amalapurapua2b6c372010-03-05 17:40:11 -08001284 }
1285 }
Kenny Root05ca4c92011-09-15 10:36:25 -07001286
1287 // Only search the tree when the tag is directly below <manifest>
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001288 int type;
Kenny Root05ca4c92011-09-15 10:36:25 -07001289 final int searchDepth = parser.getDepth() + 1;
1290
1291 final List<VerifierInfo> verifiers = new ArrayList<VerifierInfo>();
1292 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
1293 && (type != XmlPullParser.END_TAG || parser.getDepth() >= searchDepth)) {
1294 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
1295 continue;
1296 }
1297
1298 if (parser.getDepth() == searchDepth && "package-verifier".equals(parser.getName())) {
Jeff Sharkey275e0852014-06-17 18:18:49 -07001299 final VerifierInfo verifier = parseVerifier(res, parser, attrs, flags);
Kenny Root05ca4c92011-09-15 10:36:25 -07001300 if (verifier != null) {
1301 verifiers.add(verifier);
1302 }
1303 }
Narayan Kamatha8755a82014-07-15 12:26:35 +01001304
1305 if (parser.getDepth() == searchDepth && "application".equals(parser.getName())) {
1306 for (int i = 0; i < attrs.getAttributeCount(); ++i) {
1307 final String attr = attrs.getAttributeName(i);
1308 if ("multiArch".equals(attr)) {
1309 multiArch = attrs.getAttributeBooleanValue(i, false);
1310 break;
1311 }
1312 }
1313 }
Kenny Root05ca4c92011-09-15 10:36:25 -07001314 }
1315
Jeff Sharkeybe520fb2014-07-04 18:23:17 -07001316 return new ApkLite(codePath, packageSplit.first, packageSplit.second, versionCode,
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -08001317 revisionCode, installLocation, verifiers, signatures, coreApp, multiArch);
Suchi Amalapurapua2b6c372010-03-05 17:40:11 -08001318 }
1319
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001320 /**
1321 * Temporary.
1322 */
1323 static public Signature stringToSignature(String str) {
1324 final int N = str.length();
1325 byte[] sig = new byte[N];
1326 for (int i=0; i<N; i++) {
1327 sig[i] = (byte)str.charAt(i);
1328 }
1329 return new Signature(sig);
1330 }
1331
Jeff Sharkeyda96e132014-07-15 14:54:09 -07001332 /**
1333 * Parse the manifest of a <em>base APK</em>.
1334 * <p>
1335 * When adding new features, carefully consider if they should also be
1336 * supported by split APKs.
1337 */
Jeff Sharkeyc4858a22014-06-16 10:51:20 -07001338 private Package parseBaseApk(Resources res, XmlResourceParser parser, int flags,
Jeff Sharkeyda96e132014-07-15 14:54:09 -07001339 String[] outError) throws XmlPullParserException, IOException {
1340 final boolean trustedOverlay = (flags & PARSE_TRUSTED_OVERLAY) != 0;
1341
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001342 AttributeSet attrs = parser;
1343
Dianne Hackborn1d442e02009-04-20 18:14:05 -07001344 mParseInstrumentationArgs = null;
1345 mParseActivityArgs = null;
1346 mParseServiceArgs = null;
1347 mParseProviderArgs = null;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001348
1349 final String pkgName;
1350 final String splitName;
1351 try {
1352 Pair<String, String> packageSplit = parsePackageSplitNames(parser, attrs, flags);
1353 pkgName = packageSplit.first;
1354 splitName = packageSplit.second;
1355 } catch (PackageParserException e) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001356 mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME;
1357 return null;
1358 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001359
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001360 int type;
1361
Jeff Sharkeyc4858a22014-06-16 10:51:20 -07001362 if (!TextUtils.isEmpty(splitName)) {
1363 outError[0] = "Expected base APK, but found split " + splitName;
1364 mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME;
1365 return null;
1366 }
1367
1368 final Package pkg = new Package(pkgName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001369 boolean foundApp = false;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001370
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001371 TypedArray sa = res.obtainAttributes(attrs,
1372 com.android.internal.R.styleable.AndroidManifest);
Dianne Hackborn8472e612014-01-23 17:57:20 -08001373 pkg.mVersionCode = pkg.applicationInfo.versionCode = sa.getInteger(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001374 com.android.internal.R.styleable.AndroidManifest_versionCode, 0);
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -08001375 pkg.baseRevisionCode = sa.getInteger(
1376 com.android.internal.R.styleable.AndroidManifest_revisionCode, 0);
Dianne Hackborncf244ad2010-03-09 15:00:30 -08001377 pkg.mVersionName = sa.getNonConfigurationString(
1378 com.android.internal.R.styleable.AndroidManifest_versionName, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001379 if (pkg.mVersionName != null) {
1380 pkg.mVersionName = pkg.mVersionName.intern();
1381 }
Dianne Hackborncf244ad2010-03-09 15:00:30 -08001382 String str = sa.getNonConfigurationString(
1383 com.android.internal.R.styleable.AndroidManifest_sharedUserId, 0);
1384 if (str != null && str.length() > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001385 String nameError = validateName(str, true);
1386 if (nameError != null && !"android".equals(pkgName)) {
1387 outError[0] = "<manifest> specifies bad sharedUserId name \""
1388 + str + "\": " + nameError;
1389 mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID;
1390 return null;
1391 }
1392 pkg.mSharedUserId = str.intern();
1393 pkg.mSharedUserLabel = sa.getResourceId(
1394 com.android.internal.R.styleable.AndroidManifest_sharedUserLabel, 0);
1395 }
Suchi Amalapurapuaaec7792010-02-25 11:49:43 -08001396
Suchi Amalapurapu117818e2010-02-09 03:45:40 -08001397 pkg.installLocation = sa.getInteger(
1398 com.android.internal.R.styleable.AndroidManifest_installLocation,
Suchi Amalapurapu90d8ee62010-03-18 11:38:35 -07001399 PARSE_DEFAULT_INSTALL_LOCATION);
Dianne Hackborn54e570f2010-10-04 18:32:32 -07001400 pkg.applicationInfo.installLocation = pkg.installLocation;
Kenny Root7cb9be22012-05-30 15:30:37 -07001401
Jeff Hao272bf3a2014-10-08 13:34:43 -07001402 pkg.coreApp = attrs.getAttributeBooleanValue(null, "coreApp", false);
1403
Alan Viverettefd274a02014-03-27 15:39:15 -07001404 sa.recycle();
1405
Kenny Root7cb9be22012-05-30 15:30:37 -07001406 /* Set the global "forward lock" flag */
1407 if ((flags & PARSE_FORWARD_LOCK) != 0) {
Alex Klyubinb9f8a522015-02-03 11:12:59 -08001408 pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK;
Kenny Root7cb9be22012-05-30 15:30:37 -07001409 }
1410
1411 /* Set the global "on SD card" flag */
1412 if ((flags & PARSE_ON_SDCARD) != 0) {
1413 pkg.applicationInfo.flags |= ApplicationInfo.FLAG_EXTERNAL_STORAGE;
1414 }
1415
Dianne Hackborn723738c2009-06-25 19:48:04 -07001416 // Resource boolean are -1, so 1 means we don't know the value.
1417 int supportsSmallScreens = 1;
1418 int supportsNormalScreens = 1;
1419 int supportsLargeScreens = 1;
Dianne Hackborn14cee9f2010-04-23 17:51:26 -07001420 int supportsXLargeScreens = 1;
Dianne Hackbornc4db95c2009-07-21 17:46:02 -07001421 int resizeable = 1;
Dianne Hackborn11b822d2009-07-21 20:03:02 -07001422 int anyDensity = 1;
Dianne Hackborn723738c2009-06-25 19:48:04 -07001423
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001424 int outerDepth = parser.getDepth();
Kenny Rootd2d29252011-08-08 11:27:57 -07001425 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
1426 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
1427 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001428 continue;
1429 }
1430
1431 String tagName = parser.getName();
1432 if (tagName.equals("application")) {
1433 if (foundApp) {
1434 if (RIGID_PARSER) {
1435 outError[0] = "<manifest> has more than one <application>";
1436 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1437 return null;
1438 } else {
Kenny Rootd2d29252011-08-08 11:27:57 -07001439 Slog.w(TAG, "<manifest> has more than one <application>");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001440 XmlUtils.skipCurrentTag(parser);
1441 continue;
1442 }
1443 }
1444
1445 foundApp = true;
Jeff Sharkeyda96e132014-07-15 14:54:09 -07001446 if (!parseBaseApplication(pkg, res, parser, attrs, flags, outError)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001447 return null;
1448 }
MÃ¥rten Kongstad48d22322014-01-31 14:43:27 +01001449 } else if (tagName.equals("overlay")) {
1450 pkg.mTrustedOverlay = trustedOverlay;
1451
1452 sa = res.obtainAttributes(attrs,
1453 com.android.internal.R.styleable.AndroidManifestResourceOverlay);
1454 pkg.mOverlayTarget = sa.getString(
1455 com.android.internal.R.styleable.AndroidManifestResourceOverlay_targetPackage);
1456 pkg.mOverlayPriority = sa.getInt(
1457 com.android.internal.R.styleable.AndroidManifestResourceOverlay_priority,
1458 -1);
1459 sa.recycle();
1460
1461 if (pkg.mOverlayTarget == null) {
1462 outError[0] = "<overlay> does not specify a target package";
1463 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1464 return null;
1465 }
1466 if (pkg.mOverlayPriority < 0 || pkg.mOverlayPriority > 9999) {
1467 outError[0] = "<overlay> priority must be between 0 and 9999";
1468 mParseError =
1469 PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1470 return null;
1471 }
1472 XmlUtils.skipCurrentTag(parser);
1473
dcashman989eb3712014-06-17 12:56:12 -07001474 } else if (tagName.equals("key-sets")) {
1475 if (!parseKeySets(pkg, res, parser, attrs, outError)) {
Geremy Condraf1bcca82013-01-07 22:35:24 -08001476 return null;
1477 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001478 } else if (tagName.equals("permission-group")) {
Dianne Hackbornfd5015b2012-04-30 16:33:56 -07001479 if (parsePermissionGroup(pkg, flags, res, parser, attrs, outError) == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001480 return null;
1481 }
1482 } else if (tagName.equals("permission")) {
1483 if (parsePermission(pkg, res, parser, attrs, outError) == null) {
1484 return null;
1485 }
1486 } else if (tagName.equals("permission-tree")) {
1487 if (parsePermissionTree(pkg, res, parser, attrs, outError) == null) {
1488 return null;
1489 }
1490 } else if (tagName.equals("uses-permission")) {
Nick Kralevich73f2d3c2013-04-04 14:38:13 -07001491 if (!parseUsesPermission(pkg, res, parser, attrs, outError)) {
1492 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001493 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001494 } else if (tagName.equals("uses-configuration")) {
1495 ConfigurationInfo cPref = new ConfigurationInfo();
1496 sa = res.obtainAttributes(attrs,
1497 com.android.internal.R.styleable.AndroidManifestUsesConfiguration);
1498 cPref.reqTouchScreen = sa.getInt(
1499 com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqTouchScreen,
1500 Configuration.TOUCHSCREEN_UNDEFINED);
1501 cPref.reqKeyboardType = sa.getInt(
1502 com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqKeyboardType,
1503 Configuration.KEYBOARD_UNDEFINED);
1504 if (sa.getBoolean(
1505 com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqHardKeyboard,
1506 false)) {
1507 cPref.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
1508 }
1509 cPref.reqNavigation = sa.getInt(
1510 com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqNavigation,
1511 Configuration.NAVIGATION_UNDEFINED);
1512 if (sa.getBoolean(
1513 com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqFiveWayNav,
1514 false)) {
1515 cPref.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
1516 }
1517 sa.recycle();
Jeff Sharkeyda96e132014-07-15 14:54:09 -07001518 pkg.configPreferences = ArrayUtils.add(pkg.configPreferences, cPref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001519
1520 XmlUtils.skipCurrentTag(parser);
1521
Suchi Amalapurapud299b812009-06-05 10:26:19 -07001522 } else if (tagName.equals("uses-feature")) {
Adam Lesinskid3edfde2014-08-08 17:32:44 -07001523 FeatureInfo fi = parseUsesFeature(res, attrs);
Jeff Sharkeyda96e132014-07-15 14:54:09 -07001524 pkg.reqFeatures = ArrayUtils.add(pkg.reqFeatures, fi);
1525
Dianne Hackborn49237342009-08-27 20:08:01 -07001526 if (fi.name == null) {
1527 ConfigurationInfo cPref = new ConfigurationInfo();
1528 cPref.reqGlEsVersion = fi.reqGlEsVersion;
Jeff Sharkeyda96e132014-07-15 14:54:09 -07001529 pkg.configPreferences = ArrayUtils.add(pkg.configPreferences, cPref);
Dianne Hackborn49237342009-08-27 20:08:01 -07001530 }
Suchi Amalapurapud299b812009-06-05 10:26:19 -07001531
1532 XmlUtils.skipCurrentTag(parser);
1533
Adam Lesinski2c72b682014-06-24 09:56:01 -07001534 } else if (tagName.equals("feature-group")) {
Adam Lesinskid3edfde2014-08-08 17:32:44 -07001535 FeatureGroupInfo group = new FeatureGroupInfo();
1536 ArrayList<FeatureInfo> features = null;
1537 final int innerDepth = parser.getDepth();
1538 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
1539 && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
1540 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
1541 continue;
1542 }
Adam Lesinski2c72b682014-06-24 09:56:01 -07001543
Adam Lesinskid3edfde2014-08-08 17:32:44 -07001544 final String innerTagName = parser.getName();
1545 if (innerTagName.equals("uses-feature")) {
1546 FeatureInfo featureInfo = parseUsesFeature(res, attrs);
1547 // FeatureGroups are stricter and mandate that
1548 // any <uses-feature> declared are mandatory.
1549 featureInfo.flags |= FeatureInfo.FLAG_REQUIRED;
1550 features = ArrayUtils.add(features, featureInfo);
1551 } else {
1552 Slog.w(TAG, "Unknown element under <feature-group>: " + innerTagName +
1553 " at " + mArchiveSourcePath + " " +
1554 parser.getPositionDescription());
1555 }
1556 XmlUtils.skipCurrentTag(parser);
1557 }
1558
1559 if (features != null) {
1560 group.features = new FeatureInfo[features.size()];
1561 group.features = features.toArray(group.features);
1562 }
1563 pkg.featureGroups = ArrayUtils.add(pkg.featureGroups, group);
Adam Lesinski2c72b682014-06-24 09:56:01 -07001564
Dianne Hackborn851a5412009-05-08 12:06:44 -07001565 } else if (tagName.equals("uses-sdk")) {
Suchi Amalapurapu8d5ae982009-10-06 09:26:09 -07001566 if (SDK_VERSION > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001567 sa = res.obtainAttributes(attrs,
1568 com.android.internal.R.styleable.AndroidManifestUsesSdk);
1569
Dianne Hackborn851a5412009-05-08 12:06:44 -07001570 int minVers = 0;
1571 String minCode = null;
1572 int targetVers = 0;
1573 String targetCode = null;
1574
1575 TypedValue val = sa.peekValue(
1576 com.android.internal.R.styleable.AndroidManifestUsesSdk_minSdkVersion);
1577 if (val != null) {
1578 if (val.type == TypedValue.TYPE_STRING && val.string != null) {
1579 targetCode = minCode = val.string.toString();
1580 } else {
1581 // If it's not a string, it's an integer.
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001582 targetVers = minVers = val.data;
Dianne Hackborn851a5412009-05-08 12:06:44 -07001583 }
1584 }
1585
1586 val = sa.peekValue(
1587 com.android.internal.R.styleable.AndroidManifestUsesSdk_targetSdkVersion);
1588 if (val != null) {
1589 if (val.type == TypedValue.TYPE_STRING && val.string != null) {
1590 targetCode = minCode = val.string.toString();
1591 } else {
1592 // If it's not a string, it's an integer.
1593 targetVers = val.data;
1594 }
1595 }
1596
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001597 sa.recycle();
1598
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001599 if (minCode != null) {
Dianne Hackbornffcda102014-04-24 13:06:27 -07001600 boolean allowedCodename = false;
1601 for (String codename : SDK_CODENAMES) {
1602 if (minCode.equals(codename)) {
1603 allowedCodename = true;
1604 break;
1605 }
1606 }
1607 if (!allowedCodename) {
1608 if (SDK_CODENAMES.length > 0) {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001609 outError[0] = "Requires development platform " + minCode
Dianne Hackbornffcda102014-04-24 13:06:27 -07001610 + " (current platform is any of "
1611 + Arrays.toString(SDK_CODENAMES) + ")";
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001612 } else {
1613 outError[0] = "Requires development platform " + minCode
1614 + " but this is a release platform.";
1615 }
1616 mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK;
1617 return null;
1618 }
Suchi Amalapurapu8d5ae982009-10-06 09:26:09 -07001619 } else if (minVers > SDK_VERSION) {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001620 outError[0] = "Requires newer sdk version #" + minVers
Suchi Amalapurapu8d5ae982009-10-06 09:26:09 -07001621 + " (current version is #" + SDK_VERSION + ")";
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001622 mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK;
1623 return null;
1624 }
1625
Dianne Hackborn851a5412009-05-08 12:06:44 -07001626 if (targetCode != null) {
Dianne Hackbornffcda102014-04-24 13:06:27 -07001627 boolean allowedCodename = false;
1628 for (String codename : SDK_CODENAMES) {
1629 if (targetCode.equals(codename)) {
1630 allowedCodename = true;
1631 break;
1632 }
1633 }
1634 if (!allowedCodename) {
1635 if (SDK_CODENAMES.length > 0) {
Dianne Hackborn851a5412009-05-08 12:06:44 -07001636 outError[0] = "Requires development platform " + targetCode
Dianne Hackbornffcda102014-04-24 13:06:27 -07001637 + " (current platform is any of "
1638 + Arrays.toString(SDK_CODENAMES) + ")";
Dianne Hackborn851a5412009-05-08 12:06:44 -07001639 } else {
1640 outError[0] = "Requires development platform " + targetCode
1641 + " but this is a release platform.";
1642 }
1643 mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK;
1644 return null;
1645 }
1646 // If the code matches, it definitely targets this SDK.
Dianne Hackborna96cbb42009-05-13 15:06:13 -07001647 pkg.applicationInfo.targetSdkVersion
1648 = android.os.Build.VERSION_CODES.CUR_DEVELOPMENT;
1649 } else {
1650 pkg.applicationInfo.targetSdkVersion = targetVers;
Dianne Hackborn851a5412009-05-08 12:06:44 -07001651 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001652 }
1653
1654 XmlUtils.skipCurrentTag(parser);
1655
Dianne Hackborn723738c2009-06-25 19:48:04 -07001656 } else if (tagName.equals("supports-screens")) {
1657 sa = res.obtainAttributes(attrs,
1658 com.android.internal.R.styleable.AndroidManifestSupportsScreens);
1659
Dianne Hackborndf6e9802011-05-26 14:20:23 -07001660 pkg.applicationInfo.requiresSmallestWidthDp = sa.getInteger(
1661 com.android.internal.R.styleable.AndroidManifestSupportsScreens_requiresSmallestWidthDp,
1662 0);
1663 pkg.applicationInfo.compatibleWidthLimitDp = sa.getInteger(
1664 com.android.internal.R.styleable.AndroidManifestSupportsScreens_compatibleWidthLimitDp,
1665 0);
Dianne Hackborn2762ff32011-06-01 21:27:05 -07001666 pkg.applicationInfo.largestWidthLimitDp = sa.getInteger(
1667 com.android.internal.R.styleable.AndroidManifestSupportsScreens_largestWidthLimitDp,
1668 0);
Dianne Hackborndf6e9802011-05-26 14:20:23 -07001669
Dianne Hackborn723738c2009-06-25 19:48:04 -07001670 // This is a trick to get a boolean and still able to detect
1671 // if a value was actually set.
1672 supportsSmallScreens = sa.getInteger(
1673 com.android.internal.R.styleable.AndroidManifestSupportsScreens_smallScreens,
1674 supportsSmallScreens);
1675 supportsNormalScreens = sa.getInteger(
1676 com.android.internal.R.styleable.AndroidManifestSupportsScreens_normalScreens,
1677 supportsNormalScreens);
1678 supportsLargeScreens = sa.getInteger(
1679 com.android.internal.R.styleable.AndroidManifestSupportsScreens_largeScreens,
1680 supportsLargeScreens);
Dianne Hackborn14cee9f2010-04-23 17:51:26 -07001681 supportsXLargeScreens = sa.getInteger(
1682 com.android.internal.R.styleable.AndroidManifestSupportsScreens_xlargeScreens,
1683 supportsXLargeScreens);
Dianne Hackbornc4db95c2009-07-21 17:46:02 -07001684 resizeable = sa.getInteger(
1685 com.android.internal.R.styleable.AndroidManifestSupportsScreens_resizeable,
Dianne Hackborn14cee9f2010-04-23 17:51:26 -07001686 resizeable);
Dianne Hackborn11b822d2009-07-21 20:03:02 -07001687 anyDensity = sa.getInteger(
1688 com.android.internal.R.styleable.AndroidManifestSupportsScreens_anyDensity,
1689 anyDensity);
Dianne Hackborn723738c2009-06-25 19:48:04 -07001690
1691 sa.recycle();
1692
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07001693 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn854060af2009-07-09 18:14:31 -07001694
1695 } else if (tagName.equals("protected-broadcast")) {
1696 sa = res.obtainAttributes(attrs,
1697 com.android.internal.R.styleable.AndroidManifestProtectedBroadcast);
1698
Dianne Hackborncf244ad2010-03-09 15:00:30 -08001699 // Note: don't allow this value to be a reference to a resource
1700 // that may change.
Dianne Hackborn854060af2009-07-09 18:14:31 -07001701 String name = sa.getNonResourceString(
1702 com.android.internal.R.styleable.AndroidManifestProtectedBroadcast_name);
1703
1704 sa.recycle();
1705
1706 if (name != null && (flags&PARSE_IS_SYSTEM) != 0) {
1707 if (pkg.protectedBroadcasts == null) {
1708 pkg.protectedBroadcasts = new ArrayList<String>();
1709 }
1710 if (!pkg.protectedBroadcasts.contains(name)) {
1711 pkg.protectedBroadcasts.add(name.intern());
1712 }
1713 }
1714
1715 XmlUtils.skipCurrentTag(parser);
1716
1717 } else if (tagName.equals("instrumentation")) {
1718 if (parseInstrumentation(pkg, res, parser, attrs, outError) == null) {
1719 return null;
1720 }
1721
Dianne Hackbornb858dfd2010-02-02 10:49:14 -08001722 } else if (tagName.equals("original-package")) {
1723 sa = res.obtainAttributes(attrs,
1724 com.android.internal.R.styleable.AndroidManifestOriginalPackage);
1725
Dianne Hackborncf244ad2010-03-09 15:00:30 -08001726 String orig =sa.getNonConfigurationString(
1727 com.android.internal.R.styleable.AndroidManifestOriginalPackage_name, 0);
Dianne Hackborn6dee18c2010-02-09 23:59:16 -08001728 if (!pkg.packageName.equals(orig)) {
Dianne Hackbornc1552392010-03-03 16:19:01 -08001729 if (pkg.mOriginalPackages == null) {
1730 pkg.mOriginalPackages = new ArrayList<String>();
1731 pkg.mRealPackage = pkg.packageName;
1732 }
1733 pkg.mOriginalPackages.add(orig);
Dianne Hackborn6dee18c2010-02-09 23:59:16 -08001734 }
Dianne Hackbornb858dfd2010-02-02 10:49:14 -08001735
1736 sa.recycle();
1737
Dianne Hackbornb858dfd2010-02-02 10:49:14 -08001738 XmlUtils.skipCurrentTag(parser);
1739
1740 } else if (tagName.equals("adopt-permissions")) {
1741 sa = res.obtainAttributes(attrs,
1742 com.android.internal.R.styleable.AndroidManifestOriginalPackage);
1743
Dianne Hackborncf244ad2010-03-09 15:00:30 -08001744 String name = sa.getNonConfigurationString(
1745 com.android.internal.R.styleable.AndroidManifestOriginalPackage_name, 0);
Dianne Hackbornb858dfd2010-02-02 10:49:14 -08001746
1747 sa.recycle();
1748
Dianne Hackborn6dee18c2010-02-09 23:59:16 -08001749 if (name != null) {
Dianne Hackbornb858dfd2010-02-02 10:49:14 -08001750 if (pkg.mAdoptPermissions == null) {
1751 pkg.mAdoptPermissions = new ArrayList<String>();
1752 }
1753 pkg.mAdoptPermissions.add(name);
1754 }
1755
1756 XmlUtils.skipCurrentTag(parser);
1757
Dianne Hackborna0b46c92010-10-21 15:32:06 -07001758 } else if (tagName.equals("uses-gl-texture")) {
1759 // Just skip this tag
1760 XmlUtils.skipCurrentTag(parser);
1761 continue;
1762
1763 } else if (tagName.equals("compatible-screens")) {
1764 // Just skip this tag
1765 XmlUtils.skipCurrentTag(parser);
1766 continue;
Michael Wrighteaeb1902013-09-05 18:15:57 -07001767 } else if (tagName.equals("supports-input")) {
1768 XmlUtils.skipCurrentTag(parser);
1769 continue;
Dianne Hackborna0b46c92010-10-21 15:32:06 -07001770
Dianne Hackborn854060af2009-07-09 18:14:31 -07001771 } else if (tagName.equals("eat-comment")) {
1772 // Just skip this tag
1773 XmlUtils.skipCurrentTag(parser);
1774 continue;
1775
1776 } else if (RIGID_PARSER) {
1777 outError[0] = "Bad element under <manifest>: "
1778 + parser.getName();
1779 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1780 return null;
1781
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001782 } else {
Kenny Rootd2d29252011-08-08 11:27:57 -07001783 Slog.w(TAG, "Unknown element under <manifest>: " + parser.getName()
Dianne Hackbornbd0a81f2009-10-04 13:30:50 -07001784 + " at " + mArchiveSourcePath + " "
1785 + parser.getPositionDescription());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001786 XmlUtils.skipCurrentTag(parser);
1787 continue;
1788 }
1789 }
1790
1791 if (!foundApp && pkg.instrumentation.size() == 0) {
1792 outError[0] = "<manifest> does not contain an <application> or <instrumentation>";
1793 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_EMPTY;
1794 }
1795
Dianne Hackborna96cbb42009-05-13 15:06:13 -07001796 final int NP = PackageParser.NEW_PERMISSIONS.length;
Dianne Hackborna33e3f72009-09-29 17:28:24 -07001797 StringBuilder implicitPerms = null;
Dianne Hackborna96cbb42009-05-13 15:06:13 -07001798 for (int ip=0; ip<NP; ip++) {
1799 final PackageParser.NewPermissionInfo npi
1800 = PackageParser.NEW_PERMISSIONS[ip];
1801 if (pkg.applicationInfo.targetSdkVersion >= npi.sdkVersion) {
1802 break;
1803 }
1804 if (!pkg.requestedPermissions.contains(npi.name)) {
Dianne Hackborna33e3f72009-09-29 17:28:24 -07001805 if (implicitPerms == null) {
1806 implicitPerms = new StringBuilder(128);
1807 implicitPerms.append(pkg.packageName);
1808 implicitPerms.append(": compat added ");
1809 } else {
1810 implicitPerms.append(' ');
1811 }
1812 implicitPerms.append(npi.name);
Dianne Hackborna96cbb42009-05-13 15:06:13 -07001813 pkg.requestedPermissions.add(npi.name);
Dianne Hackborn65696252012-03-05 18:49:21 -08001814 pkg.requestedPermissionsRequired.add(Boolean.TRUE);
Dianne Hackborna96cbb42009-05-13 15:06:13 -07001815 }
Dianne Hackborn851a5412009-05-08 12:06:44 -07001816 }
Dianne Hackborna33e3f72009-09-29 17:28:24 -07001817 if (implicitPerms != null) {
Kenny Rootd2d29252011-08-08 11:27:57 -07001818 Slog.i(TAG, implicitPerms.toString());
Dianne Hackborna33e3f72009-09-29 17:28:24 -07001819 }
Dianne Hackborn79245122012-03-12 10:51:26 -07001820
1821 final int NS = PackageParser.SPLIT_PERMISSIONS.length;
1822 for (int is=0; is<NS; is++) {
1823 final PackageParser.SplitPermissionInfo spi
1824 = PackageParser.SPLIT_PERMISSIONS[is];
Dianne Hackborn31b0e0e2012-04-05 19:33:30 -07001825 if (pkg.applicationInfo.targetSdkVersion >= spi.targetSdk
1826 || !pkg.requestedPermissions.contains(spi.rootPerm)) {
Dianne Hackborn5e4705a2012-04-06 12:55:53 -07001827 continue;
Dianne Hackborn79245122012-03-12 10:51:26 -07001828 }
1829 for (int in=0; in<spi.newPerms.length; in++) {
1830 final String perm = spi.newPerms[in];
1831 if (!pkg.requestedPermissions.contains(perm)) {
1832 pkg.requestedPermissions.add(perm);
1833 pkg.requestedPermissionsRequired.add(Boolean.TRUE);
1834 }
1835 }
1836 }
1837
Dianne Hackborn723738c2009-06-25 19:48:04 -07001838 if (supportsSmallScreens < 0 || (supportsSmallScreens > 0
1839 && pkg.applicationInfo.targetSdkVersion
Dianne Hackborn11b822d2009-07-21 20:03:02 -07001840 >= android.os.Build.VERSION_CODES.DONUT)) {
Dianne Hackborn723738c2009-06-25 19:48:04 -07001841 pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS;
1842 }
1843 if (supportsNormalScreens != 0) {
1844 pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS;
1845 }
1846 if (supportsLargeScreens < 0 || (supportsLargeScreens > 0
1847 && pkg.applicationInfo.targetSdkVersion
Dianne Hackborn11b822d2009-07-21 20:03:02 -07001848 >= android.os.Build.VERSION_CODES.DONUT)) {
Dianne Hackborn723738c2009-06-25 19:48:04 -07001849 pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS;
1850 }
Dianne Hackborn14cee9f2010-04-23 17:51:26 -07001851 if (supportsXLargeScreens < 0 || (supportsXLargeScreens > 0
1852 && pkg.applicationInfo.targetSdkVersion
1853 >= android.os.Build.VERSION_CODES.GINGERBREAD)) {
1854 pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS;
1855 }
Dianne Hackbornc4db95c2009-07-21 17:46:02 -07001856 if (resizeable < 0 || (resizeable > 0
1857 && pkg.applicationInfo.targetSdkVersion
Dianne Hackborn11b822d2009-07-21 20:03:02 -07001858 >= android.os.Build.VERSION_CODES.DONUT)) {
Dianne Hackbornc4db95c2009-07-21 17:46:02 -07001859 pkg.applicationInfo.flags |= ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS;
1860 }
Dianne Hackborn11b822d2009-07-21 20:03:02 -07001861 if (anyDensity < 0 || (anyDensity > 0
1862 && pkg.applicationInfo.targetSdkVersion
1863 >= android.os.Build.VERSION_CODES.DONUT)) {
1864 pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES;
Mitsuru Oshima8d112672009-04-27 12:01:23 -07001865 }
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -07001866
Nick Kralevich38f130e2013-04-04 13:19:10 -07001867 /*
1868 * b/8528162: Ignore the <uses-permission android:required> attribute if
1869 * targetSdkVersion < JELLY_BEAN_MR2. There are lots of apps in the wild
1870 * which are improperly using this attribute, even though it never worked.
1871 */
1872 if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR2) {
1873 for (int i = 0; i < pkg.requestedPermissionsRequired.size(); i++) {
1874 pkg.requestedPermissionsRequired.set(i, Boolean.TRUE);
1875 }
1876 }
1877
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001878 return pkg;
1879 }
1880
Adam Lesinskid3edfde2014-08-08 17:32:44 -07001881 private FeatureInfo parseUsesFeature(Resources res, AttributeSet attrs)
1882 throws XmlPullParserException, IOException {
1883 FeatureInfo fi = new FeatureInfo();
1884 TypedArray sa = res.obtainAttributes(attrs,
1885 com.android.internal.R.styleable.AndroidManifestUsesFeature);
1886 // Note: don't allow this value to be a reference to a resource
1887 // that may change.
1888 fi.name = sa.getNonResourceString(
1889 com.android.internal.R.styleable.AndroidManifestUsesFeature_name);
1890 if (fi.name == null) {
1891 fi.reqGlEsVersion = sa.getInt(
1892 com.android.internal.R.styleable.AndroidManifestUsesFeature_glEsVersion,
1893 FeatureInfo.GL_ES_VERSION_UNDEFINED);
1894 }
1895 if (sa.getBoolean(
1896 com.android.internal.R.styleable.AndroidManifestUsesFeature_required, true)) {
1897 fi.flags |= FeatureInfo.FLAG_REQUIRED;
1898 }
1899 sa.recycle();
1900 return fi;
1901 }
1902
Nick Kralevich73f2d3c2013-04-04 14:38:13 -07001903 private boolean parseUsesPermission(Package pkg, Resources res, XmlResourceParser parser,
1904 AttributeSet attrs, String[] outError)
1905 throws XmlPullParserException, IOException {
1906 TypedArray sa = res.obtainAttributes(attrs,
1907 com.android.internal.R.styleable.AndroidManifestUsesPermission);
1908
1909 // Note: don't allow this value to be a reference to a resource
1910 // that may change.
1911 String name = sa.getNonResourceString(
1912 com.android.internal.R.styleable.AndroidManifestUsesPermission_name);
Nick Kralevich32eb5b182013-04-11 10:20:09 -07001913/*
Nick Kralevich73f2d3c2013-04-04 14:38:13 -07001914 boolean required = sa.getBoolean(
1915 com.android.internal.R.styleable.AndroidManifestUsesPermission_required, true);
Nick Kralevich32eb5b182013-04-11 10:20:09 -07001916*/
1917 boolean required = true; // Optional <uses-permission> not supported
Nick Kralevich73f2d3c2013-04-04 14:38:13 -07001918
Christopher Tatefb0676a2013-09-16 16:34:52 -07001919 int maxSdkVersion = 0;
1920 TypedValue val = sa.peekValue(
1921 com.android.internal.R.styleable.AndroidManifestUsesPermission_maxSdkVersion);
1922 if (val != null) {
1923 if (val.type >= TypedValue.TYPE_FIRST_INT && val.type <= TypedValue.TYPE_LAST_INT) {
1924 maxSdkVersion = val.data;
1925 }
1926 }
1927
Nick Kralevich73f2d3c2013-04-04 14:38:13 -07001928 sa.recycle();
1929
Christopher Tatefb0676a2013-09-16 16:34:52 -07001930 if ((maxSdkVersion == 0) || (maxSdkVersion >= Build.VERSION.RESOURCES_SDK_INT)) {
1931 if (name != null) {
1932 int index = pkg.requestedPermissions.indexOf(name);
1933 if (index == -1) {
1934 pkg.requestedPermissions.add(name.intern());
1935 pkg.requestedPermissionsRequired.add(required ? Boolean.TRUE : Boolean.FALSE);
1936 } else {
1937 if (pkg.requestedPermissionsRequired.get(index) != required) {
1938 outError[0] = "conflicting <uses-permission> entries";
1939 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1940 return false;
1941 }
Nick Kralevich73f2d3c2013-04-04 14:38:13 -07001942 }
1943 }
1944 }
1945
1946 XmlUtils.skipCurrentTag(parser);
1947 return true;
1948 }
1949
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001950 private static String buildClassName(String pkg, CharSequence clsSeq,
1951 String[] outError) {
1952 if (clsSeq == null || clsSeq.length() <= 0) {
1953 outError[0] = "Empty class name in package " + pkg;
1954 return null;
1955 }
1956 String cls = clsSeq.toString();
1957 char c = cls.charAt(0);
1958 if (c == '.') {
1959 return (pkg + cls).intern();
1960 }
1961 if (cls.indexOf('.') < 0) {
1962 StringBuilder b = new StringBuilder(pkg);
1963 b.append('.');
1964 b.append(cls);
1965 return b.toString().intern();
1966 }
1967 if (c >= 'a' && c <= 'z') {
1968 return cls.intern();
1969 }
1970 outError[0] = "Bad class name " + cls + " in package " + pkg;
1971 return null;
1972 }
1973
1974 private static String buildCompoundName(String pkg,
1975 CharSequence procSeq, String type, String[] outError) {
1976 String proc = procSeq.toString();
1977 char c = proc.charAt(0);
1978 if (pkg != null && c == ':') {
1979 if (proc.length() < 2) {
1980 outError[0] = "Bad " + type + " name " + proc + " in package " + pkg
1981 + ": must be at least two characters";
1982 return null;
1983 }
1984 String subName = proc.substring(1);
1985 String nameError = validateName(subName, false);
1986 if (nameError != null) {
1987 outError[0] = "Invalid " + type + " name " + proc + " in package "
1988 + pkg + ": " + nameError;
1989 return null;
1990 }
1991 return (pkg + proc).intern();
1992 }
1993 String nameError = validateName(proc, true);
1994 if (nameError != null && !"system".equals(proc)) {
1995 outError[0] = "Invalid " + type + " name " + proc + " in package "
1996 + pkg + ": " + nameError;
1997 return null;
1998 }
1999 return proc.intern();
2000 }
2001
2002 private static String buildProcessName(String pkg, String defProc,
2003 CharSequence procSeq, int flags, String[] separateProcesses,
2004 String[] outError) {
2005 if ((flags&PARSE_IGNORE_PROCESSES) != 0 && !"system".equals(procSeq)) {
2006 return defProc != null ? defProc : pkg;
2007 }
2008 if (separateProcesses != null) {
2009 for (int i=separateProcesses.length-1; i>=0; i--) {
2010 String sp = separateProcesses[i];
2011 if (sp.equals(pkg) || sp.equals(defProc) || sp.equals(procSeq)) {
2012 return pkg;
2013 }
2014 }
2015 }
2016 if (procSeq == null || procSeq.length() <= 0) {
2017 return defProc;
2018 }
Dianne Hackbornd1cff1b2010-04-02 16:51:26 -07002019 return buildCompoundName(pkg, procSeq, "process", outError);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002020 }
2021
2022 private static String buildTaskAffinityName(String pkg, String defProc,
2023 CharSequence procSeq, String[] outError) {
2024 if (procSeq == null) {
2025 return defProc;
2026 }
2027 if (procSeq.length() <= 0) {
2028 return null;
2029 }
2030 return buildCompoundName(pkg, procSeq, "taskAffinity", outError);
2031 }
Geremy Condraf1bcca82013-01-07 22:35:24 -08002032
dcashman989eb3712014-06-17 12:56:12 -07002033 private boolean parseKeySets(Package owner, Resources res,
Geremy Condraf1bcca82013-01-07 22:35:24 -08002034 XmlPullParser parser, AttributeSet attrs, String[] outError)
2035 throws XmlPullParserException, IOException {
dcashman989eb3712014-06-17 12:56:12 -07002036 // we've encountered the 'key-sets' tag
Geremy Condraf1bcca82013-01-07 22:35:24 -08002037 // all the keys and keysets that we want must be defined here
2038 // so we're going to iterate over the parser and pull out the things we want
2039 int outerDepth = parser.getDepth();
dcashman989eb3712014-06-17 12:56:12 -07002040 int currentKeySetDepth = -1;
Geremy Condraf1bcca82013-01-07 22:35:24 -08002041 int type;
dcashman989eb3712014-06-17 12:56:12 -07002042 String currentKeySet = null;
2043 ArrayMap<String, PublicKey> publicKeys = new ArrayMap<String, PublicKey>();
2044 ArraySet<String> upgradeKeySets = new ArraySet<String>();
2045 ArrayMap<String, ArraySet<String>> definedKeySets = new ArrayMap<String, ArraySet<String>>();
2046 ArraySet<String> improperKeySets = new ArraySet<String>();
Geremy Condraf1bcca82013-01-07 22:35:24 -08002047 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
2048 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
2049 if (type == XmlPullParser.END_TAG) {
dcashman989eb3712014-06-17 12:56:12 -07002050 if (parser.getDepth() == currentKeySetDepth) {
2051 currentKeySet = null;
2052 currentKeySetDepth = -1;
Kenny Root37dca152013-07-10 14:01:49 -07002053 }
Geremy Condraf1bcca82013-01-07 22:35:24 -08002054 continue;
2055 }
dcashman989eb3712014-06-17 12:56:12 -07002056 String tagName = parser.getName();
2057 if (tagName.equals("key-set")) {
2058 if (currentKeySet != null) {
2059 Slog.w(TAG, "Improperly nested 'key-set' tag at "
2060 + parser.getPositionDescription());
2061 return false;
2062 }
Geremy Condraf1bcca82013-01-07 22:35:24 -08002063 final TypedArray sa = res.obtainAttributes(attrs,
dcashman989eb3712014-06-17 12:56:12 -07002064 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 Slog.w(TAG, "Improperly nested 'public-key' tag at "
2074 + parser.getPositionDescription());
2075 return false;
2076 }
2077 final TypedArray sa = res.obtainAttributes(attrs,
2078 com.android.internal.R.styleable.AndroidManifestPublicKey);
2079 final String publicKeyName = sa.getNonResourceString(
2080 com.android.internal.R.styleable.AndroidManifestPublicKey_name);
Geremy Condraf1bcca82013-01-07 22:35:24 -08002081 final String encodedKey = sa.getNonResourceString(
dcashman989eb3712014-06-17 12:56:12 -07002082 com.android.internal.R.styleable.AndroidManifestPublicKey_value);
2083 if (encodedKey == null && publicKeys.get(publicKeyName) == null) {
2084 Slog.w(TAG, "'public-key' " + publicKeyName + " must define a public-key value"
2085 + " on first use at " + parser.getPositionDescription());
Kenny Root37dca152013-07-10 14:01:49 -07002086 sa.recycle();
dcashman989eb3712014-06-17 12:56:12 -07002087 return false;
2088 } else if (encodedKey != null) {
2089 PublicKey currentKey = parsePublicKey(encodedKey);
2090 if (currentKey == null) {
2091 Slog.w(TAG, "No recognized valid key in 'public-key' tag at "
2092 + parser.getPositionDescription() + " key-set " + currentKeySet
2093 + " will not be added to the package's defined key-sets.");
2094 sa.recycle();
2095 improperKeySets.add(currentKeySet);
2096 XmlUtils.skipCurrentTag(parser);
2097 continue;
2098 }
2099 if (publicKeys.get(publicKeyName) == null
2100 || publicKeys.get(publicKeyName).equals(currentKey)) {
2101
2102 /* public-key first definition, or matches old definition */
2103 publicKeys.put(publicKeyName, currentKey);
2104 } else {
2105 Slog.w(TAG, "Value of 'public-key' " + publicKeyName
2106 + " conflicts with previously defined value at "
2107 + parser.getPositionDescription());
2108 sa.recycle();
2109 return false;
2110 }
Kenny Root37dca152013-07-10 14:01:49 -07002111 }
dcashman989eb3712014-06-17 12:56:12 -07002112 definedKeySets.get(currentKeySet).add(publicKeyName);
Geremy Condraf1bcca82013-01-07 22:35:24 -08002113 sa.recycle();
dcashman989eb3712014-06-17 12:56:12 -07002114 XmlUtils.skipCurrentTag(parser);
2115 } else if (tagName.equals("upgrade-key-set")) {
Geremy Condraf1bcca82013-01-07 22:35:24 -08002116 final TypedArray sa = res.obtainAttributes(attrs,
dcashman989eb3712014-06-17 12:56:12 -07002117 com.android.internal.R.styleable.AndroidManifestUpgradeKeySet);
2118 String name = sa.getNonResourceString(
2119 com.android.internal.R.styleable.AndroidManifestUpgradeKeySet_name);
2120 upgradeKeySets.add(name);
Geremy Condraf1bcca82013-01-07 22:35:24 -08002121 sa.recycle();
dcashman989eb3712014-06-17 12:56:12 -07002122 XmlUtils.skipCurrentTag(parser);
Geremy Condraf1bcca82013-01-07 22:35:24 -08002123 } else if (RIGID_PARSER) {
dcashman989eb3712014-06-17 12:56:12 -07002124 Slog.w(TAG, "Bad element under <key-sets>: " + parser.getName()
Geremy Condraf1bcca82013-01-07 22:35:24 -08002125 + " at " + mArchiveSourcePath + " "
2126 + parser.getPositionDescription());
2127 return false;
2128 } else {
dcashman989eb3712014-06-17 12:56:12 -07002129 Slog.w(TAG, "Unknown element under <key-sets>: " + parser.getName()
Geremy Condraf1bcca82013-01-07 22:35:24 -08002130 + " at " + mArchiveSourcePath + " "
2131 + parser.getPositionDescription());
2132 XmlUtils.skipCurrentTag(parser);
2133 continue;
2134 }
2135 }
dcashman989eb3712014-06-17 12:56:12 -07002136 Set<String> publicKeyNames = publicKeys.keySet();
2137 if (publicKeyNames.removeAll(definedKeySets.keySet())) {
2138 Slog.w(TAG, "Package" + owner.packageName + " AndroidManifext.xml "
2139 + "'key-set' and 'public-key' names must be distinct.");
2140 return false;
2141 }
2142 owner.mKeySetMapping = new ArrayMap<String, ArraySet<PublicKey>>();
2143 for (ArrayMap.Entry<String, ArraySet<String>> e: definedKeySets.entrySet()) {
2144 final String keySetName = e.getKey();
2145 if (e.getValue().size() == 0) {
2146 Slog.w(TAG, "Package" + owner.packageName + " AndroidManifext.xml "
2147 + "'key-set' " + keySetName + " has no valid associated 'public-key'."
2148 + " Not including in package's defined key-sets.");
2149 continue;
2150 } else if (improperKeySets.contains(keySetName)) {
2151 Slog.w(TAG, "Package" + owner.packageName + " AndroidManifext.xml "
2152 + "'key-set' " + keySetName + " contained improper 'public-key'"
2153 + " tags. Not including in package's defined key-sets.");
2154 continue;
2155 }
2156 owner.mKeySetMapping.put(keySetName, new ArraySet<PublicKey>());
2157 for (String s : e.getValue()) {
2158 owner.mKeySetMapping.get(keySetName).add(publicKeys.get(s));
Geremy Condraf1bcca82013-01-07 22:35:24 -08002159 }
2160 }
dcashman989eb3712014-06-17 12:56:12 -07002161 if (owner.mKeySetMapping.keySet().containsAll(upgradeKeySets)) {
2162 owner.mUpgradeKeySets = upgradeKeySets;
2163 } else {
2164 Slog.w(TAG, "Package" + owner.packageName + " AndroidManifext.xml "
2165 + "does not define all 'upgrade-key-set's .");
2166 return false;
2167 }
Geremy Condraf1bcca82013-01-07 22:35:24 -08002168 return true;
2169 }
2170
Dianne Hackbornfd5015b2012-04-30 16:33:56 -07002171 private PermissionGroup parsePermissionGroup(Package owner, int flags, Resources res,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002172 XmlPullParser parser, AttributeSet attrs, String[] outError)
2173 throws XmlPullParserException, IOException {
2174 PermissionGroup perm = new PermissionGroup(owner);
2175
2176 TypedArray sa = res.obtainAttributes(attrs,
2177 com.android.internal.R.styleable.AndroidManifestPermissionGroup);
2178
2179 if (!parsePackageItemInfo(owner, perm.info, outError,
2180 "<permission-group>", sa,
2181 com.android.internal.R.styleable.AndroidManifestPermissionGroup_name,
2182 com.android.internal.R.styleable.AndroidManifestPermissionGroup_label,
Adam Powell81cd2e92010-04-21 16:35:18 -07002183 com.android.internal.R.styleable.AndroidManifestPermissionGroup_icon,
Jose Limaf78e3122014-03-06 12:13:15 -08002184 com.android.internal.R.styleable.AndroidManifestPermissionGroup_logo,
2185 com.android.internal.R.styleable.AndroidManifestPermissionGroup_banner)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002186 sa.recycle();
2187 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2188 return null;
2189 }
2190
2191 perm.info.descriptionRes = sa.getResourceId(
2192 com.android.internal.R.styleable.AndroidManifestPermissionGroup_description,
2193 0);
Dianne Hackborn7454d3b2012-09-12 17:22:00 -07002194 perm.info.flags = sa.getInt(
2195 com.android.internal.R.styleable.AndroidManifestPermissionGroup_permissionGroupFlags, 0);
Dianne Hackbornfd5015b2012-04-30 16:33:56 -07002196 perm.info.priority = sa.getInt(
2197 com.android.internal.R.styleable.AndroidManifestPermissionGroup_priority, 0);
Dianne Hackborn99222d22012-05-06 16:30:15 -07002198 if (perm.info.priority > 0 && (flags&PARSE_IS_SYSTEM) == 0) {
Dianne Hackbornfd5015b2012-04-30 16:33:56 -07002199 perm.info.priority = 0;
2200 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002201
2202 sa.recycle();
2203
2204 if (!parseAllMetaData(res, parser, attrs, "<permission-group>", perm,
2205 outError)) {
2206 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2207 return null;
2208 }
2209
2210 owner.permissionGroups.add(perm);
2211
2212 return perm;
2213 }
2214
2215 private Permission parsePermission(Package owner, Resources res,
2216 XmlPullParser parser, AttributeSet attrs, String[] outError)
2217 throws XmlPullParserException, IOException {
2218 Permission perm = new Permission(owner);
2219
2220 TypedArray sa = res.obtainAttributes(attrs,
2221 com.android.internal.R.styleable.AndroidManifestPermission);
2222
2223 if (!parsePackageItemInfo(owner, perm.info, outError,
2224 "<permission>", sa,
2225 com.android.internal.R.styleable.AndroidManifestPermission_name,
2226 com.android.internal.R.styleable.AndroidManifestPermission_label,
Adam Powell81cd2e92010-04-21 16:35:18 -07002227 com.android.internal.R.styleable.AndroidManifestPermission_icon,
Jose Limaf78e3122014-03-06 12:13:15 -08002228 com.android.internal.R.styleable.AndroidManifestPermission_logo,
2229 com.android.internal.R.styleable.AndroidManifestPermission_banner)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002230 sa.recycle();
2231 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2232 return null;
2233 }
2234
Dianne Hackborncf244ad2010-03-09 15:00:30 -08002235 // Note: don't allow this value to be a reference to a resource
2236 // that may change.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002237 perm.info.group = sa.getNonResourceString(
2238 com.android.internal.R.styleable.AndroidManifestPermission_permissionGroup);
2239 if (perm.info.group != null) {
2240 perm.info.group = perm.info.group.intern();
2241 }
2242
2243 perm.info.descriptionRes = sa.getResourceId(
2244 com.android.internal.R.styleable.AndroidManifestPermission_description,
2245 0);
2246
2247 perm.info.protectionLevel = sa.getInt(
2248 com.android.internal.R.styleable.AndroidManifestPermission_protectionLevel,
2249 PermissionInfo.PROTECTION_NORMAL);
2250
Dianne Hackborn2ca2c872012-09-16 16:03:36 -07002251 perm.info.flags = sa.getInt(
2252 com.android.internal.R.styleable.AndroidManifestPermission_permissionFlags, 0);
2253
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002254 sa.recycle();
Dianne Hackborne639da72012-02-21 15:11:13 -08002255
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002256 if (perm.info.protectionLevel == -1) {
2257 outError[0] = "<permission> does not specify protectionLevel";
2258 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2259 return null;
2260 }
Dianne Hackborne639da72012-02-21 15:11:13 -08002261
2262 perm.info.protectionLevel = PermissionInfo.fixProtectionLevel(perm.info.protectionLevel);
2263
2264 if ((perm.info.protectionLevel&PermissionInfo.PROTECTION_MASK_FLAGS) != 0) {
2265 if ((perm.info.protectionLevel&PermissionInfo.PROTECTION_MASK_BASE) !=
2266 PermissionInfo.PROTECTION_SIGNATURE) {
2267 outError[0] = "<permission> protectionLevel specifies a flag but is "
2268 + "not based on signature type";
2269 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2270 return null;
2271 }
2272 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002273
2274 if (!parseAllMetaData(res, parser, attrs, "<permission>", perm,
2275 outError)) {
2276 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2277 return null;
2278 }
2279
2280 owner.permissions.add(perm);
2281
2282 return perm;
2283 }
2284
2285 private Permission parsePermissionTree(Package owner, Resources res,
2286 XmlPullParser parser, AttributeSet attrs, String[] outError)
2287 throws XmlPullParserException, IOException {
2288 Permission perm = new Permission(owner);
2289
2290 TypedArray sa = res.obtainAttributes(attrs,
2291 com.android.internal.R.styleable.AndroidManifestPermissionTree);
2292
2293 if (!parsePackageItemInfo(owner, perm.info, outError,
2294 "<permission-tree>", sa,
2295 com.android.internal.R.styleable.AndroidManifestPermissionTree_name,
2296 com.android.internal.R.styleable.AndroidManifestPermissionTree_label,
Adam Powell81cd2e92010-04-21 16:35:18 -07002297 com.android.internal.R.styleable.AndroidManifestPermissionTree_icon,
Jose Limaf78e3122014-03-06 12:13:15 -08002298 com.android.internal.R.styleable.AndroidManifestPermissionTree_logo,
2299 com.android.internal.R.styleable.AndroidManifestPermissionTree_banner)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002300 sa.recycle();
2301 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2302 return null;
2303 }
2304
2305 sa.recycle();
2306
2307 int index = perm.info.name.indexOf('.');
2308 if (index > 0) {
2309 index = perm.info.name.indexOf('.', index+1);
2310 }
2311 if (index < 0) {
2312 outError[0] = "<permission-tree> name has less than three segments: "
2313 + perm.info.name;
2314 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2315 return null;
2316 }
2317
2318 perm.info.descriptionRes = 0;
2319 perm.info.protectionLevel = PermissionInfo.PROTECTION_NORMAL;
2320 perm.tree = true;
2321
2322 if (!parseAllMetaData(res, parser, attrs, "<permission-tree>", perm,
2323 outError)) {
2324 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2325 return null;
2326 }
2327
2328 owner.permissions.add(perm);
2329
2330 return perm;
2331 }
2332
2333 private Instrumentation parseInstrumentation(Package owner, Resources res,
2334 XmlPullParser parser, AttributeSet attrs, String[] outError)
2335 throws XmlPullParserException, IOException {
2336 TypedArray sa = res.obtainAttributes(attrs,
2337 com.android.internal.R.styleable.AndroidManifestInstrumentation);
2338
Dianne Hackborn1d442e02009-04-20 18:14:05 -07002339 if (mParseInstrumentationArgs == null) {
2340 mParseInstrumentationArgs = new ParsePackageItemArgs(owner, outError,
2341 com.android.internal.R.styleable.AndroidManifestInstrumentation_name,
2342 com.android.internal.R.styleable.AndroidManifestInstrumentation_label,
Adam Powell81cd2e92010-04-21 16:35:18 -07002343 com.android.internal.R.styleable.AndroidManifestInstrumentation_icon,
Jose Limaf78e3122014-03-06 12:13:15 -08002344 com.android.internal.R.styleable.AndroidManifestInstrumentation_logo,
2345 com.android.internal.R.styleable.AndroidManifestInstrumentation_banner);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07002346 mParseInstrumentationArgs.tag = "<instrumentation>";
2347 }
2348
2349 mParseInstrumentationArgs.sa = sa;
2350
2351 Instrumentation a = new Instrumentation(mParseInstrumentationArgs,
2352 new InstrumentationInfo());
2353 if (outError[0] != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002354 sa.recycle();
2355 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2356 return null;
2357 }
2358
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002359 String str;
Dianne Hackborncf244ad2010-03-09 15:00:30 -08002360 // Note: don't allow this value to be a reference to a resource
2361 // that may change.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002362 str = sa.getNonResourceString(
2363 com.android.internal.R.styleable.AndroidManifestInstrumentation_targetPackage);
2364 a.info.targetPackage = str != null ? str.intern() : null;
2365
2366 a.info.handleProfiling = sa.getBoolean(
2367 com.android.internal.R.styleable.AndroidManifestInstrumentation_handleProfiling,
2368 false);
2369
2370 a.info.functionalTest = sa.getBoolean(
2371 com.android.internal.R.styleable.AndroidManifestInstrumentation_functionalTest,
2372 false);
2373
2374 sa.recycle();
2375
2376 if (a.info.targetPackage == null) {
2377 outError[0] = "<instrumentation> does not specify targetPackage";
2378 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2379 return null;
2380 }
2381
2382 if (!parseAllMetaData(res, parser, attrs, "<instrumentation>", a,
2383 outError)) {
2384 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2385 return null;
2386 }
2387
2388 owner.instrumentation.add(a);
2389
2390 return a;
2391 }
2392
Jeff Sharkeyda96e132014-07-15 14:54:09 -07002393 /**
2394 * Parse the {@code application} XML tree at the current parse location in a
2395 * <em>base APK</em> manifest.
2396 * <p>
2397 * When adding new features, carefully consider if they should also be
2398 * supported by split APKs.
2399 */
2400 private boolean parseBaseApplication(Package owner, Resources res,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002401 XmlPullParser parser, AttributeSet attrs, int flags, String[] outError)
2402 throws XmlPullParserException, IOException {
2403 final ApplicationInfo ai = owner.applicationInfo;
2404 final String pkgName = owner.applicationInfo.packageName;
2405
2406 TypedArray sa = res.obtainAttributes(attrs,
2407 com.android.internal.R.styleable.AndroidManifestApplication);
2408
Dianne Hackborncf244ad2010-03-09 15:00:30 -08002409 String name = sa.getNonConfigurationString(
2410 com.android.internal.R.styleable.AndroidManifestApplication_name, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002411 if (name != null) {
2412 ai.className = buildClassName(pkgName, name, outError);
2413 if (ai.className == null) {
2414 sa.recycle();
2415 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2416 return false;
2417 }
2418 }
2419
Dianne Hackborncf244ad2010-03-09 15:00:30 -08002420 String manageSpaceActivity = sa.getNonConfigurationString(
Dianne Hackborn1d0b1772013-09-06 14:02:54 -07002421 com.android.internal.R.styleable.AndroidManifestApplication_manageSpaceActivity,
2422 Configuration.NATIVE_CONFIG_VERSION);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002423 if (manageSpaceActivity != null) {
2424 ai.manageSpaceActivityName = buildClassName(pkgName, manageSpaceActivity,
2425 outError);
2426 }
2427
Christopher Tate181fafa2009-05-14 11:12:14 -07002428 boolean allowBackup = sa.getBoolean(
2429 com.android.internal.R.styleable.AndroidManifestApplication_allowBackup, true);
2430 if (allowBackup) {
2431 ai.flags |= ApplicationInfo.FLAG_ALLOW_BACKUP;
Christopher Tate5e1ab332009-09-01 20:32:49 -07002432
Christopher Tate3de55bc2010-03-12 17:28:08 -08002433 // backupAgent, killAfterRestore, and restoreAnyVersion are only relevant
2434 // if backup is possible for the given application.
Dianne Hackborncf244ad2010-03-09 15:00:30 -08002435 String backupAgent = sa.getNonConfigurationString(
Dianne Hackborn1d0b1772013-09-06 14:02:54 -07002436 com.android.internal.R.styleable.AndroidManifestApplication_backupAgent,
2437 Configuration.NATIVE_CONFIG_VERSION);
Christopher Tate181fafa2009-05-14 11:12:14 -07002438 if (backupAgent != null) {
2439 ai.backupAgentName = buildClassName(pkgName, backupAgent, outError);
Kenny Rootd2d29252011-08-08 11:27:57 -07002440 if (DEBUG_BACKUP) {
2441 Slog.v(TAG, "android:backupAgent = " + ai.backupAgentName
Dianne Hackborna33e3f72009-09-29 17:28:24 -07002442 + " from " + pkgName + "+" + backupAgent);
2443 }
Christopher Tate5e1ab332009-09-01 20:32:49 -07002444
2445 if (sa.getBoolean(
2446 com.android.internal.R.styleable.AndroidManifestApplication_killAfterRestore,
2447 true)) {
2448 ai.flags |= ApplicationInfo.FLAG_KILL_AFTER_RESTORE;
2449 }
2450 if (sa.getBoolean(
Christopher Tate3dda5182010-02-24 16:06:18 -08002451 com.android.internal.R.styleable.AndroidManifestApplication_restoreAnyVersion,
2452 false)) {
2453 ai.flags |= ApplicationInfo.FLAG_RESTORE_ANY_VERSION;
2454 }
Christopher Tated1de2562014-06-17 17:12:35 -07002455 if (sa.getBoolean(
2456 com.android.internal.R.styleable.AndroidManifestApplication_fullBackupOnly,
2457 false)) {
2458 ai.flags |= ApplicationInfo.FLAG_FULL_BACKUP_ONLY;
2459 }
Christopher Tate181fafa2009-05-14 11:12:14 -07002460 }
2461 }
Christopher Tate4a627c72011-04-01 14:43:32 -07002462
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002463 TypedValue v = sa.peekValue(
2464 com.android.internal.R.styleable.AndroidManifestApplication_label);
2465 if (v != null && (ai.labelRes=v.resourceId) == 0) {
2466 ai.nonLocalizedLabel = v.coerceToString();
2467 }
2468
2469 ai.icon = sa.getResourceId(
2470 com.android.internal.R.styleable.AndroidManifestApplication_icon, 0);
Adam Powell81cd2e92010-04-21 16:35:18 -07002471 ai.logo = sa.getResourceId(
2472 com.android.internal.R.styleable.AndroidManifestApplication_logo, 0);
Jose Limaf78e3122014-03-06 12:13:15 -08002473 ai.banner = sa.getResourceId(
2474 com.android.internal.R.styleable.AndroidManifestApplication_banner, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002475 ai.theme = sa.getResourceId(
Dianne Hackbornb35cd542011-01-04 21:30:53 -08002476 com.android.internal.R.styleable.AndroidManifestApplication_theme, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002477 ai.descriptionRes = sa.getResourceId(
2478 com.android.internal.R.styleable.AndroidManifestApplication_description, 0);
2479
2480 if ((flags&PARSE_IS_SYSTEM) != 0) {
2481 if (sa.getBoolean(
2482 com.android.internal.R.styleable.AndroidManifestApplication_persistent,
2483 false)) {
2484 ai.flags |= ApplicationInfo.FLAG_PERSISTENT;
2485 }
Amith Yamasani0d8750d2013-05-01 15:25:28 -07002486 }
2487
2488 if (sa.getBoolean(
2489 com.android.internal.R.styleable.AndroidManifestApplication_requiredForAllUsers,
2490 false)) {
2491 owner.mRequiredForAllUsers = true;
Amith Yamasanie993ae12013-04-15 13:42:57 -07002492 }
2493
2494 String restrictedAccountType = sa.getString(com.android.internal.R.styleable
2495 .AndroidManifestApplication_restrictedAccountType);
2496 if (restrictedAccountType != null && restrictedAccountType.length() > 0) {
2497 owner.mRestrictedAccountType = restrictedAccountType;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002498 }
2499
Amith Yamasaniccbe3892013-04-12 17:52:42 -07002500 String requiredAccountType = sa.getString(com.android.internal.R.styleable
2501 .AndroidManifestApplication_requiredAccountType);
2502 if (requiredAccountType != null && requiredAccountType.length() > 0) {
2503 owner.mRequiredAccountType = requiredAccountType;
2504 }
2505
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002506 if (sa.getBoolean(
2507 com.android.internal.R.styleable.AndroidManifestApplication_debuggable,
2508 false)) {
2509 ai.flags |= ApplicationInfo.FLAG_DEBUGGABLE;
2510 }
2511
2512 if (sa.getBoolean(
Ben Chengef3f5dd2010-03-29 15:47:26 -07002513 com.android.internal.R.styleable.AndroidManifestApplication_vmSafeMode,
Ben Cheng23085b72010-02-08 16:06:32 -08002514 false)) {
2515 ai.flags |= ApplicationInfo.FLAG_VM_SAFE_MODE;
2516 }
2517
Jeff Sharkeyda96e132014-07-15 14:54:09 -07002518 owner.baseHardwareAccelerated = sa.getBoolean(
Romain Guy812ccbe2010-06-01 14:07:24 -07002519 com.android.internal.R.styleable.AndroidManifestApplication_hardwareAccelerated,
Dianne Hackborn2d6833b2011-06-24 16:04:19 -07002520 owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.ICE_CREAM_SANDWICH);
Romain Guy812ccbe2010-06-01 14:07:24 -07002521
2522 if (sa.getBoolean(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002523 com.android.internal.R.styleable.AndroidManifestApplication_hasCode,
2524 true)) {
2525 ai.flags |= ApplicationInfo.FLAG_HAS_CODE;
2526 }
2527
2528 if (sa.getBoolean(
2529 com.android.internal.R.styleable.AndroidManifestApplication_allowTaskReparenting,
2530 false)) {
2531 ai.flags |= ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING;
2532 }
2533
2534 if (sa.getBoolean(
2535 com.android.internal.R.styleable.AndroidManifestApplication_allowClearUserData,
2536 true)) {
2537 ai.flags |= ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA;
2538 }
2539
Dianne Hackbornade3eca2009-05-11 18:54:45 -07002540 if (sa.getBoolean(
2541 com.android.internal.R.styleable.AndroidManifestApplication_testOnly,
Dianne Hackborne7fe35b2009-05-13 10:53:41 -07002542 false)) {
Dianne Hackbornade3eca2009-05-11 18:54:45 -07002543 ai.flags |= ApplicationInfo.FLAG_TEST_ONLY;
2544 }
2545
Jason parksa3cdaa52011-01-13 14:15:43 -06002546 if (sa.getBoolean(
Dianne Hackborn3b81bc12011-01-15 11:50:52 -08002547 com.android.internal.R.styleable.AndroidManifestApplication_largeHeap,
Jason parksa3cdaa52011-01-13 14:15:43 -06002548 false)) {
Dianne Hackborn3b81bc12011-01-15 11:50:52 -08002549 ai.flags |= ApplicationInfo.FLAG_LARGE_HEAP;
Jason parksa3cdaa52011-01-13 14:15:43 -06002550 }
2551
Fabrice Di Meglio59dfce82012-04-02 16:17:20 -07002552 if (sa.getBoolean(
2553 com.android.internal.R.styleable.AndroidManifestApplication_supportsRtl,
2554 false /* default is no RTL support*/)) {
2555 ai.flags |= ApplicationInfo.FLAG_SUPPORTS_RTL;
2556 }
2557
Narayan Kamath589a1bc2014-07-03 14:43:26 +01002558 if (sa.getBoolean(
2559 com.android.internal.R.styleable.AndroidManifestApplication_multiArch,
2560 false)) {
2561 ai.flags |= ApplicationInfo.FLAG_MULTIARCH;
2562 }
2563
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002564 String str;
Dianne Hackborncf244ad2010-03-09 15:00:30 -08002565 str = sa.getNonConfigurationString(
2566 com.android.internal.R.styleable.AndroidManifestApplication_permission, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002567 ai.permission = (str != null && str.length() > 0) ? str.intern() : null;
2568
Dianne Hackbornd1cff1b2010-04-02 16:51:26 -07002569 if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.FROYO) {
2570 str = sa.getNonConfigurationString(
Dianne Hackborn1d0b1772013-09-06 14:02:54 -07002571 com.android.internal.R.styleable.AndroidManifestApplication_taskAffinity,
2572 Configuration.NATIVE_CONFIG_VERSION);
Dianne Hackbornd1cff1b2010-04-02 16:51:26 -07002573 } else {
2574 // Some older apps have been seen to use a resource reference
2575 // here that on older builds was ignored (with a warning). We
2576 // need to continue to do this for them so they don't break.
2577 str = sa.getNonResourceString(
2578 com.android.internal.R.styleable.AndroidManifestApplication_taskAffinity);
2579 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002580 ai.taskAffinity = buildTaskAffinityName(ai.packageName, ai.packageName,
2581 str, outError);
2582
2583 if (outError[0] == null) {
Dianne Hackbornd1cff1b2010-04-02 16:51:26 -07002584 CharSequence pname;
2585 if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.FROYO) {
2586 pname = sa.getNonConfigurationString(
Dianne Hackborn1d0b1772013-09-06 14:02:54 -07002587 com.android.internal.R.styleable.AndroidManifestApplication_process,
2588 Configuration.NATIVE_CONFIG_VERSION);
Dianne Hackbornd1cff1b2010-04-02 16:51:26 -07002589 } else {
2590 // Some older apps have been seen to use a resource reference
2591 // here that on older builds was ignored (with a warning). We
2592 // need to continue to do this for them so they don't break.
2593 pname = sa.getNonResourceString(
2594 com.android.internal.R.styleable.AndroidManifestApplication_process);
2595 }
2596 ai.processName = buildProcessName(ai.packageName, null, pname,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002597 flags, mSeparateProcesses, outError);
2598
Dianne Hackborncf244ad2010-03-09 15:00:30 -08002599 ai.enabled = sa.getBoolean(
2600 com.android.internal.R.styleable.AndroidManifestApplication_enabled, true);
Dianne Hackborn860755f2010-06-03 18:47:52 -07002601
Jose Lima12d0b4c2014-03-14 16:55:12 -07002602 if (sa.getBoolean(
2603 com.android.internal.R.styleable.AndroidManifestApplication_isGame, false)) {
2604 ai.flags |= ApplicationInfo.FLAG_IS_GAME;
2605 }
2606
Dianne Hackborn02486b12010-08-26 14:18:37 -07002607 if (false) {
2608 if (sa.getBoolean(
2609 com.android.internal.R.styleable.AndroidManifestApplication_cantSaveState,
2610 false)) {
Alex Klyubinb9f8a522015-02-03 11:12:59 -08002611 ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE;
Dianne Hackborn02486b12010-08-26 14:18:37 -07002612
2613 // A heavy-weight application can not be in a custom process.
2614 // We can do direct compare because we intern all strings.
2615 if (ai.processName != null && ai.processName != ai.packageName) {
2616 outError[0] = "cantSaveState applications can not use custom processes";
2617 }
Dianne Hackborn860755f2010-06-03 18:47:52 -07002618 }
2619 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002620 }
2621
Adam Powell269248d2011-08-02 10:26:54 -07002622 ai.uiOptions = sa.getInt(
2623 com.android.internal.R.styleable.AndroidManifestApplication_uiOptions, 0);
2624
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002625 sa.recycle();
2626
2627 if (outError[0] != null) {
2628 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2629 return false;
2630 }
2631
2632 final int innerDepth = parser.getDepth();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002633 int type;
Kenny Rootd2d29252011-08-08 11:27:57 -07002634 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
2635 && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
2636 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002637 continue;
2638 }
2639
2640 String tagName = parser.getName();
2641 if (tagName.equals("activity")) {
Romain Guy529b60a2010-08-03 18:05:47 -07002642 Activity a = parseActivity(owner, res, parser, attrs, flags, outError, false,
Jeff Sharkeyda96e132014-07-15 14:54:09 -07002643 owner.baseHardwareAccelerated);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002644 if (a == null) {
2645 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2646 return false;
2647 }
2648
2649 owner.activities.add(a);
2650
2651 } else if (tagName.equals("receiver")) {
Romain Guy529b60a2010-08-03 18:05:47 -07002652 Activity a = parseActivity(owner, res, parser, attrs, flags, outError, true, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002653 if (a == null) {
2654 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2655 return false;
2656 }
2657
2658 owner.receivers.add(a);
2659
2660 } else if (tagName.equals("service")) {
2661 Service s = parseService(owner, res, parser, attrs, flags, outError);
2662 if (s == null) {
2663 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2664 return false;
2665 }
2666
2667 owner.services.add(s);
2668
2669 } else if (tagName.equals("provider")) {
2670 Provider p = parseProvider(owner, res, parser, attrs, flags, outError);
2671 if (p == null) {
2672 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2673 return false;
2674 }
2675
2676 owner.providers.add(p);
2677
2678 } else if (tagName.equals("activity-alias")) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07002679 Activity a = parseActivityAlias(owner, res, parser, attrs, flags, outError);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002680 if (a == null) {
2681 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2682 return false;
2683 }
2684
2685 owner.activities.add(a);
2686
2687 } else if (parser.getName().equals("meta-data")) {
2688 // note: application meta-data is stored off to the side, so it can
2689 // remain null in the primary copy (we like to avoid extra copies because
2690 // it can be large)
2691 if ((owner.mAppMetaData = parseMetaData(res, parser, attrs, owner.mAppMetaData,
2692 outError)) == null) {
2693 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2694 return false;
2695 }
2696
Dianne Hackbornc895be72013-03-11 17:48:43 -07002697 } else if (tagName.equals("library")) {
2698 sa = res.obtainAttributes(attrs,
2699 com.android.internal.R.styleable.AndroidManifestLibrary);
2700
2701 // Note: don't allow this value to be a reference to a resource
2702 // that may change.
2703 String lname = sa.getNonResourceString(
2704 com.android.internal.R.styleable.AndroidManifestLibrary_name);
2705
2706 sa.recycle();
2707
2708 if (lname != null) {
Jeff Sharkeyda96e132014-07-15 14:54:09 -07002709 lname = lname.intern();
2710 if (!ArrayUtils.contains(owner.libraryNames, lname)) {
2711 owner.libraryNames = ArrayUtils.add(owner.libraryNames, lname);
Dianne Hackbornc895be72013-03-11 17:48:43 -07002712 }
2713 }
2714
2715 XmlUtils.skipCurrentTag(parser);
2716
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002717 } else if (tagName.equals("uses-library")) {
2718 sa = res.obtainAttributes(attrs,
2719 com.android.internal.R.styleable.AndroidManifestUsesLibrary);
2720
Dianne Hackborncf244ad2010-03-09 15:00:30 -08002721 // Note: don't allow this value to be a reference to a resource
2722 // that may change.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002723 String lname = sa.getNonResourceString(
2724 com.android.internal.R.styleable.AndroidManifestUsesLibrary_name);
Dianne Hackborn49237342009-08-27 20:08:01 -07002725 boolean req = sa.getBoolean(
2726 com.android.internal.R.styleable.AndroidManifestUsesLibrary_required,
2727 true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002728
2729 sa.recycle();
2730
Dianne Hackborn49237342009-08-27 20:08:01 -07002731 if (lname != null) {
Jeff Sharkeyda96e132014-07-15 14:54:09 -07002732 lname = lname.intern();
Dianne Hackborn49237342009-08-27 20:08:01 -07002733 if (req) {
Jeff Sharkeyda96e132014-07-15 14:54:09 -07002734 owner.usesLibraries = ArrayUtils.add(owner.usesLibraries, lname);
Dianne Hackborn49237342009-08-27 20:08:01 -07002735 } else {
Jeff Sharkeyda96e132014-07-15 14:54:09 -07002736 owner.usesOptionalLibraries = ArrayUtils.add(
2737 owner.usesOptionalLibraries, lname);
2738 }
2739 }
2740
2741 XmlUtils.skipCurrentTag(parser);
2742
2743 } else if (tagName.equals("uses-package")) {
2744 // Dependencies for app installers; we don't currently try to
2745 // enforce this.
2746 XmlUtils.skipCurrentTag(parser);
2747
2748 } else {
2749 if (!RIGID_PARSER) {
2750 Slog.w(TAG, "Unknown element under <application>: " + tagName
2751 + " at " + mArchiveSourcePath + " "
2752 + parser.getPositionDescription());
2753 XmlUtils.skipCurrentTag(parser);
2754 continue;
2755 } else {
2756 outError[0] = "Bad element under <application>: " + tagName;
2757 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2758 return false;
2759 }
2760 }
2761 }
2762
2763 return true;
2764 }
2765
2766 /**
2767 * Parse the {@code application} XML tree at the current parse location in a
2768 * <em>split APK</em> manifest.
2769 * <p>
2770 * Note that split APKs have many more restrictions on what they're capable
2771 * of doing, so many valid features of a base APK have been carefully
2772 * omitted here.
2773 */
2774 private boolean parseSplitApplication(Package owner, Resources res, XmlPullParser parser,
2775 AttributeSet attrs, int flags, int splitIndex, String[] outError)
2776 throws XmlPullParserException, IOException {
2777 TypedArray sa = res.obtainAttributes(attrs,
2778 com.android.internal.R.styleable.AndroidManifestApplication);
2779
2780 if (sa.getBoolean(
2781 com.android.internal.R.styleable.AndroidManifestApplication_hasCode, true)) {
2782 owner.splitFlags[splitIndex] |= ApplicationInfo.FLAG_HAS_CODE;
2783 }
2784
2785 final int innerDepth = parser.getDepth();
2786 int type;
2787 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
2788 && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
2789 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
2790 continue;
2791 }
2792
2793 String tagName = parser.getName();
2794 if (tagName.equals("activity")) {
2795 Activity a = parseActivity(owner, res, parser, attrs, flags, outError, false,
2796 owner.baseHardwareAccelerated);
2797 if (a == null) {
2798 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2799 return false;
2800 }
2801
2802 owner.activities.add(a);
2803
2804 } else if (tagName.equals("receiver")) {
2805 Activity a = parseActivity(owner, res, parser, attrs, flags, outError, true, false);
2806 if (a == null) {
2807 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2808 return false;
2809 }
2810
2811 owner.receivers.add(a);
2812
2813 } else if (tagName.equals("service")) {
2814 Service s = parseService(owner, res, parser, attrs, flags, outError);
2815 if (s == null) {
2816 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2817 return false;
2818 }
2819
2820 owner.services.add(s);
2821
2822 } else if (tagName.equals("provider")) {
2823 Provider p = parseProvider(owner, res, parser, attrs, flags, outError);
2824 if (p == null) {
2825 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2826 return false;
2827 }
2828
2829 owner.providers.add(p);
2830
2831 } else if (tagName.equals("activity-alias")) {
2832 Activity a = parseActivityAlias(owner, res, parser, attrs, flags, outError);
2833 if (a == null) {
2834 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2835 return false;
2836 }
2837
2838 owner.activities.add(a);
2839
2840 } else if (parser.getName().equals("meta-data")) {
2841 // note: application meta-data is stored off to the side, so it can
2842 // remain null in the primary copy (we like to avoid extra copies because
2843 // it can be large)
2844 if ((owner.mAppMetaData = parseMetaData(res, parser, attrs, owner.mAppMetaData,
2845 outError)) == null) {
2846 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2847 return false;
2848 }
2849
2850 } else if (tagName.equals("uses-library")) {
2851 sa = res.obtainAttributes(attrs,
2852 com.android.internal.R.styleable.AndroidManifestUsesLibrary);
2853
2854 // Note: don't allow this value to be a reference to a resource
2855 // that may change.
2856 String lname = sa.getNonResourceString(
2857 com.android.internal.R.styleable.AndroidManifestUsesLibrary_name);
2858 boolean req = sa.getBoolean(
2859 com.android.internal.R.styleable.AndroidManifestUsesLibrary_required,
2860 true);
2861
2862 sa.recycle();
2863
2864 if (lname != null) {
2865 lname = lname.intern();
2866 if (req) {
2867 // Upgrade to treat as stronger constraint
2868 owner.usesLibraries = ArrayUtils.add(owner.usesLibraries, lname);
2869 owner.usesOptionalLibraries = ArrayUtils.remove(
2870 owner.usesOptionalLibraries, lname);
2871 } else {
2872 // Ignore if someone already defined as required
2873 if (!ArrayUtils.contains(owner.usesLibraries, lname)) {
2874 owner.usesOptionalLibraries = ArrayUtils.add(
2875 owner.usesOptionalLibraries, lname);
Dianne Hackborn49237342009-08-27 20:08:01 -07002876 }
2877 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002878 }
2879
2880 XmlUtils.skipCurrentTag(parser);
2881
Dianne Hackborncef65ee2010-09-30 18:27:22 -07002882 } else if (tagName.equals("uses-package")) {
2883 // Dependencies for app installers; we don't currently try to
2884 // enforce this.
2885 XmlUtils.skipCurrentTag(parser);
2886
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002887 } else {
2888 if (!RIGID_PARSER) {
Kenny Rootd2d29252011-08-08 11:27:57 -07002889 Slog.w(TAG, "Unknown element under <application>: " + tagName
Dianne Hackborna33e3f72009-09-29 17:28:24 -07002890 + " at " + mArchiveSourcePath + " "
2891 + parser.getPositionDescription());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002892 XmlUtils.skipCurrentTag(parser);
2893 continue;
2894 } else {
2895 outError[0] = "Bad element under <application>: " + tagName;
2896 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
2897 return false;
2898 }
2899 }
2900 }
2901
2902 return true;
2903 }
2904
2905 private boolean parsePackageItemInfo(Package owner, PackageItemInfo outInfo,
2906 String[] outError, String tag, TypedArray sa,
Jose Limaf78e3122014-03-06 12:13:15 -08002907 int nameRes, int labelRes, int iconRes, int logoRes, int bannerRes) {
Dianne Hackborncf244ad2010-03-09 15:00:30 -08002908 String name = sa.getNonConfigurationString(nameRes, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002909 if (name == null) {
2910 outError[0] = tag + " does not specify android:name";
2911 return false;
2912 }
2913
2914 outInfo.name
2915 = buildClassName(owner.applicationInfo.packageName, name, outError);
2916 if (outInfo.name == null) {
2917 return false;
2918 }
2919
2920 int iconVal = sa.getResourceId(iconRes, 0);
2921 if (iconVal != 0) {
2922 outInfo.icon = iconVal;
2923 outInfo.nonLocalizedLabel = null;
2924 }
Adam Powell81cd2e92010-04-21 16:35:18 -07002925
2926 int logoVal = sa.getResourceId(logoRes, 0);
2927 if (logoVal != 0) {
2928 outInfo.logo = logoVal;
2929 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002930
Jose Limaf78e3122014-03-06 12:13:15 -08002931 int bannerVal = sa.getResourceId(bannerRes, 0);
2932 if (bannerVal != 0) {
2933 outInfo.banner = bannerVal;
2934 }
2935
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002936 TypedValue v = sa.peekValue(labelRes);
2937 if (v != null && (outInfo.labelRes=v.resourceId) == 0) {
2938 outInfo.nonLocalizedLabel = v.coerceToString();
2939 }
2940
2941 outInfo.packageName = owner.packageName;
2942
2943 return true;
2944 }
2945
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002946 private Activity parseActivity(Package owner, Resources res,
2947 XmlPullParser parser, AttributeSet attrs, int flags, String[] outError,
Romain Guy529b60a2010-08-03 18:05:47 -07002948 boolean receiver, boolean hardwareAccelerated)
2949 throws XmlPullParserException, IOException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002950 TypedArray sa = res.obtainAttributes(attrs,
2951 com.android.internal.R.styleable.AndroidManifestActivity);
2952
Dianne Hackborn1d442e02009-04-20 18:14:05 -07002953 if (mParseActivityArgs == null) {
2954 mParseActivityArgs = new ParseComponentArgs(owner, outError,
2955 com.android.internal.R.styleable.AndroidManifestActivity_name,
2956 com.android.internal.R.styleable.AndroidManifestActivity_label,
2957 com.android.internal.R.styleable.AndroidManifestActivity_icon,
Adam Powell81cd2e92010-04-21 16:35:18 -07002958 com.android.internal.R.styleable.AndroidManifestActivity_logo,
Jose Limaf78e3122014-03-06 12:13:15 -08002959 com.android.internal.R.styleable.AndroidManifestActivity_banner,
Dianne Hackborn1d442e02009-04-20 18:14:05 -07002960 mSeparateProcesses,
2961 com.android.internal.R.styleable.AndroidManifestActivity_process,
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08002962 com.android.internal.R.styleable.AndroidManifestActivity_description,
Dianne Hackborn1d442e02009-04-20 18:14:05 -07002963 com.android.internal.R.styleable.AndroidManifestActivity_enabled);
2964 }
2965
2966 mParseActivityArgs.tag = receiver ? "<receiver>" : "<activity>";
2967 mParseActivityArgs.sa = sa;
2968 mParseActivityArgs.flags = flags;
2969
2970 Activity a = new Activity(mParseActivityArgs, new ActivityInfo());
2971 if (outError[0] != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002972 sa.recycle();
2973 return null;
2974 }
2975
Dianne Hackborn7d19e022012-08-07 19:12:33 -07002976 boolean setExported = sa.hasValue(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002977 com.android.internal.R.styleable.AndroidManifestActivity_exported);
2978 if (setExported) {
2979 a.info.exported = sa.getBoolean(
2980 com.android.internal.R.styleable.AndroidManifestActivity_exported, false);
2981 }
2982
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002983 a.info.theme = sa.getResourceId(
2984 com.android.internal.R.styleable.AndroidManifestActivity_theme, 0);
2985
Adam Powell269248d2011-08-02 10:26:54 -07002986 a.info.uiOptions = sa.getInt(
2987 com.android.internal.R.styleable.AndroidManifestActivity_uiOptions,
2988 a.info.applicationInfo.uiOptions);
2989
Adam Powelldd8fab22012-03-22 17:47:27 -07002990 String parentName = sa.getNonConfigurationString(
Dianne Hackborn1d0b1772013-09-06 14:02:54 -07002991 com.android.internal.R.styleable.AndroidManifestActivity_parentActivityName,
2992 Configuration.NATIVE_CONFIG_VERSION);
Adam Powelldd8fab22012-03-22 17:47:27 -07002993 if (parentName != null) {
2994 String parentClassName = buildClassName(a.info.packageName, parentName, outError);
2995 if (outError[0] == null) {
2996 a.info.parentActivityName = parentClassName;
2997 } else {
2998 Log.e(TAG, "Activity " + a.info.name + " specified invalid parentActivityName " +
2999 parentName);
3000 outError[0] = null;
3001 }
3002 }
3003
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003004 String str;
Dianne Hackborncf244ad2010-03-09 15:00:30 -08003005 str = sa.getNonConfigurationString(
3006 com.android.internal.R.styleable.AndroidManifestActivity_permission, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003007 if (str == null) {
3008 a.info.permission = owner.applicationInfo.permission;
3009 } else {
3010 a.info.permission = str.length() > 0 ? str.toString().intern() : null;
3011 }
3012
Dianne Hackborncf244ad2010-03-09 15:00:30 -08003013 str = sa.getNonConfigurationString(
Dianne Hackborn1d0b1772013-09-06 14:02:54 -07003014 com.android.internal.R.styleable.AndroidManifestActivity_taskAffinity,
3015 Configuration.NATIVE_CONFIG_VERSION);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003016 a.info.taskAffinity = buildTaskAffinityName(owner.applicationInfo.packageName,
3017 owner.applicationInfo.taskAffinity, str, outError);
3018
3019 a.info.flags = 0;
3020 if (sa.getBoolean(
3021 com.android.internal.R.styleable.AndroidManifestActivity_multiprocess,
3022 false)) {
3023 a.info.flags |= ActivityInfo.FLAG_MULTIPROCESS;
3024 }
3025
3026 if (sa.getBoolean(
3027 com.android.internal.R.styleable.AndroidManifestActivity_finishOnTaskLaunch,
3028 false)) {
3029 a.info.flags |= ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH;
3030 }
3031
3032 if (sa.getBoolean(
3033 com.android.internal.R.styleable.AndroidManifestActivity_clearTaskOnLaunch,
3034 false)) {
3035 a.info.flags |= ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH;
3036 }
3037
3038 if (sa.getBoolean(
3039 com.android.internal.R.styleable.AndroidManifestActivity_noHistory,
3040 false)) {
3041 a.info.flags |= ActivityInfo.FLAG_NO_HISTORY;
3042 }
3043
3044 if (sa.getBoolean(
3045 com.android.internal.R.styleable.AndroidManifestActivity_alwaysRetainTaskState,
3046 false)) {
3047 a.info.flags |= ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE;
3048 }
3049
3050 if (sa.getBoolean(
3051 com.android.internal.R.styleable.AndroidManifestActivity_stateNotNeeded,
3052 false)) {
3053 a.info.flags |= ActivityInfo.FLAG_STATE_NOT_NEEDED;
3054 }
3055
3056 if (sa.getBoolean(
3057 com.android.internal.R.styleable.AndroidManifestActivity_excludeFromRecents,
3058 false)) {
3059 a.info.flags |= ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS;
3060 }
3061
3062 if (sa.getBoolean(
3063 com.android.internal.R.styleable.AndroidManifestActivity_allowTaskReparenting,
3064 (owner.applicationInfo.flags&ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING) != 0)) {
3065 a.info.flags |= ActivityInfo.FLAG_ALLOW_TASK_REPARENTING;
3066 }
3067
Dianne Hackbornffa42482009-09-23 22:20:11 -07003068 if (sa.getBoolean(
3069 com.android.internal.R.styleable.AndroidManifestActivity_finishOnCloseSystemDialogs,
3070 false)) {
3071 a.info.flags |= ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS;
3072 }
3073
Daniel Sandler613dde42010-06-21 13:46:39 -04003074 if (sa.getBoolean(
Craig Mautner5962b122012-10-05 14:45:52 -07003075 com.android.internal.R.styleable.AndroidManifestActivity_showOnLockScreen,
3076 false)) {
3077 a.info.flags |= ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN;
3078 }
3079
3080 if (sa.getBoolean(
Daniel Sandler613dde42010-06-21 13:46:39 -04003081 com.android.internal.R.styleable.AndroidManifestActivity_immersive,
3082 false)) {
3083 a.info.flags |= ActivityInfo.FLAG_IMMERSIVE;
3084 }
Craig Mautner5962b122012-10-05 14:45:52 -07003085
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003086 if (!receiver) {
Romain Guy529b60a2010-08-03 18:05:47 -07003087 if (sa.getBoolean(
3088 com.android.internal.R.styleable.AndroidManifestActivity_hardwareAccelerated,
3089 hardwareAccelerated)) {
3090 a.info.flags |= ActivityInfo.FLAG_HARDWARE_ACCELERATED;
3091 }
3092
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003093 a.info.launchMode = sa.getInt(
3094 com.android.internal.R.styleable.AndroidManifestActivity_launchMode,
3095 ActivityInfo.LAUNCH_MULTIPLE);
Craig Mautner2dac0562014-05-06 09:06:44 -07003096 a.info.documentLaunchMode = sa.getInt(
3097 com.android.internal.R.styleable.AndroidManifestActivity_documentLaunchMode,
3098 ActivityInfo.DOCUMENT_LAUNCH_NONE);
Craig Mautnerffcfcaa2014-06-05 09:54:38 -07003099 a.info.maxRecents = sa.getInt(
3100 com.android.internal.R.styleable.AndroidManifestActivity_maxRecents,
Dianne Hackborn852975d2014-08-22 17:42:43 -07003101 ActivityManager.getDefaultAppRecentsLimitStatic());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003102 a.info.screenOrientation = sa.getInt(
3103 com.android.internal.R.styleable.AndroidManifestActivity_screenOrientation,
3104 ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
3105 a.info.configChanges = sa.getInt(
3106 com.android.internal.R.styleable.AndroidManifestActivity_configChanges,
3107 0);
3108 a.info.softInputMode = sa.getInt(
3109 com.android.internal.R.styleable.AndroidManifestActivity_windowSoftInputMode,
3110 0);
Craig Mautner2dac0562014-05-06 09:06:44 -07003111
Craig Mautner43e52ed2014-06-16 17:18:52 -07003112 a.info.persistableMode = sa.getInteger(
3113 com.android.internal.R.styleable.AndroidManifestActivity_persistableMode,
3114 ActivityInfo.PERSIST_ROOT_ONLY);
Craig Mautner2dac0562014-05-06 09:06:44 -07003115
3116 if (sa.getBoolean(
3117 com.android.internal.R.styleable.AndroidManifestActivity_allowEmbedded,
3118 false)) {
3119 a.info.flags |= ActivityInfo.FLAG_ALLOW_EMBEDDED;
3120 }
3121
3122 if (sa.getBoolean(
3123 com.android.internal.R.styleable.AndroidManifestActivity_autoRemoveFromRecents,
3124 false)) {
3125 a.info.flags |= ActivityInfo.FLAG_AUTO_REMOVE_FROM_RECENTS;
3126 }
Craig Mautner9d4e9bc2014-06-18 18:34:56 -07003127
3128 if (sa.getBoolean(
3129 com.android.internal.R.styleable.AndroidManifestActivity_relinquishTaskIdentity,
3130 false)) {
3131 a.info.flags |= ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY;
3132 }
Dianne Hackborna4e102e2014-09-04 22:52:27 -07003133
3134 if (sa.getBoolean(
3135 com.android.internal.R.styleable.AndroidManifestActivity_resumeWhilePausing,
3136 false)) {
3137 a.info.flags |= ActivityInfo.FLAG_RESUME_WHILE_PAUSING;
3138 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003139 } else {
3140 a.info.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
3141 a.info.configChanges = 0;
3142 }
3143
Dianne Hackborn7d19e022012-08-07 19:12:33 -07003144 if (receiver) {
3145 if (sa.getBoolean(
3146 com.android.internal.R.styleable.AndroidManifestActivity_singleUser,
3147 false)) {
Dianne Hackbornd4ac8d72012-09-27 23:20:10 -07003148 a.info.flags |= ActivityInfo.FLAG_SINGLE_USER;
Amith Yamasani4b9d79c2014-05-21 19:14:21 -07003149 if (a.info.exported && (flags & PARSE_IS_PRIVILEGED) == 0) {
Dianne Hackborn7d19e022012-08-07 19:12:33 -07003150 Slog.w(TAG, "Activity exported request ignored due to singleUser: "
3151 + a.className + " at " + mArchiveSourcePath + " "
3152 + parser.getPositionDescription());
3153 a.info.exported = false;
Amith Yamasani4b9d79c2014-05-21 19:14:21 -07003154 setExported = true;
Dianne Hackborn7d19e022012-08-07 19:12:33 -07003155 }
Dianne Hackborn7d19e022012-08-07 19:12:33 -07003156 }
Dianne Hackbornd4ac8d72012-09-27 23:20:10 -07003157 if (sa.getBoolean(
3158 com.android.internal.R.styleable.AndroidManifestActivity_primaryUserOnly,
3159 false)) {
3160 a.info.flags |= ActivityInfo.FLAG_PRIMARY_USER_ONLY;
3161 }
Dianne Hackborn7d19e022012-08-07 19:12:33 -07003162 }
3163
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003164 sa.recycle();
3165
Alex Klyubinb9f8a522015-02-03 11:12:59 -08003166 if (receiver && (owner.applicationInfo.privateFlags
3167 &ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0) {
Dianne Hackborn860755f2010-06-03 18:47:52 -07003168 // A heavy-weight application can not have receives in its main process
3169 // We can do direct compare because we intern all strings.
3170 if (a.info.processName == owner.packageName) {
3171 outError[0] = "Heavy-weight applications can not have receivers in main process";
3172 }
3173 }
3174
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003175 if (outError[0] != null) {
3176 return null;
3177 }
3178
3179 int outerDepth = parser.getDepth();
3180 int type;
3181 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
3182 && (type != XmlPullParser.END_TAG
3183 || parser.getDepth() > outerDepth)) {
3184 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
3185 continue;
3186 }
3187
3188 if (parser.getName().equals("intent-filter")) {
3189 ActivityIntentInfo intent = new ActivityIntentInfo(a);
Dianne Hackbornb09491f2013-07-22 15:30:11 -07003190 if (!parseIntent(res, parser, attrs, true, intent, outError)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003191 return null;
3192 }
3193 if (intent.countActions() == 0) {
Kenny Rootd2d29252011-08-08 11:27:57 -07003194 Slog.w(TAG, "No actions in intent filter at "
Dianne Hackbornbd0a81f2009-10-04 13:30:50 -07003195 + mArchiveSourcePath + " "
3196 + parser.getPositionDescription());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003197 } else {
3198 a.intents.add(intent);
3199 }
Dianne Hackbornb09491f2013-07-22 15:30:11 -07003200 } else if (!receiver && parser.getName().equals("preferred")) {
3201 ActivityIntentInfo intent = new ActivityIntentInfo(a);
3202 if (!parseIntent(res, parser, attrs, false, intent, outError)) {
3203 return null;
3204 }
3205 if (intent.countActions() == 0) {
3206 Slog.w(TAG, "No actions in preferred at "
3207 + mArchiveSourcePath + " "
3208 + parser.getPositionDescription());
3209 } else {
3210 if (owner.preferredActivityFilters == null) {
3211 owner.preferredActivityFilters = new ArrayList<ActivityIntentInfo>();
3212 }
3213 owner.preferredActivityFilters.add(intent);
3214 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003215 } else if (parser.getName().equals("meta-data")) {
3216 if ((a.metaData=parseMetaData(res, parser, attrs, a.metaData,
3217 outError)) == null) {
3218 return null;
3219 }
3220 } else {
3221 if (!RIGID_PARSER) {
Kenny Rootd2d29252011-08-08 11:27:57 -07003222 Slog.w(TAG, "Problem in package " + mArchiveSourcePath + ":");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003223 if (receiver) {
Kenny Rootd2d29252011-08-08 11:27:57 -07003224 Slog.w(TAG, "Unknown element under <receiver>: " + parser.getName()
Dianne Hackborna33e3f72009-09-29 17:28:24 -07003225 + " at " + mArchiveSourcePath + " "
3226 + parser.getPositionDescription());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003227 } else {
Kenny Rootd2d29252011-08-08 11:27:57 -07003228 Slog.w(TAG, "Unknown element under <activity>: " + parser.getName()
Dianne Hackborna33e3f72009-09-29 17:28:24 -07003229 + " at " + mArchiveSourcePath + " "
3230 + parser.getPositionDescription());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003231 }
3232 XmlUtils.skipCurrentTag(parser);
3233 continue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003234 } else {
Kenny Rootd2d29252011-08-08 11:27:57 -07003235 if (receiver) {
3236 outError[0] = "Bad element under <receiver>: " + parser.getName();
3237 } else {
3238 outError[0] = "Bad element under <activity>: " + parser.getName();
3239 }
3240 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003241 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003242 }
3243 }
3244
3245 if (!setExported) {
3246 a.info.exported = a.intents.size() > 0;
3247 }
3248
3249 return a;
3250 }
3251
3252 private Activity parseActivityAlias(Package owner, Resources res,
Dianne Hackborn1d442e02009-04-20 18:14:05 -07003253 XmlPullParser parser, AttributeSet attrs, int flags, String[] outError)
3254 throws XmlPullParserException, IOException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003255 TypedArray sa = res.obtainAttributes(attrs,
3256 com.android.internal.R.styleable.AndroidManifestActivityAlias);
3257
Dianne Hackborncf244ad2010-03-09 15:00:30 -08003258 String targetActivity = sa.getNonConfigurationString(
Dianne Hackborn1d0b1772013-09-06 14:02:54 -07003259 com.android.internal.R.styleable.AndroidManifestActivityAlias_targetActivity,
3260 Configuration.NATIVE_CONFIG_VERSION);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003261 if (targetActivity == null) {
3262 outError[0] = "<activity-alias> does not specify android:targetActivity";
3263 sa.recycle();
3264 return null;
3265 }
3266
3267 targetActivity = buildClassName(owner.applicationInfo.packageName,
3268 targetActivity, outError);
3269 if (targetActivity == null) {
3270 sa.recycle();
3271 return null;
3272 }
3273
Dianne Hackborn1d442e02009-04-20 18:14:05 -07003274 if (mParseActivityAliasArgs == null) {
3275 mParseActivityAliasArgs = new ParseComponentArgs(owner, outError,
3276 com.android.internal.R.styleable.AndroidManifestActivityAlias_name,
3277 com.android.internal.R.styleable.AndroidManifestActivityAlias_label,
3278 com.android.internal.R.styleable.AndroidManifestActivityAlias_icon,
Adam Powell81cd2e92010-04-21 16:35:18 -07003279 com.android.internal.R.styleable.AndroidManifestActivityAlias_logo,
Jose Limaf78e3122014-03-06 12:13:15 -08003280 com.android.internal.R.styleable.AndroidManifestActivityAlias_banner,
Dianne Hackborn1d442e02009-04-20 18:14:05 -07003281 mSeparateProcesses,
3282 0,
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08003283 com.android.internal.R.styleable.AndroidManifestActivityAlias_description,
Dianne Hackborn1d442e02009-04-20 18:14:05 -07003284 com.android.internal.R.styleable.AndroidManifestActivityAlias_enabled);
3285 mParseActivityAliasArgs.tag = "<activity-alias>";
3286 }
3287
3288 mParseActivityAliasArgs.sa = sa;
3289 mParseActivityAliasArgs.flags = flags;
3290
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003291 Activity target = null;
3292
3293 final int NA = owner.activities.size();
3294 for (int i=0; i<NA; i++) {
3295 Activity t = owner.activities.get(i);
3296 if (targetActivity.equals(t.info.name)) {
3297 target = t;
3298 break;
3299 }
3300 }
3301
3302 if (target == null) {
3303 outError[0] = "<activity-alias> target activity " + targetActivity
3304 + " not found in manifest";
3305 sa.recycle();
3306 return null;
3307 }
3308
Dianne Hackborn1d442e02009-04-20 18:14:05 -07003309 ActivityInfo info = new ActivityInfo();
3310 info.targetActivity = targetActivity;
3311 info.configChanges = target.info.configChanges;
3312 info.flags = target.info.flags;
3313 info.icon = target.info.icon;
Adam Powell81cd2e92010-04-21 16:35:18 -07003314 info.logo = target.info.logo;
Jose Limaf78e3122014-03-06 12:13:15 -08003315 info.banner = target.info.banner;
Dianne Hackborn1d442e02009-04-20 18:14:05 -07003316 info.labelRes = target.info.labelRes;
3317 info.nonLocalizedLabel = target.info.nonLocalizedLabel;
3318 info.launchMode = target.info.launchMode;
3319 info.processName = target.info.processName;
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08003320 if (info.descriptionRes == 0) {
3321 info.descriptionRes = target.info.descriptionRes;
3322 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07003323 info.screenOrientation = target.info.screenOrientation;
3324 info.taskAffinity = target.info.taskAffinity;
3325 info.theme = target.info.theme;
Dianne Hackborn0836c7c2011-10-20 18:40:23 -07003326 info.softInputMode = target.info.softInputMode;
Adam Powell269248d2011-08-02 10:26:54 -07003327 info.uiOptions = target.info.uiOptions;
Adam Powelldd8fab22012-03-22 17:47:27 -07003328 info.parentActivityName = target.info.parentActivityName;
Craig Mautner8307ea72014-09-11 15:03:53 -07003329 info.maxRecents = target.info.maxRecents;
3330
Dianne Hackborn1d442e02009-04-20 18:14:05 -07003331 Activity a = new Activity(mParseActivityAliasArgs, info);
3332 if (outError[0] != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003333 sa.recycle();
3334 return null;
3335 }
3336
3337 final boolean setExported = sa.hasValue(
3338 com.android.internal.R.styleable.AndroidManifestActivityAlias_exported);
3339 if (setExported) {
3340 a.info.exported = sa.getBoolean(
3341 com.android.internal.R.styleable.AndroidManifestActivityAlias_exported, false);
3342 }
3343
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003344 String str;
Dianne Hackborncf244ad2010-03-09 15:00:30 -08003345 str = sa.getNonConfigurationString(
3346 com.android.internal.R.styleable.AndroidManifestActivityAlias_permission, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003347 if (str != null) {
3348 a.info.permission = str.length() > 0 ? str.toString().intern() : null;
3349 }
3350
Adam Powelldd8fab22012-03-22 17:47:27 -07003351 String parentName = sa.getNonConfigurationString(
3352 com.android.internal.R.styleable.AndroidManifestActivityAlias_parentActivityName,
Dianne Hackborn1d0b1772013-09-06 14:02:54 -07003353 Configuration.NATIVE_CONFIG_VERSION);
Adam Powelldd8fab22012-03-22 17:47:27 -07003354 if (parentName != null) {
3355 String parentClassName = buildClassName(a.info.packageName, parentName, outError);
3356 if (outError[0] == null) {
3357 a.info.parentActivityName = parentClassName;
3358 } else {
3359 Log.e(TAG, "Activity alias " + a.info.name +
3360 " specified invalid parentActivityName " + parentName);
3361 outError[0] = null;
3362 }
3363 }
3364
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003365 sa.recycle();
3366
3367 if (outError[0] != null) {
3368 return null;
3369 }
3370
3371 int outerDepth = parser.getDepth();
3372 int type;
3373 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
3374 && (type != XmlPullParser.END_TAG
3375 || parser.getDepth() > outerDepth)) {
3376 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
3377 continue;
3378 }
3379
3380 if (parser.getName().equals("intent-filter")) {
3381 ActivityIntentInfo intent = new ActivityIntentInfo(a);
Dianne Hackbornb09491f2013-07-22 15:30:11 -07003382 if (!parseIntent(res, parser, attrs, true, intent, outError)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003383 return null;
3384 }
3385 if (intent.countActions() == 0) {
Kenny Rootd2d29252011-08-08 11:27:57 -07003386 Slog.w(TAG, "No actions in intent filter at "
Dianne Hackbornbd0a81f2009-10-04 13:30:50 -07003387 + mArchiveSourcePath + " "
3388 + parser.getPositionDescription());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003389 } else {
3390 a.intents.add(intent);
3391 }
3392 } else if (parser.getName().equals("meta-data")) {
3393 if ((a.metaData=parseMetaData(res, parser, attrs, a.metaData,
3394 outError)) == null) {
3395 return null;
3396 }
3397 } else {
3398 if (!RIGID_PARSER) {
Kenny Rootd2d29252011-08-08 11:27:57 -07003399 Slog.w(TAG, "Unknown element under <activity-alias>: " + parser.getName()
Dianne Hackborna33e3f72009-09-29 17:28:24 -07003400 + " at " + mArchiveSourcePath + " "
3401 + parser.getPositionDescription());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003402 XmlUtils.skipCurrentTag(parser);
3403 continue;
Kenny Rootd2d29252011-08-08 11:27:57 -07003404 } else {
3405 outError[0] = "Bad element under <activity-alias>: " + parser.getName();
3406 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003407 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003408 }
3409 }
3410
3411 if (!setExported) {
3412 a.info.exported = a.intents.size() > 0;
3413 }
3414
3415 return a;
3416 }
3417
3418 private Provider parseProvider(Package owner, Resources res,
3419 XmlPullParser parser, AttributeSet attrs, int flags, String[] outError)
3420 throws XmlPullParserException, IOException {
3421 TypedArray sa = res.obtainAttributes(attrs,
3422 com.android.internal.R.styleable.AndroidManifestProvider);
3423
Dianne Hackborn1d442e02009-04-20 18:14:05 -07003424 if (mParseProviderArgs == null) {
3425 mParseProviderArgs = new ParseComponentArgs(owner, outError,
3426 com.android.internal.R.styleable.AndroidManifestProvider_name,
3427 com.android.internal.R.styleable.AndroidManifestProvider_label,
3428 com.android.internal.R.styleable.AndroidManifestProvider_icon,
Adam Powell81cd2e92010-04-21 16:35:18 -07003429 com.android.internal.R.styleable.AndroidManifestProvider_logo,
Jose Limaf78e3122014-03-06 12:13:15 -08003430 com.android.internal.R.styleable.AndroidManifestProvider_banner,
Dianne Hackborn1d442e02009-04-20 18:14:05 -07003431 mSeparateProcesses,
3432 com.android.internal.R.styleable.AndroidManifestProvider_process,
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08003433 com.android.internal.R.styleable.AndroidManifestProvider_description,
Dianne Hackborn1d442e02009-04-20 18:14:05 -07003434 com.android.internal.R.styleable.AndroidManifestProvider_enabled);
3435 mParseProviderArgs.tag = "<provider>";
3436 }
3437
3438 mParseProviderArgs.sa = sa;
3439 mParseProviderArgs.flags = flags;
3440
3441 Provider p = new Provider(mParseProviderArgs, new ProviderInfo());
3442 if (outError[0] != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003443 sa.recycle();
3444 return null;
3445 }
3446
Nick Kralevichf097b162012-07-28 12:43:48 -07003447 boolean providerExportedDefault = false;
3448
3449 if (owner.applicationInfo.targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR1) {
3450 // For compatibility, applications targeting API level 16 or lower
3451 // should have their content providers exported by default, unless they
3452 // specify otherwise.
3453 providerExportedDefault = true;
3454 }
3455
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003456 p.info.exported = sa.getBoolean(
Nick Kralevichf097b162012-07-28 12:43:48 -07003457 com.android.internal.R.styleable.AndroidManifestProvider_exported,
3458 providerExportedDefault);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003459
Dianne Hackborncf244ad2010-03-09 15:00:30 -08003460 String cpname = sa.getNonConfigurationString(
3461 com.android.internal.R.styleable.AndroidManifestProvider_authorities, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003462
3463 p.info.isSyncable = sa.getBoolean(
3464 com.android.internal.R.styleable.AndroidManifestProvider_syncable,
3465 false);
3466
Dianne Hackborncf244ad2010-03-09 15:00:30 -08003467 String permission = sa.getNonConfigurationString(
3468 com.android.internal.R.styleable.AndroidManifestProvider_permission, 0);
3469 String str = sa.getNonConfigurationString(
3470 com.android.internal.R.styleable.AndroidManifestProvider_readPermission, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003471 if (str == null) {
3472 str = permission;
3473 }
3474 if (str == null) {
3475 p.info.readPermission = owner.applicationInfo.permission;
3476 } else {
3477 p.info.readPermission =
3478 str.length() > 0 ? str.toString().intern() : null;
3479 }
Dianne Hackborncf244ad2010-03-09 15:00:30 -08003480 str = sa.getNonConfigurationString(
3481 com.android.internal.R.styleable.AndroidManifestProvider_writePermission, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003482 if (str == null) {
3483 str = permission;
3484 }
3485 if (str == null) {
3486 p.info.writePermission = owner.applicationInfo.permission;
3487 } else {
3488 p.info.writePermission =
3489 str.length() > 0 ? str.toString().intern() : null;
3490 }
3491
3492 p.info.grantUriPermissions = sa.getBoolean(
3493 com.android.internal.R.styleable.AndroidManifestProvider_grantUriPermissions,
3494 false);
3495
3496 p.info.multiprocess = sa.getBoolean(
3497 com.android.internal.R.styleable.AndroidManifestProvider_multiprocess,
3498 false);
3499
3500 p.info.initOrder = sa.getInt(
3501 com.android.internal.R.styleable.AndroidManifestProvider_initOrder,
3502 0);
3503
Dianne Hackborn7d19e022012-08-07 19:12:33 -07003504 p.info.flags = 0;
3505
3506 if (sa.getBoolean(
3507 com.android.internal.R.styleable.AndroidManifestProvider_singleUser,
3508 false)) {
3509 p.info.flags |= ProviderInfo.FLAG_SINGLE_USER;
Amith Yamasani4b9d79c2014-05-21 19:14:21 -07003510 if (p.info.exported && (flags & PARSE_IS_PRIVILEGED) == 0) {
Dianne Hackborn7d19e022012-08-07 19:12:33 -07003511 Slog.w(TAG, "Provider exported request ignored due to singleUser: "
3512 + p.className + " at " + mArchiveSourcePath + " "
3513 + parser.getPositionDescription());
3514 p.info.exported = false;
3515 }
3516 }
3517
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003518 sa.recycle();
3519
Alex Klyubinb9f8a522015-02-03 11:12:59 -08003520 if ((owner.applicationInfo.privateFlags&ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE)
3521 != 0) {
Dianne Hackborn860755f2010-06-03 18:47:52 -07003522 // A heavy-weight application can not have providers in its main process
3523 // We can do direct compare because we intern all strings.
3524 if (p.info.processName == owner.packageName) {
3525 outError[0] = "Heavy-weight applications can not have providers in main process";
3526 return null;
3527 }
3528 }
3529
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003530 if (cpname == null) {
Nick Kralevichf097b162012-07-28 12:43:48 -07003531 outError[0] = "<provider> does not include authorities attribute";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003532 return null;
3533 }
Dianne Hackborn1bc177c2014-12-03 10:20:30 -08003534 if (cpname.length() <= 0) {
3535 outError[0] = "<provider> has empty authorities attribute";
3536 return null;
3537 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003538 p.info.authority = cpname.intern();
3539
3540 if (!parseProviderTags(res, parser, attrs, p, outError)) {
3541 return null;
3542 }
3543
3544 return p;
3545 }
3546
3547 private boolean parseProviderTags(Resources res,
3548 XmlPullParser parser, AttributeSet attrs,
3549 Provider outInfo, String[] outError)
3550 throws XmlPullParserException, IOException {
3551 int outerDepth = parser.getDepth();
3552 int type;
3553 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
3554 && (type != XmlPullParser.END_TAG
3555 || parser.getDepth() > outerDepth)) {
3556 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
3557 continue;
3558 }
3559
Jeff Sharkey85f5f812013-10-07 10:16:12 -07003560 if (parser.getName().equals("intent-filter")) {
3561 ProviderIntentInfo intent = new ProviderIntentInfo(outInfo);
3562 if (!parseIntent(res, parser, attrs, true, intent, outError)) {
3563 return false;
3564 }
3565 outInfo.intents.add(intent);
3566
3567 } else if (parser.getName().equals("meta-data")) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003568 if ((outInfo.metaData=parseMetaData(res, parser, attrs,
3569 outInfo.metaData, outError)) == null) {
3570 return false;
3571 }
Dianne Hackborn2af632f2009-07-08 14:56:37 -07003572
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003573 } else if (parser.getName().equals("grant-uri-permission")) {
3574 TypedArray sa = res.obtainAttributes(attrs,
3575 com.android.internal.R.styleable.AndroidManifestGrantUriPermission);
3576
3577 PatternMatcher pa = null;
3578
Dianne Hackborncf244ad2010-03-09 15:00:30 -08003579 String str = sa.getNonConfigurationString(
3580 com.android.internal.R.styleable.AndroidManifestGrantUriPermission_path, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003581 if (str != null) {
3582 pa = new PatternMatcher(str, PatternMatcher.PATTERN_LITERAL);
3583 }
3584
Dianne Hackborncf244ad2010-03-09 15:00:30 -08003585 str = sa.getNonConfigurationString(
3586 com.android.internal.R.styleable.AndroidManifestGrantUriPermission_pathPrefix, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003587 if (str != null) {
3588 pa = new PatternMatcher(str, PatternMatcher.PATTERN_PREFIX);
3589 }
3590
Dianne Hackborncf244ad2010-03-09 15:00:30 -08003591 str = sa.getNonConfigurationString(
3592 com.android.internal.R.styleable.AndroidManifestGrantUriPermission_pathPattern, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003593 if (str != null) {
3594 pa = new PatternMatcher(str, PatternMatcher.PATTERN_SIMPLE_GLOB);
3595 }
Dianne Hackborn2af632f2009-07-08 14:56:37 -07003596
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003597 sa.recycle();
3598
3599 if (pa != null) {
3600 if (outInfo.info.uriPermissionPatterns == null) {
3601 outInfo.info.uriPermissionPatterns = new PatternMatcher[1];
3602 outInfo.info.uriPermissionPatterns[0] = pa;
3603 } else {
3604 final int N = outInfo.info.uriPermissionPatterns.length;
3605 PatternMatcher[] newp = new PatternMatcher[N+1];
3606 System.arraycopy(outInfo.info.uriPermissionPatterns, 0, newp, 0, N);
3607 newp[N] = pa;
3608 outInfo.info.uriPermissionPatterns = newp;
3609 }
3610 outInfo.info.grantUriPermissions = true;
Dianne Hackborn2af632f2009-07-08 14:56:37 -07003611 } else {
3612 if (!RIGID_PARSER) {
Kenny Rootd2d29252011-08-08 11:27:57 -07003613 Slog.w(TAG, "Unknown element under <path-permission>: "
Dianne Hackborna33e3f72009-09-29 17:28:24 -07003614 + parser.getName() + " at " + mArchiveSourcePath + " "
3615 + parser.getPositionDescription());
Dianne Hackborn2af632f2009-07-08 14:56:37 -07003616 XmlUtils.skipCurrentTag(parser);
3617 continue;
Kenny Rootd2d29252011-08-08 11:27:57 -07003618 } else {
3619 outError[0] = "No path, pathPrefix, or pathPattern for <path-permission>";
3620 return false;
Dianne Hackborn2af632f2009-07-08 14:56:37 -07003621 }
Dianne Hackborn2af632f2009-07-08 14:56:37 -07003622 }
3623 XmlUtils.skipCurrentTag(parser);
3624
3625 } else if (parser.getName().equals("path-permission")) {
3626 TypedArray sa = res.obtainAttributes(attrs,
3627 com.android.internal.R.styleable.AndroidManifestPathPermission);
3628
3629 PathPermission pa = null;
3630
Dianne Hackborncf244ad2010-03-09 15:00:30 -08003631 String permission = sa.getNonConfigurationString(
3632 com.android.internal.R.styleable.AndroidManifestPathPermission_permission, 0);
3633 String readPermission = sa.getNonConfigurationString(
3634 com.android.internal.R.styleable.AndroidManifestPathPermission_readPermission, 0);
Dianne Hackborn2af632f2009-07-08 14:56:37 -07003635 if (readPermission == null) {
3636 readPermission = permission;
3637 }
Dianne Hackborncf244ad2010-03-09 15:00:30 -08003638 String writePermission = sa.getNonConfigurationString(
3639 com.android.internal.R.styleable.AndroidManifestPathPermission_writePermission, 0);
Dianne Hackborn2af632f2009-07-08 14:56:37 -07003640 if (writePermission == null) {
3641 writePermission = permission;
3642 }
3643
3644 boolean havePerm = false;
3645 if (readPermission != null) {
3646 readPermission = readPermission.intern();
3647 havePerm = true;
3648 }
3649 if (writePermission != null) {
Bjorn Bringerte04b1ad2010-02-09 13:56:08 +00003650 writePermission = writePermission.intern();
Dianne Hackborn2af632f2009-07-08 14:56:37 -07003651 havePerm = true;
3652 }
3653
3654 if (!havePerm) {
3655 if (!RIGID_PARSER) {
Kenny Rootd2d29252011-08-08 11:27:57 -07003656 Slog.w(TAG, "No readPermission or writePermssion for <path-permission>: "
Dianne Hackborna33e3f72009-09-29 17:28:24 -07003657 + parser.getName() + " at " + mArchiveSourcePath + " "
3658 + parser.getPositionDescription());
Dianne Hackborn2af632f2009-07-08 14:56:37 -07003659 XmlUtils.skipCurrentTag(parser);
3660 continue;
Kenny Rootd2d29252011-08-08 11:27:57 -07003661 } else {
3662 outError[0] = "No readPermission or writePermssion for <path-permission>";
3663 return false;
Dianne Hackborn2af632f2009-07-08 14:56:37 -07003664 }
Dianne Hackborn2af632f2009-07-08 14:56:37 -07003665 }
3666
Dianne Hackborncf244ad2010-03-09 15:00:30 -08003667 String path = sa.getNonConfigurationString(
3668 com.android.internal.R.styleable.AndroidManifestPathPermission_path, 0);
Dianne Hackborn2af632f2009-07-08 14:56:37 -07003669 if (path != null) {
3670 pa = new PathPermission(path,
3671 PatternMatcher.PATTERN_LITERAL, readPermission, writePermission);
3672 }
3673
Dianne Hackborncf244ad2010-03-09 15:00:30 -08003674 path = sa.getNonConfigurationString(
3675 com.android.internal.R.styleable.AndroidManifestPathPermission_pathPrefix, 0);
Dianne Hackborn2af632f2009-07-08 14:56:37 -07003676 if (path != null) {
3677 pa = new PathPermission(path,
3678 PatternMatcher.PATTERN_PREFIX, readPermission, writePermission);
3679 }
3680
Dianne Hackborncf244ad2010-03-09 15:00:30 -08003681 path = sa.getNonConfigurationString(
3682 com.android.internal.R.styleable.AndroidManifestPathPermission_pathPattern, 0);
Dianne Hackborn2af632f2009-07-08 14:56:37 -07003683 if (path != null) {
3684 pa = new PathPermission(path,
3685 PatternMatcher.PATTERN_SIMPLE_GLOB, readPermission, writePermission);
3686 }
3687
3688 sa.recycle();
3689
3690 if (pa != null) {
3691 if (outInfo.info.pathPermissions == null) {
3692 outInfo.info.pathPermissions = new PathPermission[1];
3693 outInfo.info.pathPermissions[0] = pa;
3694 } else {
3695 final int N = outInfo.info.pathPermissions.length;
3696 PathPermission[] newp = new PathPermission[N+1];
3697 System.arraycopy(outInfo.info.pathPermissions, 0, newp, 0, N);
3698 newp[N] = pa;
3699 outInfo.info.pathPermissions = newp;
3700 }
3701 } else {
3702 if (!RIGID_PARSER) {
Kenny Rootd2d29252011-08-08 11:27:57 -07003703 Slog.w(TAG, "No path, pathPrefix, or pathPattern for <path-permission>: "
Dianne Hackborna33e3f72009-09-29 17:28:24 -07003704 + parser.getName() + " at " + mArchiveSourcePath + " "
3705 + parser.getPositionDescription());
Dianne Hackborn2af632f2009-07-08 14:56:37 -07003706 XmlUtils.skipCurrentTag(parser);
3707 continue;
3708 }
3709 outError[0] = "No path, pathPrefix, or pathPattern for <path-permission>";
3710 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003711 }
3712 XmlUtils.skipCurrentTag(parser);
3713
3714 } else {
3715 if (!RIGID_PARSER) {
Kenny Rootd2d29252011-08-08 11:27:57 -07003716 Slog.w(TAG, "Unknown element under <provider>: "
Dianne Hackborna33e3f72009-09-29 17:28:24 -07003717 + parser.getName() + " at " + mArchiveSourcePath + " "
3718 + parser.getPositionDescription());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003719 XmlUtils.skipCurrentTag(parser);
3720 continue;
Kenny Rootd2d29252011-08-08 11:27:57 -07003721 } else {
3722 outError[0] = "Bad element under <provider>: " + parser.getName();
3723 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003724 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003725 }
3726 }
3727 return true;
3728 }
3729
3730 private Service parseService(Package owner, Resources res,
3731 XmlPullParser parser, AttributeSet attrs, int flags, String[] outError)
3732 throws XmlPullParserException, IOException {
3733 TypedArray sa = res.obtainAttributes(attrs,
3734 com.android.internal.R.styleable.AndroidManifestService);
3735
Dianne Hackborn1d442e02009-04-20 18:14:05 -07003736 if (mParseServiceArgs == null) {
3737 mParseServiceArgs = new ParseComponentArgs(owner, outError,
3738 com.android.internal.R.styleable.AndroidManifestService_name,
3739 com.android.internal.R.styleable.AndroidManifestService_label,
3740 com.android.internal.R.styleable.AndroidManifestService_icon,
Adam Powell81cd2e92010-04-21 16:35:18 -07003741 com.android.internal.R.styleable.AndroidManifestService_logo,
Jose Limaf78e3122014-03-06 12:13:15 -08003742 com.android.internal.R.styleable.AndroidManifestService_banner,
Dianne Hackborn1d442e02009-04-20 18:14:05 -07003743 mSeparateProcesses,
3744 com.android.internal.R.styleable.AndroidManifestService_process,
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08003745 com.android.internal.R.styleable.AndroidManifestService_description,
Dianne Hackborn1d442e02009-04-20 18:14:05 -07003746 com.android.internal.R.styleable.AndroidManifestService_enabled);
3747 mParseServiceArgs.tag = "<service>";
3748 }
3749
3750 mParseServiceArgs.sa = sa;
3751 mParseServiceArgs.flags = flags;
3752
3753 Service s = new Service(mParseServiceArgs, new ServiceInfo());
3754 if (outError[0] != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003755 sa.recycle();
3756 return null;
3757 }
3758
Dianne Hackbornb4163a62012-08-02 18:31:26 -07003759 boolean setExported = sa.hasValue(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003760 com.android.internal.R.styleable.AndroidManifestService_exported);
3761 if (setExported) {
3762 s.info.exported = sa.getBoolean(
3763 com.android.internal.R.styleable.AndroidManifestService_exported, false);
3764 }
3765
Dianne Hackborncf244ad2010-03-09 15:00:30 -08003766 String str = sa.getNonConfigurationString(
3767 com.android.internal.R.styleable.AndroidManifestService_permission, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003768 if (str == null) {
3769 s.info.permission = owner.applicationInfo.permission;
3770 } else {
3771 s.info.permission = str.length() > 0 ? str.toString().intern() : null;
3772 }
3773
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07003774 s.info.flags = 0;
3775 if (sa.getBoolean(
3776 com.android.internal.R.styleable.AndroidManifestService_stopWithTask,
3777 false)) {
3778 s.info.flags |= ServiceInfo.FLAG_STOP_WITH_TASK;
3779 }
Dianne Hackborna0c283e2012-02-09 10:47:01 -08003780 if (sa.getBoolean(
3781 com.android.internal.R.styleable.AndroidManifestService_isolatedProcess,
3782 false)) {
3783 s.info.flags |= ServiceInfo.FLAG_ISOLATED_PROCESS;
3784 }
Dianne Hackbornb4163a62012-08-02 18:31:26 -07003785 if (sa.getBoolean(
3786 com.android.internal.R.styleable.AndroidManifestService_singleUser,
3787 false)) {
3788 s.info.flags |= ServiceInfo.FLAG_SINGLE_USER;
Amith Yamasani4b9d79c2014-05-21 19:14:21 -07003789 if (s.info.exported && (flags & PARSE_IS_PRIVILEGED) == 0) {
Dianne Hackbornb4163a62012-08-02 18:31:26 -07003790 Slog.w(TAG, "Service exported request ignored due to singleUser: "
3791 + s.className + " at " + mArchiveSourcePath + " "
3792 + parser.getPositionDescription());
3793 s.info.exported = false;
Amith Yamasani4b9d79c2014-05-21 19:14:21 -07003794 setExported = true;
Dianne Hackbornb4163a62012-08-02 18:31:26 -07003795 }
Dianne Hackbornb4163a62012-08-02 18:31:26 -07003796 }
Dianne Hackborn0c5001d2011-04-12 18:16:08 -07003797
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003798 sa.recycle();
3799
Alex Klyubinb9f8a522015-02-03 11:12:59 -08003800 if ((owner.applicationInfo.privateFlags&ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE)
3801 != 0) {
Dianne Hackborn860755f2010-06-03 18:47:52 -07003802 // A heavy-weight application can not have services in its main process
3803 // We can do direct compare because we intern all strings.
3804 if (s.info.processName == owner.packageName) {
3805 outError[0] = "Heavy-weight applications can not have services in main process";
3806 return null;
3807 }
3808 }
3809
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003810 int outerDepth = parser.getDepth();
3811 int type;
3812 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
3813 && (type != XmlPullParser.END_TAG
3814 || parser.getDepth() > outerDepth)) {
3815 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
3816 continue;
3817 }
3818
3819 if (parser.getName().equals("intent-filter")) {
3820 ServiceIntentInfo intent = new ServiceIntentInfo(s);
Dianne Hackbornb09491f2013-07-22 15:30:11 -07003821 if (!parseIntent(res, parser, attrs, true, intent, outError)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003822 return null;
3823 }
3824
3825 s.intents.add(intent);
3826 } else if (parser.getName().equals("meta-data")) {
3827 if ((s.metaData=parseMetaData(res, parser, attrs, s.metaData,
3828 outError)) == null) {
3829 return null;
3830 }
3831 } else {
3832 if (!RIGID_PARSER) {
Kenny Rootd2d29252011-08-08 11:27:57 -07003833 Slog.w(TAG, "Unknown element under <service>: "
Dianne Hackborna33e3f72009-09-29 17:28:24 -07003834 + parser.getName() + " at " + mArchiveSourcePath + " "
3835 + parser.getPositionDescription());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003836 XmlUtils.skipCurrentTag(parser);
3837 continue;
Kenny Rootd2d29252011-08-08 11:27:57 -07003838 } else {
3839 outError[0] = "Bad element under <service>: " + parser.getName();
3840 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003841 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003842 }
3843 }
3844
3845 if (!setExported) {
3846 s.info.exported = s.intents.size() > 0;
3847 }
3848
3849 return s;
3850 }
3851
3852 private boolean parseAllMetaData(Resources res,
3853 XmlPullParser parser, AttributeSet attrs, String tag,
3854 Component outInfo, String[] outError)
3855 throws XmlPullParserException, IOException {
3856 int outerDepth = parser.getDepth();
3857 int type;
3858 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
3859 && (type != XmlPullParser.END_TAG
3860 || parser.getDepth() > outerDepth)) {
3861 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
3862 continue;
3863 }
3864
3865 if (parser.getName().equals("meta-data")) {
3866 if ((outInfo.metaData=parseMetaData(res, parser, attrs,
3867 outInfo.metaData, outError)) == null) {
3868 return false;
3869 }
3870 } else {
3871 if (!RIGID_PARSER) {
Kenny Rootd2d29252011-08-08 11:27:57 -07003872 Slog.w(TAG, "Unknown element under " + tag + ": "
Dianne Hackborna33e3f72009-09-29 17:28:24 -07003873 + parser.getName() + " at " + mArchiveSourcePath + " "
3874 + parser.getPositionDescription());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003875 XmlUtils.skipCurrentTag(parser);
3876 continue;
Kenny Rootd2d29252011-08-08 11:27:57 -07003877 } else {
3878 outError[0] = "Bad element under " + tag + ": " + parser.getName();
3879 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003880 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003881 }
3882 }
3883 return true;
3884 }
3885
3886 private Bundle parseMetaData(Resources res,
3887 XmlPullParser parser, AttributeSet attrs,
3888 Bundle data, String[] outError)
3889 throws XmlPullParserException, IOException {
3890
3891 TypedArray sa = res.obtainAttributes(attrs,
3892 com.android.internal.R.styleable.AndroidManifestMetaData);
3893
3894 if (data == null) {
3895 data = new Bundle();
3896 }
3897
Dianne Hackborncf244ad2010-03-09 15:00:30 -08003898 String name = sa.getNonConfigurationString(
3899 com.android.internal.R.styleable.AndroidManifestMetaData_name, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003900 if (name == null) {
3901 outError[0] = "<meta-data> requires an android:name attribute";
3902 sa.recycle();
3903 return null;
3904 }
3905
Dianne Hackborn854060af2009-07-09 18:14:31 -07003906 name = name.intern();
3907
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003908 TypedValue v = sa.peekValue(
3909 com.android.internal.R.styleable.AndroidManifestMetaData_resource);
3910 if (v != null && v.resourceId != 0) {
Kenny Rootd2d29252011-08-08 11:27:57 -07003911 //Slog.i(TAG, "Meta data ref " + name + ": " + v);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003912 data.putInt(name, v.resourceId);
3913 } else {
3914 v = sa.peekValue(
3915 com.android.internal.R.styleable.AndroidManifestMetaData_value);
Kenny Rootd2d29252011-08-08 11:27:57 -07003916 //Slog.i(TAG, "Meta data " + name + ": " + v);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003917 if (v != null) {
3918 if (v.type == TypedValue.TYPE_STRING) {
3919 CharSequence cs = v.coerceToString();
Dianne Hackborn854060af2009-07-09 18:14:31 -07003920 data.putString(name, cs != null ? cs.toString().intern() : null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003921 } else if (v.type == TypedValue.TYPE_INT_BOOLEAN) {
3922 data.putBoolean(name, v.data != 0);
3923 } else if (v.type >= TypedValue.TYPE_FIRST_INT
3924 && v.type <= TypedValue.TYPE_LAST_INT) {
3925 data.putInt(name, v.data);
3926 } else if (v.type == TypedValue.TYPE_FLOAT) {
3927 data.putFloat(name, v.getFloat());
3928 } else {
3929 if (!RIGID_PARSER) {
Kenny Rootd2d29252011-08-08 11:27:57 -07003930 Slog.w(TAG, "<meta-data> only supports string, integer, float, color, boolean, and resource reference types: "
Dianne Hackborna33e3f72009-09-29 17:28:24 -07003931 + parser.getName() + " at " + mArchiveSourcePath + " "
3932 + parser.getPositionDescription());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003933 } else {
3934 outError[0] = "<meta-data> only supports string, integer, float, color, boolean, and resource reference types";
3935 data = null;
3936 }
3937 }
3938 } else {
3939 outError[0] = "<meta-data> requires an android:value or android:resource attribute";
3940 data = null;
3941 }
3942 }
3943
3944 sa.recycle();
3945
3946 XmlUtils.skipCurrentTag(parser);
3947
3948 return data;
3949 }
3950
Kenny Root05ca4c92011-09-15 10:36:25 -07003951 private static VerifierInfo parseVerifier(Resources res, XmlPullParser parser,
Jeff Sharkey275e0852014-06-17 18:18:49 -07003952 AttributeSet attrs, int flags) {
Kenny Root05ca4c92011-09-15 10:36:25 -07003953 final TypedArray sa = res.obtainAttributes(attrs,
3954 com.android.internal.R.styleable.AndroidManifestPackageVerifier);
3955
3956 final String packageName = sa.getNonResourceString(
3957 com.android.internal.R.styleable.AndroidManifestPackageVerifier_name);
3958
3959 final String encodedPublicKey = sa.getNonResourceString(
3960 com.android.internal.R.styleable.AndroidManifestPackageVerifier_publicKey);
3961
3962 sa.recycle();
3963
3964 if (packageName == null || packageName.length() == 0) {
3965 Slog.i(TAG, "verifier package name was null; skipping");
3966 return null;
Kenny Root05ca4c92011-09-15 10:36:25 -07003967 }
3968
Christopher Tate30147332014-04-15 12:57:47 -07003969 final PublicKey publicKey = parsePublicKey(encodedPublicKey);
3970 if (publicKey == null) {
3971 Slog.i(TAG, "Unable to parse verifier public key for " + packageName);
3972 return null;
Geremy Condraf1bcca82013-01-07 22:35:24 -08003973 }
3974
Christopher Tate30147332014-04-15 12:57:47 -07003975 return new VerifierInfo(packageName, publicKey);
Geremy Condraf1bcca82013-01-07 22:35:24 -08003976 }
3977
Christopher Tate30147332014-04-15 12:57:47 -07003978 public static final PublicKey parsePublicKey(final String encodedPublicKey) {
3979 if (encodedPublicKey == null) {
3980 Slog.i(TAG, "Could not parse null public key");
3981 return null;
3982 }
3983
Kenny Root05ca4c92011-09-15 10:36:25 -07003984 EncodedKeySpec keySpec;
3985 try {
3986 final byte[] encoded = Base64.decode(encodedPublicKey, Base64.DEFAULT);
3987 keySpec = new X509EncodedKeySpec(encoded);
3988 } catch (IllegalArgumentException e) {
Geremy Condraf1bcca82013-01-07 22:35:24 -08003989 Slog.i(TAG, "Could not parse verifier public key; invalid Base64");
Kenny Root05ca4c92011-09-15 10:36:25 -07003990 return null;
3991 }
3992
3993 /* First try the key as an RSA key. */
3994 try {
3995 final KeyFactory keyFactory = KeyFactory.getInstance("RSA");
Geremy Condraf1bcca82013-01-07 22:35:24 -08003996 return keyFactory.generatePublic(keySpec);
Kenny Root05ca4c92011-09-15 10:36:25 -07003997 } catch (NoSuchAlgorithmException e) {
3998 Log.wtf(TAG, "Could not parse public key because RSA isn't included in build");
3999 return null;
4000 } catch (InvalidKeySpecException e) {
4001 // Not a RSA public key.
4002 }
4003
4004 /* Now try it as a DSA key. */
4005 try {
4006 final KeyFactory keyFactory = KeyFactory.getInstance("DSA");
Geremy Condraf1bcca82013-01-07 22:35:24 -08004007 return keyFactory.generatePublic(keySpec);
Kenny Root05ca4c92011-09-15 10:36:25 -07004008 } catch (NoSuchAlgorithmException e) {
4009 Log.wtf(TAG, "Could not parse public key because DSA isn't included in build");
4010 return null;
4011 } catch (InvalidKeySpecException e) {
4012 // Not a DSA public key.
4013 }
4014
4015 return null;
4016 }
4017
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004018 private static final String ANDROID_RESOURCES
4019 = "http://schemas.android.com/apk/res/android";
4020
Dianne Hackbornb09491f2013-07-22 15:30:11 -07004021 private boolean parseIntent(Resources res, XmlPullParser parser, AttributeSet attrs,
4022 boolean allowGlobs, IntentInfo outInfo, String[] outError)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004023 throws XmlPullParserException, IOException {
4024
4025 TypedArray sa = res.obtainAttributes(attrs,
4026 com.android.internal.R.styleable.AndroidManifestIntentFilter);
4027
4028 int priority = sa.getInt(
4029 com.android.internal.R.styleable.AndroidManifestIntentFilter_priority, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004030 outInfo.setPriority(priority);
Kenny Root502e9a42011-01-10 13:48:15 -08004031
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004032 TypedValue v = sa.peekValue(
4033 com.android.internal.R.styleable.AndroidManifestIntentFilter_label);
4034 if (v != null && (outInfo.labelRes=v.resourceId) == 0) {
4035 outInfo.nonLocalizedLabel = v.coerceToString();
4036 }
4037
4038 outInfo.icon = sa.getResourceId(
4039 com.android.internal.R.styleable.AndroidManifestIntentFilter_icon, 0);
Adam Powell81cd2e92010-04-21 16:35:18 -07004040
4041 outInfo.logo = sa.getResourceId(
4042 com.android.internal.R.styleable.AndroidManifestIntentFilter_logo, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004043
Jose Limaf78e3122014-03-06 12:13:15 -08004044 outInfo.banner = sa.getResourceId(
4045 com.android.internal.R.styleable.AndroidManifestIntentFilter_banner, 0);
4046
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004047 sa.recycle();
4048
4049 int outerDepth = parser.getDepth();
4050 int type;
Kenny Rootd2d29252011-08-08 11:27:57 -07004051 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
4052 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
4053 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004054 continue;
4055 }
4056
4057 String nodeName = parser.getName();
4058 if (nodeName.equals("action")) {
4059 String value = attrs.getAttributeValue(
4060 ANDROID_RESOURCES, "name");
4061 if (value == null || value == "") {
4062 outError[0] = "No value supplied for <android:name>";
4063 return false;
4064 }
4065 XmlUtils.skipCurrentTag(parser);
4066
4067 outInfo.addAction(value);
4068 } else if (nodeName.equals("category")) {
4069 String value = attrs.getAttributeValue(
4070 ANDROID_RESOURCES, "name");
4071 if (value == null || value == "") {
4072 outError[0] = "No value supplied for <android:name>";
4073 return false;
4074 }
4075 XmlUtils.skipCurrentTag(parser);
4076
4077 outInfo.addCategory(value);
4078
4079 } else if (nodeName.equals("data")) {
4080 sa = res.obtainAttributes(attrs,
4081 com.android.internal.R.styleable.AndroidManifestData);
4082
Dianne Hackborncf244ad2010-03-09 15:00:30 -08004083 String str = sa.getNonConfigurationString(
4084 com.android.internal.R.styleable.AndroidManifestData_mimeType, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004085 if (str != null) {
4086 try {
4087 outInfo.addDataType(str);
4088 } catch (IntentFilter.MalformedMimeTypeException e) {
4089 outError[0] = e.toString();
4090 sa.recycle();
4091 return false;
4092 }
4093 }
4094
Dianne Hackborncf244ad2010-03-09 15:00:30 -08004095 str = sa.getNonConfigurationString(
4096 com.android.internal.R.styleable.AndroidManifestData_scheme, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004097 if (str != null) {
4098 outInfo.addDataScheme(str);
4099 }
4100
Dianne Hackborndf1c0bf2013-06-12 16:21:38 -07004101 str = sa.getNonConfigurationString(
4102 com.android.internal.R.styleable.AndroidManifestData_ssp, 0);
4103 if (str != null) {
4104 outInfo.addDataSchemeSpecificPart(str, PatternMatcher.PATTERN_LITERAL);
4105 }
4106
4107 str = sa.getNonConfigurationString(
4108 com.android.internal.R.styleable.AndroidManifestData_sspPrefix, 0);
4109 if (str != null) {
4110 outInfo.addDataSchemeSpecificPart(str, PatternMatcher.PATTERN_PREFIX);
4111 }
4112
4113 str = sa.getNonConfigurationString(
4114 com.android.internal.R.styleable.AndroidManifestData_sspPattern, 0);
4115 if (str != null) {
Dianne Hackbornb09491f2013-07-22 15:30:11 -07004116 if (!allowGlobs) {
4117 outError[0] = "sspPattern not allowed here; ssp must be literal";
4118 return false;
4119 }
Dianne Hackborndf1c0bf2013-06-12 16:21:38 -07004120 outInfo.addDataSchemeSpecificPart(str, PatternMatcher.PATTERN_SIMPLE_GLOB);
4121 }
4122
Dianne Hackborncf244ad2010-03-09 15:00:30 -08004123 String host = sa.getNonConfigurationString(
4124 com.android.internal.R.styleable.AndroidManifestData_host, 0);
4125 String port = sa.getNonConfigurationString(
4126 com.android.internal.R.styleable.AndroidManifestData_port, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004127 if (host != null) {
4128 outInfo.addDataAuthority(host, port);
4129 }
4130
Dianne Hackborncf244ad2010-03-09 15:00:30 -08004131 str = sa.getNonConfigurationString(
4132 com.android.internal.R.styleable.AndroidManifestData_path, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004133 if (str != null) {
4134 outInfo.addDataPath(str, PatternMatcher.PATTERN_LITERAL);
4135 }
4136
Dianne Hackborncf244ad2010-03-09 15:00:30 -08004137 str = sa.getNonConfigurationString(
4138 com.android.internal.R.styleable.AndroidManifestData_pathPrefix, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004139 if (str != null) {
4140 outInfo.addDataPath(str, PatternMatcher.PATTERN_PREFIX);
4141 }
4142
Dianne Hackborncf244ad2010-03-09 15:00:30 -08004143 str = sa.getNonConfigurationString(
4144 com.android.internal.R.styleable.AndroidManifestData_pathPattern, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004145 if (str != null) {
Dianne Hackbornb09491f2013-07-22 15:30:11 -07004146 if (!allowGlobs) {
4147 outError[0] = "pathPattern not allowed here; path must be literal";
4148 return false;
4149 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004150 outInfo.addDataPath(str, PatternMatcher.PATTERN_SIMPLE_GLOB);
4151 }
4152
4153 sa.recycle();
4154 XmlUtils.skipCurrentTag(parser);
4155 } else if (!RIGID_PARSER) {
Kenny Rootd2d29252011-08-08 11:27:57 -07004156 Slog.w(TAG, "Unknown element under <intent-filter>: "
Dianne Hackborna33e3f72009-09-29 17:28:24 -07004157 + parser.getName() + " at " + mArchiveSourcePath + " "
4158 + parser.getPositionDescription());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004159 XmlUtils.skipCurrentTag(parser);
4160 } else {
4161 outError[0] = "Bad element under <intent-filter>: " + parser.getName();
4162 return false;
4163 }
4164 }
4165
4166 outInfo.hasDefault = outInfo.hasCategory(Intent.CATEGORY_DEFAULT);
Kenny Rootd2d29252011-08-08 11:27:57 -07004167
4168 if (DEBUG_PARSER) {
4169 final StringBuilder cats = new StringBuilder("Intent d=");
4170 cats.append(outInfo.hasDefault);
4171 cats.append(", cat=");
4172
4173 final Iterator<String> it = outInfo.categoriesIterator();
4174 if (it != null) {
4175 while (it.hasNext()) {
4176 cats.append(' ');
4177 cats.append(it.next());
4178 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004179 }
Kenny Rootd2d29252011-08-08 11:27:57 -07004180 Slog.d(TAG, cats.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004181 }
4182
4183 return true;
4184 }
4185
Jeff Sharkeyc4858a22014-06-16 10:51:20 -07004186 /**
4187 * Representation of a full package parsed from APK files on disk. A package
4188 * consists of a single base APK, and zero or more split APKs.
4189 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004190 public final static class Package {
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07004191
Dianne Hackborn6dee18c2010-02-09 23:59:16 -08004192 public String packageName;
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -08004193
Jeff Sharkey57dcf5b2014-06-18 17:46:05 -07004194 /** Names of any split APKs, ordered by parsed splitName */
4195 public String[] splitNames;
Jeff Sharkeyc4858a22014-06-16 10:51:20 -07004196
4197 // TODO: work towards making these paths invariant
Jeff Sharkey275e0852014-06-17 18:18:49 -07004198
Jeff Sharkey57dcf5b2014-06-18 17:46:05 -07004199 /**
4200 * Path where this package was found on disk. For monolithic packages
4201 * this is path to single base APK file; for cluster packages this is
4202 * path to the cluster directory.
4203 */
Jeff Sharkeyc4858a22014-06-16 10:51:20 -07004204 public String codePath;
Jeff Sharkey57dcf5b2014-06-18 17:46:05 -07004205
4206 /** Path of base APK */
4207 public String baseCodePath;
4208 /** Paths of any split APKs, ordered by parsed splitName */
Jeff Sharkeyc4858a22014-06-16 10:51:20 -07004209 public String[] splitCodePaths;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004210
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -08004211 /** Revision code of base APK */
4212 public int baseRevisionCode;
4213 /** Revision codes of any split APKs, ordered by parsed splitName */
4214 public int[] splitRevisionCodes;
4215
Jeff Sharkeyda96e132014-07-15 14:54:09 -07004216 /** Flags of any split APKs; ordered by parsed splitName */
4217 public int[] splitFlags;
4218
Alex Klyubinb9f8a522015-02-03 11:12:59 -08004219 /**
4220 * Private flags of any split APKs; ordered by parsed splitName.
4221 *
4222 * {@hide}
4223 */
4224 public int[] splitPrivateFlags;
4225
Jeff Sharkeyda96e132014-07-15 14:54:09 -07004226 public boolean baseHardwareAccelerated;
4227
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004228 // For now we only support one application per package.
4229 public final ApplicationInfo applicationInfo = new ApplicationInfo();
4230
4231 public final ArrayList<Permission> permissions = new ArrayList<Permission>(0);
4232 public final ArrayList<PermissionGroup> permissionGroups = new ArrayList<PermissionGroup>(0);
4233 public final ArrayList<Activity> activities = new ArrayList<Activity>(0);
4234 public final ArrayList<Activity> receivers = new ArrayList<Activity>(0);
4235 public final ArrayList<Provider> providers = new ArrayList<Provider>(0);
4236 public final ArrayList<Service> services = new ArrayList<Service>(0);
4237 public final ArrayList<Instrumentation> instrumentation = new ArrayList<Instrumentation>(0);
4238
4239 public final ArrayList<String> requestedPermissions = new ArrayList<String>();
Dianne Hackborne639da72012-02-21 15:11:13 -08004240 public final ArrayList<Boolean> requestedPermissionsRequired = new ArrayList<Boolean>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004241
Dianne Hackborn854060af2009-07-09 18:14:31 -07004242 public ArrayList<String> protectedBroadcasts;
Dianne Hackbornc895be72013-03-11 17:48:43 -07004243
4244 public ArrayList<String> libraryNames = null;
Dianne Hackborn49237342009-08-27 20:08:01 -07004245 public ArrayList<String> usesLibraries = null;
4246 public ArrayList<String> usesOptionalLibraries = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004247 public String[] usesLibraryFiles = null;
4248
Dianne Hackbornb09491f2013-07-22 15:30:11 -07004249 public ArrayList<ActivityIntentInfo> preferredActivityFilters = null;
4250
Dianne Hackbornc1552392010-03-03 16:19:01 -08004251 public ArrayList<String> mOriginalPackages = null;
Dianne Hackborn6dee18c2010-02-09 23:59:16 -08004252 public String mRealPackage = null;
Dianne Hackbornb858dfd2010-02-02 10:49:14 -08004253 public ArrayList<String> mAdoptPermissions = null;
4254
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004255 // We store the application meta-data independently to avoid multiple unwanted references
4256 public Bundle mAppMetaData = null;
4257
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004258 // The version code declared for this package.
4259 public int mVersionCode;
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -08004260
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004261 // The version name declared for this package.
4262 public String mVersionName;
4263
4264 // The shared user id that this package wants to use.
4265 public String mSharedUserId;
4266
4267 // The shared user label that this package wants to use.
4268 public int mSharedUserLabel;
4269
4270 // Signatures that were read from the package.
Jeff Sharkey275e0852014-06-17 18:18:49 -07004271 public Signature[] mSignatures;
4272 public Certificate[][] mCertificates;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004273
4274 // For use by package manager service for quick lookup of
4275 // preferred up order.
4276 public int mPreferredOrder = 0;
4277
Brian Carlstromff1ec4d2014-03-17 15:21:35 -07004278 // For use by package manager to keep track of where it needs to do dexopt.
Narayan Kamath20531682014-07-14 13:18:43 +01004279 public final ArraySet<String> mDexOptPerformed = new ArraySet<>(4);
Brian Carlstromff1ec4d2014-03-17 15:21:35 -07004280
4281 // For use by package manager to keep track of when a package was last used.
4282 public long mLastPackageUsageTimeInMills;
4283
Amith Yamasani13593602012-03-22 16:16:17 -07004284 // // User set enabled state.
4285 // public int mSetEnabled = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
4286 //
4287 // // Whether the package has been stopped.
4288 // public boolean mSetStopped = false;
Dianne Hackborne7f97212011-02-24 14:40:20 -08004289
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004290 // Additional data supplied by callers.
4291 public Object mExtras;
Kenny Rootdeb11262010-08-02 11:36:21 -07004292
4293 // Whether an operation is currently pending on this package
4294 public boolean mOperationPending;
4295
Jeff Sharkeyda96e132014-07-15 14:54:09 -07004296 // Applications hardware preferences
4297 public ArrayList<ConfigurationInfo> configPreferences = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004298
Jeff Sharkeyda96e132014-07-15 14:54:09 -07004299 // Applications requested features
Dianne Hackborn49237342009-08-27 20:08:01 -07004300 public ArrayList<FeatureInfo> reqFeatures = null;
4301
Adam Lesinskid3edfde2014-08-08 17:32:44 -07004302 // Applications requested feature groups
4303 public ArrayList<FeatureGroupInfo> featureGroups = null;
4304
Suchi Amalapurapu117818e2010-02-09 03:45:40 -08004305 public int installLocation;
4306
Jeff Hao272bf3a2014-10-08 13:34:43 -07004307 public boolean coreApp;
4308
Amith Yamasanidf2e92a2013-03-01 17:04:38 -08004309 /* An app that's required for all users and cannot be uninstalled for a user */
4310 public boolean mRequiredForAllUsers;
4311
Amith Yamasani0ac1fc92013-03-27 18:56:08 -07004312 /* The restricted account authenticator type that is used by this application */
4313 public String mRestrictedAccountType;
4314
Amith Yamasaniccbe3892013-04-12 17:52:42 -07004315 /* The required account type without which this application will not function */
4316 public String mRequiredAccountType;
4317
Kenny Rootbcc954d2011-08-08 16:19:08 -07004318 /**
4319 * Digest suitable for comparing whether this package's manifest is the
4320 * same as another.
4321 */
4322 public ManifestDigest manifestDigest;
4323
MÃ¥rten Kongstad48d22322014-01-31 14:43:27 +01004324 public String mOverlayTarget;
4325 public int mOverlayPriority;
4326 public boolean mTrustedOverlay;
4327
Geremy Condraf1bcca82013-01-07 22:35:24 -08004328 /**
dcashman989eb3712014-06-17 12:56:12 -07004329 * Data used to feed the KeySetManagerService
Geremy Condraf1bcca82013-01-07 22:35:24 -08004330 */
dcashman989eb3712014-06-17 12:56:12 -07004331 public ArraySet<PublicKey> mSigningKeys;
4332 public ArraySet<String> mUpgradeKeySets;
4333 public ArrayMap<String, ArraySet<PublicKey>> mKeySetMapping;
Geremy Condraf1bcca82013-01-07 22:35:24 -08004334
Narayan Kamath4903f642014-08-11 13:33:45 +01004335 /**
4336 * The install time abi override for this package, if any.
4337 *
4338 * TODO: This seems like a horrible place to put the abiOverride because
4339 * this isn't something the packageParser parsers. However, this fits in with
4340 * the rest of the PackageManager where package scanning randomly pushes
4341 * and prods fields out of {@code this.applicationInfo}.
4342 */
4343 public String cpuAbiOverride;
4344
Jeff Sharkeyc4858a22014-06-16 10:51:20 -07004345 public Package(String packageName) {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07004346 this.packageName = packageName;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07004347 applicationInfo.packageName = packageName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004348 applicationInfo.uid = -1;
4349 }
4350
Jeff Sharkey57dcf5b2014-06-18 17:46:05 -07004351 public List<String> getAllCodePaths() {
Jeff Sharkey275e0852014-06-17 18:18:49 -07004352 ArrayList<String> paths = new ArrayList<>();
Jeff Sharkey57dcf5b2014-06-18 17:46:05 -07004353 paths.add(baseCodePath);
Jeff Sharkey275e0852014-06-17 18:18:49 -07004354 if (!ArrayUtils.isEmpty(splitCodePaths)) {
4355 Collections.addAll(paths, splitCodePaths);
4356 }
4357 return paths;
4358 }
4359
Jeff Sharkeyda96e132014-07-15 14:54:09 -07004360 /**
4361 * Filtered set of {@link #getAllCodePaths()} that excludes
4362 * resource-only APKs.
4363 */
4364 public List<String> getAllCodePathsExcludingResourceOnly() {
4365 ArrayList<String> paths = new ArrayList<>();
4366 if ((applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) != 0) {
4367 paths.add(baseCodePath);
4368 }
4369 if (!ArrayUtils.isEmpty(splitCodePaths)) {
4370 for (int i = 0; i < splitCodePaths.length; i++) {
4371 if ((splitFlags[i] & ApplicationInfo.FLAG_HAS_CODE) != 0) {
4372 paths.add(splitCodePaths[i]);
4373 }
4374 }
4375 }
4376 return paths;
4377 }
4378
Dianne Hackborn6dee18c2010-02-09 23:59:16 -08004379 public void setPackageName(String newName) {
4380 packageName = newName;
4381 applicationInfo.packageName = newName;
4382 for (int i=permissions.size()-1; i>=0; i--) {
4383 permissions.get(i).setPackageName(newName);
4384 }
4385 for (int i=permissionGroups.size()-1; i>=0; i--) {
4386 permissionGroups.get(i).setPackageName(newName);
4387 }
4388 for (int i=activities.size()-1; i>=0; i--) {
4389 activities.get(i).setPackageName(newName);
4390 }
4391 for (int i=receivers.size()-1; i>=0; i--) {
4392 receivers.get(i).setPackageName(newName);
4393 }
4394 for (int i=providers.size()-1; i>=0; i--) {
4395 providers.get(i).setPackageName(newName);
4396 }
4397 for (int i=services.size()-1; i>=0; i--) {
4398 services.get(i).setPackageName(newName);
4399 }
4400 for (int i=instrumentation.size()-1; i>=0; i--) {
4401 instrumentation.get(i).setPackageName(newName);
4402 }
4403 }
Dianne Hackborn65696252012-03-05 18:49:21 -08004404
4405 public boolean hasComponentClassName(String name) {
4406 for (int i=activities.size()-1; i>=0; i--) {
4407 if (name.equals(activities.get(i).className)) {
4408 return true;
4409 }
4410 }
4411 for (int i=receivers.size()-1; i>=0; i--) {
4412 if (name.equals(receivers.get(i).className)) {
4413 return true;
4414 }
4415 }
4416 for (int i=providers.size()-1; i>=0; i--) {
4417 if (name.equals(providers.get(i).className)) {
4418 return true;
4419 }
4420 }
4421 for (int i=services.size()-1; i>=0; i--) {
4422 if (name.equals(services.get(i).className)) {
4423 return true;
4424 }
4425 }
4426 for (int i=instrumentation.size()-1; i>=0; i--) {
4427 if (name.equals(instrumentation.get(i).className)) {
4428 return true;
4429 }
4430 }
4431 return false;
4432 }
4433
Fyodor Kupolov74876572015-02-23 17:14:45 -08004434 /**
4435 * @hide
4436 */
4437 public boolean isForwardLocked() {
4438 return applicationInfo.isForwardLocked();
4439 }
4440
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004441 public String toString() {
4442 return "Package{"
4443 + Integer.toHexString(System.identityHashCode(this))
4444 + " " + packageName + "}";
4445 }
4446 }
4447
4448 public static class Component<II extends IntentInfo> {
4449 public final Package owner;
Dianne Hackborn1d442e02009-04-20 18:14:05 -07004450 public final ArrayList<II> intents;
Dianne Hackborn6dee18c2010-02-09 23:59:16 -08004451 public final String className;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004452 public Bundle metaData;
4453
Dianne Hackborn6dee18c2010-02-09 23:59:16 -08004454 ComponentName componentName;
4455 String componentShortName;
4456
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004457 public Component(Package _owner) {
4458 owner = _owner;
Dianne Hackborn1d442e02009-04-20 18:14:05 -07004459 intents = null;
Dianne Hackborn6dee18c2010-02-09 23:59:16 -08004460 className = null;
Dianne Hackborn1d442e02009-04-20 18:14:05 -07004461 }
4462
4463 public Component(final ParsePackageItemArgs args, final PackageItemInfo outInfo) {
4464 owner = args.owner;
4465 intents = new ArrayList<II>(0);
Dianne Hackborncf244ad2010-03-09 15:00:30 -08004466 String name = args.sa.getNonConfigurationString(args.nameRes, 0);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07004467 if (name == null) {
Dianne Hackborn6dee18c2010-02-09 23:59:16 -08004468 className = null;
Dianne Hackborn1d442e02009-04-20 18:14:05 -07004469 args.outError[0] = args.tag + " does not specify android:name";
4470 return;
4471 }
4472
4473 outInfo.name
4474 = buildClassName(owner.applicationInfo.packageName, name, args.outError);
4475 if (outInfo.name == null) {
Dianne Hackborn6dee18c2010-02-09 23:59:16 -08004476 className = null;
Dianne Hackborn1d442e02009-04-20 18:14:05 -07004477 args.outError[0] = args.tag + " does not have valid android:name";
4478 return;
4479 }
4480
Dianne Hackborn6dee18c2010-02-09 23:59:16 -08004481 className = outInfo.name;
Dianne Hackborn1d442e02009-04-20 18:14:05 -07004482
4483 int iconVal = args.sa.getResourceId(args.iconRes, 0);
4484 if (iconVal != 0) {
4485 outInfo.icon = iconVal;
4486 outInfo.nonLocalizedLabel = null;
4487 }
Adam Powell81cd2e92010-04-21 16:35:18 -07004488
4489 int logoVal = args.sa.getResourceId(args.logoRes, 0);
4490 if (logoVal != 0) {
4491 outInfo.logo = logoVal;
4492 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07004493
Jose Limaf78e3122014-03-06 12:13:15 -08004494 int bannerVal = args.sa.getResourceId(args.bannerRes, 0);
4495 if (bannerVal != 0) {
4496 outInfo.banner = bannerVal;
4497 }
4498
Dianne Hackborn1d442e02009-04-20 18:14:05 -07004499 TypedValue v = args.sa.peekValue(args.labelRes);
4500 if (v != null && (outInfo.labelRes=v.resourceId) == 0) {
4501 outInfo.nonLocalizedLabel = v.coerceToString();
4502 }
4503
4504 outInfo.packageName = owner.packageName;
4505 }
4506
4507 public Component(final ParseComponentArgs args, final ComponentInfo outInfo) {
4508 this(args, (PackageItemInfo)outInfo);
4509 if (args.outError[0] != null) {
4510 return;
4511 }
4512
4513 if (args.processRes != 0) {
Dianne Hackbornd1cff1b2010-04-02 16:51:26 -07004514 CharSequence pname;
4515 if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.FROYO) {
Dianne Hackborn1d0b1772013-09-06 14:02:54 -07004516 pname = args.sa.getNonConfigurationString(args.processRes,
4517 Configuration.NATIVE_CONFIG_VERSION);
Dianne Hackbornd1cff1b2010-04-02 16:51:26 -07004518 } else {
4519 // Some older apps have been seen to use a resource reference
4520 // here that on older builds was ignored (with a warning). We
4521 // need to continue to do this for them so they don't break.
4522 pname = args.sa.getNonResourceString(args.processRes);
4523 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07004524 outInfo.processName = buildProcessName(owner.applicationInfo.packageName,
Dianne Hackbornd1cff1b2010-04-02 16:51:26 -07004525 owner.applicationInfo.processName, pname,
Dianne Hackborn1d442e02009-04-20 18:14:05 -07004526 args.flags, args.sepProcesses, args.outError);
4527 }
Dianne Hackborn8aa2e892010-01-22 11:31:30 -08004528
4529 if (args.descriptionRes != 0) {
4530 outInfo.descriptionRes = args.sa.getResourceId(args.descriptionRes, 0);
4531 }
4532
Dianne Hackborn1d442e02009-04-20 18:14:05 -07004533 outInfo.enabled = args.sa.getBoolean(args.enabledRes, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004534 }
4535
4536 public Component(Component<II> clone) {
4537 owner = clone.owner;
Dianne Hackborn1d442e02009-04-20 18:14:05 -07004538 intents = clone.intents;
Dianne Hackborn6dee18c2010-02-09 23:59:16 -08004539 className = clone.className;
4540 componentName = clone.componentName;
Dianne Hackborn1d442e02009-04-20 18:14:05 -07004541 componentShortName = clone.componentShortName;
Dianne Hackborn6dee18c2010-02-09 23:59:16 -08004542 }
4543
4544 public ComponentName getComponentName() {
4545 if (componentName != null) {
4546 return componentName;
4547 }
4548 if (className != null) {
4549 componentName = new ComponentName(owner.applicationInfo.packageName,
4550 className);
4551 }
4552 return componentName;
4553 }
Dianne Hackborn6d8dfbd2013-09-23 17:38:51 -07004554
4555 public void appendComponentShortName(StringBuilder sb) {
4556 ComponentName.appendShortString(sb, owner.applicationInfo.packageName, className);
Dianne Hackborn6dee18c2010-02-09 23:59:16 -08004557 }
Dianne Hackborn6d8dfbd2013-09-23 17:38:51 -07004558
4559 public void printComponentShortName(PrintWriter pw) {
4560 ComponentName.printShortString(pw, owner.applicationInfo.packageName, className);
4561 }
4562
Dianne Hackborn6dee18c2010-02-09 23:59:16 -08004563 public void setPackageName(String packageName) {
4564 componentName = null;
4565 componentShortName = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004566 }
4567 }
4568
4569 public final static class Permission extends Component<IntentInfo> {
4570 public final PermissionInfo info;
4571 public boolean tree;
4572 public PermissionGroup group;
4573
4574 public Permission(Package _owner) {
4575 super(_owner);
4576 info = new PermissionInfo();
4577 }
4578
4579 public Permission(Package _owner, PermissionInfo _info) {
4580 super(_owner);
4581 info = _info;
4582 }
Dianne Hackborn6dee18c2010-02-09 23:59:16 -08004583
4584 public void setPackageName(String packageName) {
4585 super.setPackageName(packageName);
4586 info.packageName = packageName;
4587 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004588
4589 public String toString() {
4590 return "Permission{"
4591 + Integer.toHexString(System.identityHashCode(this))
4592 + " " + info.name + "}";
4593 }
4594 }
4595
4596 public final static class PermissionGroup extends Component<IntentInfo> {
4597 public final PermissionGroupInfo info;
4598
4599 public PermissionGroup(Package _owner) {
4600 super(_owner);
4601 info = new PermissionGroupInfo();
4602 }
4603
4604 public PermissionGroup(Package _owner, PermissionGroupInfo _info) {
4605 super(_owner);
4606 info = _info;
4607 }
4608
Dianne Hackborn6dee18c2010-02-09 23:59:16 -08004609 public void setPackageName(String packageName) {
4610 super.setPackageName(packageName);
4611 info.packageName = packageName;
4612 }
4613
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004614 public String toString() {
4615 return "PermissionGroup{"
4616 + Integer.toHexString(System.identityHashCode(this))
4617 + " " + info.name + "}";
4618 }
4619 }
4620
Dianne Hackborn7767eac2012-08-23 18:25:40 -07004621 private static boolean copyNeeded(int flags, Package p,
4622 PackageUserState state, Bundle metaData, int userId) {
4623 if (userId != 0) {
4624 // We always need to copy for other users, since we need
4625 // to fix up the uid.
4626 return true;
4627 }
4628 if (state.enabled != PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
4629 boolean enabled = state.enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
Dianne Hackborn46730fc2010-07-24 16:32:42 -07004630 if (p.applicationInfo.enabled != enabled) {
4631 return true;
4632 }
4633 }
Amith Yamasanie5bcff62014-07-19 15:44:09 -07004634 if (!state.installed || state.hidden) {
Dianne Hackborn7767eac2012-08-23 18:25:40 -07004635 return true;
4636 }
4637 if (state.stopped) {
4638 return true;
4639 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004640 if ((flags & PackageManager.GET_META_DATA) != 0
4641 && (metaData != null || p.mAppMetaData != null)) {
4642 return true;
4643 }
4644 if ((flags & PackageManager.GET_SHARED_LIBRARY_FILES) != 0
4645 && p.usesLibraryFiles != null) {
4646 return true;
4647 }
4648 return false;
4649 }
4650
Dianne Hackborn7767eac2012-08-23 18:25:40 -07004651 public static ApplicationInfo generateApplicationInfo(Package p, int flags,
4652 PackageUserState state) {
4653 return generateApplicationInfo(p, flags, state, UserHandle.getCallingUserId());
Amith Yamasani742a6712011-05-04 14:49:28 -07004654 }
4655
Dianne Hackbornfd7aded2013-01-22 17:10:23 -08004656 private static void updateApplicationInfo(ApplicationInfo ai, int flags,
4657 PackageUserState state) {
4658 // CompatibilityMode is global state.
4659 if (!sCompatibilityModeEnabled) {
4660 ai.disableCompatibilityMode();
4661 }
4662 if (state.installed) {
4663 ai.flags |= ApplicationInfo.FLAG_INSTALLED;
4664 } else {
4665 ai.flags &= ~ApplicationInfo.FLAG_INSTALLED;
4666 }
Amith Yamasanie5bcff62014-07-19 15:44:09 -07004667 if (state.hidden) {
Alex Klyubinb9f8a522015-02-03 11:12:59 -08004668 ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_HIDDEN;
Amith Yamasani655d0e22013-06-12 14:19:10 -07004669 } else {
Alex Klyubinb9f8a522015-02-03 11:12:59 -08004670 ai.privateFlags &= ~ApplicationInfo.PRIVATE_FLAG_HIDDEN;
Amith Yamasani655d0e22013-06-12 14:19:10 -07004671 }
Dianne Hackbornfd7aded2013-01-22 17:10:23 -08004672 if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
4673 ai.enabled = true;
4674 } else if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
4675 ai.enabled = (flags&PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS) != 0;
4676 } else if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED
4677 || state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) {
4678 ai.enabled = false;
4679 }
4680 ai.enabledSetting = state.enabled;
4681 }
4682
Amith Yamasani13593602012-03-22 16:16:17 -07004683 public static ApplicationInfo generateApplicationInfo(Package p, int flags,
Dianne Hackborn7767eac2012-08-23 18:25:40 -07004684 PackageUserState state, int userId) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004685 if (p == null) return null;
Amith Yamasanie5bcff62014-07-19 15:44:09 -07004686 if (!checkUseInstalledOrHidden(flags, state)) {
Dianne Hackborn7767eac2012-08-23 18:25:40 -07004687 return null;
4688 }
Dianne Hackbornfd7aded2013-01-22 17:10:23 -08004689 if (!copyNeeded(flags, p, state, null, userId)
4690 && ((flags&PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS) == 0
4691 || state.enabled != PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED)) {
4692 // In this case it is safe to directly modify the internal ApplicationInfo state:
4693 // - CompatibilityMode is global state, so will be the same for every call.
4694 // - We only come in to here if the app should reported as installed; this is the
4695 // default state, and we will do a copy otherwise.
4696 // - The enable state will always be reported the same for the application across
4697 // calls; the only exception is for the UNTIL_USED mode, and in that case we will
4698 // be doing a copy.
4699 updateApplicationInfo(p.applicationInfo, flags, state);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004700 return p.applicationInfo;
4701 }
4702
4703 // Make shallow copy so we can store the metadata/libraries safely
4704 ApplicationInfo ai = new ApplicationInfo(p.applicationInfo);
Amith Yamasani742a6712011-05-04 14:49:28 -07004705 if (userId != 0) {
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07004706 ai.uid = UserHandle.getUid(userId, ai.uid);
Amith Yamasani742a6712011-05-04 14:49:28 -07004707 ai.dataDir = PackageManager.getDataDirForUser(userId, ai.packageName);
4708 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004709 if ((flags & PackageManager.GET_META_DATA) != 0) {
4710 ai.metaData = p.mAppMetaData;
4711 }
4712 if ((flags & PackageManager.GET_SHARED_LIBRARY_FILES) != 0) {
4713 ai.sharedLibraryFiles = p.usesLibraryFiles;
4714 }
Dianne Hackborn7767eac2012-08-23 18:25:40 -07004715 if (state.stopped) {
Amith Yamasania4a54e22012-04-16 15:44:19 -07004716 ai.flags |= ApplicationInfo.FLAG_STOPPED;
Dianne Hackborne7f97212011-02-24 14:40:20 -08004717 } else {
Amith Yamasania4a54e22012-04-16 15:44:19 -07004718 ai.flags &= ~ApplicationInfo.FLAG_STOPPED;
Dianne Hackborne7f97212011-02-24 14:40:20 -08004719 }
Dianne Hackbornfd7aded2013-01-22 17:10:23 -08004720 updateApplicationInfo(ai, flags, state);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004721 return ai;
4722 }
4723
Dianne Hackbornace27912014-09-18 18:38:30 -07004724 public static ApplicationInfo generateApplicationInfo(ApplicationInfo ai, int flags,
4725 PackageUserState state, int userId) {
4726 if (ai == null) return null;
4727 if (!checkUseInstalledOrHidden(flags, state)) {
4728 return null;
4729 }
4730 // This is only used to return the ResolverActivity; we will just always
4731 // make a copy.
4732 ai = new ApplicationInfo(ai);
4733 if (userId != 0) {
4734 ai.uid = UserHandle.getUid(userId, ai.uid);
4735 ai.dataDir = PackageManager.getDataDirForUser(userId, ai.packageName);
4736 }
4737 if (state.stopped) {
4738 ai.flags |= ApplicationInfo.FLAG_STOPPED;
4739 } else {
4740 ai.flags &= ~ApplicationInfo.FLAG_STOPPED;
4741 }
4742 updateApplicationInfo(ai, flags, state);
4743 return ai;
4744 }
4745
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004746 public static final PermissionInfo generatePermissionInfo(
4747 Permission p, int flags) {
4748 if (p == null) return null;
4749 if ((flags&PackageManager.GET_META_DATA) == 0) {
4750 return p.info;
4751 }
4752 PermissionInfo pi = new PermissionInfo(p.info);
4753 pi.metaData = p.metaData;
4754 return pi;
4755 }
4756
4757 public static final PermissionGroupInfo generatePermissionGroupInfo(
4758 PermissionGroup pg, int flags) {
4759 if (pg == null) return null;
4760 if ((flags&PackageManager.GET_META_DATA) == 0) {
4761 return pg.info;
4762 }
4763 PermissionGroupInfo pgi = new PermissionGroupInfo(pg.info);
4764 pgi.metaData = pg.metaData;
4765 return pgi;
4766 }
4767
4768 public final static class Activity extends Component<ActivityIntentInfo> {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07004769 public final ActivityInfo info;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004770
Dianne Hackborn1d442e02009-04-20 18:14:05 -07004771 public Activity(final ParseComponentArgs args, final ActivityInfo _info) {
4772 super(args, _info);
4773 info = _info;
4774 info.applicationInfo = args.owner.applicationInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004775 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07004776
Dianne Hackborn6dee18c2010-02-09 23:59:16 -08004777 public void setPackageName(String packageName) {
4778 super.setPackageName(packageName);
4779 info.packageName = packageName;
4780 }
4781
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004782 public String toString() {
Dianne Hackborn6d8dfbd2013-09-23 17:38:51 -07004783 StringBuilder sb = new StringBuilder(128);
4784 sb.append("Activity{");
4785 sb.append(Integer.toHexString(System.identityHashCode(this)));
4786 sb.append(' ');
4787 appendComponentShortName(sb);
4788 sb.append('}');
4789 return sb.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004790 }
4791 }
4792
Dianne Hackborn7767eac2012-08-23 18:25:40 -07004793 public static final ActivityInfo generateActivityInfo(Activity a, int flags,
4794 PackageUserState state, int userId) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004795 if (a == null) return null;
Amith Yamasanie5bcff62014-07-19 15:44:09 -07004796 if (!checkUseInstalledOrHidden(flags, state)) {
Dianne Hackborn7767eac2012-08-23 18:25:40 -07004797 return null;
4798 }
4799 if (!copyNeeded(flags, a.owner, state, a.metaData, userId)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004800 return a.info;
4801 }
4802 // Make shallow copies so we can store the metadata safely
4803 ActivityInfo ai = new ActivityInfo(a.info);
4804 ai.metaData = a.metaData;
Dianne Hackborn7767eac2012-08-23 18:25:40 -07004805 ai.applicationInfo = generateApplicationInfo(a.owner, flags, state, userId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004806 return ai;
4807 }
4808
Dianne Hackbornace27912014-09-18 18:38:30 -07004809 public static final ActivityInfo generateActivityInfo(ActivityInfo ai, int flags,
4810 PackageUserState state, int userId) {
4811 if (ai == null) return null;
4812 if (!checkUseInstalledOrHidden(flags, state)) {
4813 return null;
4814 }
4815 // This is only used to return the ResolverActivity; we will just always
4816 // make a copy.
4817 ai = new ActivityInfo(ai);
4818 ai.applicationInfo = generateApplicationInfo(ai.applicationInfo, flags, state, userId);
4819 return ai;
4820 }
4821
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004822 public final static class Service extends Component<ServiceIntentInfo> {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07004823 public final ServiceInfo info;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004824
Dianne Hackborn1d442e02009-04-20 18:14:05 -07004825 public Service(final ParseComponentArgs args, final ServiceInfo _info) {
4826 super(args, _info);
4827 info = _info;
4828 info.applicationInfo = args.owner.applicationInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004829 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07004830
Dianne Hackborn6dee18c2010-02-09 23:59:16 -08004831 public void setPackageName(String packageName) {
4832 super.setPackageName(packageName);
4833 info.packageName = packageName;
4834 }
4835
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004836 public String toString() {
Dianne Hackborn6d8dfbd2013-09-23 17:38:51 -07004837 StringBuilder sb = new StringBuilder(128);
4838 sb.append("Service{");
4839 sb.append(Integer.toHexString(System.identityHashCode(this)));
4840 sb.append(' ');
4841 appendComponentShortName(sb);
4842 sb.append('}');
4843 return sb.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004844 }
4845 }
4846
Dianne Hackborn7767eac2012-08-23 18:25:40 -07004847 public static final ServiceInfo generateServiceInfo(Service s, int flags,
4848 PackageUserState state, int userId) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004849 if (s == null) return null;
Amith Yamasanie5bcff62014-07-19 15:44:09 -07004850 if (!checkUseInstalledOrHidden(flags, state)) {
Dianne Hackborn7767eac2012-08-23 18:25:40 -07004851 return null;
4852 }
4853 if (!copyNeeded(flags, s.owner, state, s.metaData, userId)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004854 return s.info;
4855 }
4856 // Make shallow copies so we can store the metadata safely
4857 ServiceInfo si = new ServiceInfo(s.info);
4858 si.metaData = s.metaData;
Dianne Hackborn7767eac2012-08-23 18:25:40 -07004859 si.applicationInfo = generateApplicationInfo(s.owner, flags, state, userId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004860 return si;
4861 }
4862
Jeff Sharkey85f5f812013-10-07 10:16:12 -07004863 public final static class Provider extends Component<ProviderIntentInfo> {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004864 public final ProviderInfo info;
4865 public boolean syncable;
4866
Dianne Hackborn1d442e02009-04-20 18:14:05 -07004867 public Provider(final ParseComponentArgs args, final ProviderInfo _info) {
4868 super(args, _info);
4869 info = _info;
4870 info.applicationInfo = args.owner.applicationInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004871 syncable = false;
4872 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07004873
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004874 public Provider(Provider existingProvider) {
4875 super(existingProvider);
4876 this.info = existingProvider.info;
4877 this.syncable = existingProvider.syncable;
4878 }
4879
Dianne Hackborn6dee18c2010-02-09 23:59:16 -08004880 public void setPackageName(String packageName) {
4881 super.setPackageName(packageName);
4882 info.packageName = packageName;
4883 }
4884
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004885 public String toString() {
Dianne Hackborn6d8dfbd2013-09-23 17:38:51 -07004886 StringBuilder sb = new StringBuilder(128);
4887 sb.append("Provider{");
4888 sb.append(Integer.toHexString(System.identityHashCode(this)));
4889 sb.append(' ');
4890 appendComponentShortName(sb);
4891 sb.append('}');
4892 return sb.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004893 }
4894 }
4895
Dianne Hackborn7767eac2012-08-23 18:25:40 -07004896 public static final ProviderInfo generateProviderInfo(Provider p, int flags,
4897 PackageUserState state, int userId) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004898 if (p == null) return null;
Amith Yamasanie5bcff62014-07-19 15:44:09 -07004899 if (!checkUseInstalledOrHidden(flags, state)) {
Dianne Hackborn7767eac2012-08-23 18:25:40 -07004900 return null;
4901 }
4902 if (!copyNeeded(flags, p.owner, state, p.metaData, userId)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004903 && ((flags & PackageManager.GET_URI_PERMISSION_PATTERNS) != 0
Dianne Hackborn7767eac2012-08-23 18:25:40 -07004904 || p.info.uriPermissionPatterns == null)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004905 return p.info;
4906 }
4907 // Make shallow copies so we can store the metadata safely
4908 ProviderInfo pi = new ProviderInfo(p.info);
4909 pi.metaData = p.metaData;
4910 if ((flags & PackageManager.GET_URI_PERMISSION_PATTERNS) == 0) {
4911 pi.uriPermissionPatterns = null;
4912 }
Dianne Hackborn7767eac2012-08-23 18:25:40 -07004913 pi.applicationInfo = generateApplicationInfo(p.owner, flags, state, userId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004914 return pi;
4915 }
4916
4917 public final static class Instrumentation extends Component {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07004918 public final InstrumentationInfo info;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004919
Dianne Hackborn1d442e02009-04-20 18:14:05 -07004920 public Instrumentation(final ParsePackageItemArgs args, final InstrumentationInfo _info) {
4921 super(args, _info);
4922 info = _info;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004923 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07004924
Dianne Hackborn6dee18c2010-02-09 23:59:16 -08004925 public void setPackageName(String packageName) {
4926 super.setPackageName(packageName);
4927 info.packageName = packageName;
4928 }
4929
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004930 public String toString() {
Dianne Hackborn6d8dfbd2013-09-23 17:38:51 -07004931 StringBuilder sb = new StringBuilder(128);
4932 sb.append("Instrumentation{");
4933 sb.append(Integer.toHexString(System.identityHashCode(this)));
4934 sb.append(' ');
4935 appendComponentShortName(sb);
4936 sb.append('}');
4937 return sb.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004938 }
4939 }
4940
4941 public static final InstrumentationInfo generateInstrumentationInfo(
4942 Instrumentation i, int flags) {
4943 if (i == null) return null;
4944 if ((flags&PackageManager.GET_META_DATA) == 0) {
4945 return i.info;
4946 }
4947 InstrumentationInfo ii = new InstrumentationInfo(i.info);
4948 ii.metaData = i.metaData;
4949 return ii;
4950 }
4951
4952 public static class IntentInfo extends IntentFilter {
4953 public boolean hasDefault;
4954 public int labelRes;
4955 public CharSequence nonLocalizedLabel;
4956 public int icon;
Adam Powell81cd2e92010-04-21 16:35:18 -07004957 public int logo;
Jose Limaf78e3122014-03-06 12:13:15 -08004958 public int banner;
Dianne Hackbornb09491f2013-07-22 15:30:11 -07004959 public int preferred;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004960 }
4961
4962 public final static class ActivityIntentInfo extends IntentInfo {
4963 public final Activity activity;
4964
4965 public ActivityIntentInfo(Activity _activity) {
4966 activity = _activity;
4967 }
4968
4969 public String toString() {
Dianne Hackborn6d8dfbd2013-09-23 17:38:51 -07004970 StringBuilder sb = new StringBuilder(128);
4971 sb.append("ActivityIntentInfo{");
4972 sb.append(Integer.toHexString(System.identityHashCode(this)));
4973 sb.append(' ');
4974 activity.appendComponentShortName(sb);
4975 sb.append('}');
4976 return sb.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004977 }
4978 }
4979
4980 public final static class ServiceIntentInfo extends IntentInfo {
4981 public final Service service;
4982
4983 public ServiceIntentInfo(Service _service) {
4984 service = _service;
4985 }
4986
4987 public String toString() {
Dianne Hackborn6d8dfbd2013-09-23 17:38:51 -07004988 StringBuilder sb = new StringBuilder(128);
4989 sb.append("ServiceIntentInfo{");
4990 sb.append(Integer.toHexString(System.identityHashCode(this)));
4991 sb.append(' ');
4992 service.appendComponentShortName(sb);
4993 sb.append('}');
4994 return sb.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004995 }
4996 }
Mitsuru Oshima69fff4a2009-07-21 09:51:05 -07004997
Jeff Sharkey85f5f812013-10-07 10:16:12 -07004998 public static final class ProviderIntentInfo extends IntentInfo {
4999 public final Provider provider;
5000
5001 public ProviderIntentInfo(Provider provider) {
5002 this.provider = provider;
5003 }
5004
5005 public String toString() {
5006 StringBuilder sb = new StringBuilder(128);
5007 sb.append("ProviderIntentInfo{");
5008 sb.append(Integer.toHexString(System.identityHashCode(this)));
5009 sb.append(' ');
5010 provider.appendComponentShortName(sb);
5011 sb.append('}');
5012 return sb.toString();
5013 }
5014 }
5015
Mitsuru Oshima69fff4a2009-07-21 09:51:05 -07005016 /**
5017 * @hide
5018 */
5019 public static void setCompatibilityModeEnabled(boolean compatibilityModeEnabled) {
5020 sCompatibilityModeEnabled = compatibilityModeEnabled;
5021 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07005022
Jeff Sharkey275e0852014-06-17 18:18:49 -07005023 private static AtomicReference<byte[]> sBuffer = new AtomicReference<byte[]>();
5024
5025 public static long readFullyIgnoringContents(InputStream in) throws IOException {
5026 byte[] buffer = sBuffer.getAndSet(null);
5027 if (buffer == null) {
5028 buffer = new byte[4096];
5029 }
5030
5031 int n = 0;
5032 int count = 0;
5033 while ((n = in.read(buffer, 0, buffer.length)) != -1) {
5034 count += n;
5035 }
5036
5037 sBuffer.set(buffer);
5038 return count;
5039 }
5040
5041 public static void closeQuietly(StrictJarFile jarFile) {
5042 if (jarFile != null) {
5043 try {
5044 jarFile.close();
5045 } catch (Exception ignored) {
5046 }
5047 }
5048 }
5049
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07005050 public static class PackageParserException extends Exception {
5051 public final int error;
5052
5053 public PackageParserException(int error, String detailMessage) {
5054 super(detailMessage);
5055 this.error = error;
5056 }
Jeff Sharkey275e0852014-06-17 18:18:49 -07005057
5058 public PackageParserException(int error, String detailMessage, Throwable throwable) {
5059 super(detailMessage, throwable);
5060 this.error = error;
5061 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07005062 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005063}