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

Commit c41638cb authored by Narayan Kamath's avatar Narayan Kamath
Browse files

Make zygotes aware of their supported ABIs.

Query system properties for the list of ABIs and pass
it as a command line argument to ZygoteInit.

Also add a new Zygote command that returns this list of
ABIs to peers.

Change-Id: I68034c6f63fa626911122579a011a0a25a8cda94
parent 22ec1eef
Loading
Loading
Loading
Loading
+19 −1
Original line number Diff line number Diff line
@@ -10,8 +10,9 @@
#include <binder/IPCThreadState.h>
#include <binder/ProcessState.h>
#include <utils/Log.h>
#include <cutils/process_name.h>
#include <cutils/memory.h>
#include <cutils/process_name.h>
#include <cutils/properties.h>
#include <cutils/trace.h>
#include <android_runtime/AndroidRuntime.h>

@@ -135,6 +136,12 @@ static size_t computeArgBlockSize(int argc, char* const argv[]) {
    return (end - start);
}

#if defined(__LP64__)
static const char ABI_LIST_PROPERTY[] = "ro.product.cpu.abilist64";
#else
static const char ABI_LIST_PROPERTY[] = "ro.product.cpu.abilist32";
#endif

int main(int argc, char* const argv[])
{
    AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
@@ -205,6 +212,17 @@ int main(int argc, char* const argv[])
            args.add(String8("start-system-server"));
        }

        char prop[PROP_VALUE_MAX];
        if (property_get(ABI_LIST_PROPERTY, prop, NULL) == 0) {
            LOG_ALWAYS_FATAL("app_process: Unable to deterimine ABI list from property %s.",
                ABI_LIST_PROPERTY);
            return 11;
        }

        String8 abiFlag("--abi-list=");
        abiFlag.append(prop);
        args.add(abiFlag);

        // In zygote mode, pass all remaining arguments to the zygote
        // main() method.
        for (; i < argc; ++i) {
+31 −43
Original line number Diff line number Diff line
@@ -22,9 +22,7 @@ import android.os.Process;
import android.os.SELinux;
import android.os.SystemProperties;
import android.util.Log;

import dalvik.system.PathClassLoader;

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
@@ -34,8 +32,8 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;

import libcore.io.ErrnoException;
import libcore.io.IoUtils;
import libcore.io.Libcore;
@@ -73,15 +71,18 @@ class ZygoteConnection {
    private final BufferedReader mSocketReader;
    private final Credentials peer;
    private final String peerSecurityContext;
    private final String abiList;

    /**
     * Constructs instance from connected socket.
     *
     * @param socket non-null; connected socket
     * @param abiList non-null; a list of ABIs this zygote supports.
     * @throws IOException
     */
    ZygoteConnection(LocalSocket socket) throws IOException {
    ZygoteConnection(LocalSocket socket, String abiList) throws IOException {
        mSocket = socket;
        this.abiList = abiList;

        mSocketOutStream
                = new DataOutputStream(socket.getOutputStream());
@@ -110,43 +111,6 @@ class ZygoteConnection {
        return mSocket.getFileDescriptor();
    }

    /**
     * Reads start commands from an open command socket.
     * Start commands are presently a pair of newline-delimited lines
     * indicating a) class to invoke main() on b) nice name to set argv[0] to.
     * Continues to read commands and forkAndSpecialize children until
     * the socket is closed. This method is used in ZYGOTE_FORK_MODE
     *
     * @throws ZygoteInit.MethodAndArgsCaller trampoline to invoke main()
     * method in child process
     */
    void run() throws ZygoteInit.MethodAndArgsCaller {

        int loopCount = ZygoteInit.GC_LOOP_COUNT;

        while (true) {
            /*
             * Call gc() before we block in readArgumentList().
             * It's work that has to be done anyway, and it's better
             * to avoid making every child do it.  It will also
             * madvise() any free memory as a side-effect.
             *
             * Don't call it every time, because walking the entire
             * heap is a lot of overhead to free a few hundred bytes.
             */
            if (loopCount <= 0) {
                ZygoteInit.gc();
                loopCount = ZygoteInit.GC_LOOP_COUNT;
            } else {
                loopCount--;
            }

            if (runOnce()) {
                break;
            }
        }
    }

    /**
     * Reads one start command from the command socket. If successful,
     * a child is forked and a {@link ZygoteInit.MethodAndArgsCaller}
@@ -196,6 +160,11 @@ class ZygoteConnection {

        try {
            parsedArgs = new Arguments(args);

            if (parsedArgs.abiListQuery) {
                return handleAbiListQuery();
            }

            if (parsedArgs.permittedCapabilities != 0 || parsedArgs.effectiveCapabilities != 0) {
                throw new ZygoteSecurityException("Client may not specify capabilities: " +
                        "permitted=0x" + Long.toHexString(parsedArgs.permittedCapabilities) +
@@ -287,6 +256,18 @@ class ZygoteConnection {
        }
    }

    private boolean handleAbiListQuery() {
        try {
            final byte[] abiListBytes = abiList.getBytes(StandardCharsets.US_ASCII);
            mSocketOutStream.writeInt(abiListBytes.length);
            mSocketOutStream.write(abiListBytes);
            return false;
        } catch (IOException ioe) {
            Log.e(TAG, "Error writing to command socket", ioe);
            return true;
        }
    }

    /**
     * Closes socket associated with this connection.
     */
@@ -387,6 +368,11 @@ class ZygoteConnection {
         */
        String remainingArgs[];

        /**
         * Whether the current arguments constitute an ABI list query.
         */
        boolean abiListQuery;

        /**
         * Constructs instance and parses args
         * @param args zygote command-line args
@@ -540,6 +526,8 @@ class ZygoteConnection {
                    mountExternal = Zygote.MOUNT_EXTERNAL_MULTIUSER;
                } else if (arg.equals("--mount-external-multiuser-all")) {
                    mountExternal = Zygote.MOUNT_EXTERNAL_MULTIUSER_ALL;
                } else if (arg.equals("--query-abi-list")) {
                    abiListQuery = true;
                } else {
                    break;
                }
@@ -975,7 +963,7 @@ class ZygoteConnection {
            mSocketOutStream.writeInt(pid);
            mSocketOutStream.writeBoolean(usingWrapper);
        } catch (IOException ex) {
            Log.e(TAG, "Error reading from command socket", ex);
            Log.e(TAG, "Error writing to command socket", ex);
            return true;
        }

+34 −22
Original line number Diff line number Diff line
@@ -64,7 +64,7 @@ public class ZygoteInit {

    private static final String PROPERTY_DISABLE_OPENGL_PRELOADING = "ro.zygote.disable_gl_preload";

    private static final String ANDROID_SOCKET_ENV = "ANDROID_SOCKET_zygote";
    private static final String ANDROID_SOCKET_PREFIX = "ANDROID_SOCKET_";

    private static final int LOG_BOOT_PROGRESS_PRELOAD_START = 3020;
    private static final int LOG_BOOT_PROGRESS_PRELOAD_END = 3030;
@@ -72,8 +72,9 @@ public class ZygoteInit {
    /** when preloading, GC after allocating this many bytes */
    private static final int PRELOAD_GC_THRESHOLD = 50000;

    public static final String USAGE_STRING =
            " <\"start-system-server\"|\"\" for startSystemServer>";
    private static final String ABI_LIST_ARG = "--abi-list=";

    private static final String SOCKET_NAME_ARG = "--socket-name=";

    private static LocalServerSocket sServerSocket;

@@ -150,15 +151,15 @@ public class ZygoteInit {
     *
     * @throws RuntimeException when open fails
     */
    private static void registerZygoteSocket() {
    private static void registerZygoteSocket(String socketName) {
        if (sServerSocket == null) {
            int fileDesc;
            final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
            try {
                String env = System.getenv(ANDROID_SOCKET_ENV);
                String env = System.getenv(fullSocketName);
                fileDesc = Integer.parseInt(env);
            } catch (RuntimeException ex) {
                throw new RuntimeException(
                        ANDROID_SOCKET_ENV + " unset or invalid", ex);
                throw new RuntimeException(fullSocketName + " unset or invalid", ex);
            }

            try {
@@ -175,9 +176,9 @@ public class ZygoteInit {
     * Waits for and accepts a single command connection. Throws
     * RuntimeException on failure.
     */
    private static ZygoteConnection acceptCommandPeer() {
    private static ZygoteConnection acceptCommandPeer(String abiList) {
        try {
            return new ZygoteConnection(sServerSocket.accept());
            return new ZygoteConnection(sServerSocket.accept(), abiList);
        } catch (IOException ex) {
            throw new RuntimeException(
                    "IOException during accept()", ex);
@@ -567,7 +568,26 @@ public class ZygoteInit {
            // Start profiling the zygote initialization.
            SamplingProfilerIntegration.start();

            registerZygoteSocket();
            boolean startSystemServer = false;
            String socketName = "zygote";
            String abiList = null;
            for (int i = 1; i < argv.length; i++) {
                if ("start-system-server".equals(argv[i])) {
                    startSystemServer = true;
                } else if (argv[i].startsWith(ABI_LIST_ARG)) {
                    abiList = argv[i].substring(ABI_LIST_ARG.length());
                } else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
                    socketName = argv[i].substring(SOCKET_NAME_ARG.length());
                } else {
                    throw new RuntimeException("Unknown command line argument: " + argv[i]);
                }
            }

            if (abiList == null) {
                throw new RuntimeException("No ABI list supplied.");
            }

            registerZygoteSocket(socketName);
            EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
                SystemClock.uptimeMillis());
            preload();
@@ -584,20 +604,12 @@ public class ZygoteInit {
            // Zygote.
            Trace.setTracingEnabled(false);

            // If requested, start system server directly from Zygote
            if (argv.length != 2) {
                throw new RuntimeException(argv[0] + USAGE_STRING);
            }

            if (argv[1].equals("start-system-server")) {
            if (startSystemServer) {
                startSystemServer();
            } else if (!argv[1].equals("")) {
                throw new RuntimeException(argv[0] + USAGE_STRING);
            }

            Log.i(TAG, "Accepting command socket connections");

            runSelectLoop();
            runSelectLoop(abiList);

            closeServerSocket();
        } catch (MethodAndArgsCaller caller) {
@@ -617,7 +629,7 @@ public class ZygoteInit {
     * @throws MethodAndArgsCaller in a child process when a main() should
     * be executed.
     */
    private static void runSelectLoop() throws MethodAndArgsCaller {
    private static void runSelectLoop(String abiList) throws MethodAndArgsCaller {
        ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
        ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
        FileDescriptor[] fdArray = new FileDescriptor[4];
@@ -656,7 +668,7 @@ public class ZygoteInit {
            if (index < 0) {
                throw new RuntimeException("Error in select()");
            } else if (index == 0) {
                ZygoteConnection newPeer = acceptCommandPeer();
                ZygoteConnection newPeer = acceptCommandPeer(abiList);
                peers.add(newPeer);
                fds.add(newPeer.getFileDesciptor());
            } else {