ZygoteServer.java revision b9679dc1fad508a001e30a941148e1bdc3fe953f
1/* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.internal.os; 18 19import static android.system.OsConstants.POLLIN; 20 21import android.net.LocalServerSocket; 22import android.system.Os; 23import android.system.ErrnoException; 24import android.system.StructPollfd; 25import android.util.Log; 26 27import java.io.IOException; 28import java.io.FileDescriptor; 29import java.util.ArrayList; 30 31/** 32 * Server socket class for zygote processes. 33 * 34 * Provides functions to wait for commands on a UNIX domain socket, and fork 35 * off child processes that inherit the initial state of the VM.% 36 * 37 * Please see {@link ZygoteConnection.Arguments} for documentation on the 38 * client protocol. 39 */ 40class ZygoteServer { 41 public static final String TAG = "ZygoteServer"; 42 43 private static final String ANDROID_SOCKET_PREFIX = "ANDROID_SOCKET_"; 44 45 private LocalServerSocket mServerSocket; 46 47 ZygoteServer() { 48 } 49 50 /** 51 * Registers a server socket for zygote command connections 52 * 53 * @throws RuntimeException when open fails 54 */ 55 void registerServerSocket(String socketName) { 56 if (mServerSocket == null) { 57 int fileDesc; 58 final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName; 59 try { 60 String env = System.getenv(fullSocketName); 61 fileDesc = Integer.parseInt(env); 62 } catch (RuntimeException ex) { 63 throw new RuntimeException(fullSocketName + " unset or invalid", ex); 64 } 65 66 try { 67 FileDescriptor fd = new FileDescriptor(); 68 fd.setInt$(fileDesc); 69 mServerSocket = new LocalServerSocket(fd); 70 } catch (IOException ex) { 71 throw new RuntimeException( 72 "Error binding to local socket '" + fileDesc + "'", ex); 73 } 74 } 75 } 76 77 /** 78 * Waits for and accepts a single command connection. Throws 79 * RuntimeException on failure. 80 */ 81 private ZygoteConnection acceptCommandPeer(String abiList) { 82 try { 83 return new ZygoteConnection(mServerSocket.accept(), abiList); 84 } catch (IOException ex) { 85 throw new RuntimeException( 86 "IOException during accept()", ex); 87 } 88 } 89 90 /** 91 * Close and clean up zygote sockets. Called on shutdown and on the 92 * child's exit path. 93 */ 94 void closeServerSocket() { 95 try { 96 if (mServerSocket != null) { 97 FileDescriptor fd = mServerSocket.getFileDescriptor(); 98 mServerSocket.close(); 99 if (fd != null) { 100 Os.close(fd); 101 } 102 } 103 } catch (IOException ex) { 104 Log.e(TAG, "Zygote: error closing sockets", ex); 105 } catch (ErrnoException ex) { 106 Log.e(TAG, "Zygote: error closing descriptor", ex); 107 } 108 109 mServerSocket = null; 110 } 111 112 /** 113 * Return the server socket's underlying file descriptor, so that 114 * ZygoteConnection can pass it to the native code for proper 115 * closure after a child process is forked off. 116 */ 117 118 FileDescriptor getServerSocketFileDescriptor() { 119 return mServerSocket.getFileDescriptor(); 120 } 121 122 /** 123 * Runs the zygote process's select loop. Accepts new connections as 124 * they happen, and reads commands from connections one spawn-request's 125 * worth at a time. 126 * 127 * @throws Zygote.MethodAndArgsCaller in a child process when a main() 128 * should be executed. 129 */ 130 void runSelectLoop(String abiList) throws Zygote.MethodAndArgsCaller { 131 ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>(); 132 ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>(); 133 134 fds.add(mServerSocket.getFileDescriptor()); 135 peers.add(null); 136 137 while (true) { 138 StructPollfd[] pollFds = new StructPollfd[fds.size()]; 139 for (int i = 0; i < pollFds.length; ++i) { 140 pollFds[i] = new StructPollfd(); 141 pollFds[i].fd = fds.get(i); 142 pollFds[i].events = (short) POLLIN; 143 } 144 try { 145 Os.poll(pollFds, -1); 146 } catch (ErrnoException ex) { 147 throw new RuntimeException("poll failed", ex); 148 } 149 for (int i = pollFds.length - 1; i >= 0; --i) { 150 if ((pollFds[i].revents & POLLIN) == 0) { 151 continue; 152 } 153 if (i == 0) { 154 ZygoteConnection newPeer = acceptCommandPeer(abiList); 155 peers.add(newPeer); 156 fds.add(newPeer.getFileDesciptor()); 157 } else { 158 boolean done = peers.get(i).runOnce(this); 159 if (done) { 160 peers.remove(i); 161 fds.remove(i); 162 } 163 } 164 } 165 } 166 } 167} 168