Merge "Zygote: Add support for explicit preloading of resources."
diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java
index fa9f394..b3366d8 100644
--- a/core/java/android/os/ZygoteProcess.java
+++ b/core/java/android/os/ZygoteProcess.java
@@ -506,4 +506,24 @@
             state.writer.flush();
         }
     }
+
+    /**
+     * Instructs the zygote to preload the default set of classes and resources. Returns
+     * {@code true} if a preload was performed as a result of this call, and {@code false}
+     * otherwise. The latter usually means that the zygote eagerly preloaded at startup
+     * or due to a previous call to {@code preloadDefault}. Note that this call is synchronous.
+     */
+    public boolean preloadDefault(String abi) throws ZygoteStartFailedEx, IOException {
+        synchronized (mLock) {
+            ZygoteState state = openZygoteSocketIfNeeded(abi);
+            // Each query starts with the argument count (1 in this case)
+            state.writer.write("1");
+            state.writer.newLine();
+            state.writer.write("--preload-default");
+            state.writer.newLine();
+            state.writer.flush();
+
+            return (state.inputStream.readInt() == 0);
+        }
+    }
 }
diff --git a/core/java/com/android/internal/os/WebViewZygoteInit.java b/core/java/com/android/internal/os/WebViewZygoteInit.java
index d82a211..f27c0d4 100644
--- a/core/java/com/android/internal/os/WebViewZygoteInit.java
+++ b/core/java/com/android/internal/os/WebViewZygoteInit.java
@@ -55,8 +55,15 @@
         }
 
         @Override
-        protected void maybePreload() {
-            // Do nothing, we don't need to call ZygoteInit.maybePreload() for the WebView zygote.
+        protected void preload() {
+            // Nothing to preload by default.
+        }
+
+        @Override
+        protected boolean isPreloadComplete() {
+            // Webview zygotes don't preload any classes or resources or defaults, all of their
+            // preloading is package specific.
+            return true;
         }
 
         @Override
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index a7f311b..e2485e9 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -171,7 +171,9 @@
                 return handleAbiListQuery();
             }
 
-            maybePreload();
+            if (parsedArgs.preloadDefault) {
+                return handlePreload();
+            }
 
             if (parsedArgs.preloadPackage != null) {
                 return handlePreloadPackage(parsedArgs.preloadPackage,
@@ -282,8 +284,34 @@
         }
     }
 
-    protected void maybePreload() {
-        ZygoteInit.maybePreload();
+    /**
+     * Preloads resources if the zygote is in lazily preload mode. Writes the result of the
+     * preload operation; {@code 0} when a preload was initiated due to this request and {@code 1}
+     * if no preload was initiated. The latter implies that the zygote is not configured to load
+     * resources lazy or that the zygote has already handled a previous request to handlePreload.
+     */
+    private boolean handlePreload() {
+        try {
+            if (isPreloadComplete()) {
+                mSocketOutStream.writeInt(1);
+            } else {
+                preload();
+                mSocketOutStream.writeInt(0);
+            }
+
+            return false;
+        } catch (IOException ioe) {
+            Log.e(TAG, "Error writing to command socket", ioe);
+            return true;
+        }
+    }
+
+    protected void preload() {
+        ZygoteInit.lazyPreload();
+    }
+
+    protected boolean isPreloadComplete() {
+        return ZygoteInit.isPreloadComplete();
     }
 
     protected boolean handlePreloadPackage(String packagePath, String libsPath) {
@@ -402,6 +430,13 @@
         String preloadPackageLibs;
 
         /**
+         * Whether this is a request to start preloading the default resources and classes.
+         * This argument only makes sense when the zygote is in lazy preload mode (i.e, when
+         * it's started with --enable-lazy-preload).
+         */
+        boolean preloadDefault;
+
+        /**
          * Constructs instance and parses args
          * @param args zygote command-line args
          * @throws IllegalArgumentException
@@ -564,6 +599,8 @@
                 } else if (arg.equals("--preload-package")) {
                     preloadPackage = args[++curArg];
                     preloadPackageLibs = args[++curArg];
+                } else if (arg.equals("--preload-default")) {
+                    preloadDefault = true;
                 } else {
                     break;
                 }
@@ -578,7 +615,7 @@
                     throw new IllegalArgumentException(
                             "Unexpected arguments after --preload-package.");
                 }
-            } else {
+            } else if (!preloadDefault) {
                 if (!seenRuntimeArgs) {
                     throw new IllegalArgumentException("Unexpected argument : " + args[curArg]);
                 }
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 1fb31b4..0b5a1b7 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -51,6 +51,7 @@
 
 import com.android.internal.logging.MetricsLogger;
 
+import com.android.internal.util.Preconditions;
 import dalvik.system.DexFile;
 import dalvik.system.PathClassLoader;
 import dalvik.system.VMRuntime;
@@ -146,11 +147,11 @@
         sPreloadComplete = true;
     }
 
-    public static void maybePreload() {
-        if (!sPreloadComplete) {
-            Log.i(TAG, "Lazily preloading resources.");
-            preload(new BootTimingsTraceLog("ZygoteInitTiming_lazy", Trace.TRACE_TAG_DALVIK));
-        }
+    public static void lazyPreload() {
+        Preconditions.checkState(!sPreloadComplete);
+        Log.i(TAG, "Lazily preloading resources.");
+
+        preload(new BootTimingsTraceLog("ZygoteInitTiming_lazy", Trace.TRACE_TAG_DALVIK));
     }
 
     private static void beginIcuCachePinning() {
@@ -785,6 +786,10 @@
         }
     }
 
+    static boolean isPreloadComplete() {
+        return sPreloadComplete;
+    }
+
     /**
      * Class not instantiable.
      */