19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2007 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage com.android.internal.os;
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.net.Credentials;
209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.net.LocalSocket;
219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Process;
225b1ada2562c17921adf6a62ea62bcb445160983cJeff Sharkeyimport android.os.SELinux;
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.SystemProperties;
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Log;
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport dalvik.system.PathClassLoader;
279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport dalvik.system.Zygote;
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.BufferedReader;
30ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brownimport java.io.DataInputStream;
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.DataOutputStream;
329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.FileDescriptor;
33ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brownimport java.io.FileInputStream;
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.FileOutputStream;
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.IOException;
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.InputStreamReader;
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.PrintStream;
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.ArrayList;
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
40ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brownimport libcore.io.ErrnoException;
41ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brownimport libcore.io.IoUtils;
42ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brownimport libcore.io.Libcore;
43ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * A connection that can make spawn requests.
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectclass ZygoteConnection {
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String TAG = "Zygote";
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** a prototype instance for a future List.toArray() */
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int[][] intArray2d = new int[0][0];
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * {@link android.net.LocalSocket#setSoTimeout} value for connections.
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Effectively, the amount of time a requestor has between the start of
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * the request and the completed request. The select-loop mode Zygote
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * doesn't have the logic to return to the select loop in the middle of
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * a request, so we need to time out here to avoid being denial-of-serviced.
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int CONNECTION_TIMEOUT_MILLIS = 1000;
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** max number of arguments that a connection can specify */
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int MAX_ZYGOTE_ARGC=1024;
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * The command socket.
679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * mSocket is retained in the child process in "peer wait" mode, so
699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * that it closes when the child process terminates. In other cases,
709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * it is closed in the peer.
719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final LocalSocket mSocket;
739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final DataOutputStream mSocketOutStream;
749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final BufferedReader mSocketReader;
759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final Credentials peer;
7683d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley    private final String peerSecurityContext;
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * A long-lived reference to the original command socket used to launch
809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * this peer. If "peer wait" mode is specified, the process that requested
819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * the new VM instance intends to track the lifetime of the spawned instance
829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * via the command socket. In this case, the command socket is closed
839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * in the Zygote and placed here in the spawned instance so that it will
849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * not be collected and finalized. This field remains null at all times
859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * in the original Zygote process, and in all spawned processes where
869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * "peer-wait" mode was not requested.
879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static LocalSocket sPeerWaitSocket = null;
899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Constructs instance from connected socket.
929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param socket non-null; connected socket
949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @throws IOException
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ZygoteConnection(LocalSocket socket) throws IOException {
979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mSocket = socket;
989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mSocketOutStream
1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                = new DataOutputStream(socket.getOutputStream());
1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mSocketReader = new BufferedReader(
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                new InputStreamReader(socket.getInputStream()), 256);
1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mSocket.setSoTimeout(CONNECTION_TIMEOUT_MILLIS);
1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            peer = mSocket.getPeerCredentials();
1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (IOException ex) {
1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Log.e(TAG, "Cannot read peer credentials", ex);
1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw ex;
1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11383d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley
11483d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley        peerSecurityContext = SELinux.getPeerContext(mSocket.getFileDescriptor());
1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Returns the file descriptor of the associated socket.
1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return null-ok; file descriptor
1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    FileDescriptor getFileDesciptor() {
1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mSocket.getFileDescriptor();
1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Reads start commands from an open command socket.
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Start commands are presently a pair of newline-delimited lines
1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * indicating a) class to invoke main() on b) nice name to set argv[0] to.
1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Continues to read commands and forkAndSpecialize children until
1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * the socket is closed. This method is used in ZYGOTE_FORK_MODE
1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @throws ZygoteInit.MethodAndArgsCaller trampoline to invoke main()
1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * method in child process
1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    void run() throws ZygoteInit.MethodAndArgsCaller {
1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int loopCount = ZygoteInit.GC_LOOP_COUNT;
1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        while (true) {
1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            /*
1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             * Call gc() before we block in readArgumentList().
1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             * It's work that has to be done anyway, and it's better
1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             * to avoid making every child do it.  It will also
1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             * madvise() any free memory as a side-effect.
1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             *
1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             * Don't call it every time, because walking the entire
1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             * heap is a lot of overhead to free a few hundred bytes.
1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             */
1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (loopCount <= 0) {
1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                ZygoteInit.gc();
1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                loopCount = ZygoteInit.GC_LOOP_COUNT;
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                loopCount--;
1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (runOnce()) {
1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Reads one start command from the command socket. If successful,
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * a child is forked and a {@link ZygoteInit.MethodAndArgsCaller}
1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * exception is thrown in that child while in the parent process,
1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * the method returns normally. On failure, the child is not
1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * spawned and messages are printed to the log and stderr. Returns
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * a boolean status value indicating whether an end-of-file on the command
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * socket has been encountered.
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return false if command socket should continue to be read from, or
1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * true if an end-of-file has been encountered.
1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @throws ZygoteInit.MethodAndArgsCaller trampoline to invoke main()
1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * method in child process
1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {
1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        String args[];
1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Arguments parsedArgs = null;
1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        FileDescriptor[] descriptors;
1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            args = readArgumentList();
1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            descriptors = mSocket.getAncillaryFileDescriptors();
1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (IOException ex) {
1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Log.w(TAG, "IOException on command socket " + ex.getMessage());
1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            closeSocket();
1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return true;
1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (args == null) {
1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // EOF reached.
1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            closeSocket();
1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return true;
1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /** the stderr of the most recent request, if avail */
1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        PrintStream newStderr = null;
2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (descriptors != null && descriptors.length >= 3) {
2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            newStderr = new PrintStream(
2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    new FileOutputStream(descriptors[2]));
2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
206ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown        int pid = -1;
207ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown        FileDescriptor childPipeFd = null;
208ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown        FileDescriptor serverPipeFd = null;
2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            parsedArgs = new Arguments(args);
2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
21383d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley            applyUidSecurityPolicy(parsedArgs, peer, peerSecurityContext);
21483d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley            applyRlimitSecurityPolicy(parsedArgs, peer, peerSecurityContext);
21583d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley            applyCapabilitiesSecurityPolicy(parsedArgs, peer, peerSecurityContext);
21683d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley            applyInvokeWithSecurityPolicy(parsedArgs, peer, peerSecurityContext);
21783d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley            applyseInfoSecurityPolicy(parsedArgs, peer, peerSecurityContext);
218ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown
219ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown            applyDebuggerSystemProperty(parsedArgs);
220ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown            applyInvokeWithSystemProperty(parsedArgs);
2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int[][] rlimits = null;
2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (parsedArgs.rlimits != null) {
2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                rlimits = parsedArgs.rlimits.toArray(intArray2d);
2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
228ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown            if (parsedArgs.runtimeInit && parsedArgs.invokeWith != null) {
229ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown                FileDescriptor[] pipeFds = Libcore.os.pipe();
230ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown                childPipeFd = pipeFds[1];
231ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown                serverPipeFd = pipeFds[0];
232ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown                ZygoteInit.setCloseOnExec(serverPipeFd, true);
233ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown            }
234ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown
2355b1ada2562c17921adf6a62ea62bcb445160983cJeff Sharkey            pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
2365b1ada2562c17921adf6a62ea62bcb445160983cJeff Sharkey                    parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
2375b1ada2562c17921adf6a62ea62bcb445160983cJeff Sharkey                    parsedArgs.niceName);
238ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown        } catch (IOException ex) {
239ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown            logAndPrintError(newStderr, "Exception creating pipe", ex);
240ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown        } catch (ErrnoException ex) {
241ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown            logAndPrintError(newStderr, "Exception creating pipe", ex);
2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (IllegalArgumentException ex) {
243ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown            logAndPrintError(newStderr, "Invalid zygote arguments", ex);
2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (ZygoteSecurityException ex) {
2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            logAndPrintError(newStderr,
2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    "Zygote security policy prevents request: ", ex);
2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
249ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown        try {
250ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown            if (pid == 0) {
251ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown                // in child
252ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown                IoUtils.closeQuietly(serverPipeFd);
253ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown                serverPipeFd = null;
254ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown                handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);
255ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown
256ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown                // should never get here, the child is expected to either
257ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown                // throw ZygoteInit.MethodAndArgsCaller or exec().
258ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown                return true;
259ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown            } else {
260ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown                // in parent...pid of < 0 means failure
261ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown                IoUtils.closeQuietly(childPipeFd);
262ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown                childPipeFd = null;
263ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown                return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs);
264ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown            }
265ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown        } finally {
266ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown            IoUtils.closeQuietly(childPipeFd);
267ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown            IoUtils.closeQuietly(serverPipeFd);
2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Closes socket associated with this connection.
2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    void closeSocket() {
2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mSocket.close();
2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (IOException ex) {
2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Log.e(TAG, "Exception while closing command "
2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    + "socket in parent", ex);
2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
284ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown     * Handles argument parsing for args related to the zygote spawner.
285ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown     *
2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Current recognized args:
2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <ul>
2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *   <li> --setuid=<i>uid of child process, defaults to 0</i>
2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *   <li> --setgid=<i>gid of child process, defaults to 0</i>
2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *   <li> --setgroups=<i>comma-separated list of supplimentary gid's</i>
2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *   <li> --capabilities=<i>a pair of comma-separated integer strings
2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * indicating Linux capabilities(2) set for child. The first string
2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * represents the <code>permitted</code> set, and the second the
2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <code>effective</code> set. Precede each with 0 or
2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * 0x for octal or hexidecimal value. If unspecified, both default to 0.
2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * This parameter is only applied if the uid of the new process will
2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * be non-0. </i>
2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *   <li> --rlimit=r,c,m<i>tuple of values for setrlimit() call.
2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *    <code>r</code> is the resource, <code>c</code> and <code>m</code>
3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *    are the settings for current and max value.</i>
3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *   <li> --peer-wait indicates that the command socket should
3029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * be inherited by (and set to close-on-exec in) the spawned process
3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * and used to track the lifetime of that process. The spawning process
3049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * then exits. Without this flag, it is retained by the spawning process
3059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * (and closed in the child) in expectation of a new spawn request.
3069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *   <li> --classpath=<i>colon-separated classpath</i> indicates
3079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * that the specified class (which must b first non-flag argument) should
3089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * be loaded from jar files in the specified classpath. Incompatible with
3099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * --runtime-init
3109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *   <li> --runtime-init indicates that the remaining arg list should
3119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * be handed off to com.android.internal.os.RuntimeInit, rather than
3129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * processed directly
3139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Android runtime startup (eg, Binder initialization) is also eschewed.
314ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown     *   <li> --nice-name=<i>nice name to appear in ps</i>
3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *   <li> If <code>--runtime-init</code> is present:
3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *      [--] &lt;args for RuntimeInit &gt;
3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *   <li> If <code>--runtime-init</code> is absent:
3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *      [--] &lt;classname&gt; [args...]
3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * </ul>
3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static class Arguments {
3229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /** from --setuid */
3239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int uid = 0;
3249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean uidSpecified;
3259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /** from --setgid */
3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int gid = 0;
3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean gidSpecified;
3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /** from --setgroups */
3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int[] gids;
3329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /** from --peer-wait */
3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean peerWait;
3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
33623085b781e145ed684e7270af1d5ced6800b8effBen Cheng        /**
337ae07ecf3766c38af1c12822458b98036b28bd4c0Elliott Hughes         * From --enable-debugger, --enable-checkjni, --enable-assert,
338ae07ecf3766c38af1c12822458b98036b28bd4c0Elliott Hughes         * --enable-safemode, and --enable-jni-logging.
33923085b781e145ed684e7270af1d5ced6800b8effBen Cheng         */
3409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int debugFlags;
3419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3425b1ada2562c17921adf6a62ea62bcb445160983cJeff Sharkey        /** From --mount-external */
3435b1ada2562c17921adf6a62ea62bcb445160983cJeff Sharkey        int mountExternal = Zygote.MOUNT_EXTERNAL_NONE;
3445b1ada2562c17921adf6a62ea62bcb445160983cJeff Sharkey
345e1dfcb7ab01fb991079ec1f70f75281a0ca9073eElliott Hughes        /** from --target-sdk-version. */
346e1dfcb7ab01fb991079ec1f70f75281a0ca9073eElliott Hughes        int targetSdkVersion;
347e1dfcb7ab01fb991079ec1f70f75281a0ca9073eElliott Hughes        boolean targetSdkVersionSpecified;
348e1dfcb7ab01fb991079ec1f70f75281a0ca9073eElliott Hughes
3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /** from --classpath */
3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        String classpath;
3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /** from --runtime-init */
3539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean runtimeInit;
3549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
355ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown        /** from --nice-name */
356ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown        String niceName;
357ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown
3589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /** from --capabilities */
3599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean capabilitiesSpecified;
3609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        long permittedCapabilities;
3619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        long effectiveCapabilities;
3629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
36383d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley        /** from --seinfo */
36483d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley        boolean seInfoSpecified;
36583d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley        String seInfo;
36683d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley
3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /** from all --rlimit=r,c,m */
3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ArrayList<int[]> rlimits;
3699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
370ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown        /** from --invoke-with */
371ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown        String invokeWith;
372ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown
3739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
3749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Any args after and including the first non-option arg
3759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * (or after a '--')
3769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
3779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        String remainingArgs[];
3789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
3809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Constructs instance and parses args
3819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @param args zygote command-line args
3829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @throws IllegalArgumentException
3839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
3849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Arguments(String args[]) throws IllegalArgumentException {
3859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            parseArgs(args);
3869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
3899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Parses the commandline arguments intended for the Zygote spawner
3909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * (such as "--setuid=" and "--setgid=") and creates an array
3919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * containing the remaining args.
3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *
3939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Per security review bug #1112214, duplicate args are disallowed in
3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * critical cases to make injection harder.
3959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
3969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private void parseArgs(String args[])
3979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                throws IllegalArgumentException {
3989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int curArg = 0;
3999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for ( /* curArg */ ; curArg < args.length; curArg++) {
4019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                String arg = args[curArg];
4029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (arg.equals("--")) {
4049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    curArg++;
4059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
4069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else if (arg.startsWith("--setuid=")) {
4079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (uidSpecified) {
4089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        throw new IllegalArgumentException(
4099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                "Duplicate arg specified");
4109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
4119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    uidSpecified = true;
4129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    uid = Integer.parseInt(
4139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            arg.substring(arg.indexOf('=') + 1));
4149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else if (arg.startsWith("--setgid=")) {
4159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (gidSpecified) {
4169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        throw new IllegalArgumentException(
4179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                "Duplicate arg specified");
4189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
4199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    gidSpecified = true;
4209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    gid = Integer.parseInt(
4219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            arg.substring(arg.indexOf('=') + 1));
422e1dfcb7ab01fb991079ec1f70f75281a0ca9073eElliott Hughes                } else if (arg.startsWith("--target-sdk-version=")) {
423e1dfcb7ab01fb991079ec1f70f75281a0ca9073eElliott Hughes                    if (targetSdkVersionSpecified) {
424e1dfcb7ab01fb991079ec1f70f75281a0ca9073eElliott Hughes                        throw new IllegalArgumentException(
425e1dfcb7ab01fb991079ec1f70f75281a0ca9073eElliott Hughes                                "Duplicate target-sdk-version specified");
426e1dfcb7ab01fb991079ec1f70f75281a0ca9073eElliott Hughes                    }
427e1dfcb7ab01fb991079ec1f70f75281a0ca9073eElliott Hughes                    targetSdkVersionSpecified = true;
428e1dfcb7ab01fb991079ec1f70f75281a0ca9073eElliott Hughes                    targetSdkVersion = Integer.parseInt(
429e1dfcb7ab01fb991079ec1f70f75281a0ca9073eElliott Hughes                            arg.substring(arg.indexOf('=') + 1));
4309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else if (arg.equals("--enable-debugger")) {
4319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
43223085b781e145ed684e7270af1d5ced6800b8effBen Cheng                } else if (arg.equals("--enable-safemode")) {
43323085b781e145ed684e7270af1d5ced6800b8effBen Cheng                    debugFlags |= Zygote.DEBUG_ENABLE_SAFEMODE;
4349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else if (arg.equals("--enable-checkjni")) {
4359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
436ae07ecf3766c38af1c12822458b98036b28bd4c0Elliott Hughes                } else if (arg.equals("--enable-jni-logging")) {
437ae07ecf3766c38af1c12822458b98036b28bd4c0Elliott Hughes                    debugFlags |= Zygote.DEBUG_ENABLE_JNI_LOGGING;
4389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else if (arg.equals("--enable-assert")) {
4399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;
4409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else if (arg.equals("--peer-wait")) {
4419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    peerWait = true;
4429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else if (arg.equals("--runtime-init")) {
4439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    runtimeInit = true;
44483d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley                } else if (arg.startsWith("--seinfo=")) {
44583d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley                    if (seInfoSpecified) {
44683d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley                        throw new IllegalArgumentException(
44783d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley                                "Duplicate arg specified");
44883d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley                    }
44983d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley                    seInfoSpecified = true;
45083d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley                    seInfo = arg.substring(arg.indexOf('=') + 1);
4519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else if (arg.startsWith("--capabilities=")) {
4529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (capabilitiesSpecified) {
4539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        throw new IllegalArgumentException(
4549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                "Duplicate arg specified");
4559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
4569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    capabilitiesSpecified = true;
4579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    String capString = arg.substring(arg.indexOf('=')+1);
4589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    String[] capStrings = capString.split(",", 2);
4609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (capStrings.length == 1) {
4629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        effectiveCapabilities = Long.decode(capStrings[0]);
4639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        permittedCapabilities = effectiveCapabilities;
4649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    } else {
4659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        permittedCapabilities = Long.decode(capStrings[0]);
4669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        effectiveCapabilities = Long.decode(capStrings[1]);
4679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
4689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else if (arg.startsWith("--rlimit=")) {
4699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // Duplicate --rlimit arguments are specifically allowed.
4709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    String[] limitStrings
4719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            = arg.substring(arg.indexOf('=')+1).split(",");
4729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (limitStrings.length != 3) {
4749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        throw new IllegalArgumentException(
4759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                "--rlimit= should have 3 comma-delimited ints");
4769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
4779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    int[] rlimitTuple = new int[limitStrings.length];
4789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    for(int i=0; i < limitStrings.length; i++) {
4809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        rlimitTuple[i] = Integer.parseInt(limitStrings[i]);
4819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
4829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (rlimits == null) {
4849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        rlimits = new ArrayList();
4859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
4869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    rlimits.add(rlimitTuple);
4889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else if (arg.equals("-classpath")) {
4899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (classpath != null) {
4909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        throw new IllegalArgumentException(
4919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                "Duplicate arg specified");
4929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
4939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    try {
4949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        classpath = args[++curArg];
4959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    } catch (IndexOutOfBoundsException ex) {
4969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        throw new IllegalArgumentException(
4979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                "-classpath requires argument");
4989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
4999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else if (arg.startsWith("--setgroups=")) {
5009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (gids != null) {
5019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        throw new IllegalArgumentException(
5029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                "Duplicate arg specified");
5039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
5049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    String[] params
5069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            = arg.substring(arg.indexOf('=') + 1).split(",");
5079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    gids = new int[params.length];
5099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    for (int i = params.length - 1; i >= 0 ; i--) {
5119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        gids[i] = Integer.parseInt(params[i]);
5129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
513ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown                } else if (arg.equals("--invoke-with")) {
514ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown                    if (invokeWith != null) {
515ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown                        throw new IllegalArgumentException(
516ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown                                "Duplicate arg specified");
517ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown                    }
518ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown                    try {
519ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown                        invokeWith = args[++curArg];
520ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown                    } catch (IndexOutOfBoundsException ex) {
521ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown                        throw new IllegalArgumentException(
522ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown                                "--invoke-with requires argument");
523ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown                    }
524ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown                } else if (arg.startsWith("--nice-name=")) {
525ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown                    if (niceName != null) {
526ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown                        throw new IllegalArgumentException(
527ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown                                "Duplicate arg specified");
528ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown                    }
529ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown                    niceName = arg.substring(arg.indexOf('=') + 1);
5305b1ada2562c17921adf6a62ea62bcb445160983cJeff Sharkey                } else if (arg.equals("--mount-external-multiuser")) {
5315b1ada2562c17921adf6a62ea62bcb445160983cJeff Sharkey                    mountExternal = Zygote.MOUNT_EXTERNAL_MULTIUSER;
532e217ee4d7a8223289a1af7363627c69956c46d41Jeff Sharkey                } else if (arg.equals("--mount-external-multiuser-all")) {
533e217ee4d7a8223289a1af7363627c69956c46d41Jeff Sharkey                    mountExternal = Zygote.MOUNT_EXTERNAL_MULTIUSER_ALL;
5349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else {
5359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
5369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
5379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (runtimeInit && classpath != null) {
5409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                throw new IllegalArgumentException(
5419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        "--runtime-init and -classpath are incompatible");
5429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            remainingArgs = new String[args.length - curArg];
5459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            System.arraycopy(args, curArg, remainingArgs, 0,
5479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    remainingArgs.length);
5489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
5529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Reads an argument list from the command socket/
5539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return Argument list or null if EOF is reached
5549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @throws IOException passed straight through
5559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
5569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private String[] readArgumentList()
5579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throws IOException {
5589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
5609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * See android.os.Process.zygoteSendArgsAndGetPid()
5619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Presently the wire format to the zygote process is:
5629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * a) a count of arguments (argc, in essence)
5639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * b) a number of newline-separated argument strings equal to count
5649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *
5659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * After the zygote process reads these it will write the pid of
5669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * the child or -1 on failure.
5679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
5689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int argc;
5709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
5729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            String s = mSocketReader.readLine();
5739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (s == null) {
5759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // EOF reached.
5769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return null;
5779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            argc = Integer.parseInt(s);
5799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (NumberFormatException ex) {
5809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Log.e(TAG, "invalid Zygote wire format: non-int at argc");
5819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new IOException("invalid wire format");
5829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // See bug 1092107: large argc can be used for a DOS attack
5859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (argc > MAX_ZYGOTE_ARGC) {
5869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new IOException("max arg count exceeded");
5879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        String[] result = new String[argc];
5909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < argc; i++) {
5919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            result[i] = mSocketReader.readLine();
5929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (result[i] == null) {
5939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // We got an unexpected EOF.
5949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                throw new IOException("truncated request");
5959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return result;
5999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
6029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Applies zygote security policy per bugs #875058 and #1082165.
6039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Based on the credentials of the process issuing a zygote command:
6049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <ol>
6059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <li> uid 0 (root) may specify any uid, gid, and setgroups() list
6069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <li> uid 1000 (Process.SYSTEM_UID) may specify any uid &gt; 1000 in normal
6079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * operation. It may also specify any gid and setgroups() list it chooses.
6089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * In factory test mode, it may specify any UID.
6099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <li> Any other uid may not specify any uid, gid, or setgroups list. The
6109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * uid and gid will be inherited from the requesting process.
6119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * </ul>
6129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
6139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param args non-null; zygote spawner arguments
6149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param peer non-null; peer credentials
6159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @throws ZygoteSecurityException
6169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
61783d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley    private static void applyUidSecurityPolicy(Arguments args, Credentials peer,
61883d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley            String peerSecurityContext)
6199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throws ZygoteSecurityException {
6209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int peerUid = peer.getUid();
6229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (peerUid == 0) {
6249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Root can do what it wants
6259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (peerUid == Process.SYSTEM_UID ) {
6269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // System UID is restricted, except in factory test mode
6279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            String factoryTest = SystemProperties.get("ro.factorytest");
6289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            boolean uidRestricted;
6299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            /* In normal operation, SYSTEM_UID can only specify a restricted
6319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             * set of UIDs. In factory test mode, SYSTEM_UID may specify any uid.
6329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             */
6339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            uidRestricted
6349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                 = !(factoryTest.equals("1") || factoryTest.equals("2"));
6359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (uidRestricted
6379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    && args.uidSpecified && (args.uid < Process.SYSTEM_UID)) {
6389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                throw new ZygoteSecurityException(
6399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        "System UID may not launch process with UID < "
6409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                + Process.SYSTEM_UID);
6419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
6439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Everything else
6449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (args.uidSpecified || args.gidSpecified
6459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                || args.gids != null) {
6469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                throw new ZygoteSecurityException(
6479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        "App UIDs may not specify uid's or gid's");
6489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
65183d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley        if (args.uidSpecified || args.gidSpecified || args.gids != null) {
65283d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley            boolean allowed = SELinux.checkSELinuxAccess(peerSecurityContext,
65383d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley                                                         peerSecurityContext,
65483d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley                                                         "zygote",
65583d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley                                                         "specifyids");
65683d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley            if (!allowed) {
65783d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley                throw new ZygoteSecurityException(
65883d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley                        "Peer may not specify uid's or gid's");
65983d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley            }
66083d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley        }
66183d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley
6629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // If not otherwise specified, uid and gid are inherited from peer
6639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!args.uidSpecified) {
6649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            args.uid = peer.getUid();
6659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            args.uidSpecified = true;
6669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!args.gidSpecified) {
6689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            args.gid = peer.getGid();
6699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            args.gidSpecified = true;
6709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
675ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown     * Applies debugger system properties to the zygote arguments.
676ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown     *
6779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * If "ro.debuggable" is "1", all apps are debuggable. Otherwise,
6789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * the debugger state is specified via the "--enable-debugger" flag
6799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * in the spawn request.
6809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
6819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param args non-null; zygote spawner args
6829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
683ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown    public static void applyDebuggerSystemProperty(Arguments args) {
6849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if ("1".equals(SystemProperties.get("ro.debuggable"))) {
6859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            args.debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
6869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
6909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Applies zygote security policy per bug #1042973. Based on the credentials
6919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * of the process issuing a zygote command:
6929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <ol>
6939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <li> peers of  uid 0 (root) and uid 1000 (Process.SYSTEM_UID)
6949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * may specify any rlimits.
6959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <li> All other uids may not specify rlimits.
6969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * </ul>
6979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param args non-null; zygote spawner arguments
6989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param peer non-null; peer credentials
6999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @throws ZygoteSecurityException
7009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
7019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static void applyRlimitSecurityPolicy(
70283d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley            Arguments args, Credentials peer, String peerSecurityContext)
7039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throws ZygoteSecurityException {
7049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int peerUid = peer.getUid();
7069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!(peerUid == 0 || peerUid == Process.SYSTEM_UID)) {
7089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // All peers with UID other than root or SYSTEM_UID
7099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (args.rlimits != null) {
7109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                throw new ZygoteSecurityException(
7119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        "This UID may not specify rlimits.");
7129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
71483d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley
71583d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley        if (args.rlimits != null) {
71683d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley            boolean allowed = SELinux.checkSELinuxAccess(peerSecurityContext,
71783d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley                                                         peerSecurityContext,
71883d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley                                                         "zygote",
71983d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley                                                         "specifyrlimits");
72083d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley            if (!allowed) {
72183d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley                throw new ZygoteSecurityException(
72283d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley                        "Peer may not specify rlimits");
72383d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley            }
72483d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley         }
7259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
7289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Applies zygote security policy per bug #1042973. A root peer may
7299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * spawn an instance with any capabilities. All other uids may spawn
7309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * instances with any of the capabilities in the peer's permitted set
7319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * but no more.
7329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
7339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param args non-null; zygote spawner arguments
7349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param peer non-null; peer credentials
7359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @throws ZygoteSecurityException
7369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
7379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static void applyCapabilitiesSecurityPolicy(
73883d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley            Arguments args, Credentials peer, String peerSecurityContext)
7399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throws ZygoteSecurityException {
7409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (args.permittedCapabilities == 0
7429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                && args.effectiveCapabilities == 0) {
7439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // nothing to check
7449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
7459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
74783d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley        boolean allowed = SELinux.checkSELinuxAccess(peerSecurityContext,
74883d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley                                                     peerSecurityContext,
74983d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley                                                     "zygote",
75083d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley                                                     "specifycapabilities");
75183d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley        if (!allowed) {
75283d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley            throw new ZygoteSecurityException(
75383d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley                    "Peer may not specify capabilities");
75483d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley        }
75583d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley
7569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (peer.getUid() == 0) {
7579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // root may specify anything
7589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
7599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        long permittedCaps;
7629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
7649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            permittedCaps = ZygoteInit.capgetPermitted(peer.getPid());
7659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (IOException ex) {
7669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new ZygoteSecurityException(
7679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    "Error retrieving peer's capabilities.");
7689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /*
7719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Ensure that the client did not specify an effective set larger
7729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * than the permitted set. The kernel will enforce this too, but we
7739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * do it here to make the following check easier.
7749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
7759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (((~args.permittedCapabilities) & args.effectiveCapabilities) != 0) {
7769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new ZygoteSecurityException(
7779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    "Effective capabilities cannot be superset of "
7789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            + " permitted capabilities" );
7799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /*
7829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Ensure that the new permitted (and thus the new effective) set is
7839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * a subset of the peer process's permitted set
7849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
7859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (((~permittedCaps) & args.permittedCapabilities) != 0) {
7879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new ZygoteSecurityException(
7889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    "Peer specified unpermitted capabilities" );
7899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
793ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown     * Applies zygote security policy.
794ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown     * Based on the credentials of the process issuing a zygote command:
795ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown     * <ol>
796ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown     * <li> uid 0 (root) may specify --invoke-with to launch Zygote with a
797ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown     * wrapper command.
798ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown     * <li> Any other uid may not specify any invoke-with argument.
799ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown     * </ul>
800ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown     *
801ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown     * @param args non-null; zygote spawner arguments
802ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown     * @param peer non-null; peer credentials
803ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown     * @throws ZygoteSecurityException
804ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown     */
80583d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley    private static void applyInvokeWithSecurityPolicy(Arguments args, Credentials peer,
80683d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley            String peerSecurityContext)
807ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown            throws ZygoteSecurityException {
808ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown        int peerUid = peer.getUid();
809ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown
810ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown        if (args.invokeWith != null && peerUid != 0) {
811ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown            throw new ZygoteSecurityException("Peer is not permitted to specify "
812ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown                    + "an explicit invoke-with wrapper command");
813ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown        }
81483d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley
81583d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley        if (args.invokeWith != null) {
81683d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley            boolean allowed = SELinux.checkSELinuxAccess(peerSecurityContext,
81783d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley                                                         peerSecurityContext,
81883d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley                                                         "zygote",
81983d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley                                                         "specifyinvokewith");
82083d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley            if (!allowed) {
82183d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley                throw new ZygoteSecurityException("Peer is not permitted to specify "
82283d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley                    + "an explicit invoke-with wrapper command");
82383d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley            }
82483d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley        }
82583d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley    }
82683d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley
82783d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley    /**
82883d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley     * Applies zygote security policy for SEAndroid information.
82983d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley     *
83083d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley     * @param args non-null; zygote spawner arguments
83183d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley     * @param peer non-null; peer credentials
83283d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley     * @throws ZygoteSecurityException
83383d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley     */
83483d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley    private static void applyseInfoSecurityPolicy(
83583d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley            Arguments args, Credentials peer, String peerSecurityContext)
83683d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley            throws ZygoteSecurityException {
83783d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley        int peerUid = peer.getUid();
83883d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley
83983d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley        if (args.seInfo == null) {
84083d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley            // nothing to check
84183d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley            return;
84283d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley        }
84383d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley
84483d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley        if (!(peerUid == 0 || peerUid == Process.SYSTEM_UID)) {
84583d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley            // All peers with UID other than root or SYSTEM_UID
84683d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley            throw new ZygoteSecurityException(
84783d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley                    "This UID may not specify SEAndroid info.");
84883d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley        }
84983d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley
85083d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley        boolean allowed = SELinux.checkSELinuxAccess(peerSecurityContext,
85183d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley                                                     peerSecurityContext,
85283d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley                                                     "zygote",
85383d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley                                                     "specifyseinfo");
85483d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley        if (!allowed) {
85583d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley            throw new ZygoteSecurityException(
85683d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley                    "Peer may not specify SEAndroid info");
85783d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley        }
85883d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley
85983d9eda9c2c411e3480c52f01e192bf3c86be8e9Stephen Smalley        return;
860ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown    }
861ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown
862ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown    /**
863ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown     * Applies invoke-with system properties to the zygote arguments.
864ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown     *
865ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown     * @param parsedArgs non-null; zygote args
866ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown     */
867ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown    public static void applyInvokeWithSystemProperty(Arguments args) {
868ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown        if (args.invokeWith == null && args.niceName != null) {
869ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown            if (args.niceName != null) {
870ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown                String property = "wrap." + args.niceName;
871ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown                if (property.length() > 31) {
872ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown                    property = property.substring(0, 31);
873ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown                }
874ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown                args.invokeWith = SystemProperties.get(property);
875ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown                if (args.invokeWith != null && args.invokeWith.length() == 0) {
876ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown                    args.invokeWith = null;
877ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown                }
878ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown            }
879ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown        }
880ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown    }
881ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown
882ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown    /**
8839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Handles post-fork setup of child proc, closing sockets as appropriate,
8849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * reopen stdio as appropriate, and ultimately throwing MethodAndArgsCaller
8859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * if successful or returning if failed.
8869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
8879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param parsedArgs non-null; zygote args
8889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param descriptors null-ok; new file descriptors for stdio if available.
889ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown     * @param pipeFd null-ok; pipe for communication back to Zygote.
8909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param newStderr null-ok; stream to use for stderr until stdio
8919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * is reopened.
8929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
8939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @throws ZygoteInit.MethodAndArgsCaller on success to
8949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * trampoline to code that invokes static main.
8959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
8969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void handleChildProc(Arguments parsedArgs,
897ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown            FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr)
8989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throws ZygoteInit.MethodAndArgsCaller {
8999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /*
9019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Close the socket, unless we're in "peer wait" mode, in which
9029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * case it's used to track the liveness of this process.
9039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
9049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (parsedArgs.peerWait) {
9069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
9079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                ZygoteInit.setCloseOnExec(mSocket.getFileDescriptor(), true);
9089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                sPeerWaitSocket = mSocket;
9099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } catch (IOException ex) {
9109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Log.e(TAG, "Zygote Child: error setting peer wait "
9119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        + "socket to be close-on-exec", ex);
9129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
9139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
9149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            closeSocket();
9159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ZygoteInit.closeServerSocket();
9169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (descriptors != null) {
9199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
9209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                ZygoteInit.reopenStdio(descriptors[0],
9219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        descriptors[1], descriptors[2]);
9229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                for (FileDescriptor fd: descriptors) {
924ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown                    IoUtils.closeQuietly(fd);
9259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
9269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                newStderr = System.err;
9279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } catch (IOException ex) {
9289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Log.e(TAG, "Error reopening stdio", ex);
9299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
9309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
932ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown        if (parsedArgs.niceName != null) {
933ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown            Process.setArgV0(parsedArgs.niceName);
934ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown        }
9359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
936ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown        if (parsedArgs.runtimeInit) {
937ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown            if (parsedArgs.invokeWith != null) {
938ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown                WrapperInit.execApplication(parsedArgs.invokeWith,
939e1dfcb7ab01fb991079ec1f70f75281a0ca9073eElliott Hughes                        parsedArgs.niceName, parsedArgs.targetSdkVersion,
940e1dfcb7ab01fb991079ec1f70f75281a0ca9073eElliott Hughes                        pipeFd, parsedArgs.remainingArgs);
9419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
942e1dfcb7ab01fb991079ec1f70f75281a0ca9073eElliott Hughes                RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion,
943e1dfcb7ab01fb991079ec1f70f75281a0ca9073eElliott Hughes                        parsedArgs.remainingArgs);
9449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
945ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown        } else {
9469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            String className;
9479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
9489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                className = parsedArgs.remainingArgs[0];
9499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } catch (ArrayIndexOutOfBoundsException ex) {
950ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown                logAndPrintError(newStderr,
9519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        "Missing required class name argument", null);
9529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return;
9539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
9549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
955ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown            String[] mainArgs = new String[parsedArgs.remainingArgs.length - 1];
9569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            System.arraycopy(parsedArgs.remainingArgs, 1,
9579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mainArgs, 0, mainArgs.length);
9589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
959ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown            if (parsedArgs.invokeWith != null) {
960ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown                WrapperInit.execStandalone(parsedArgs.invokeWith,
961ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown                        parsedArgs.classpath, className, mainArgs);
962ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown            } else {
963ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown                ClassLoader cloader;
964ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown                if (parsedArgs.classpath != null) {
965ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown                    cloader = new PathClassLoader(parsedArgs.classpath,
966ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown                            ClassLoader.getSystemClassLoader());
967ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown                } else {
968ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown                    cloader = ClassLoader.getSystemClassLoader();
969ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown                }
970ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown
971ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown                try {
972ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown                    ZygoteInit.invokeStaticMain(cloader, className, mainArgs);
973ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown                } catch (RuntimeException ex) {
974ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown                    logAndPrintError(newStderr, "Error starting.", ex);
975ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown                }
9769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
9779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
9819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Handles post-fork cleanup of parent proc
9829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
9839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param pid != 0; pid of child if &gt; 0 or indication of failed fork
9849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * if &lt; 0;
9859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param descriptors null-ok; file descriptors for child's new stdio if
9869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * specified.
987ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown     * @param pipeFd null-ok; pipe for communication with child.
9889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param parsedArgs non-null; zygote args
9899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return true for "exit command loop" and false for "continue command
9909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * loop"
9919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
9929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean handleParentProc(int pid,
993ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown            FileDescriptor[] descriptors, FileDescriptor pipeFd, Arguments parsedArgs) {
994ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown
995ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown        if (pid > 0) {
996ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown            setChildPgid(pid);
997ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown        }
998ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown
999ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown        if (descriptors != null) {
1000ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown            for (FileDescriptor fd: descriptors) {
1001ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown                IoUtils.closeQuietly(fd);
1002ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown            }
1003ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown        }
10049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10053f9dd287b99340efaaa257759e71a8f81b2ed113Jeff Brown        boolean usingWrapper = false;
1006ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown        if (pipeFd != null && pid > 0) {
1007ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown            DataInputStream is = new DataInputStream(new FileInputStream(pipeFd));
1008ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown            int innerPid = -1;
10099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
1010ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown                innerPid = is.readInt();
10119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } catch (IOException ex) {
1012ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown                Log.w(TAG, "Error reading pid from wrapped process, child may have died", ex);
1013ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown            } finally {
1014ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown                try {
1015ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown                    is.close();
1016ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown                } catch (IOException ex) {
1017ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown                }
10189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
10199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1020ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown            // Ensure that the pid reported by the wrapped process is either the
1021ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown            // child process that we forked, or a descendant of it.
1022ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown            if (innerPid > 0) {
1023ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown                int parentPid = innerPid;
1024ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown                while (parentPid > 0 && parentPid != pid) {
1025ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown                    parentPid = Process.getParentPid(parentPid);
1026ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown                }
1027ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown                if (parentPid > 0) {
1028ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown                    Log.i(TAG, "Wrapped process has pid " + innerPid);
1029ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown                    pid = innerPid;
10303f9dd287b99340efaaa257759e71a8f81b2ed113Jeff Brown                    usingWrapper = true;
1031ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown                } else {
1032ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown                    Log.w(TAG, "Wrapped process reported a pid that is not a child of "
1033ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown                            + "the process that we forked: childPid=" + pid
1034ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown                            + " innerPid=" + innerPid);
10359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
10369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
10379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
10409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mSocketOutStream.writeInt(pid);
10413f9dd287b99340efaaa257759e71a8f81b2ed113Jeff Brown            mSocketOutStream.writeBoolean(usingWrapper);
10429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (IOException ex) {
10439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Log.e(TAG, "Error reading from command socket", ex);
10449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return true;
10459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /*
10489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * If the peer wants to use the socket to wait on the
10499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * newly spawned process, then we're all done.
10509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
10519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (parsedArgs.peerWait) {
10529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
10539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mSocket.close();
10549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } catch (IOException ex) {
10559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Log.e(TAG, "Zygote: error closing sockets", ex);
10569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
10579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return true;
10589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return false;
10609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1062ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown    private void setChildPgid(int pid) {
1063ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown        // Try to move the new child into the peer's process group.
1064ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown        try {
1065ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown            ZygoteInit.setpgid(pid, ZygoteInit.getpgid(peer.getPid()));
1066ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown        } catch (IOException ex) {
1067ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown            // This exception is expected in the case where
1068ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown            // the peer is not in our session
1069ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown            // TODO get rid of this log message in the case where
1070ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown            // getsid(0) != getsid(peer.getPid())
1071ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown            Log.i(TAG, "Zygote: setpgid failed. This is "
1072ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown                + "normal if peer is not in our session");
1073ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown        }
1074ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown    }
1075ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown
10769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
10779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Logs an error message and prints it to the specified stream, if
10789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * provided
10799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
10809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param newStderr null-ok; a standard error stream
10819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param message non-null; error message
10829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param ex null-ok an exception
10839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
10849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static void logAndPrintError (PrintStream newStderr,
10859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            String message, Throwable ex) {
10869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Log.e(TAG, message, ex);
10879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (newStderr != null) {
10889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            newStderr.println(message + (ex == null ? "" : ex));
10899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1092