Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 554cfd1f authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "Add Zygote.startChildZygote() to fork a new process that itself is a zygote."

parents b8d25ed3 d0a190df
Loading
Loading
Loading
Loading
+44 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 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.os;

import android.net.LocalSocketAddress;

/**
 * Represents a connection to a child-zygote process. A child-zygote is spawend from another
 * zygote process using {@link startChildZygote()}.
 *
 * {@hide}
 */
public class ChildZygoteProcess extends ZygoteProcess {
    /**
     * The PID of the child zygote process.
     */
    private final int mPid;

    ChildZygoteProcess(LocalSocketAddress socketAddress, int pid) {
        super(socketAddress, null);
        mPid = pid;
    }

    /**
     * Returns the PID of the child-zygote process.
     */
    public int getPid() {
        return mPid;
    }
}
+54 −1
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@ import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;

/*package*/ class ZygoteStartFailedEx extends Exception {
    ZygoteStartFailedEx(String s) {
@@ -217,7 +218,8 @@ public class ZygoteProcess {
        try {
            return startViaZygote(processClass, niceName, uid, gid, gids,
                    runtimeFlags, mountExternal, targetSdkVersion, seInfo,
                    abi, instructionSet, appDataDir, invokeWith, zygoteArgs);
                    abi, instructionSet, appDataDir, invokeWith, false /* startChildZygote */,
                    zygoteArgs);
        } catch (ZygoteStartFailedEx ex) {
            Log.e(LOG_TAG,
                    "Starting VM process through Zygote failed");
@@ -333,6 +335,8 @@ public class ZygoteProcess {
     * @param abi the ABI the process should use.
     * @param instructionSet null-ok the instruction set to use.
     * @param appDataDir null-ok the data directory of the app.
     * @param startChildZygote Start a sub-zygote. This creates a new zygote process
     * that has its state cloned from this zygote process.
     * @param extraArgs Additional arguments to supply to the zygote process.
     * @return An object that describes the result of the attempt to start the process.
     * @throws ZygoteStartFailedEx if process start failed for any reason
@@ -348,6 +352,7 @@ public class ZygoteProcess {
                                                      String instructionSet,
                                                      String appDataDir,
                                                      String invokeWith,
                                                      boolean startChildZygote,
                                                      String[] extraArgs)
                                                      throws ZygoteStartFailedEx {
        ArrayList<String> argsForZygote = new ArrayList<String>();
@@ -404,6 +409,10 @@ public class ZygoteProcess {
            argsForZygote.add(invokeWith);
        }

        if (startChildZygote) {
            argsForZygote.add("--start-child-zygote");
        }

        argsForZygote.add(processClass);

        if (extraArgs != null) {
@@ -417,6 +426,18 @@ public class ZygoteProcess {
        }
    }

    /**
     * Closes the connections to the zygote, if they exist.
     */
    public void close() {
        if (primaryZygoteState != null) {
            primaryZygoteState.close();
        }
        if (secondaryZygoteState != null) {
            secondaryZygoteState.close();
        }
    }

    /**
     * Tries to establish a connection to the zygote that handles a given {@code abi}. Might block
     * and retry if the zygote is unresponsive. This method is a no-op if a connection is
@@ -549,4 +570,36 @@ public class ZygoteProcess {
        }
        Slog.wtf(LOG_TAG, "Failed to connect to Zygote through socket " + address.getName());
    }

    /**
     * Starts a new zygote process as a child of this zygote. This is used to create
     * secondary zygotes that inherit data from the zygote that this object
     * communicates with. This returns a new ZygoteProcess representing a connection
     * to the newly created zygote. Throws an exception if the zygote cannot be started.
     */
    public ChildZygoteProcess startChildZygote(final String processClass,
                                               final String niceName,
                                               int uid, int gid, int[] gids,
                                               int runtimeFlags,
                                               String seInfo,
                                               String abi,
                                               String instructionSet) {
        // Create an unguessable address in the global abstract namespace.
        final LocalSocketAddress serverAddress = new LocalSocketAddress(
                processClass + "/" + UUID.randomUUID().toString());

        final String[] extraArgs = {Zygote.CHILD_ZYGOTE_SOCKET_NAME_ARG + serverAddress.getName()};

        Process.ProcessStartResult result;
        try {
            result = startViaZygote(processClass, niceName, uid, gid,
                    gids, runtimeFlags, 0 /* mountExternal */, 0 /* targetSdkVersion */, seInfo,
                    abi, instructionSet, null /* appDataDir */, null /* invokeWith */,
                    true /* startChildZygote */, extraArgs);
        } catch (ZygoteStartFailedEx ex) {
            throw new RuntimeException("Starting child-zygote through Zygote failed", ex);
        }

        return new ChildZygoteProcess(serverAddress, result.pid);
    }
}
+1 −1
Original line number Diff line number Diff line
@@ -230,7 +230,7 @@ public class RuntimeInit {
     * @param argv Argument vector for main()
     * @param classLoader the classLoader to load {@className} with
     */
    private static Runnable findStaticMain(String className, String[] argv,
    protected static Runnable findStaticMain(String className, String[] argv,
            ClassLoader classLoader) {
        Class<?> cl;

+1 −1
Original line number Diff line number Diff line
@@ -129,7 +129,7 @@ class WebViewZygoteInit {

        final Runnable caller;
        try {
            sServer.registerServerSocket("webview_zygote");
            sServer.registerServerSocketFromEnv("webview_zygote");
            // The select loop returns early in the child process after a fork and
            // loops forever in the zygote.
            caller = sServer.runSelectLoop(TextUtils.join(",", Build.SUPPORTED_ABIS));
+14 −5
Original line number Diff line number Diff line
@@ -71,6 +71,13 @@ public final class Zygote {

    private static final ZygoteHooks VM_HOOKS = new ZygoteHooks();

    /**
     * An extraArg passed when a zygote process is forking a child-zygote, specifying a name
     * in the abstract socket namespace. This socket name is what the new child zygote
     * should listen for connections on.
     */
    public static final String CHILD_ZYGOTE_SOCKET_NAME_ARG = "--zygote-socket=";

    private Zygote() {}

    /** Called for some security initialization before any fork. */
@@ -102,6 +109,8 @@ public final class Zygote {
     * @param fdsToIgnore null-ok an array of ints, either null or holding
     * one or more POSIX file descriptor numbers that are to be ignored
     * in the file descriptor table check.
     * @param startChildZygote if true, the new child process will itself be a
     * new zygote process.
     * @param instructionSet null-ok the instruction set to use.
     * @param appDataDir null-ok the data directory of the app.
     *
@@ -110,13 +119,13 @@ public final class Zygote {
     */
    public static int forkAndSpecialize(int uid, int gid, int[] gids, int runtimeFlags,
          int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose,
          int[] fdsToIgnore, String instructionSet, String appDataDir) {
          int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir) {
        VM_HOOKS.preFork();
        // Resets nice priority for zygote process.
        resetNicePriority();
        int pid = nativeForkAndSpecialize(
                  uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose,
                  fdsToIgnore, instructionSet, appDataDir);
                  fdsToIgnore, startChildZygote, instructionSet, appDataDir);
        // Enable tracing as soon as possible for the child process.
        if (pid == 0) {
            Trace.setTracingEnabled(true, runtimeFlags);
@@ -130,7 +139,7 @@ public final class Zygote {

    native private static int nativeForkAndSpecialize(int uid, int gid, int[] gids,int runtimeFlags,
          int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose,
          int[] fdsToIgnore, String instructionSet, String appDataDir);
          int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir);

    /**
     * Called to do any initialization before starting an application.
@@ -190,8 +199,8 @@ public final class Zygote {
    native protected static void nativeUnmountStorageOnInit();

    private static void callPostForkChildHooks(int runtimeFlags, boolean isSystemServer,
            String instructionSet) {
        VM_HOOKS.postForkChild(runtimeFlags, isSystemServer, instructionSet);
            boolean isZygote, String instructionSet) {
        VM_HOOKS.postForkChild(runtimeFlags, isSystemServer, isZygote, instructionSet);
    }

    /**
Loading