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