Home | History | Annotate | Download | only in os
      1 /*
      2  * Copyright (C) 2016 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 android.os;
     18 
     19 import android.net.LocalSocket;
     20 import android.net.LocalSocketAddress;
     21 import android.util.Log;
     22 import android.util.Slog;
     23 
     24 import com.android.internal.annotations.GuardedBy;
     25 import com.android.internal.os.Zygote;
     26 import com.android.internal.util.Preconditions;
     27 
     28 import java.io.BufferedWriter;
     29 import java.io.DataInputStream;
     30 import java.io.IOException;
     31 import java.io.OutputStreamWriter;
     32 import java.nio.charset.StandardCharsets;
     33 import java.util.ArrayList;
     34 import java.util.Arrays;
     35 import java.util.Collections;
     36 import java.util.List;
     37 import java.util.UUID;
     38 
     39 /*package*/ class ZygoteStartFailedEx extends Exception {
     40     ZygoteStartFailedEx(String s) {
     41         super(s);
     42     }
     43 
     44     ZygoteStartFailedEx(Throwable cause) {
     45         super(cause);
     46     }
     47 
     48     ZygoteStartFailedEx(String s, Throwable cause) {
     49         super(s, cause);
     50     }
     51 }
     52 
     53 /**
     54  * Maintains communication state with the zygote processes. This class is responsible
     55  * for the sockets opened to the zygotes and for starting processes on behalf of the
     56  * {@link android.os.Process} class.
     57  *
     58  * {@hide}
     59  */
     60 public class ZygoteProcess {
     61     private static final String LOG_TAG = "ZygoteProcess";
     62 
     63     /**
     64      * The name of the socket used to communicate with the primary zygote.
     65      */
     66     private final LocalSocketAddress mSocket;
     67 
     68     /**
     69      * The name of the secondary (alternate ABI) zygote socket.
     70      */
     71     private final LocalSocketAddress mSecondarySocket;
     72 
     73     public ZygoteProcess(String primarySocket, String secondarySocket) {
     74         this(new LocalSocketAddress(primarySocket, LocalSocketAddress.Namespace.RESERVED),
     75                 new LocalSocketAddress(secondarySocket, LocalSocketAddress.Namespace.RESERVED));
     76     }
     77 
     78     public ZygoteProcess(LocalSocketAddress primarySocket, LocalSocketAddress secondarySocket) {
     79         mSocket = primarySocket;
     80         mSecondarySocket = secondarySocket;
     81     }
     82 
     83     public LocalSocketAddress getPrimarySocketAddress() {
     84         return mSocket;
     85     }
     86 
     87     /**
     88      * State for communicating with the zygote process.
     89      */
     90     public static class ZygoteState {
     91         final LocalSocket socket;
     92         final DataInputStream inputStream;
     93         final BufferedWriter writer;
     94         final List<String> abiList;
     95 
     96         boolean mClosed;
     97 
     98         private ZygoteState(LocalSocket socket, DataInputStream inputStream,
     99                 BufferedWriter writer, List<String> abiList) {
    100             this.socket = socket;
    101             this.inputStream = inputStream;
    102             this.writer = writer;
    103             this.abiList = abiList;
    104         }
    105 
    106         public static ZygoteState connect(LocalSocketAddress address) throws IOException {
    107             DataInputStream zygoteInputStream = null;
    108             BufferedWriter zygoteWriter = null;
    109             final LocalSocket zygoteSocket = new LocalSocket();
    110 
    111             try {
    112                 zygoteSocket.connect(address);
    113 
    114                 zygoteInputStream = new DataInputStream(zygoteSocket.getInputStream());
    115 
    116                 zygoteWriter = new BufferedWriter(new OutputStreamWriter(
    117                         zygoteSocket.getOutputStream()), 256);
    118             } catch (IOException ex) {
    119                 try {
    120                     zygoteSocket.close();
    121                 } catch (IOException ignore) {
    122                 }
    123 
    124                 throw ex;
    125             }
    126 
    127             String abiListString = getAbiList(zygoteWriter, zygoteInputStream);
    128             Log.i("Zygote", "Process: zygote socket " + address.getNamespace() + "/"
    129                     + address.getName() + " opened, supported ABIS: " + abiListString);
    130 
    131             return new ZygoteState(zygoteSocket, zygoteInputStream, zygoteWriter,
    132                     Arrays.asList(abiListString.split(",")));
    133         }
    134 
    135         boolean matches(String abi) {
    136             return abiList.contains(abi);
    137         }
    138 
    139         public void close() {
    140             try {
    141                 socket.close();
    142             } catch (IOException ex) {
    143                 Log.e(LOG_TAG,"I/O exception on routine close", ex);
    144             }
    145 
    146             mClosed = true;
    147         }
    148 
    149         boolean isClosed() {
    150             return mClosed;
    151         }
    152     }
    153 
    154     /**
    155      * Lock object to protect access to the two ZygoteStates below. This lock must be
    156      * acquired while communicating over the ZygoteState's socket, to prevent
    157      * interleaved access.
    158      */
    159     private final Object mLock = new Object();
    160 
    161     /**
    162      * List of exemptions to the API blacklist. These are prefix matches on the runtime format
    163      * symbol signature. Any matching symbol is treated by the runtime as being on the light grey
    164      * list.
    165      */
    166     private List<String> mApiBlacklistExemptions = Collections.emptyList();
    167 
    168     /**
    169      * Proportion of hidden API accesses that should be logged to the event log; 0 - 0x10000.
    170      */
    171     private int mHiddenApiAccessLogSampleRate;
    172 
    173     /**
    174      * The state of the connection to the primary zygote.
    175      */
    176     private ZygoteState primaryZygoteState;
    177 
    178     /**
    179      * The state of the connection to the secondary zygote.
    180      */
    181     private ZygoteState secondaryZygoteState;
    182 
    183     /**
    184      * Start a new process.
    185      *
    186      * <p>If processes are enabled, a new process is created and the
    187      * static main() function of a <var>processClass</var> is executed there.
    188      * The process will continue running after this function returns.
    189      *
    190      * <p>If processes are not enabled, a new thread in the caller's
    191      * process is created and main() of <var>processclass</var> called there.
    192      *
    193      * <p>The niceName parameter, if not an empty string, is a custom name to
    194      * give to the process instead of using processClass.  This allows you to
    195      * make easily identifyable processes even if you are using the same base
    196      * <var>processClass</var> to start them.
    197      *
    198      * When invokeWith is not null, the process will be started as a fresh app
    199      * and not a zygote fork. Note that this is only allowed for uid 0 or when
    200      * runtimeFlags contains DEBUG_ENABLE_DEBUGGER.
    201      *
    202      * @param processClass The class to use as the process's main entry
    203      *                     point.
    204      * @param niceName A more readable name to use for the process.
    205      * @param uid The user-id under which the process will run.
    206      * @param gid The group-id under which the process will run.
    207      * @param gids Additional group-ids associated with the process.
    208      * @param runtimeFlags Additional flags.
    209      * @param targetSdkVersion The target SDK version for the app.
    210      * @param seInfo null-ok SELinux information for the new process.
    211      * @param abi non-null the ABI this app should be started with.
    212      * @param instructionSet null-ok the instruction set to use.
    213      * @param appDataDir null-ok the data directory of the app.
    214      * @param invokeWith null-ok the command to invoke with.
    215      * @param zygoteArgs Additional arguments to supply to the zygote process.
    216      *
    217      * @return An object that describes the result of the attempt to start the process.
    218      * @throws RuntimeException on fatal start failure
    219      */
    220     public final Process.ProcessStartResult start(final String processClass,
    221                                                   final String niceName,
    222                                                   int uid, int gid, int[] gids,
    223                                                   int runtimeFlags, int mountExternal,
    224                                                   int targetSdkVersion,
    225                                                   String seInfo,
    226                                                   String abi,
    227                                                   String instructionSet,
    228                                                   String appDataDir,
    229                                                   String invokeWith,
    230                                                   String[] zygoteArgs) {
    231         try {
    232             return startViaZygote(processClass, niceName, uid, gid, gids,
    233                     runtimeFlags, mountExternal, targetSdkVersion, seInfo,
    234                     abi, instructionSet, appDataDir, invokeWith, false /* startChildZygote */,
    235                     zygoteArgs);
    236         } catch (ZygoteStartFailedEx ex) {
    237             Log.e(LOG_TAG,
    238                     "Starting VM process through Zygote failed");
    239             throw new RuntimeException(
    240                     "Starting VM process through Zygote failed", ex);
    241         }
    242     }
    243 
    244     /** retry interval for opening a zygote socket */
    245     static final int ZYGOTE_RETRY_MILLIS = 500;
    246 
    247     /**
    248      * Queries the zygote for the list of ABIS it supports.
    249      *
    250      * @throws ZygoteStartFailedEx if the query failed.
    251      */
    252     @GuardedBy("mLock")
    253     private static String getAbiList(BufferedWriter writer, DataInputStream inputStream)
    254             throws IOException {
    255         // Each query starts with the argument count (1 in this case)
    256         writer.write("1");
    257         // ... followed by a new-line.
    258         writer.newLine();
    259         // ... followed by our only argument.
    260         writer.write("--query-abi-list");
    261         writer.newLine();
    262         writer.flush();
    263 
    264         // The response is a length prefixed stream of ASCII bytes.
    265         int numBytes = inputStream.readInt();
    266         byte[] bytes = new byte[numBytes];
    267         inputStream.readFully(bytes);
    268 
    269         return new String(bytes, StandardCharsets.US_ASCII);
    270     }
    271 
    272     /**
    273      * Sends an argument list to the zygote process, which starts a new child
    274      * and returns the child's pid. Please note: the present implementation
    275      * replaces newlines in the argument list with spaces.
    276      *
    277      * @throws ZygoteStartFailedEx if process start failed for any reason
    278      */
    279     @GuardedBy("mLock")
    280     private static Process.ProcessStartResult zygoteSendArgsAndGetResult(
    281             ZygoteState zygoteState, ArrayList<String> args)
    282             throws ZygoteStartFailedEx {
    283         try {
    284             // Throw early if any of the arguments are malformed. This means we can
    285             // avoid writing a partial response to the zygote.
    286             int sz = args.size();
    287             for (int i = 0; i < sz; i++) {
    288                 if (args.get(i).indexOf('\n') >= 0) {
    289                     throw new ZygoteStartFailedEx("embedded newlines not allowed");
    290                 }
    291             }
    292 
    293             /**
    294              * See com.android.internal.os.SystemZygoteInit.readArgumentList()
    295              * Presently the wire format to the zygote process is:
    296              * a) a count of arguments (argc, in essence)
    297              * b) a number of newline-separated argument strings equal to count
    298              *
    299              * After the zygote process reads these it will write the pid of
    300              * the child or -1 on failure, followed by boolean to
    301              * indicate whether a wrapper process was used.
    302              */
    303             final BufferedWriter writer = zygoteState.writer;
    304             final DataInputStream inputStream = zygoteState.inputStream;
    305 
    306             writer.write(Integer.toString(args.size()));
    307             writer.newLine();
    308 
    309             for (int i = 0; i < sz; i++) {
    310                 String arg = args.get(i);
    311                 writer.write(arg);
    312                 writer.newLine();
    313             }
    314 
    315             writer.flush();
    316 
    317             // Should there be a timeout on this?
    318             Process.ProcessStartResult result = new Process.ProcessStartResult();
    319 
    320             // Always read the entire result from the input stream to avoid leaving
    321             // bytes in the stream for future process starts to accidentally stumble
    322             // upon.
    323             result.pid = inputStream.readInt();
    324             result.usingWrapper = inputStream.readBoolean();
    325 
    326             if (result.pid < 0) {
    327                 throw new ZygoteStartFailedEx("fork() failed");
    328             }
    329             return result;
    330         } catch (IOException ex) {
    331             zygoteState.close();
    332             throw new ZygoteStartFailedEx(ex);
    333         }
    334     }
    335 
    336     /**
    337      * Starts a new process via the zygote mechanism.
    338      *
    339      * @param processClass Class name whose static main() to run
    340      * @param niceName 'nice' process name to appear in ps
    341      * @param uid a POSIX uid that the new process should setuid() to
    342      * @param gid a POSIX gid that the new process shuold setgid() to
    343      * @param gids null-ok; a list of supplementary group IDs that the
    344      * new process should setgroup() to.
    345      * @param runtimeFlags Additional flags for the runtime.
    346      * @param targetSdkVersion The target SDK version for the app.
    347      * @param seInfo null-ok SELinux information for the new process.
    348      * @param abi the ABI the process should use.
    349      * @param instructionSet null-ok the instruction set to use.
    350      * @param appDataDir null-ok the data directory of the app.
    351      * @param startChildZygote Start a sub-zygote. This creates a new zygote process
    352      * that has its state cloned from this zygote process.
    353      * @param extraArgs Additional arguments to supply to the zygote process.
    354      * @return An object that describes the result of the attempt to start the process.
    355      * @throws ZygoteStartFailedEx if process start failed for any reason
    356      */
    357     private Process.ProcessStartResult startViaZygote(final String processClass,
    358                                                       final String niceName,
    359                                                       final int uid, final int gid,
    360                                                       final int[] gids,
    361                                                       int runtimeFlags, int mountExternal,
    362                                                       int targetSdkVersion,
    363                                                       String seInfo,
    364                                                       String abi,
    365                                                       String instructionSet,
    366                                                       String appDataDir,
    367                                                       String invokeWith,
    368                                                       boolean startChildZygote,
    369                                                       String[] extraArgs)
    370                                                       throws ZygoteStartFailedEx {
    371         ArrayList<String> argsForZygote = new ArrayList<String>();
    372 
    373         // --runtime-args, --setuid=, --setgid=,
    374         // and --setgroups= must go first
    375         argsForZygote.add("--runtime-args");
    376         argsForZygote.add("--setuid=" + uid);
    377         argsForZygote.add("--setgid=" + gid);
    378         argsForZygote.add("--runtime-flags=" + runtimeFlags);
    379         if (mountExternal == Zygote.MOUNT_EXTERNAL_DEFAULT) {
    380             argsForZygote.add("--mount-external-default");
    381         } else if (mountExternal == Zygote.MOUNT_EXTERNAL_READ) {
    382             argsForZygote.add("--mount-external-read");
    383         } else if (mountExternal == Zygote.MOUNT_EXTERNAL_WRITE) {
    384             argsForZygote.add("--mount-external-write");
    385         }
    386         argsForZygote.add("--target-sdk-version=" + targetSdkVersion);
    387 
    388         // --setgroups is a comma-separated list
    389         if (gids != null && gids.length > 0) {
    390             StringBuilder sb = new StringBuilder();
    391             sb.append("--setgroups=");
    392 
    393             int sz = gids.length;
    394             for (int i = 0; i < sz; i++) {
    395                 if (i != 0) {
    396                     sb.append(',');
    397                 }
    398                 sb.append(gids[i]);
    399             }
    400 
    401             argsForZygote.add(sb.toString());
    402         }
    403 
    404         if (niceName != null) {
    405             argsForZygote.add("--nice-name=" + niceName);
    406         }
    407 
    408         if (seInfo != null) {
    409             argsForZygote.add("--seinfo=" + seInfo);
    410         }
    411 
    412         if (instructionSet != null) {
    413             argsForZygote.add("--instruction-set=" + instructionSet);
    414         }
    415 
    416         if (appDataDir != null) {
    417             argsForZygote.add("--app-data-dir=" + appDataDir);
    418         }
    419 
    420         if (invokeWith != null) {
    421             argsForZygote.add("--invoke-with");
    422             argsForZygote.add(invokeWith);
    423         }
    424 
    425         if (startChildZygote) {
    426             argsForZygote.add("--start-child-zygote");
    427         }
    428 
    429         argsForZygote.add(processClass);
    430 
    431         if (extraArgs != null) {
    432             for (String arg : extraArgs) {
    433                 argsForZygote.add(arg);
    434             }
    435         }
    436 
    437         synchronized(mLock) {
    438             return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
    439         }
    440     }
    441 
    442     /**
    443      * Closes the connections to the zygote, if they exist.
    444      */
    445     public void close() {
    446         if (primaryZygoteState != null) {
    447             primaryZygoteState.close();
    448         }
    449         if (secondaryZygoteState != null) {
    450             secondaryZygoteState.close();
    451         }
    452     }
    453 
    454     /**
    455      * Tries to establish a connection to the zygote that handles a given {@code abi}. Might block
    456      * and retry if the zygote is unresponsive. This method is a no-op if a connection is
    457      * already open.
    458      */
    459     public void establishZygoteConnectionForAbi(String abi) {
    460         try {
    461             synchronized(mLock) {
    462                 openZygoteSocketIfNeeded(abi);
    463             }
    464         } catch (ZygoteStartFailedEx ex) {
    465             throw new RuntimeException("Unable to connect to zygote for abi: " + abi, ex);
    466         }
    467     }
    468 
    469     /**
    470      * Push hidden API blacklisting exemptions into the zygote process(es).
    471      *
    472      * <p>The list of exemptions will take affect for all new processes forked from the zygote after
    473      * this call.
    474      *
    475      * @param exemptions List of hidden API exemption prefixes. Any matching members are treated as
    476      *        whitelisted/public APIs (i.e. allowed, no logging of usage).
    477      */
    478     public boolean setApiBlacklistExemptions(List<String> exemptions) {
    479         synchronized (mLock) {
    480             mApiBlacklistExemptions = exemptions;
    481             boolean ok = maybeSetApiBlacklistExemptions(primaryZygoteState, true);
    482             if (ok) {
    483                 ok = maybeSetApiBlacklistExemptions(secondaryZygoteState, true);
    484             }
    485             return ok;
    486         }
    487     }
    488 
    489     /**
    490      * Set the precentage of detected hidden API accesses that are logged to the event log.
    491      *
    492      * <p>This rate will take affect for all new processes forked from the zygote after this call.
    493      *
    494      * @param rate An integer between 0 and 0x10000 inclusive. 0 means no event logging.
    495      */
    496     public void setHiddenApiAccessLogSampleRate(int rate) {
    497         synchronized (mLock) {
    498             mHiddenApiAccessLogSampleRate = rate;
    499             maybeSetHiddenApiAccessLogSampleRate(primaryZygoteState);
    500             maybeSetHiddenApiAccessLogSampleRate(secondaryZygoteState);
    501         }
    502     }
    503 
    504     @GuardedBy("mLock")
    505     private boolean maybeSetApiBlacklistExemptions(ZygoteState state, boolean sendIfEmpty) {
    506         if (state == null || state.isClosed()) {
    507             Slog.e(LOG_TAG, "Can't set API blacklist exemptions: no zygote connection");
    508             return false;
    509         }
    510         if (!sendIfEmpty && mApiBlacklistExemptions.isEmpty()) {
    511             return true;
    512         }
    513         try {
    514             state.writer.write(Integer.toString(mApiBlacklistExemptions.size() + 1));
    515             state.writer.newLine();
    516             state.writer.write("--set-api-blacklist-exemptions");
    517             state.writer.newLine();
    518             for (int i = 0; i < mApiBlacklistExemptions.size(); ++i) {
    519                 state.writer.write(mApiBlacklistExemptions.get(i));
    520                 state.writer.newLine();
    521             }
    522             state.writer.flush();
    523             int status = state.inputStream.readInt();
    524             if (status != 0) {
    525                 Slog.e(LOG_TAG, "Failed to set API blacklist exemptions; status " + status);
    526             }
    527             return true;
    528         } catch (IOException ioe) {
    529             Slog.e(LOG_TAG, "Failed to set API blacklist exemptions", ioe);
    530             mApiBlacklistExemptions = Collections.emptyList();
    531             return false;
    532         }
    533     }
    534 
    535     private void maybeSetHiddenApiAccessLogSampleRate(ZygoteState state) {
    536         if (state == null || state.isClosed()) {
    537             return;
    538         }
    539         if (mHiddenApiAccessLogSampleRate == -1) {
    540             return;
    541         }
    542         try {
    543             state.writer.write(Integer.toString(1));
    544             state.writer.newLine();
    545             state.writer.write("--hidden-api-log-sampling-rate="
    546                     + Integer.toString(mHiddenApiAccessLogSampleRate));
    547             state.writer.newLine();
    548             state.writer.flush();
    549             int status = state.inputStream.readInt();
    550             if (status != 0) {
    551                 Slog.e(LOG_TAG, "Failed to set hidden API log sampling rate; status " + status);
    552             }
    553         } catch (IOException ioe) {
    554             Slog.e(LOG_TAG, "Failed to set hidden API log sampling rate", ioe);
    555         }
    556     }
    557 
    558     /**
    559      * Tries to open socket to Zygote process if not already open. If
    560      * already open, does nothing.  May block and retry.  Requires that mLock be held.
    561      */
    562     @GuardedBy("mLock")
    563     private ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
    564         Preconditions.checkState(Thread.holdsLock(mLock), "ZygoteProcess lock not held");
    565 
    566         if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
    567             try {
    568                 primaryZygoteState = ZygoteState.connect(mSocket);
    569             } catch (IOException ioe) {
    570                 throw new ZygoteStartFailedEx("Error connecting to primary zygote", ioe);
    571             }
    572             maybeSetApiBlacklistExemptions(primaryZygoteState, false);
    573             maybeSetHiddenApiAccessLogSampleRate(primaryZygoteState);
    574         }
    575         if (primaryZygoteState.matches(abi)) {
    576             return primaryZygoteState;
    577         }
    578 
    579         // The primary zygote didn't match. Try the secondary.
    580         if (secondaryZygoteState == null || secondaryZygoteState.isClosed()) {
    581             try {
    582                 secondaryZygoteState = ZygoteState.connect(mSecondarySocket);
    583             } catch (IOException ioe) {
    584                 throw new ZygoteStartFailedEx("Error connecting to secondary zygote", ioe);
    585             }
    586             maybeSetApiBlacklistExemptions(secondaryZygoteState, false);
    587             maybeSetHiddenApiAccessLogSampleRate(secondaryZygoteState);
    588         }
    589 
    590         if (secondaryZygoteState.matches(abi)) {
    591             return secondaryZygoteState;
    592         }
    593 
    594         throw new ZygoteStartFailedEx("Unsupported zygote ABI: " + abi);
    595     }
    596 
    597     /**
    598      * Instructs the zygote to pre-load the classes and native libraries at the given paths
    599      * for the specified abi. Not all zygotes support this function.
    600      */
    601     public boolean preloadPackageForAbi(String packagePath, String libsPath, String libFileName,
    602                                         String cacheKey, String abi) throws ZygoteStartFailedEx,
    603                                                                             IOException {
    604         synchronized(mLock) {
    605             ZygoteState state = openZygoteSocketIfNeeded(abi);
    606             state.writer.write("5");
    607             state.writer.newLine();
    608 
    609             state.writer.write("--preload-package");
    610             state.writer.newLine();
    611 
    612             state.writer.write(packagePath);
    613             state.writer.newLine();
    614 
    615             state.writer.write(libsPath);
    616             state.writer.newLine();
    617 
    618             state.writer.write(libFileName);
    619             state.writer.newLine();
    620 
    621             state.writer.write(cacheKey);
    622             state.writer.newLine();
    623 
    624             state.writer.flush();
    625 
    626             return (state.inputStream.readInt() == 0);
    627         }
    628     }
    629 
    630     /**
    631      * Instructs the zygote to preload the default set of classes and resources. Returns
    632      * {@code true} if a preload was performed as a result of this call, and {@code false}
    633      * otherwise. The latter usually means that the zygote eagerly preloaded at startup
    634      * or due to a previous call to {@code preloadDefault}. Note that this call is synchronous.
    635      */
    636     public boolean preloadDefault(String abi) throws ZygoteStartFailedEx, IOException {
    637         synchronized (mLock) {
    638             ZygoteState state = openZygoteSocketIfNeeded(abi);
    639             // Each query starts with the argument count (1 in this case)
    640             state.writer.write("1");
    641             state.writer.newLine();
    642             state.writer.write("--preload-default");
    643             state.writer.newLine();
    644             state.writer.flush();
    645 
    646             return (state.inputStream.readInt() == 0);
    647         }
    648     }
    649 
    650     /**
    651      * Try connecting to the Zygote over and over again until we hit a time-out.
    652      * @param socketName The name of the socket to connect to.
    653      */
    654     public static void waitForConnectionToZygote(String socketName) {
    655         final LocalSocketAddress address =
    656                 new LocalSocketAddress(socketName, LocalSocketAddress.Namespace.RESERVED);
    657         waitForConnectionToZygote(address);
    658     }
    659 
    660     /**
    661      * Try connecting to the Zygote over and over again until we hit a time-out.
    662      * @param address The name of the socket to connect to.
    663      */
    664     public static void waitForConnectionToZygote(LocalSocketAddress address) {
    665         for (int n = 20; n >= 0; n--) {
    666             try {
    667                 final ZygoteState zs = ZygoteState.connect(address);
    668                 zs.close();
    669                 return;
    670             } catch (IOException ioe) {
    671                 Log.w(LOG_TAG,
    672                         "Got error connecting to zygote, retrying. msg= " + ioe.getMessage());
    673             }
    674 
    675             try {
    676                 Thread.sleep(1000);
    677             } catch (InterruptedException ie) {
    678             }
    679         }
    680         Slog.wtf(LOG_TAG, "Failed to connect to Zygote through socket " + address.getName());
    681     }
    682 
    683     /**
    684      * Starts a new zygote process as a child of this zygote. This is used to create
    685      * secondary zygotes that inherit data from the zygote that this object
    686      * communicates with. This returns a new ZygoteProcess representing a connection
    687      * to the newly created zygote. Throws an exception if the zygote cannot be started.
    688      */
    689     public ChildZygoteProcess startChildZygote(final String processClass,
    690                                                final String niceName,
    691                                                int uid, int gid, int[] gids,
    692                                                int runtimeFlags,
    693                                                String seInfo,
    694                                                String abi,
    695                                                String instructionSet) {
    696         // Create an unguessable address in the global abstract namespace.
    697         final LocalSocketAddress serverAddress = new LocalSocketAddress(
    698                 processClass + "/" + UUID.randomUUID().toString());
    699 
    700         final String[] extraArgs = {Zygote.CHILD_ZYGOTE_SOCKET_NAME_ARG + serverAddress.getName()};
    701 
    702         Process.ProcessStartResult result;
    703         try {
    704             result = startViaZygote(processClass, niceName, uid, gid,
    705                     gids, runtimeFlags, 0 /* mountExternal */, 0 /* targetSdkVersion */, seInfo,
    706                     abi, instructionSet, null /* appDataDir */, null /* invokeWith */,
    707                     true /* startChildZygote */, extraArgs);
    708         } catch (ZygoteStartFailedEx ex) {
    709             throw new RuntimeException("Starting child-zygote through Zygote failed", ex);
    710         }
    711 
    712         return new ChildZygoteProcess(serverAddress, result.pid);
    713     }
    714 }
    715