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
28b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeantimport java.io.IOException;
29b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeantimport java.io.FileDescriptor;
30b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeantimport java.util.ArrayList;
31b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant
32b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant/**
33b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant * Server socket class for zygote processes.
34b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant *
35b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant * Provides functions to wait for commands on a UNIX domain socket, and fork
36b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant * off child processes that inherit the initial state of the VM.%
37b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant *
38b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant * Please see {@link ZygoteConnection.Arguments} for documentation on the
39b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant * client protocol.
40b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant */
41b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeantclass ZygoteServer {
42b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant    public static final String TAG = "ZygoteServer";
43b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant
44b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant    private static final String ANDROID_SOCKET_PREFIX = "ANDROID_SOCKET_";
45b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant
46b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant    private LocalServerSocket mServerSocket;
47b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant
48b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant    ZygoteServer() {
49b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant    }
50b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant
51b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant    /**
52b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant     * Registers a server socket for zygote command connections
53b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant     *
54b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant     * @throws RuntimeException when open fails
55b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant     */
56b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant    void registerServerSocket(String socketName) {
57b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant        if (mServerSocket == null) {
58b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant            int fileDesc;
59b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant            final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
60b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant            try {
61b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant                String env = System.getenv(fullSocketName);
62b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant                fileDesc = Integer.parseInt(env);
63b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant            } catch (RuntimeException ex) {
64b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant                throw new RuntimeException(fullSocketName + " unset or invalid", ex);
65b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant            }
66b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant
67b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant            try {
68b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant                FileDescriptor fd = new FileDescriptor();
69b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant                fd.setInt$(fileDesc);
70b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant                mServerSocket = new LocalServerSocket(fd);
71b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant            } catch (IOException ex) {
72b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant                throw new RuntimeException(
73b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant                        "Error binding to local socket '" + fileDesc + "'", ex);
74b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant            }
75b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant        }
76b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant    }
77b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant
78b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant    /**
79b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant     * Waits for and accepts a single command connection. Throws
80b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant     * RuntimeException on failure.
81b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant     */
82b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant    private ZygoteConnection acceptCommandPeer(String abiList) {
83b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant        try {
84ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek            return createNewConnection(mServerSocket.accept(), abiList);
85b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant        } catch (IOException ex) {
86b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant            throw new RuntimeException(
87b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant                    "IOException during accept()", ex);
88b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant        }
89b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant    }
90b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant
91ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek    protected ZygoteConnection createNewConnection(LocalSocket socket, String abiList)
92ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek            throws IOException {
93ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek        return new ZygoteConnection(socket, abiList);
94ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek    }
95ded209843616a98e6f97db0d1784f6d630cbd5e9Robert Sesek
96b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant    /**
97b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant     * Close and clean up zygote sockets. Called on shutdown and on the
98b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant     * child's exit path.
99b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant     */
100b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant    void closeServerSocket() {
101b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant        try {
102b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant            if (mServerSocket != null) {
103b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant                FileDescriptor fd = mServerSocket.getFileDescriptor();
104b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant                mServerSocket.close();
105b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant                if (fd != null) {
106b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant                    Os.close(fd);
107b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant                }
108b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant            }
109b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant        } catch (IOException ex) {
110b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant            Log.e(TAG, "Zygote:  error closing sockets", ex);
111b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant        } catch (ErrnoException ex) {
112b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant            Log.e(TAG, "Zygote:  error closing descriptor", ex);
113b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant        }
114b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant
115b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant        mServerSocket = null;
116b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant    }
117b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant
118b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant    /**
119b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant     * Return the server socket's underlying file descriptor, so that
120b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant     * ZygoteConnection can pass it to the native code for proper
121b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant     * closure after a child process is forked off.
122b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant     */
123b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant
124b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant    FileDescriptor getServerSocketFileDescriptor() {
125b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant        return mServerSocket.getFileDescriptor();
126b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant    }
127b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant
128b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant    /**
129b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant     * Runs the zygote process's select loop. Accepts new connections as
130b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant     * they happen, and reads commands from connections one spawn-request's
131b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant     * worth at a time.
132b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant     *
133b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant     * @throws Zygote.MethodAndArgsCaller in a child process when a main()
134b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant     * should be executed.
135b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant     */
136b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant    void runSelectLoop(String abiList) throws Zygote.MethodAndArgsCaller {
137b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant        ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
138b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant        ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
139b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant
140b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant        fds.add(mServerSocket.getFileDescriptor());
141b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant        peers.add(null);
142b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant
143b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant        while (true) {
144b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant            StructPollfd[] pollFds = new StructPollfd[fds.size()];
145b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant            for (int i = 0; i < pollFds.length; ++i) {
146b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant                pollFds[i] = new StructPollfd();
147b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant                pollFds[i].fd = fds.get(i);
148b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant                pollFds[i].events = (short) POLLIN;
149b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant            }
150b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant            try {
151b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant                Os.poll(pollFds, -1);
152b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant            } catch (ErrnoException ex) {
153b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant                throw new RuntimeException("poll failed", ex);
154b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant            }
155b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant            for (int i = pollFds.length - 1; i >= 0; --i) {
156b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant                if ((pollFds[i].revents & POLLIN) == 0) {
157b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant                    continue;
158b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant                }
159b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant                if (i == 0) {
160b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant                    ZygoteConnection newPeer = acceptCommandPeer(abiList);
161b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant                    peers.add(newPeer);
162b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant                    fds.add(newPeer.getFileDesciptor());
163b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant                } else {
164b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant                    boolean done = peers.get(i).runOnce(this);
165b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant                    if (done) {
166b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant                        peers.remove(i);
167b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant                        fds.remove(i);
168b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant                    }
169b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant                }
170b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant            }
171b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant        }
172b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant    }
173b9679dc1fad508a001e30a941148e1bdc3fe953fTobias Sargeant}
174