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