diff --git a/api/current.txt b/api/current.txt
index 8ad59fff2721c..41f6d6f26ba0d 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 {
@@ -6477,6 +6478,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 0000000000000..a295af352c0aa
--- /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 <application> 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 <service> tag set to true.
+ *
+ * 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 5d6d1444eaf32..1358bc25a07b1 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 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 eb59cfc0fc4ba..1fab443629a4f 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 6ba584d76ee84..0e83e41a74239 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 de6468dbb72a4..752d2e108fdb9 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1113,6 +1113,15 @@
-->
+
+
+
+
+ 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. -->
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index ec1bac1a41d62..b5266e247e3af 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2936,6 +2936,7 @@
+