summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Martijn Coenen <maco@google.com> 2019-01-31 12:35:13 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2019-01-31 12:35:13 +0000
commit81973983b02c8cd7289b45afa3cc794eae0833a7 (patch)
treeaf5218d4108c39ae66bdbb811c4b5dce68dc85b5
parent3b4ee41b21930e1ec1f25d2cafbc65327593410f (diff)
parentfb7caa96f9511273ef32e1e80b740b28ca91a536 (diff)
Merge "Allow app to specify class name for app zygote preloading."
-rw-r--r--api/current.txt5
-rw-r--r--core/java/android/app/ZygotePreload.java42
-rw-r--r--core/java/android/content/pm/ApplicationInfo.java6
-rw-r--r--core/java/android/content/pm/PackageParser.java3
-rw-r--r--core/java/com/android/internal/os/AppZygoteInit.java39
-rw-r--r--core/res/res/values/attrs_manifest.xml21
-rw-r--r--core/res/res/values/public.xml1
7 files changed, 98 insertions, 19 deletions
diff --git a/api/current.txt b/api/current.txt
index 2f4f2c35acc2..83de0b17181f 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -1622,6 +1622,7 @@ package android {
field @Deprecated public static final int yearListSelectorColor = 16843930; // 0x101049a
field public static final int yesNoPreferenceStyle = 16842896; // 0x1010090
field public static final int zAdjustment = 16843201; // 0x10101c1
+ field public static final int zygotePreloadName = 16844195; // 0x10105a3
}
public static final class R.bool {
@@ -6483,6 +6484,10 @@ package android.app {
method public void onColorsChanged(android.app.WallpaperColors, int);
}
+ public interface ZygotePreload {
+ method public void doPreload(android.content.pm.ApplicationInfo);
+ }
+
}
package android.app.admin {
diff --git a/core/java/android/app/ZygotePreload.java b/core/java/android/app/ZygotePreload.java
new file mode 100644
index 000000000000..a295af352c0a
--- /dev/null
+++ b/core/java/android/app/ZygotePreload.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.app;
+
+import android.content.pm.ApplicationInfo;
+
+/**
+ * This is the interface to be implemented for the class that is specified by the
+ * {@link android.R.styleable#AndroidManifestApplication_zygotePreloadName
+ * android:zygotePreloadName} of the &lt;application&gt; tag.
+ *
+ * It is responsible for preloading application code and data, that will be shared by all
+ * isolated services that have the
+ * {@link android.R.styleable#AndroidManifestService_useAppZygote android:useAppZygote} attribute
+ * of the &lt;service&gt; tag set to <code>true</code>.
+ *
+ * Note that this implementations of this class must provide a default constructor with no
+ * arguments.
+ */
+public interface ZygotePreload {
+ /**
+ * This method is called once every time the Application Zygote is started. It is normally
+ * started the first time an isolated service that uses it is started. The Application Zygote
+ * will be stopped when all isolated services that use it are stopped.
+ *
+ * @param appInfo The ApplicationInfo object belonging to the application
+ */
+ void doPreload(ApplicationInfo appInfo);
+}
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 5d6d1444eaf3..1358bc25a07b 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -1192,6 +1192,9 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
/** @hide */
public boolean hiddenUntilInstalled;
+ /** @hide */
+ public String zygotePreloadName;
+
/**
* Represents the default policy. The actual policy used will depend on other properties of
* the application, e.g. the target SDK version.
@@ -1533,6 +1536,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
compileSdkVersionCodename = orig.compileSdkVersionCodename;
mHiddenApiPolicy = orig.mHiddenApiPolicy;
hiddenUntilInstalled = orig.hiddenUntilInstalled;
+ zygotePreloadName = orig.zygotePreloadName;
}
public String toString() {
@@ -1609,6 +1613,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
dest.writeString(appComponentFactory);
dest.writeInt(mHiddenApiPolicy);
dest.writeInt(hiddenUntilInstalled ? 1 : 0);
+ dest.writeString(zygotePreloadName);
}
public static final Parcelable.Creator<ApplicationInfo> CREATOR
@@ -1682,6 +1687,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
appComponentFactory = source.readString();
mHiddenApiPolicy = source.readInt();
hiddenUntilInstalled = source.readInt() != 0;
+ zygotePreloadName = source.readString();
}
/**
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index eb59cfc0fc4b..1fab443629a4 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -3907,6 +3907,9 @@ public class PackageParser {
outError[0] = "Invalid class loader name: " + ai.classLoaderName;
}
+ ai.zygotePreloadName = sa.getString(
+ com.android.internal.R.styleable.AndroidManifestApplication_zygotePreloadName);
+
sa.recycle();
if (outError[0] != null) {
diff --git a/core/java/com/android/internal/os/AppZygoteInit.java b/core/java/com/android/internal/os/AppZygoteInit.java
index 6ba584d76ee8..0e83e41a7423 100644
--- a/core/java/com/android/internal/os/AppZygoteInit.java
+++ b/core/java/com/android/internal/os/AppZygoteInit.java
@@ -17,13 +17,15 @@
package com.android.internal.os;
import android.app.LoadedApk;
+import android.app.ZygotePreload;
+import android.content.ComponentName;
import android.content.pm.ApplicationInfo;
import android.net.LocalSocket;
import android.util.Log;
import java.io.DataOutputStream;
import java.io.IOException;
-import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
/**
@@ -76,20 +78,29 @@ class AppZygoteInit {
Zygote.allowAppFilesAcrossFork(appInfo);
- Class<?> cl;
- Method m;
- try {
- cl = Class.forName(appInfo.packageName + ".ZygotePreload", true, loader);
- m = cl.getMethod("doPreload");
- m.setAccessible(true);
- m.invoke(null);
- } catch (ClassNotFoundException e) {
- // Don't treat this as an error since an app may not want to do any preloads
- Log.w(TAG, "No ZygotePreload class found for " + appInfo.packageName);
- } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
- Log.e(TAG, "AppZygote application preload failed for "
- + appInfo.packageName, e);
+ if (appInfo.zygotePreloadName != null) {
+ Class<?> cl;
+ Method m;
+ try {
+ ComponentName preloadName = ComponentName.createRelative(appInfo.packageName,
+ appInfo.zygotePreloadName);
+ cl = Class.forName(preloadName.getClassName(), true, loader);
+ if (!ZygotePreload.class.isAssignableFrom(cl)) {
+ Log.e(TAG, preloadName.getClassName() + " does not implement "
+ + ZygotePreload.class.getName());
+ } else {
+ Constructor<?> ctor = cl.getConstructor();
+ ZygotePreload preloadObject = (ZygotePreload) ctor.newInstance();
+ preloadObject.doPreload(appInfo);
+ }
+ } catch (ReflectiveOperationException e) {
+ Log.e(TAG, "AppZygote application preload failed for "
+ + appInfo.zygotePreloadName, e);
+ }
+ } else {
+ Log.i(TAG, "No zygotePreloadName attribute specified.");
}
+
try {
DataOutputStream socketOut = getSocketOutputStream();
socketOut.writeInt(loader != null ? 1 : 0);
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 0abe456c82f9..1eece03e3023 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1116,6 +1116,15 @@
-->
<attr name="classLoader" format="string" />
+ <!-- Name of the class that gets invoked for preloading application code, when starting an
+ {@link android.R.attr#isolatedProcess} service that has
+ {@link android.R.attr#useAppZygote} set to <code>true</code>. This is a fully
+ qualified class name (for example, com.mycompany.myapp.MyZygotePreload); as a
+ short-hand if the first character of the class is a period then it is appended
+ to your package name. The class must implement the {@link android.app.ZygotePreload}
+ interface. -->
+ <attr name="zygotePreloadName" format="string"/>
+
<!-- If set to <code>true</code>, indicates to the platform that this APK is
a 'feature' split and that it implicitly depends on the base APK. This distinguishes
this split APK from a 'configuration' split, which provides resource overrides
@@ -1644,6 +1653,7 @@
<!-- If {@code true} the user is prompted to keep the app's data on uninstall -->
<attr name="hasFragileUserData" />
+ <attr name="zygotePreloadName" />
</declare-styleable>
<!-- The <code>permission</code> tag declares a security permission that can be
used to control access from other packages to specific components or
@@ -2300,17 +2310,18 @@
<!-- If true, and this is an {@link android.R.attr#isolatedProcess} service, the service
will be spawned from an Application Zygote, instead of the regular Zygote.
<p>
- The Application Zygote will pre-initialize the application's class loader,
- and call a static callback into the application to allow it to perform
+ The Application Zygote will first pre-initialize the application's class loader. Then,
+ if the application has defined the {@link android.R.attr#zygotePreloadName} attribute,
+ the Application Zygote will call into that class to allow it to perform
application-specific preloads (such as loading a shared library). Therefore,
spawning from the Application Zygote will typically reduce the service
launch time and reduce its memory usage. The downside of using this flag
is that you will have an additional process (the app zygote itself) that
is taking up memory. Whether actual memory usage is improved therefore strongly
depends on the number of isolated services that an application starts,
- and how much memory those services save by preloading. Therefore, it is
- recommended to measure memory usage under typical workloads to determine
- whether it makes sense to use this flag. -->
+ and how much memory those services save by preloading and sharing memory with
+ the app zygote. Therefore, it is recommended to measure memory usage under
+ typical workloads to determine whether it makes sense to use this flag. -->
<attr name="useAppZygote" format="boolean" />
<!-- If this is a foreground service, specify its category. -->
<attr name="foregroundServiceType" />
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index ec1bac1a41d6..b5266e247e3a 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2936,6 +2936,7 @@
<public name="minAspectRatio" />
<!-- @hide @SystemApi -->
<public name="inheritShowWhenLocked" />
+ <public name="zygotePreloadName" />
</public-group>
<public-group type="drawable" first-id="0x010800b4">