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

Commit 402120a2 authored by Narayan Kamath's avatar Narayan Kamath Committed by Gerrit Code Review
Browse files

Merge "Wait for secondary zygote before bringing up the system_server."

parents 706b1d7e 64cd907a
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;
@@ -496,7 +497,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,
@@ -544,6 +545,10 @@ public class ZygoteInit {

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

            handleSystemServerProcess(parsedArgs);
        }

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

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

            Log.i(TAG, "Accepting command socket connections");
@@ -622,6 +627,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