import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
import static android.content.pm.ApplicationInfo.FLAG_SUSPENDED;
-import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_UNRESIZEABLE;
import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE;
import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
+import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_UNRESIZEABLE;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING;
import android.content.ComponentName;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.split.DefaultSplitAssetLoader;
import android.content.pm.split.SplitAssetDependencyLoader;
import android.content.pm.split.SplitAssetLoader;
-import android.content.pm.split.DefaultSplitAssetLoader;
import android.content.res.AssetManager;
import android.content.res.Configuration;
import android.content.res.Resources;
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.os.ClassLoaderFactory;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.XmlUtils;
private static final String PROPERTY_CHILD_PACKAGES_ENABLED =
"persist.sys.child_packages_enabled";
+ // TODO: Decide the correct default before O-MR1.
private static final boolean MULTI_PACKAGE_APK_ENABLED = Build.IS_DEBUGGABLE &&
- SystemProperties.getBoolean(PROPERTY_CHILD_PACKAGES_ENABLED, false);
+ SystemProperties.getBoolean(PROPERTY_CHILD_PACKAGES_ENABLED, true);
private static final int MAX_PACKAGES_PER_APK = 5;
public final boolean extractNativeLibs;
public final boolean isolatedSplits;
+ public final String classLoaderName;
+ public final String[] splitClassLoaderNames;
+
public PackageLite(String codePath, ApkLite baseApk, String[] splitNames,
boolean[] isFeatureSplits, String[] usesSplitNames, String[] configForSplit,
- String[] splitCodePaths, int[] splitRevisionCodes) {
+ String[] splitCodePaths, int[] splitRevisionCodes, String[] splitClassLoaderNames) {
this.packageName = baseApk.packageName;
this.versionCode = baseApk.versionCode;
this.installLocation = baseApk.installLocation;
this.use32bitAbi = baseApk.use32bitAbi;
this.extractNativeLibs = baseApk.extractNativeLibs;
this.isolatedSplits = baseApk.isolatedSplits;
+
+ this.classLoaderName = baseApk.classLoaderName;
+ this.splitClassLoaderNames = splitClassLoaderNames;
}
public List<String> getAllCodePaths() {
public final boolean use32bitAbi;
public final boolean extractNativeLibs;
public final boolean isolatedSplits;
+ public final String classLoaderName;
public ApkLite(String codePath, String packageName, String splitName, boolean isFeatureSplit,
String configForSplit, String usesSplitName, int versionCode, int revisionCode,
int installLocation, List<VerifierInfo> verifiers, Signature[] signatures,
Certificate[][] certificates, boolean coreApp, boolean debuggable,
boolean multiArch, boolean use32bitAbi, boolean extractNativeLibs,
- boolean isolatedSplits) {
+ boolean isolatedSplits, String classLoaderName) {
this.codePath = codePath;
this.packageName = packageName;
this.splitName = splitName;
this.use32bitAbi = use32bitAbi;
this.extractNativeLibs = extractNativeLibs;
this.isolatedSplits = isolatedSplits;
+ this.classLoaderName = classLoaderName;
}
}
+ /**
+ * Cached parse state for new components.
+ *
+ * Allows reuse of the same parse argument records to avoid GC pressure. Lifetime is carefully
+ * scoped to the parsing of a single application element.
+ */
+ private static class CachedComponentArgs {
+ ParseComponentArgs mActivityArgs;
+ ParseComponentArgs mActivityAliasArgs;
+ ParseComponentArgs mServiceArgs;
+ ParseComponentArgs mProviderArgs;
+ }
+
+ /**
+ * Cached state for parsing instrumentation to avoid GC pressure.
+ *
+ * Must be manually reset to null for each new manifest.
+ */
private ParsePackageItemArgs mParseInstrumentationArgs;
- private ParseComponentArgs mParseActivityArgs;
- private ParseComponentArgs mParseActivityAliasArgs;
- private ParseComponentArgs mParseServiceArgs;
- private ParseComponentArgs mParseProviderArgs;
/** If set to true, we will only allow package files that exactly match
* the DTD. Otherwise, we try to get as much from the package as we
final ApkLite baseApk = parseApkLite(packageFile, flags);
final String packagePath = packageFile.getAbsolutePath();
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
- return new PackageLite(packagePath, baseApk, null, null, null, null, null, null);
+ return new PackageLite(packagePath, baseApk, null, null, null, null, null, null, null);
}
static PackageLite parseClusterPackageLite(File packageDir, int flags)
String[] configForSplits = null;
String[] splitCodePaths = null;
int[] splitRevisionCodes = null;
+ String[] splitClassLoaderNames = null;
if (size > 0) {
splitNames = new String[size];
isFeatureSplits = new boolean[size];
configForSplits = new String[size];
splitCodePaths = new String[size];
splitRevisionCodes = new int[size];
+ splitClassLoaderNames = new String[size];
splitNames = apks.keySet().toArray(splitNames);
Arrays.sort(splitNames, sSplitNameComparator);
configForSplits[i] = apk.configForSplit;
splitCodePaths[i] = apk.codePath;
splitRevisionCodes[i] = apk.revisionCode;
+ splitClassLoaderNames[i] = apk.classLoaderName;
}
}
final String codePath = packageDir.getAbsolutePath();
return new PackageLite(codePath, baseApk, splitNames, isFeatureSplits, usesSplitNames,
- configForSplits, splitCodePaths, splitRevisionCodes);
+ configForSplits, splitCodePaths, splitRevisionCodes, splitClassLoaderNames);
}
/**
pkg.splitPrivateFlags = new int[num];
pkg.applicationInfo.splitNames = pkg.splitNames;
pkg.applicationInfo.splitDependencies = splitDependencies;
+ pkg.applicationInfo.classLoaderName = lite.classLoaderName;
+ pkg.applicationInfo.splitClassLoaderNames = lite.splitClassLoaderNames;
for (int i = 0; i < num; i++) {
final AssetManager splitAssets = assetLoader.getSplitAssetManager(i);
parsePackageSplitNames(parser, attrs);
mParseInstrumentationArgs = null;
- mParseActivityArgs = null;
- mParseServiceArgs = null;
- mParseProviderArgs = null;
int type;
}
final AttributeSet attrs = parser;
- return parseApkLite(apkPath, parser, attrs, flags, signatures, certificates);
+ return parseApkLite(apkPath, parser, attrs, signatures, certificates);
} catch (XmlPullParserException | IOException | RuntimeException e) {
Slog.w(TAG, "Failed to parse " + apkPath, e);
}
private static ApkLite parseApkLite(String codePath, XmlPullParser parser, AttributeSet attrs,
- int flags, Signature[] signatures, Certificate[][] certificates)
+ Signature[] signatures, Certificate[][] certificates)
throws IOException, XmlPullParserException, PackageParserException {
final Pair<String, String> packageSplit = parsePackageSplitNames(parser, attrs);
boolean isFeatureSplit = false;
String configForSplit = null;
String usesSplitName = null;
+ String classLoaderName = null;
for (int i = 0; i < attrs.getAttributeCount(); i++) {
final String attr = attrs.getAttributeName(i);
if ("extractNativeLibs".equals(attr)) {
extractNativeLibs = attrs.getAttributeBooleanValue(i, true);
}
+ if ("classLoader".equals(attr)) {
+ classLoaderName = attrs.getAttributeValue(i);
+ if (!ClassLoaderFactory.isValidClassLoaderName(classLoaderName)) {
+ throw new PackageParserException(
+ PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ "Invalid class loader name: " + classLoaderName);
+ }
+ }
}
} else if (TAG_USES_SPLIT.equals(parser.getName())) {
if (usesSplitName != null) {
return new ApkLite(codePath, packageSplit.first, packageSplit.second, isFeatureSplit,
configForSplit, usesSplitName, versionCode, revisionCode, installLocation,
verifiers, signatures, certificates, coreApp, debuggable, multiArch, use32bitAbi,
- extractNativeLibs, isolatedSplits);
- }
-
- /**
- * Temporary.
- */
- static public Signature stringToSignature(String str) {
- final int N = str.length();
- byte[] sig = new byte[N];
- for (int i=0; i<N; i++) {
- sig[i] = (byte)str.charAt(i);
- }
- return new Signature(sig);
+ extractNativeLibs, isolatedSplits, classLoaderName);
}
/**
XmlResourceParser parser, int flags, String[] outError) throws XmlPullParserException,
IOException {
mParseInstrumentationArgs = null;
- mParseActivityArgs = null;
- mParseServiceArgs = null;
- mParseProviderArgs = null;
int type;
boolean foundApp = false;
}
final int innerDepth = parser.getDepth();
+ // IMPORTANT: These must only be cached for a single <application> to avoid components
+ // getting added to the wrong package.
+ final CachedComponentArgs cachedArgs = new CachedComponentArgs();
int type;
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
String tagName = parser.getName();
if (tagName.equals("activity")) {
- Activity a = parseActivity(owner, res, parser, flags, outError, false,
+ Activity a = parseActivity(owner, res, parser, flags, outError, cachedArgs, false,
owner.baseHardwareAccelerated);
if (a == null) {
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
owner.activities.add(a);
} else if (tagName.equals("receiver")) {
- Activity a = parseActivity(owner, res, parser, flags, outError, true, false);
+ Activity a = parseActivity(owner, res, parser, flags, outError, cachedArgs,
+ true, false);
if (a == null) {
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return false;
owner.receivers.add(a);
} else if (tagName.equals("service")) {
- Service s = parseService(owner, res, parser, flags, outError);
+ Service s = parseService(owner, res, parser, flags, outError, cachedArgs);
if (s == null) {
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return false;
owner.services.add(s);
} else if (tagName.equals("provider")) {
- Provider p = parseProvider(owner, res, parser, flags, outError);
+ Provider p = parseProvider(owner, res, parser, flags, outError, cachedArgs);
if (p == null) {
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return false;
owner.providers.add(p);
} else if (tagName.equals("activity-alias")) {
- Activity a = parseActivityAlias(owner, res, parser, flags, outError);
+ Activity a = parseActivityAlias(owner, res, parser, flags, outError, cachedArgs);
if (a == null) {
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return false;
ComponentInfo parsedComponent = null;
+ // IMPORTANT: These must only be cached for a single <application> to avoid components
+ // getting added to the wrong package.
+ final CachedComponentArgs cachedArgs = new CachedComponentArgs();
String tagName = parser.getName();
if (tagName.equals("activity")) {
- Activity a = parseActivity(owner, res, parser, flags, outError, false,
+ Activity a = parseActivity(owner, res, parser, flags, outError, cachedArgs, false,
owner.baseHardwareAccelerated);
if (a == null) {
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
parsedComponent = a.info;
} else if (tagName.equals("receiver")) {
- Activity a = parseActivity(owner, res, parser, flags, outError, true, false);
+ Activity a = parseActivity(owner, res, parser, flags, outError, cachedArgs,
+ true, false);
if (a == null) {
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return false;
parsedComponent = a.info;
} else if (tagName.equals("service")) {
- Service s = parseService(owner, res, parser, flags, outError);
+ Service s = parseService(owner, res, parser, flags, outError, cachedArgs);
if (s == null) {
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return false;
parsedComponent = s.info;
} else if (tagName.equals("provider")) {
- Provider p = parseProvider(owner, res, parser, flags, outError);
+ Provider p = parseProvider(owner, res, parser, flags, outError, cachedArgs);
if (p == null) {
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return false;
parsedComponent = p.info;
} else if (tagName.equals("activity-alias")) {
- Activity a = parseActivityAlias(owner, res, parser, flags, outError);
+ Activity a = parseActivityAlias(owner, res, parser, flags, outError, cachedArgs);
if (a == null) {
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return false;
}
private Activity parseActivity(Package owner, Resources res,
- XmlResourceParser parser, int flags, String[] outError,
+ XmlResourceParser parser, int flags, String[] outError, CachedComponentArgs cachedArgs,
boolean receiver, boolean hardwareAccelerated)
throws XmlPullParserException, IOException {
TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestActivity);
- if (mParseActivityArgs == null) {
- mParseActivityArgs = new ParseComponentArgs(owner, outError,
+ if (cachedArgs.mActivityArgs == null) {
+ cachedArgs.mActivityArgs = new ParseComponentArgs(owner, outError,
R.styleable.AndroidManifestActivity_name,
R.styleable.AndroidManifestActivity_label,
R.styleable.AndroidManifestActivity_icon,
R.styleable.AndroidManifestActivity_enabled);
}
- mParseActivityArgs.tag = receiver ? "<receiver>" : "<activity>";
- mParseActivityArgs.sa = sa;
- mParseActivityArgs.flags = flags;
+ cachedArgs.mActivityArgs.tag = receiver ? "<receiver>" : "<activity>";
+ cachedArgs.mActivityArgs.sa = sa;
+ cachedArgs.mActivityArgs.flags = flags;
- Activity a = new Activity(mParseActivityArgs, new ActivityInfo());
+ Activity a = new Activity(cachedArgs.mActivityArgs, new ActivityInfo());
if (outError[0] != null) {
sa.recycle();
return null;
a.info.colorMode = sa.getInt(R.styleable.AndroidManifestActivity_colorMode,
ActivityInfo.COLOR_MODE_DEFAULT);
+
+ if (sa.getBoolean(R.styleable.AndroidManifestActivity_showWhenLocked, false)) {
+ a.info.flags |= ActivityInfo.FLAG_SHOW_WHEN_LOCKED;
+ }
+
+ if (sa.getBoolean(R.styleable.AndroidManifestActivity_turnScreenOn, false)) {
+ a.info.flags |= ActivityInfo.FLAG_TURN_SCREEN_ON;
+ }
+
} else {
a.info.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
a.info.configChanges = 0;
}
private Activity parseActivityAlias(Package owner, Resources res,
- XmlResourceParser parser, int flags, String[] outError)
+ XmlResourceParser parser, int flags, String[] outError,
+ CachedComponentArgs cachedArgs)
throws XmlPullParserException, IOException {
TypedArray sa = res.obtainAttributes(parser,
com.android.internal.R.styleable.AndroidManifestActivityAlias);
return null;
}
- if (mParseActivityAliasArgs == null) {
- mParseActivityAliasArgs = new ParseComponentArgs(owner, outError,
+ if (cachedArgs.mActivityAliasArgs == null) {
+ cachedArgs.mActivityAliasArgs = new ParseComponentArgs(owner, outError,
com.android.internal.R.styleable.AndroidManifestActivityAlias_name,
com.android.internal.R.styleable.AndroidManifestActivityAlias_label,
com.android.internal.R.styleable.AndroidManifestActivityAlias_icon,
0,
com.android.internal.R.styleable.AndroidManifestActivityAlias_description,
com.android.internal.R.styleable.AndroidManifestActivityAlias_enabled);
- mParseActivityAliasArgs.tag = "<activity-alias>";
+ cachedArgs.mActivityAliasArgs.tag = "<activity-alias>";
}
- mParseActivityAliasArgs.sa = sa;
- mParseActivityAliasArgs.flags = flags;
+ cachedArgs.mActivityAliasArgs.sa = sa;
+ cachedArgs.mActivityAliasArgs.flags = flags;
Activity target = null;
info.encryptionAware = info.directBootAware = target.info.directBootAware;
- Activity a = new Activity(mParseActivityAliasArgs, info);
+ Activity a = new Activity(cachedArgs.mActivityAliasArgs, info);
if (outError[0] != null) {
sa.recycle();
return null;
}
private Provider parseProvider(Package owner, Resources res,
- XmlResourceParser parser, int flags, String[] outError)
+ XmlResourceParser parser, int flags, String[] outError,
+ CachedComponentArgs cachedArgs)
throws XmlPullParserException, IOException {
TypedArray sa = res.obtainAttributes(parser,
com.android.internal.R.styleable.AndroidManifestProvider);
- if (mParseProviderArgs == null) {
- mParseProviderArgs = new ParseComponentArgs(owner, outError,
+ if (cachedArgs.mProviderArgs == null) {
+ cachedArgs.mProviderArgs = new ParseComponentArgs(owner, outError,
com.android.internal.R.styleable.AndroidManifestProvider_name,
com.android.internal.R.styleable.AndroidManifestProvider_label,
com.android.internal.R.styleable.AndroidManifestProvider_icon,
com.android.internal.R.styleable.AndroidManifestProvider_process,
com.android.internal.R.styleable.AndroidManifestProvider_description,
com.android.internal.R.styleable.AndroidManifestProvider_enabled);
- mParseProviderArgs.tag = "<provider>";
+ cachedArgs.mProviderArgs.tag = "<provider>";
}
- mParseProviderArgs.sa = sa;
- mParseProviderArgs.flags = flags;
+ cachedArgs.mProviderArgs.sa = sa;
+ cachedArgs.mProviderArgs.flags = flags;
- Provider p = new Provider(mParseProviderArgs, new ProviderInfo());
+ Provider p = new Provider(cachedArgs.mProviderArgs, new ProviderInfo());
if (outError[0] != null) {
sa.recycle();
return null;
}
private Service parseService(Package owner, Resources res,
- XmlResourceParser parser, int flags, String[] outError)
+ XmlResourceParser parser, int flags, String[] outError,
+ CachedComponentArgs cachedArgs)
throws XmlPullParserException, IOException {
TypedArray sa = res.obtainAttributes(parser,
com.android.internal.R.styleable.AndroidManifestService);
- if (mParseServiceArgs == null) {
- mParseServiceArgs = new ParseComponentArgs(owner, outError,
+ if (cachedArgs.mServiceArgs == null) {
+ cachedArgs.mServiceArgs = new ParseComponentArgs(owner, outError,
com.android.internal.R.styleable.AndroidManifestService_name,
com.android.internal.R.styleable.AndroidManifestService_label,
com.android.internal.R.styleable.AndroidManifestService_icon,
com.android.internal.R.styleable.AndroidManifestService_process,
com.android.internal.R.styleable.AndroidManifestService_description,
com.android.internal.R.styleable.AndroidManifestService_enabled);
- mParseServiceArgs.tag = "<service>";
+ cachedArgs.mServiceArgs.tag = "<service>";
}
- mParseServiceArgs.sa = sa;
- mParseServiceArgs.flags = flags;
+ cachedArgs.mServiceArgs.sa = sa;
+ cachedArgs.mServiceArgs.flags = flags;
- Service s = new Service(mParseServiceArgs, new ServiceInfo());
+ Service s = new Service(cachedArgs.mServiceArgs, new ServiceInfo());
if (outError[0] != null) {
sa.recycle();
return null;