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

Commit 6a17f839 authored by Chris Wailes's avatar Chris Wailes
Browse files

Code cleanup in ZygoteProcess.java.

Generic code cleanup.  Changed access scopes, replaced code with utility
functions, and outlined some code.

Test: m
Test: treehugger
Change-Id: I6d9a827abf88dc30eac611642723d69cb75bb351
parent c90040e0
Loading
Loading
Loading
Loading
+65 −92
Original line number Original line Diff line number Diff line
@@ -66,22 +66,14 @@ import java.util.UUID;
 */
 */
public class ZygoteProcess {
public class ZygoteProcess {


    /**
    private static final int ZYGOTE_CONNECT_TIMEOUT_MS = 20000;
     * @hide for internal use only.
     */
    public static final int ZYGOTE_CONNECT_TIMEOUT_MS = 20000;


    /**
    /**
     * @hide for internal use only.
     *
     * Use a relatively short delay, because for app zygote, this is in the critical path of
     * Use a relatively short delay, because for app zygote, this is in the critical path of
     * service launch.
     * service launch.
     */
     */
    public static final int ZYGOTE_CONNECT_RETRY_DELAY_MS = 50;
    private static final int ZYGOTE_CONNECT_RETRY_DELAY_MS = 50;


    /**
     * @hide for internal use only
     */
    private static final String LOG_TAG = "ZygoteProcess";
    private static final String LOG_TAG = "ZygoteProcess";


    /**
    /**
@@ -141,7 +133,7 @@ public class ZygoteProcess {
    /**
    /**
     * State for communicating with the zygote process.
     * State for communicating with the zygote process.
     */
     */
    public static class ZygoteState {
    private static class ZygoteState implements AutoCloseable {
        final LocalSocketAddress mZygoteSocketAddress;
        final LocalSocketAddress mZygoteSocketAddress;
        final LocalSocketAddress mUsapSocketAddress;
        final LocalSocketAddress mUsapSocketAddress;


@@ -178,12 +170,12 @@ public class ZygoteProcess {
         * address
         * address
         * @throws IOException
         * @throws IOException
         */
         */
        public static ZygoteState connect(@NonNull LocalSocketAddress zygoteSocketAddress,
        static ZygoteState connect(@NonNull LocalSocketAddress zygoteSocketAddress,
                @Nullable LocalSocketAddress usapSocketAddress)
                @Nullable LocalSocketAddress usapSocketAddress)
                throws IOException {
                throws IOException {


            DataInputStream zygoteInputStream = null;
            DataInputStream zygoteInputStream;
            BufferedWriter zygoteOutputWriter = null;
            BufferedWriter zygoteOutputWriter;
            final LocalSocket zygoteSessionSocket = new LocalSocket();
            final LocalSocket zygoteSessionSocket = new LocalSocket();


            if (zygoteSocketAddress == null) {
            if (zygoteSocketAddress == null) {
@@ -357,8 +349,6 @@ public class ZygoteProcess {


    /**
    /**
     * Queries the zygote for the list of ABIS it supports.
     * Queries the zygote for the list of ABIS it supports.
     *
     * @throws ZygoteStartFailedEx if the query failed.
     */
     */
    @GuardedBy("mLock")
    @GuardedBy("mLock")
    private static List<String> getAbiList(BufferedWriter writer, DataInputStream inputStream)
    private static List<String> getAbiList(BufferedWriter writer, DataInputStream inputStream)
@@ -411,52 +401,24 @@ public class ZygoteProcess {
         * the child or -1 on failure, followed by boolean to
         * the child or -1 on failure, followed by boolean to
         * indicate whether a wrapper process was used.
         * indicate whether a wrapper process was used.
         */
         */
        String msgStr = Integer.toString(args.size()) + "\n"
        String msgStr = args.size() + "\n" + String.join("\n", args) + "\n";
                        + String.join("\n", args) + "\n";

        // Should there be a timeout on this?
        Process.ProcessStartResult result = new Process.ProcessStartResult();


        // TODO (chriswailes): Move branch body into separate function.
        if (useUsapPool && mUsapPoolEnabled && isValidUsapCommand(args)) {
        if (useUsapPool && mUsapPoolEnabled && isValidUsapCommand(args)) {
            LocalSocket usapSessionSocket = null;

            try {
            try {
                usapSessionSocket = zygoteState.getUsapSessionSocket();
                return attemptUsapSendArgsAndGetResult(zygoteState, msgStr);

                final BufferedWriter usapWriter =
                        new BufferedWriter(
                                new OutputStreamWriter(usapSessionSocket.getOutputStream()),
                                Zygote.SOCKET_BUFFER_SIZE);
                final DataInputStream usapReader =
                        new DataInputStream(usapSessionSocket.getInputStream());

                usapWriter.write(msgStr);
                usapWriter.flush();

                result.pid = usapReader.readInt();
                // USAPs can't be used to spawn processes that need wrappers.
                result.usingWrapper = false;

                if (result.pid < 0) {
                    throw new ZygoteStartFailedEx("USAP specialization failed");
                }

                return result;
            } catch (IOException ex) {
            } catch (IOException ex) {
                // If there was an IOException using the USAP pool we will log the error and
                // If there was an IOException using the USAP pool we will log the error and
                // attempt to start the process through the Zygote.
                // attempt to start the process through the Zygote.
                Log.e(LOG_TAG, "IO Exception while communicating with USAP pool - "
                Log.e(LOG_TAG, "IO Exception while communicating with USAP pool - "
                        + ex.getMessage());
                        + ex.getMessage());
            } finally {
                try {
                    usapSessionSocket.close();
                } catch (IOException ex) {
                    Log.e(LOG_TAG, "Failed to close USAP session socket: " + ex.getMessage());
            }
            }
        }
        }

        return attemptZygoteSendArgsAndGetResult(zygoteState, msgStr);
    }
    }


    private Process.ProcessStartResult attemptZygoteSendArgsAndGetResult(
            ZygoteState zygoteState, String msgStr) throws ZygoteStartFailedEx {
        try {
        try {
            final BufferedWriter zygoteWriter = zygoteState.mZygoteOutputWriter;
            final BufferedWriter zygoteWriter = zygoteState.mZygoteOutputWriter;
            final DataInputStream zygoteInputStream = zygoteState.mZygoteInputStream;
            final DataInputStream zygoteInputStream = zygoteState.mZygoteInputStream;
@@ -467,20 +429,48 @@ public class ZygoteProcess {
            // Always read the entire result from the input stream to avoid leaving
            // Always read the entire result from the input stream to avoid leaving
            // bytes in the stream for future process starts to accidentally stumble
            // bytes in the stream for future process starts to accidentally stumble
            // upon.
            // upon.
            Process.ProcessStartResult result = new Process.ProcessStartResult();
            result.pid = zygoteInputStream.readInt();
            result.pid = zygoteInputStream.readInt();
            result.usingWrapper = zygoteInputStream.readBoolean();
            result.usingWrapper = zygoteInputStream.readBoolean();

            if (result.pid < 0) {
                throw new ZygoteStartFailedEx("fork() failed");
            }

            return result;
        } catch (IOException ex) {
        } catch (IOException ex) {
            zygoteState.close();
            zygoteState.close();
            Log.e(LOG_TAG, "IO Exception while communicating with Zygote - "
            Log.e(LOG_TAG, "IO Exception while communicating with Zygote - "
                    + ex.toString());
                    + ex.toString());
            throw new ZygoteStartFailedEx(ex);
            throw new ZygoteStartFailedEx(ex);
        }
        }

        if (result.pid < 0) {
            throw new ZygoteStartFailedEx("fork() failed");
    }
    }


    private Process.ProcessStartResult attemptUsapSendArgsAndGetResult(
            ZygoteState zygoteState, String msgStr)
            throws ZygoteStartFailedEx, IOException {
        try (LocalSocket usapSessionSocket = zygoteState.getUsapSessionSocket()) {
            final BufferedWriter usapWriter =
                    new BufferedWriter(
                            new OutputStreamWriter(usapSessionSocket.getOutputStream()),
                            Zygote.SOCKET_BUFFER_SIZE);
            final DataInputStream usapReader =
                    new DataInputStream(usapSessionSocket.getInputStream());

            usapWriter.write(msgStr);
            usapWriter.flush();

            Process.ProcessStartResult result = new Process.ProcessStartResult();
            result.pid = usapReader.readInt();
            // USAPs can't be used to spawn processes that need wrappers.
            result.usingWrapper = false;

            if (result.pid >= 0) {
                return result;
                return result;
            } else {
                throw new ZygoteStartFailedEx("USAP specialization failed");
            }
        }
    }
    }


    /**
    /**
@@ -557,7 +547,7 @@ public class ZygoteProcess {
                                                      boolean useUnspecializedAppProcessPool,
                                                      boolean useUnspecializedAppProcessPool,
                                                      @Nullable String[] extraArgs)
                                                      @Nullable String[] extraArgs)
                                                      throws ZygoteStartFailedEx {
                                                      throws ZygoteStartFailedEx {
        ArrayList<String> argsForZygote = new ArrayList<String>();
        ArrayList<String> argsForZygote = new ArrayList<>();


        // --runtime-args, --setuid=, --setgid=,
        // --runtime-args, --setuid=, --setgid=,
        // and --setgroups= must go first
        // and --setgroups= must go first
@@ -627,17 +617,7 @@ public class ZygoteProcess {
        }
        }


        if (packagesForUid != null && packagesForUid.length > 0) {
        if (packagesForUid != null && packagesForUid.length > 0) {
            final StringBuilder sb = new StringBuilder();
            argsForZygote.add("--packages-for-uid=" + String.join(",", packagesForUid));
            sb.append("--packages-for-uid=");

            // TODO (chriswailes): Replace with String.join
            for (int i = 0; i < packagesForUid.length; ++i) {
                if (i != 0) {
                    sb.append(',');
                }
                sb.append(packagesForUid[i]);
            }
            argsForZygote.add(sb.toString());
        }
        }


        if (sandboxId != null) {
        if (sandboxId != null) {
@@ -647,9 +627,7 @@ public class ZygoteProcess {
        argsForZygote.add(processClass);
        argsForZygote.add(processClass);


        if (extraArgs != null) {
        if (extraArgs != null) {
            for (String arg : extraArgs) {
            Collections.addAll(argsForZygote, extraArgs);
                argsForZygote.add(arg);
            }
        }
        }


        synchronized(mLock) {
        synchronized(mLock) {
@@ -805,10 +783,10 @@ public class ZygoteProcess {
        if (state == null || state.isClosed()) {
        if (state == null || state.isClosed()) {
            Slog.e(LOG_TAG, "Can't set API blacklist exemptions: no zygote connection");
            Slog.e(LOG_TAG, "Can't set API blacklist exemptions: no zygote connection");
            return false;
            return false;
        }
        } else if (!sendIfEmpty && mApiBlacklistExemptions.isEmpty()) {
        if (!sendIfEmpty && mApiBlacklistExemptions.isEmpty()) {
            return true;
            return true;
        }
        }

        try {
        try {
            state.mZygoteOutputWriter.write(Integer.toString(mApiBlacklistExemptions.size() + 1));
            state.mZygoteOutputWriter.write(Integer.toString(mApiBlacklistExemptions.size() + 1));
            state.mZygoteOutputWriter.newLine();
            state.mZygoteOutputWriter.newLine();
@@ -832,17 +810,15 @@ public class ZygoteProcess {
    }
    }


    private void maybeSetHiddenApiAccessLogSampleRate(ZygoteState state) {
    private void maybeSetHiddenApiAccessLogSampleRate(ZygoteState state) {
        if (state == null || state.isClosed()) {
        if (state == null || state.isClosed() || mHiddenApiAccessLogSampleRate == -1) {
            return;
        }
        if (mHiddenApiAccessLogSampleRate == -1) {
            return;
            return;
        }
        }

        try {
        try {
            state.mZygoteOutputWriter.write(Integer.toString(1));
            state.mZygoteOutputWriter.write(Integer.toString(1));
            state.mZygoteOutputWriter.newLine();
            state.mZygoteOutputWriter.newLine();
            state.mZygoteOutputWriter.write("--hidden-api-log-sampling-rate="
            state.mZygoteOutputWriter.write("--hidden-api-log-sampling-rate="
                    + Integer.toString(mHiddenApiAccessLogSampleRate));
                    + mHiddenApiAccessLogSampleRate);
            state.mZygoteOutputWriter.newLine();
            state.mZygoteOutputWriter.newLine();
            state.mZygoteOutputWriter.flush();
            state.mZygoteOutputWriter.flush();
            int status = state.mZygoteInputStream.readInt();
            int status = state.mZygoteInputStream.readInt();
@@ -855,17 +831,15 @@ public class ZygoteProcess {
    }
    }


    private void maybeSetHiddenApiAccessStatslogSampleRate(ZygoteState state) {
    private void maybeSetHiddenApiAccessStatslogSampleRate(ZygoteState state) {
        if (state == null || state.isClosed()) {
        if (state == null || state.isClosed() || mHiddenApiAccessStatslogSampleRate == -1) {
            return;
        }
        if (mHiddenApiAccessStatslogSampleRate == -1) {
            return;
            return;
        }
        }

        try {
        try {
            state.mZygoteOutputWriter.write(Integer.toString(1));
            state.mZygoteOutputWriter.write(Integer.toString(1));
            state.mZygoteOutputWriter.newLine();
            state.mZygoteOutputWriter.newLine();
            state.mZygoteOutputWriter.write("--hidden-api-statslog-sampling-rate="
            state.mZygoteOutputWriter.write("--hidden-api-statslog-sampling-rate="
                    + Integer.toString(mHiddenApiAccessStatslogSampleRate));
                    + mHiddenApiAccessStatslogSampleRate);
            state.mZygoteOutputWriter.newLine();
            state.mZygoteOutputWriter.newLine();
            state.mZygoteOutputWriter.flush();
            state.mZygoteOutputWriter.flush();
            int status = state.mZygoteInputStream.readInt();
            int status = state.mZygoteInputStream.readInt();
@@ -942,8 +916,8 @@ public class ZygoteProcess {
     * Only the app zygote supports this function.
     * Only the app zygote supports this function.
     * TODO preloadPackageForAbi() can probably be removed and the callers an use this instead.
     * TODO preloadPackageForAbi() can probably be removed and the callers an use this instead.
     */
     */
    public boolean preloadApp(ApplicationInfo appInfo, String abi) throws ZygoteStartFailedEx,
    public boolean preloadApp(ApplicationInfo appInfo, String abi)
                                                                          IOException {
            throws ZygoteStartFailedEx, IOException {
        synchronized (mLock) {
        synchronized (mLock) {
            ZygoteState state = openZygoteSocketIfNeeded(abi);
            ZygoteState state = openZygoteSocketIfNeeded(abi);
            state.mZygoteOutputWriter.write("2");
            state.mZygoteOutputWriter.write("2");
@@ -971,9 +945,9 @@ public class ZygoteProcess {
     * Instructs the zygote to pre-load the classes and native libraries at the given paths
     * Instructs the zygote to pre-load the classes and native libraries at the given paths
     * for the specified abi. Not all zygotes support this function.
     * for the specified abi. Not all zygotes support this function.
     */
     */
    public boolean preloadPackageForAbi(String packagePath, String libsPath, String libFileName,
    public boolean preloadPackageForAbi(
                                        String cacheKey, String abi) throws ZygoteStartFailedEx,
            String packagePath, String libsPath, String libFileName, String cacheKey, String abi)
                                                                            IOException {
            throws ZygoteStartFailedEx, IOException {
        synchronized (mLock) {
        synchronized (mLock) {
            ZygoteState state = openZygoteSocketIfNeeded(abi);
            ZygoteState state = openZygoteSocketIfNeeded(abi);
            state.mZygoteOutputWriter.write("5");
            state.mZygoteOutputWriter.write("5");
@@ -1049,8 +1023,7 @@ public class ZygoteProcess {


            try {
            try {
                Thread.sleep(ZYGOTE_CONNECT_RETRY_DELAY_MS);
                Thread.sleep(ZYGOTE_CONNECT_RETRY_DELAY_MS);
            } catch (InterruptedException ie) {
            } catch (InterruptedException ignored) { }
            }
        }
        }
        Slog.wtf(LOG_TAG, "Failed to connect to Zygote through socket "
        Slog.wtf(LOG_TAG, "Failed to connect to Zygote through socket "
                + zygoteSocketAddress.getName());
                + zygoteSocketAddress.getName());