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

Commit be3dc575 authored by Narayan Kamath's avatar Narayan Kamath Committed by Android Git Automerger
Browse files

am 402120a2: Merge "Wait for secondary zygote before bringing up the system_server."

* commit '402120a2':
  Wait for secondary zygote before bringing up the system_server.
parents 6e2e6868 402120a2
Loading
Loading
Loading
Loading
+61 −94
Original line number Diff line number Diff line
@@ -31,13 +31,17 @@ import java.util.Arrays;
import java.util.List;

/*package*/ class ZygoteStartFailedEx extends Exception {
    /**
     * Something prevented the zygote process startup from happening normally
     */
    ZygoteStartFailedEx(String s) {
        super(s);
    }

    ZygoteStartFailedEx() {};
    ZygoteStartFailedEx(String s) {super(s);}
    ZygoteStartFailedEx(Throwable cause) {super(cause);}
    ZygoteStartFailedEx(Throwable cause) {
        super(cause);
    }

    ZygoteStartFailedEx(String s, Throwable cause) {
        super(s, cause);
    }
}

/**
@@ -46,9 +50,15 @@ import java.util.List;
public class Process {
    private static final String LOG_TAG = "Process";

    private static final String ZYGOTE_SOCKET = "zygote";
    /**
     * @hide for internal use only.
     */
    public static final String ZYGOTE_SOCKET = "zygote";

    private static final String SECONDARY_ZYGOTE_SOCKET = "zygote_secondary";
    /**
     * @hide for internal use only.
     */
    public static final String SECONDARY_ZYGOTE_SOCKET = "zygote_secondary";

    /**
     * Defines the UID/GID under which system code runs.
@@ -338,8 +348,10 @@ public class Process {

    /**
     * State for communicating with the zygote process.
     *
     * @hide for internal use only.
     */
    static class ZygoteState {
    public static class ZygoteState {
        final LocalSocket socket;
        final DataInputStream inputStream;
        final BufferedWriter writer;
@@ -355,32 +367,12 @@ public class Process {
            this.abiList = abiList;
        }

        static ZygoteState connect(String socketAddress, int tries) throws ZygoteStartFailedEx {
            LocalSocket zygoteSocket = null;
        public static ZygoteState connect(String socketAddress) throws IOException {
            DataInputStream zygoteInputStream = null;
            BufferedWriter zygoteWriter = null;

            /*
             * See bug #811181: Sometimes runtime can make it up before zygote.
             * Really, we'd like to do something better to avoid this condition,
             * but for now just wait a bit...
             *
             * TODO: This bug was filed in 2007. Get rid of this code. The zygote
             * forks the system_server so it shouldn't be possible for the zygote
             * socket to be brought up after the system_server is.
             */
            for (int i = 0; i < tries; i++) {
                if (i > 0) {
                    try {
                        Log.i(LOG_TAG, "Zygote not up yet, sleeping...");
                        Thread.sleep(ZYGOTE_RETRY_MILLIS);
                    } catch (InterruptedException ex) {
                        throw new ZygoteStartFailedEx(ex);
                    }
                }
            final LocalSocket zygoteSocket = new LocalSocket();

            try {
                    zygoteSocket = new LocalSocket();
                zygoteSocket.connect(new LocalSocketAddress(socketAddress,
                        LocalSocketAddress.Namespace.RESERVED));

@@ -388,22 +380,13 @@ public class Process {

                zygoteWriter = new BufferedWriter(new OutputStreamWriter(
                        zygoteSocket.getOutputStream()), 256);
                    break;
            } catch (IOException ex) {
                    if (zygoteSocket != null) {
                try {
                    zygoteSocket.close();
                        } catch (IOException ex2) {
                            Log.e(LOG_TAG,"I/O exception on close after exception", ex2);
                        }
                } catch (IOException ignore) {
                }

                    zygoteSocket = null;
                }
            }

            if (zygoteSocket == null) {
                throw new ZygoteStartFailedEx("connect failed");
                throw ex;
            }

            String abiListString = getAbiList(zygoteWriter, zygoteInputStream);
@@ -417,7 +400,7 @@ public class Process {
            return abiList.contains(abi);
        }

        void close() {
        public void close() {
            try {
                socket.close();
            } catch (IOException ex) {
@@ -503,9 +486,7 @@ public class Process {
     * @throws ZygoteStartFailedEx if the query failed.
     */
    private static String getAbiList(BufferedWriter writer, DataInputStream inputStream)
            throws ZygoteStartFailedEx {
        try {

            throws IOException {
        // Each query starts with the argument count (1 in this case)
        writer.write("1");
        // ... followed by a new-line.
@@ -521,9 +502,6 @@ public class Process {
        inputStream.readFully(bytes);

        return new String(bytes, StandardCharsets.US_ASCII);
        } catch (IOException ioe) {
            throw new ZygoteStartFailedEx(ioe);
        }
    }

    /**
@@ -676,31 +654,17 @@ public class Process {
        }
    }

    /**
     * Returns the number of times we attempt a connection to the zygote. We
     * sleep for {@link #ZYGOTE_RETRY_MILLIS} milliseconds between each try.
     *
     * This could probably be removed, see TODO in {@code ZygoteState#connect}.
     */
    private static int getNumTries(ZygoteState state) {
        // Retry 10 times for the first connection to each zygote.
        if (state == null) {
            return 11;
        }

        // This means the connection has already been established, but subsequently
        // closed, possibly due to an IOException. We retry just once if that's the
        // case.
        return 1;
    }

    /**
     * Tries to open socket to Zygote process if not already open. If
     * already open, does nothing.  May block and retry.
     */
    private static ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
        if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
            primaryZygoteState = ZygoteState.connect(ZYGOTE_SOCKET, getNumTries(primaryZygoteState));
            try {
                primaryZygoteState = ZygoteState.connect(ZYGOTE_SOCKET);
            } catch (IOException ioe) {
                throw new ZygoteStartFailedEx("Error connecting to primary zygote", ioe);
            }
        }

        if (primaryZygoteState.matches(abi)) {
@@ -709,8 +673,11 @@ public class Process {

        // The primary zygote didn't match. Try the secondary.
        if (secondaryZygoteState == null || secondaryZygoteState.isClosed()) {
            secondaryZygoteState = ZygoteState.connect(SECONDARY_ZYGOTE_SOCKET,
                    getNumTries(secondaryZygoteState));
            try {
            secondaryZygoteState = ZygoteState.connect(SECONDARY_ZYGOTE_SOCKET);
            } catch (IOException ioe) {
                throw new ZygoteStartFailedEx("Error connecting to secondary zygote", ioe);
            }
        }

        if (secondaryZygoteState.matches(abi)) {
+37 −2
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import android.content.res.Resources;
import android.content.res.TypedArray;
import android.net.LocalServerSocket;
import android.opengl.EGL14;
import android.os.Build;
import android.os.Debug;
import android.os.Process;
import android.os.SystemClock;
@@ -505,7 +506,7 @@ public class ZygoteInit {
    /**
     * Prepare the arguments and fork for the system server process.
     */
    private static boolean startSystemServer()
    private static boolean startSystemServer(String abiList, String socketName)
            throws MethodAndArgsCaller, RuntimeException {
        long capabilities = posixCapabilitiesAsBits(
            OsConstants.CAP_BLOCK_SUSPEND,
@@ -553,6 +554,10 @@ public class ZygoteInit {

        /* For child process */
        if (pid == 0) {
            if (hasSecondZygote(abiList)) {
                waitForSecondaryZygote(socketName);
            }

            handleSystemServerProcess(parsedArgs);
        }

@@ -615,7 +620,7 @@ public class ZygoteInit {
            Trace.setTracingEnabled(false);

            if (startSystemServer) {
                startSystemServer();
                startSystemServer(abiList, socketName);
            }

            Log.i(TAG, "Accepting command socket connections");
@@ -631,6 +636,36 @@ public class ZygoteInit {
        }
    }

    /**
     * Return {@code true} if this device configuration has another zygote.
     *
     * We determine this by comparing the device ABI list with this zygotes
     * list. If this zygote supports all ABIs this device supports, there won't
     * be another zygote.
     */
    private static boolean hasSecondZygote(String abiList) {
        return !SystemProperties.get("ro.product.cpu.abilist").equals(abiList);
    }

    private static void waitForSecondaryZygote(String socketName) {
        String otherZygoteName = Process.ZYGOTE_SOCKET.equals(socketName) ?
                Process.SECONDARY_ZYGOTE_SOCKET : Process.ZYGOTE_SOCKET;
        while (true) {
            try {
                final Process.ZygoteState zs = Process.ZygoteState.connect(otherZygoteName);
                zs.close();
                break;
            } catch (IOException ioe) {
                Log.w(TAG, "Got error connecting to zygote, retrying. msg= " + ioe.getMessage());
            }

            try {
                Thread.sleep(1000);
            } catch (InterruptedException ie) {
            }
        }
    }

    /**
     * Runs the zygote process's select loop. Accepts new connections as
     * they happen, and reads commands from connections one spawn-request's