1b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant/*
2b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant * Copyright (C) 2007 The Android Open Source Project
3b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant *
4b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant * Licensed under the Apache License, Version 2.0 (the "License");
5b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant * you may not use this file except in compliance with the License.
6b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant * You may obtain a copy of the License at
7b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant *
8b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant *      http://www.apache.org/licenses/LICENSE-2.0
9b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant *
10b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant * Unless required by applicable law or agreed to in writing, software
11b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant * distributed under the License is distributed on an "AS IS" BASIS,
12b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant * See the License for the specific language governing permissions and
14b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant * limitations under the License.
15b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant */
16b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant
17b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeantpackage com.android.internal.os;
18b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant
19b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeantimport static android.system.OsConstants.POLLIN;
20b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant
21b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeantimport android.net.LocalServerSocket;
22ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesekimport android.net.LocalSocket;
23b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeantimport android.system.Os;
24b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeantimport android.system.ErrnoException;
25b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeantimport android.system.StructPollfd;
26b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeantimport android.util.Log;
27b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant
28ac0b4be198960ae56c3b484052bf3acccca59d22Narayan Kamathimport android.util.Slog;
29b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeantimport java.io.IOException;
30b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeantimport java.io.FileDescriptor;
31b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeantimport java.util.ArrayList;
32b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant
33b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant/**
34b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant * Server socket class for zygote processes.
35b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant *
36b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant * Provides functions to wait for commands on a UNIX domain socket, and fork
37b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant * off child processes that inherit the initial state of the VM.%
38b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant *
39b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant * Please see {@link ZygoteConnection.Arguments} for documentation on the
40b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant * client protocol.
41b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant */
42b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeantclass ZygoteServer {
43b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant    public static final String TAG = "ZygoteServer";
44b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant
45b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant    private static final String ANDROID_SOCKET_PREFIX = "ANDROID_SOCKET_";
46b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant
47d0a190df8a04e10a6705148c02c5c4859ad75b70Robert Sesek    /**
48d0a190df8a04e10a6705148c02c5c4859ad75b70Robert Sesek     * Listening socket that accepts new server connections.
49d0a190df8a04e10a6705148c02c5c4859ad75b70Robert Sesek     */
50b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant    private LocalServerSocket mServerSocket;
51b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant
52ac0b4be198960ae56c3b484052bf3acccca59d22Narayan Kamath    /**
53d0a190df8a04e10a6705148c02c5c4859ad75b70Robert Sesek     * Whether or not mServerSocket's underlying FD should be closed directly.
54d0a190df8a04e10a6705148c02c5c4859ad75b70Robert Sesek     * If mServerSocket is created with an existing FD, closing the socket does
55d0a190df8a04e10a6705148c02c5c4859ad75b70Robert Sesek     * not close the FD and it must be closed explicitly. If the socket is created
56d0a190df8a04e10a6705148c02c5c4859ad75b70Robert Sesek     * with a name instead, then closing the socket will close the underlying FD
57d0a190df8a04e10a6705148c02c5c4859ad75b70Robert Sesek     * and it should not be double-closed.
58d0a190df8a04e10a6705148c02c5c4859ad75b70Robert Sesek     */
59d0a190df8a04e10a6705148c02c5c4859ad75b70Robert Sesek    private boolean mCloseSocketFd;
60d0a190df8a04e10a6705148c02c5c4859ad75b70Robert Sesek
61d0a190df8a04e10a6705148c02c5c4859ad75b70Robert Sesek    /**
62ac0b4be198960ae56c3b484052bf3acccca59d22Narayan Kamath     * Set by the child process, immediately after a call to {@code Zygote.forkAndSpecialize}.
63ac0b4be198960ae56c3b484052bf3acccca59d22Narayan Kamath     */
64ac0b4be198960ae56c3b484052bf3acccca59d22Narayan Kamath    private boolean mIsForkChild;
65ac0b4be198960ae56c3b484052bf3acccca59d22Narayan Kamath
66b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant    ZygoteServer() {
67b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant    }
68b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant
69ac0b4be198960ae56c3b484052bf3acccca59d22Narayan Kamath    void setForkChild() {
70ac0b4be198960ae56c3b484052bf3acccca59d22Narayan Kamath        mIsForkChild = true;
71ac0b4be198960ae56c3b484052bf3acccca59d22Narayan Kamath    }
72ac0b4be198960ae56c3b484052bf3acccca59d22Narayan Kamath
73b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant    /**
74d0a190df8a04e10a6705148c02c5c4859ad75b70Robert Sesek     * Registers a server socket for zygote command connections. This locates the server socket
75d0a190df8a04e10a6705148c02c5c4859ad75b70Robert Sesek     * file descriptor through an ANDROID_SOCKET_ environment variable.
76b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant     *
77b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant     * @throws RuntimeException when open fails
78b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant     */
79d0a190df8a04e10a6705148c02c5c4859ad75b70Robert Sesek    void registerServerSocketFromEnv(String socketName) {
80b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant        if (mServerSocket == null) {
81b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant            int fileDesc;
82b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant            final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
83b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant            try {
84b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant                String env = System.getenv(fullSocketName);
85b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant                fileDesc = Integer.parseInt(env);
86b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant            } catch (RuntimeException ex) {
87b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant                throw new RuntimeException(fullSocketName + " unset or invalid", ex);
88b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant            }
89b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant
90b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant            try {
91b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant                FileDescriptor fd = new FileDescriptor();
92b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant                fd.setInt$(fileDesc);
93b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant                mServerSocket = new LocalServerSocket(fd);
94d0a190df8a04e10a6705148c02c5c4859ad75b70Robert Sesek                mCloseSocketFd = true;
95b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant            } catch (IOException ex) {
96b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant                throw new RuntimeException(
97b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant                        "Error binding to local socket '" + fileDesc + "'", ex);
98b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant            }
99b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant        }
100b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant    }
101b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant
102b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant    /**
103d0a190df8a04e10a6705148c02c5c4859ad75b70Robert Sesek     * Registers a server socket for zygote command connections. This opens the server socket
104d0a190df8a04e10a6705148c02c5c4859ad75b70Robert Sesek     * at the specified name in the abstract socket namespace.
105d0a190df8a04e10a6705148c02c5c4859ad75b70Robert Sesek     */
106d0a190df8a04e10a6705148c02c5c4859ad75b70Robert Sesek    void registerServerSocketAtAbstractName(String socketName) {
107d0a190df8a04e10a6705148c02c5c4859ad75b70Robert Sesek        if (mServerSocket == null) {
108d0a190df8a04e10a6705148c02c5c4859ad75b70Robert Sesek            try {
109d0a190df8a04e10a6705148c02c5c4859ad75b70Robert Sesek                mServerSocket = new LocalServerSocket(socketName);
110d0a190df8a04e10a6705148c02c5c4859ad75b70Robert Sesek                mCloseSocketFd = false;
111d0a190df8a04e10a6705148c02c5c4859ad75b70Robert Sesek            } catch (IOException ex) {
112d0a190df8a04e10a6705148c02c5c4859ad75b70Robert Sesek                throw new RuntimeException(
113d0a190df8a04e10a6705148c02c5c4859ad75b70Robert Sesek                        "Error binding to abstract socket '" + socketName + "'", ex);
114d0a190df8a04e10a6705148c02c5c4859ad75b70Robert Sesek            }
115d0a190df8a04e10a6705148c02c5c4859ad75b70Robert Sesek        }
116d0a190df8a04e10a6705148c02c5c4859ad75b70Robert Sesek    }
117d0a190df8a04e10a6705148c02c5c4859ad75b70Robert Sesek
118d0a190df8a04e10a6705148c02c5c4859ad75b70Robert Sesek    /**
119b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant     * Waits for and accepts a single command connection. Throws
120b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant     * RuntimeException on failure.
121b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant     */
122b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant    private ZygoteConnection acceptCommandPeer(String abiList) {
123b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant        try {
124ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek            return createNewConnection(mServerSocket.accept(), abiList);
125b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant        } catch (IOException ex) {
126b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant            throw new RuntimeException(
127b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant                    "IOException during accept()", ex);
128b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant        }
129b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant    }
130b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant
131ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek    protected ZygoteConnection createNewConnection(LocalSocket socket, String abiList)
132ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek            throws IOException {
133ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek        return new ZygoteConnection(socket, abiList);
134ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek    }
135ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek
136b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant    /**
137b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant     * Close and clean up zygote sockets. Called on shutdown and on the
138b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant     * child's exit path.
139b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant     */
140b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant    void closeServerSocket() {
141b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant        try {
142b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant            if (mServerSocket != null) {
143b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant                FileDescriptor fd = mServerSocket.getFileDescriptor();
144b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant                mServerSocket.close();
145d0a190df8a04e10a6705148c02c5c4859ad75b70Robert Sesek                if (fd != null && mCloseSocketFd) {
146b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant                    Os.close(fd);
147b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant                }
148b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant            }
149b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant        } catch (IOException ex) {
150b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant            Log.e(TAG, "Zygote:  error closing sockets", ex);
151b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant        } catch (ErrnoException ex) {
152b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant            Log.e(TAG, "Zygote:  error closing descriptor", ex);
153b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant        }
154b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant
155b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant        mServerSocket = null;
156b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant    }
157b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant
158b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant    /**
159b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant     * Return the server socket's underlying file descriptor, so that
160b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant     * ZygoteConnection can pass it to the native code for proper
161b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant     * closure after a child process is forked off.
162b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant     */
163b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant
164b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant    FileDescriptor getServerSocketFileDescriptor() {
165b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant        return mServerSocket.getFileDescriptor();
166b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant    }
167b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant
168b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant    /**
169b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant     * Runs the zygote process's select loop. Accepts new connections as
170b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant     * they happen, and reads commands from connections one spawn-request's
171b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant     * worth at a time.
172b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant     */
173ac0b4be198960ae56c3b484052bf3acccca59d22Narayan Kamath    Runnable runSelectLoop(String abiList) {
174b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant        ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
175b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant        ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
176b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant
177b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant        fds.add(mServerSocket.getFileDescriptor());
178b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant        peers.add(null);
179b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant
180b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant        while (true) {
181b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant            StructPollfd[] pollFds = new StructPollfd[fds.size()];
182b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant            for (int i = 0; i < pollFds.length; ++i) {
183b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant                pollFds[i] = new StructPollfd();
184b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant                pollFds[i].fd = fds.get(i);
185b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant                pollFds[i].events = (short) POLLIN;
186b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant            }
187b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant            try {
188b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant                Os.poll(pollFds, -1);
189b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant            } catch (ErrnoException ex) {
190b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant                throw new RuntimeException("poll failed", ex);
191b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant            }
192b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant            for (int i = pollFds.length - 1; i >= 0; --i) {
193b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant                if ((pollFds[i].revents & POLLIN) == 0) {
194b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant                    continue;
195b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant                }
196ac0b4be198960ae56c3b484052bf3acccca59d22Narayan Kamath
197b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant                if (i == 0) {
198b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant                    ZygoteConnection newPeer = acceptCommandPeer(abiList);
199b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant                    peers.add(newPeer);
200b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant                    fds.add(newPeer.getFileDesciptor());
201b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant                } else {
202ac0b4be198960ae56c3b484052bf3acccca59d22Narayan Kamath                    try {
203ac0b4be198960ae56c3b484052bf3acccca59d22Narayan Kamath                        ZygoteConnection connection = peers.get(i);
204ac0b4be198960ae56c3b484052bf3acccca59d22Narayan Kamath                        final Runnable command = connection.processOneCommand(this);
205ac0b4be198960ae56c3b484052bf3acccca59d22Narayan Kamath
206ac0b4be198960ae56c3b484052bf3acccca59d22Narayan Kamath                        if (mIsForkChild) {
207ac0b4be198960ae56c3b484052bf3acccca59d22Narayan Kamath                            // We're in the child. We should always have a command to run at this
208ac0b4be198960ae56c3b484052bf3acccca59d22Narayan Kamath                            // stage if processOneCommand hasn't called "exec".
209ac0b4be198960ae56c3b484052bf3acccca59d22Narayan Kamath                            if (command == null) {
210ac0b4be198960ae56c3b484052bf3acccca59d22Narayan Kamath                                throw new IllegalStateException("command == null");
211ac0b4be198960ae56c3b484052bf3acccca59d22Narayan Kamath                            }
212ac0b4be198960ae56c3b484052bf3acccca59d22Narayan Kamath
213ac0b4be198960ae56c3b484052bf3acccca59d22Narayan Kamath                            return command;
214ac0b4be198960ae56c3b484052bf3acccca59d22Narayan Kamath                        } else {
215ac0b4be198960ae56c3b484052bf3acccca59d22Narayan Kamath                            // We're in the server - we should never have any commands to run.
216ac0b4be198960ae56c3b484052bf3acccca59d22Narayan Kamath                            if (command != null) {
217ac0b4be198960ae56c3b484052bf3acccca59d22Narayan Kamath                                throw new IllegalStateException("command != null");
218ac0b4be198960ae56c3b484052bf3acccca59d22Narayan Kamath                            }
219ac0b4be198960ae56c3b484052bf3acccca59d22Narayan Kamath
220ac0b4be198960ae56c3b484052bf3acccca59d22Narayan Kamath                            // We don't know whether the remote side of the socket was closed or
221ac0b4be198960ae56c3b484052bf3acccca59d22Narayan Kamath                            // not until we attempt to read from it from processOneCommand. This shows up as
222ac0b4be198960ae56c3b484052bf3acccca59d22Narayan Kamath                            // a regular POLLIN event in our regular processing loop.
223ac0b4be198960ae56c3b484052bf3acccca59d22Narayan Kamath                            if (connection.isClosedByPeer()) {
224ac0b4be198960ae56c3b484052bf3acccca59d22Narayan Kamath                                connection.closeSocket();
225ac0b4be198960ae56c3b484052bf3acccca59d22Narayan Kamath                                peers.remove(i);
226ac0b4be198960ae56c3b484052bf3acccca59d22Narayan Kamath                                fds.remove(i);
227ac0b4be198960ae56c3b484052bf3acccca59d22Narayan Kamath                            }
228ac0b4be198960ae56c3b484052bf3acccca59d22Narayan Kamath                        }
229ac0b4be198960ae56c3b484052bf3acccca59d22Narayan Kamath                    } catch (Exception e) {
230ac0b4be198960ae56c3b484052bf3acccca59d22Narayan Kamath                        if (!mIsForkChild) {
231ac0b4be198960ae56c3b484052bf3acccca59d22Narayan Kamath                            // We're in the server so any exception here is one that has taken place
232ac0b4be198960ae56c3b484052bf3acccca59d22Narayan Kamath                            // pre-fork while processing commands or reading / writing from the
233ac0b4be198960ae56c3b484052bf3acccca59d22Narayan Kamath                            // control socket. Make a loud noise about any such exceptions so that
234ac0b4be198960ae56c3b484052bf3acccca59d22Narayan Kamath                            // we know exactly what failed and why.
235ac0b4be198960ae56c3b484052bf3acccca59d22Narayan Kamath
236ac0b4be198960ae56c3b484052bf3acccca59d22Narayan Kamath                            Slog.e(TAG, "Exception executing zygote command: ", e);
237ac0b4be198960ae56c3b484052bf3acccca59d22Narayan Kamath
238ac0b4be198960ae56c3b484052bf3acccca59d22Narayan Kamath                            // Make sure the socket is closed so that the other end knows immediately
239ac0b4be198960ae56c3b484052bf3acccca59d22Narayan Kamath                            // that something has gone wrong and doesn't time out waiting for a
240ac0b4be198960ae56c3b484052bf3acccca59d22Narayan Kamath                            // response.
241ac0b4be198960ae56c3b484052bf3acccca59d22Narayan Kamath                            ZygoteConnection conn = peers.remove(i);
242ac0b4be198960ae56c3b484052bf3acccca59d22Narayan Kamath                            conn.closeSocket();
243ac0b4be198960ae56c3b484052bf3acccca59d22Narayan Kamath
244ac0b4be198960ae56c3b484052bf3acccca59d22Narayan Kamath                            fds.remove(i);
245ac0b4be198960ae56c3b484052bf3acccca59d22Narayan Kamath                        } else {
246ac0b4be198960ae56c3b484052bf3acccca59d22Narayan Kamath                            // We're in the child so any exception caught here has happened post
247ac0b4be198960ae56c3b484052bf3acccca59d22Narayan Kamath                            // fork and before we execute ActivityThread.main (or any other main()
248ac0b4be198960ae56c3b484052bf3acccca59d22Narayan Kamath                            // method). Log the details of the exception and bring down the process.
249ac0b4be198960ae56c3b484052bf3acccca59d22Narayan Kamath                            Log.e(TAG, "Caught post-fork exception in child process.", e);
250ac0b4be198960ae56c3b484052bf3acccca59d22Narayan Kamath                            throw e;
251ac0b4be198960ae56c3b484052bf3acccca59d22Narayan Kamath                        }
252d0a190df8a04e10a6705148c02c5c4859ad75b70Robert Sesek                    } finally {
253d0a190df8a04e10a6705148c02c5c4859ad75b70Robert Sesek                        // Reset the child flag, in the event that the child process is a child-
254d0a190df8a04e10a6705148c02c5c4859ad75b70Robert Sesek                        // zygote. The flag will not be consulted this loop pass after the Runnable
255d0a190df8a04e10a6705148c02c5c4859ad75b70Robert Sesek                        // is returned.
256d0a190df8a04e10a6705148c02c5c4859ad75b70Robert Sesek                        mIsForkChild = false;
257b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant                    }
258b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant                }
259b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant            }
260b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant        }
261b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant    }
262b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant}
263