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.F_SETFD;
     20 import static android.system.OsConstants.O_CLOEXEC;
     21 import static android.system.OsConstants.POLLIN;
     22 import static android.system.OsConstants.STDERR_FILENO;
     23 import static android.system.OsConstants.STDIN_FILENO;
     24 import static android.system.OsConstants.STDOUT_FILENO;
     25 import static com.android.internal.os.ZygoteConnectionConstants.CONNECTION_TIMEOUT_MILLIS;
     26 import static com.android.internal.os.ZygoteConnectionConstants.MAX_ZYGOTE_ARGC;
     27 import static com.android.internal.os.ZygoteConnectionConstants.WRAPPED_PID_TIMEOUT_MILLIS;
     28 
     29 import android.net.Credentials;
     30 import android.net.LocalSocket;
     31 import android.os.FactoryTest;
     32 import android.os.Process;
     33 import android.os.SystemProperties;
     34 import android.os.Trace;
     35 import android.system.ErrnoException;
     36 import android.system.Os;
     37 import android.system.StructPollfd;
     38 import android.util.Log;
     39 import dalvik.system.VMRuntime;
     40 import java.io.BufferedReader;
     41 import java.io.ByteArrayInputStream;
     42 import java.io.DataInputStream;
     43 import java.io.DataOutputStream;
     44 import java.io.EOFException;
     45 import java.io.FileDescriptor;
     46 import java.io.IOException;
     47 import java.io.InputStreamReader;
     48 import java.nio.charset.StandardCharsets;
     49 import java.util.ArrayList;
     50 import java.util.Arrays;
     51 
     52 import libcore.io.IoUtils;
     53 
     54 /**
     55  * A connection that can make spawn requests.
     56  */
     57 class ZygoteConnection {
     58     private static final String TAG = "Zygote";
     59 
     60     /** a prototype instance for a future List.toArray() */
     61     private static final int[][] intArray2d = new int[0][0];
     62 
     63     /**
     64      * The command socket.
     65      *
     66      * mSocket is retained in the child process in "peer wait" mode, so
     67      * that it closes when the child process terminates. In other cases,
     68      * it is closed in the peer.
     69      */
     70     private final LocalSocket mSocket;
     71     private final DataOutputStream mSocketOutStream;
     72     private final BufferedReader mSocketReader;
     73     private final Credentials peer;
     74     private final String abiList;
     75     private boolean isEof;
     76 
     77     /**
     78      * Constructs instance from connected socket.
     79      *
     80      * @param socket non-null; connected socket
     81      * @param abiList non-null; a list of ABIs this zygote supports.
     82      * @throws IOException
     83      */
     84     ZygoteConnection(LocalSocket socket, String abiList) throws IOException {
     85         mSocket = socket;
     86         this.abiList = abiList;
     87 
     88         mSocketOutStream
     89                 = new DataOutputStream(socket.getOutputStream());
     90 
     91         mSocketReader = new BufferedReader(
     92                 new InputStreamReader(socket.getInputStream()), 256);
     93 
     94         mSocket.setSoTimeout(CONNECTION_TIMEOUT_MILLIS);
     95 
     96         try {
     97             peer = mSocket.getPeerCredentials();
     98         } catch (IOException ex) {
     99             Log.e(TAG, "Cannot read peer credentials", ex);
    100             throw ex;
    101         }
    102 
    103         isEof = false;
    104     }
    105 
    106     /**
    107      * Returns the file descriptor of the associated socket.
    108      *
    109      * @return null-ok; file descriptor
    110      */
    111     FileDescriptor getFileDesciptor() {
    112         return mSocket.getFileDescriptor();
    113     }
    114 
    115     /**
    116      * Reads one start command from the command socket. If successful, a child is forked and a
    117      * {@code Runnable} that calls the childs main method (or equivalent) is returned in the child
    118      * process. {@code null} is always returned in the parent process (the zygote).
    119      *
    120      * If the client closes the socket, an {@code EOF} condition is set, which callers can test
    121      * for by calling {@code ZygoteConnection.isClosedByPeer}.
    122      */
    123     Runnable processOneCommand(ZygoteServer zygoteServer) {
    124         String args[];
    125         Arguments parsedArgs = null;
    126         FileDescriptor[] descriptors;
    127 
    128         try {
    129             args = readArgumentList();
    130             descriptors = mSocket.getAncillaryFileDescriptors();
    131         } catch (IOException ex) {
    132             throw new IllegalStateException("IOException on command socket", ex);
    133         }
    134 
    135         // readArgumentList returns null only when it has reached EOF with no available
    136         // data to read. This will only happen when the remote socket has disconnected.
    137         if (args == null) {
    138             isEof = true;
    139             return null;
    140         }
    141 
    142         int pid = -1;
    143         FileDescriptor childPipeFd = null;
    144         FileDescriptor serverPipeFd = null;
    145 
    146         parsedArgs = new Arguments(args);
    147 
    148         if (parsedArgs.abiListQuery) {
    149             handleAbiListQuery();
    150             return null;
    151         }
    152 
    153         if (parsedArgs.preloadDefault) {
    154             handlePreload();
    155             return null;
    156         }
    157 
    158         if (parsedArgs.preloadPackage != null) {
    159             handlePreloadPackage(parsedArgs.preloadPackage, parsedArgs.preloadPackageLibs,
    160                     parsedArgs.preloadPackageLibFileName, parsedArgs.preloadPackageCacheKey);
    161             return null;
    162         }
    163 
    164         if (parsedArgs.apiBlacklistExemptions != null) {
    165             handleApiBlacklistExemptions(parsedArgs.apiBlacklistExemptions);
    166             return null;
    167         }
    168 
    169         if (parsedArgs.hiddenApiAccessLogSampleRate != -1) {
    170             handleHiddenApiAccessLogSampleRate(parsedArgs.hiddenApiAccessLogSampleRate);
    171             return null;
    172         }
    173 
    174         if (parsedArgs.permittedCapabilities != 0 || parsedArgs.effectiveCapabilities != 0) {
    175             throw new ZygoteSecurityException("Client may not specify capabilities: " +
    176                     "permitted=0x" + Long.toHexString(parsedArgs.permittedCapabilities) +
    177                     ", effective=0x" + Long.toHexString(parsedArgs.effectiveCapabilities));
    178         }
    179 
    180         applyUidSecurityPolicy(parsedArgs, peer);
    181         applyInvokeWithSecurityPolicy(parsedArgs, peer);
    182 
    183         applyDebuggerSystemProperty(parsedArgs);
    184         applyInvokeWithSystemProperty(parsedArgs);
    185 
    186         int[][] rlimits = null;
    187 
    188         if (parsedArgs.rlimits != null) {
    189             rlimits = parsedArgs.rlimits.toArray(intArray2d);
    190         }
    191 
    192         int[] fdsToIgnore = null;
    193 
    194         if (parsedArgs.invokeWith != null) {
    195             try {
    196                 FileDescriptor[] pipeFds = Os.pipe2(O_CLOEXEC);
    197                 childPipeFd = pipeFds[1];
    198                 serverPipeFd = pipeFds[0];
    199                 Os.fcntlInt(childPipeFd, F_SETFD, 0);
    200                 fdsToIgnore = new int[]{childPipeFd.getInt$(), serverPipeFd.getInt$()};
    201             } catch (ErrnoException errnoEx) {
    202                 throw new IllegalStateException("Unable to set up pipe for invoke-with", errnoEx);
    203             }
    204         }
    205 
    206         /**
    207          * In order to avoid leaking descriptors to the Zygote child,
    208          * the native code must close the two Zygote socket descriptors
    209          * in the child process before it switches from Zygote-root to
    210          * the UID and privileges of the application being launched.
    211          *
    212          * In order to avoid "bad file descriptor" errors when the
    213          * two LocalSocket objects are closed, the Posix file
    214          * descriptors are released via a dup2() call which closes
    215          * the socket and substitutes an open descriptor to /dev/null.
    216          */
    217 
    218         int [] fdsToClose = { -1, -1 };
    219 
    220         FileDescriptor fd = mSocket.getFileDescriptor();
    221 
    222         if (fd != null) {
    223             fdsToClose[0] = fd.getInt$();
    224         }
    225 
    226         fd = zygoteServer.getServerSocketFileDescriptor();
    227 
    228         if (fd != null) {
    229             fdsToClose[1] = fd.getInt$();
    230         }
    231 
    232         fd = null;
    233 
    234         pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
    235                 parsedArgs.runtimeFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
    236                 parsedArgs.niceName, fdsToClose, fdsToIgnore, parsedArgs.startChildZygote,
    237                 parsedArgs.instructionSet, parsedArgs.appDataDir);
    238 
    239         try {
    240             if (pid == 0) {
    241                 // in child
    242                 zygoteServer.setForkChild();
    243 
    244                 zygoteServer.closeServerSocket();
    245                 IoUtils.closeQuietly(serverPipeFd);
    246                 serverPipeFd = null;
    247 
    248                 return handleChildProc(parsedArgs, descriptors, childPipeFd,
    249                         parsedArgs.startChildZygote);
    250             } else {
    251                 // In the parent. A pid < 0 indicates a failure and will be handled in
    252                 // handleParentProc.
    253                 IoUtils.closeQuietly(childPipeFd);
    254                 childPipeFd = null;
    255                 handleParentProc(pid, descriptors, serverPipeFd);
    256                 return null;
    257             }
    258         } finally {
    259             IoUtils.closeQuietly(childPipeFd);
    260             IoUtils.closeQuietly(serverPipeFd);
    261         }
    262     }
    263 
    264     private void handleAbiListQuery() {
    265         try {
    266             final byte[] abiListBytes = abiList.getBytes(StandardCharsets.US_ASCII);
    267             mSocketOutStream.writeInt(abiListBytes.length);
    268             mSocketOutStream.write(abiListBytes);
    269         } catch (IOException ioe) {
    270             throw new IllegalStateException("Error writing to command socket", ioe);
    271         }
    272     }
    273 
    274     /**
    275      * Preloads resources if the zygote is in lazily preload mode. Writes the result of the
    276      * preload operation; {@code 0} when a preload was initiated due to this request and {@code 1}
    277      * if no preload was initiated. The latter implies that the zygote is not configured to load
    278      * resources lazy or that the zygote has already handled a previous request to handlePreload.
    279      */
    280     private void handlePreload() {
    281         try {
    282             if (isPreloadComplete()) {
    283                 mSocketOutStream.writeInt(1);
    284             } else {
    285                 preload();
    286                 mSocketOutStream.writeInt(0);
    287             }
    288         } catch (IOException ioe) {
    289             throw new IllegalStateException("Error writing to command socket", ioe);
    290         }
    291     }
    292 
    293     private void handleApiBlacklistExemptions(String[] exemptions) {
    294         try {
    295             ZygoteInit.setApiBlacklistExemptions(exemptions);
    296             mSocketOutStream.writeInt(0);
    297         } catch (IOException ioe) {
    298             throw new IllegalStateException("Error writing to command socket", ioe);
    299         }
    300     }
    301 
    302     private void handleHiddenApiAccessLogSampleRate(int percent) {
    303         try {
    304             ZygoteInit.setHiddenApiAccessLogSampleRate(percent);
    305             mSocketOutStream.writeInt(0);
    306         } catch (IOException ioe) {
    307             throw new IllegalStateException("Error writing to command socket", ioe);
    308         }
    309     }
    310 
    311     protected void preload() {
    312         ZygoteInit.lazyPreload();
    313     }
    314 
    315     protected boolean isPreloadComplete() {
    316         return ZygoteInit.isPreloadComplete();
    317     }
    318 
    319     protected DataOutputStream getSocketOutputStream() {
    320         return mSocketOutStream;
    321     }
    322 
    323     protected void handlePreloadPackage(String packagePath, String libsPath, String libFileName,
    324             String cacheKey) {
    325         throw new RuntimeException("Zyogte does not support package preloading");
    326     }
    327 
    328     /**
    329      * Closes socket associated with this connection.
    330      */
    331     void closeSocket() {
    332         try {
    333             mSocket.close();
    334         } catch (IOException ex) {
    335             Log.e(TAG, "Exception while closing command "
    336                     + "socket in parent", ex);
    337         }
    338     }
    339 
    340     boolean isClosedByPeer() {
    341         return isEof;
    342     }
    343 
    344     /**
    345      * Handles argument parsing for args related to the zygote spawner.
    346      *
    347      * Current recognized args:
    348      * <ul>
    349      *   <li> --setuid=<i>uid of child process, defaults to 0</i>
    350      *   <li> --setgid=<i>gid of child process, defaults to 0</i>
    351      *   <li> --setgroups=<i>comma-separated list of supplimentary gid's</i>
    352      *   <li> --capabilities=<i>a pair of comma-separated integer strings
    353      * indicating Linux capabilities(2) set for child. The first string
    354      * represents the <code>permitted</code> set, and the second the
    355      * <code>effective</code> set. Precede each with 0 or
    356      * 0x for octal or hexidecimal value. If unspecified, both default to 0.
    357      * This parameter is only applied if the uid of the new process will
    358      * be non-0. </i>
    359      *   <li> --rlimit=r,c,m<i>tuple of values for setrlimit() call.
    360      *    <code>r</code> is the resource, <code>c</code> and <code>m</code>
    361      *    are the settings for current and max value.</i>
    362      *   <li> --instruction-set=<i>instruction-set-string</i> which instruction set to use/emulate.
    363      *   <li> --nice-name=<i>nice name to appear in ps</i>
    364      *   <li> --runtime-args indicates that the remaining arg list should
    365      * be handed off to com.android.internal.os.RuntimeInit, rather than
    366      * processed directly.
    367      * Android runtime startup (eg, Binder initialization) is also eschewed.
    368      *   <li> [--] &lt;args for RuntimeInit &gt;
    369      * </ul>
    370      */
    371     static class Arguments {
    372         /** from --setuid */
    373         int uid = 0;
    374         boolean uidSpecified;
    375 
    376         /** from --setgid */
    377         int gid = 0;
    378         boolean gidSpecified;
    379 
    380         /** from --setgroups */
    381         int[] gids;
    382 
    383         /**
    384          * From --runtime-flags.
    385          */
    386         int runtimeFlags;
    387 
    388         /** From --mount-external */
    389         int mountExternal = Zygote.MOUNT_EXTERNAL_NONE;
    390 
    391         /** from --target-sdk-version. */
    392         int targetSdkVersion;
    393         boolean targetSdkVersionSpecified;
    394 
    395         /** from --nice-name */
    396         String niceName;
    397 
    398         /** from --capabilities */
    399         boolean capabilitiesSpecified;
    400         long permittedCapabilities;
    401         long effectiveCapabilities;
    402 
    403         /** from --seinfo */
    404         boolean seInfoSpecified;
    405         String seInfo;
    406 
    407         /** from all --rlimit=r,c,m */
    408         ArrayList<int[]> rlimits;
    409 
    410         /** from --invoke-with */
    411         String invokeWith;
    412 
    413         /**
    414          * Any args after and including the first non-option arg
    415          * (or after a '--')
    416          */
    417         String remainingArgs[];
    418 
    419         /**
    420          * Whether the current arguments constitute an ABI list query.
    421          */
    422         boolean abiListQuery;
    423 
    424         /**
    425          * The instruction set to use, or null when not important.
    426          */
    427         String instructionSet;
    428 
    429         /**
    430          * The app data directory. May be null, e.g., for the system server. Note that this might
    431          * not be reliable in the case of process-sharing apps.
    432          */
    433         String appDataDir;
    434 
    435         /**
    436          * The APK path of the package to preload, when using --preload-package.
    437          */
    438         String preloadPackage;
    439 
    440         /**
    441          * The native library path of the package to preload, when using --preload-package.
    442          */
    443         String preloadPackageLibs;
    444 
    445         /**
    446          * The filename of the native library to preload, when using --preload-package.
    447          */
    448         String preloadPackageLibFileName;
    449 
    450         /**
    451          * The cache key under which to enter the preloaded package into the classloader cache,
    452          * when using --preload-package.
    453          */
    454         String preloadPackageCacheKey;
    455 
    456         /**
    457          * Whether this is a request to start preloading the default resources and classes.
    458          * This argument only makes sense when the zygote is in lazy preload mode (i.e, when
    459          * it's started with --enable-lazy-preload).
    460          */
    461         boolean preloadDefault;
    462 
    463         /**
    464          * Whether this is a request to start a zygote process as a child of this zygote.
    465          * Set with --start-child-zygote. The remaining arguments must include the
    466          * CHILD_ZYGOTE_SOCKET_NAME_ARG flag to indicate the abstract socket name that
    467          * should be used for communication.
    468          */
    469         boolean startChildZygote;
    470 
    471         /**
    472          * Exemptions from API blacklisting. These are sent to the pre-forked zygote at boot time,
    473          * or when they change, via --set-api-blacklist-exemptions.
    474          */
    475         String[] apiBlacklistExemptions;
    476 
    477         /**
    478          * Sampling rate for logging hidden API accesses to the event log. This is sent to the
    479          * pre-forked zygote at boot time, or when it changes, via --hidden-api-log-sampling-rate.
    480          */
    481         int hiddenApiAccessLogSampleRate = -1;
    482 
    483         /**
    484          * Constructs instance and parses args
    485          * @param args zygote command-line args
    486          * @throws IllegalArgumentException
    487          */
    488         Arguments(String args[]) throws IllegalArgumentException {
    489             parseArgs(args);
    490         }
    491 
    492         /**
    493          * Parses the commandline arguments intended for the Zygote spawner
    494          * (such as "--setuid=" and "--setgid=") and creates an array
    495          * containing the remaining args.
    496          *
    497          * Per security review bug #1112214, duplicate args are disallowed in
    498          * critical cases to make injection harder.
    499          */
    500         private void parseArgs(String args[])
    501                 throws IllegalArgumentException {
    502             int curArg = 0;
    503 
    504             boolean seenRuntimeArgs = false;
    505 
    506             boolean expectRuntimeArgs = true;
    507             for ( /* curArg */ ; curArg < args.length; curArg++) {
    508                 String arg = args[curArg];
    509 
    510                 if (arg.equals("--")) {
    511                     curArg++;
    512                     break;
    513                 } else if (arg.startsWith("--setuid=")) {
    514                     if (uidSpecified) {
    515                         throw new IllegalArgumentException(
    516                                 "Duplicate arg specified");
    517                     }
    518                     uidSpecified = true;
    519                     uid = Integer.parseInt(
    520                             arg.substring(arg.indexOf('=') + 1));
    521                 } else if (arg.startsWith("--setgid=")) {
    522                     if (gidSpecified) {
    523                         throw new IllegalArgumentException(
    524                                 "Duplicate arg specified");
    525                     }
    526                     gidSpecified = true;
    527                     gid = Integer.parseInt(
    528                             arg.substring(arg.indexOf('=') + 1));
    529                 } else if (arg.startsWith("--target-sdk-version=")) {
    530                     if (targetSdkVersionSpecified) {
    531                         throw new IllegalArgumentException(
    532                                 "Duplicate target-sdk-version specified");
    533                     }
    534                     targetSdkVersionSpecified = true;
    535                     targetSdkVersion = Integer.parseInt(
    536                             arg.substring(arg.indexOf('=') + 1));
    537                 } else if (arg.equals("--runtime-args")) {
    538                     seenRuntimeArgs = true;
    539                 } else if (arg.startsWith("--runtime-flags=")) {
    540                     runtimeFlags = Integer.parseInt(
    541                             arg.substring(arg.indexOf('=') + 1));
    542                 } else if (arg.startsWith("--seinfo=")) {
    543                     if (seInfoSpecified) {
    544                         throw new IllegalArgumentException(
    545                                 "Duplicate arg specified");
    546                     }
    547                     seInfoSpecified = true;
    548                     seInfo = arg.substring(arg.indexOf('=') + 1);
    549                 } else if (arg.startsWith("--capabilities=")) {
    550                     if (capabilitiesSpecified) {
    551                         throw new IllegalArgumentException(
    552                                 "Duplicate arg specified");
    553                     }
    554                     capabilitiesSpecified = true;
    555                     String capString = arg.substring(arg.indexOf('=')+1);
    556 
    557                     String[] capStrings = capString.split(",", 2);
    558 
    559                     if (capStrings.length == 1) {
    560                         effectiveCapabilities = Long.decode(capStrings[0]);
    561                         permittedCapabilities = effectiveCapabilities;
    562                     } else {
    563                         permittedCapabilities = Long.decode(capStrings[0]);
    564                         effectiveCapabilities = Long.decode(capStrings[1]);
    565                     }
    566                 } else if (arg.startsWith("--rlimit=")) {
    567                     // Duplicate --rlimit arguments are specifically allowed.
    568                     String[] limitStrings
    569                             = arg.substring(arg.indexOf('=')+1).split(",");
    570 
    571                     if (limitStrings.length != 3) {
    572                         throw new IllegalArgumentException(
    573                                 "--rlimit= should have 3 comma-delimited ints");
    574                     }
    575                     int[] rlimitTuple = new int[limitStrings.length];
    576 
    577                     for(int i=0; i < limitStrings.length; i++) {
    578                         rlimitTuple[i] = Integer.parseInt(limitStrings[i]);
    579                     }
    580 
    581                     if (rlimits == null) {
    582                         rlimits = new ArrayList();
    583                     }
    584 
    585                     rlimits.add(rlimitTuple);
    586                 } else if (arg.startsWith("--setgroups=")) {
    587                     if (gids != null) {
    588                         throw new IllegalArgumentException(
    589                                 "Duplicate arg specified");
    590                     }
    591 
    592                     String[] params
    593                             = arg.substring(arg.indexOf('=') + 1).split(",");
    594 
    595                     gids = new int[params.length];
    596 
    597                     for (int i = params.length - 1; i >= 0 ; i--) {
    598                         gids[i] = Integer.parseInt(params[i]);
    599                     }
    600                 } else if (arg.equals("--invoke-with")) {
    601                     if (invokeWith != null) {
    602                         throw new IllegalArgumentException(
    603                                 "Duplicate arg specified");
    604                     }
    605                     try {
    606                         invokeWith = args[++curArg];
    607                     } catch (IndexOutOfBoundsException ex) {
    608                         throw new IllegalArgumentException(
    609                                 "--invoke-with requires argument");
    610                     }
    611                 } else if (arg.startsWith("--nice-name=")) {
    612                     if (niceName != null) {
    613                         throw new IllegalArgumentException(
    614                                 "Duplicate arg specified");
    615                     }
    616                     niceName = arg.substring(arg.indexOf('=') + 1);
    617                 } else if (arg.equals("--mount-external-default")) {
    618                     mountExternal = Zygote.MOUNT_EXTERNAL_DEFAULT;
    619                 } else if (arg.equals("--mount-external-read")) {
    620                     mountExternal = Zygote.MOUNT_EXTERNAL_READ;
    621                 } else if (arg.equals("--mount-external-write")) {
    622                     mountExternal = Zygote.MOUNT_EXTERNAL_WRITE;
    623                 } else if (arg.equals("--query-abi-list")) {
    624                     abiListQuery = true;
    625                 } else if (arg.startsWith("--instruction-set=")) {
    626                     instructionSet = arg.substring(arg.indexOf('=') + 1);
    627                 } else if (arg.startsWith("--app-data-dir=")) {
    628                     appDataDir = arg.substring(arg.indexOf('=') + 1);
    629                 } else if (arg.equals("--preload-package")) {
    630                     preloadPackage = args[++curArg];
    631                     preloadPackageLibs = args[++curArg];
    632                     preloadPackageLibFileName = args[++curArg];
    633                     preloadPackageCacheKey = args[++curArg];
    634                 } else if (arg.equals("--preload-default")) {
    635                     preloadDefault = true;
    636                     expectRuntimeArgs = false;
    637                 } else if (arg.equals("--start-child-zygote")) {
    638                     startChildZygote = true;
    639                 } else if (arg.equals("--set-api-blacklist-exemptions")) {
    640                     // consume all remaining args; this is a stand-alone command, never included
    641                     // with the regular fork command.
    642                     apiBlacklistExemptions = Arrays.copyOfRange(args, curArg + 1, args.length);
    643                     curArg = args.length;
    644                     expectRuntimeArgs = false;
    645                 } else if (arg.startsWith("--hidden-api-log-sampling-rate=")) {
    646                     String rateStr = arg.substring(arg.indexOf('=') + 1);
    647                     try {
    648                         hiddenApiAccessLogSampleRate = Integer.parseInt(rateStr);
    649                     } catch (NumberFormatException nfe) {
    650                         throw new IllegalArgumentException(
    651                                 "Invalid log sampling rate: " + rateStr, nfe);
    652                     }
    653                     expectRuntimeArgs = false;
    654                 } else {
    655                     break;
    656                 }
    657             }
    658 
    659             if (abiListQuery) {
    660                 if (args.length - curArg > 0) {
    661                     throw new IllegalArgumentException("Unexpected arguments after --query-abi-list.");
    662                 }
    663             } else if (preloadPackage != null) {
    664                 if (args.length - curArg > 0) {
    665                     throw new IllegalArgumentException(
    666                             "Unexpected arguments after --preload-package.");
    667                 }
    668             } else if (expectRuntimeArgs) {
    669                 if (!seenRuntimeArgs) {
    670                     throw new IllegalArgumentException("Unexpected argument : " + args[curArg]);
    671                 }
    672 
    673                 remainingArgs = new String[args.length - curArg];
    674                 System.arraycopy(args, curArg, remainingArgs, 0, remainingArgs.length);
    675             }
    676 
    677             if (startChildZygote) {
    678                 boolean seenChildSocketArg = false;
    679                 for (String arg : remainingArgs) {
    680                     if (arg.startsWith(Zygote.CHILD_ZYGOTE_SOCKET_NAME_ARG)) {
    681                         seenChildSocketArg = true;
    682                         break;
    683                     }
    684                 }
    685                 if (!seenChildSocketArg) {
    686                     throw new IllegalArgumentException("--start-child-zygote specified " +
    687                             "without " + Zygote.CHILD_ZYGOTE_SOCKET_NAME_ARG);
    688                 }
    689             }
    690         }
    691     }
    692 
    693     /**
    694      * Reads an argument list from the command socket/
    695      * @return Argument list or null if EOF is reached
    696      * @throws IOException passed straight through
    697      */
    698     private String[] readArgumentList()
    699             throws IOException {
    700 
    701         /**
    702          * See android.os.Process.zygoteSendArgsAndGetPid()
    703          * Presently the wire format to the zygote process is:
    704          * a) a count of arguments (argc, in essence)
    705          * b) a number of newline-separated argument strings equal to count
    706          *
    707          * After the zygote process reads these it will write the pid of
    708          * the child or -1 on failure.
    709          */
    710 
    711         int argc;
    712 
    713         try {
    714             String s = mSocketReader.readLine();
    715 
    716             if (s == null) {
    717                 // EOF reached.
    718                 return null;
    719             }
    720             argc = Integer.parseInt(s);
    721         } catch (NumberFormatException ex) {
    722             Log.e(TAG, "invalid Zygote wire format: non-int at argc");
    723             throw new IOException("invalid wire format");
    724         }
    725 
    726         // See bug 1092107: large argc can be used for a DOS attack
    727         if (argc > MAX_ZYGOTE_ARGC) {
    728             throw new IOException("max arg count exceeded");
    729         }
    730 
    731         String[] result = new String[argc];
    732         for (int i = 0; i < argc; i++) {
    733             result[i] = mSocketReader.readLine();
    734             if (result[i] == null) {
    735                 // We got an unexpected EOF.
    736                 throw new IOException("truncated request");
    737             }
    738         }
    739 
    740         return result;
    741     }
    742 
    743     /**
    744      * uid 1000 (Process.SYSTEM_UID) may specify any uid &gt; 1000 in normal
    745      * operation. It may also specify any gid and setgroups() list it chooses.
    746      * In factory test mode, it may specify any UID.
    747      *
    748      * @param args non-null; zygote spawner arguments
    749      * @param peer non-null; peer credentials
    750      * @throws ZygoteSecurityException
    751      */
    752     private static void applyUidSecurityPolicy(Arguments args, Credentials peer)
    753             throws ZygoteSecurityException {
    754 
    755         if (peer.getUid() == Process.SYSTEM_UID) {
    756             /* In normal operation, SYSTEM_UID can only specify a restricted
    757              * set of UIDs. In factory test mode, SYSTEM_UID may specify any uid.
    758              */
    759             boolean uidRestricted = FactoryTest.getMode() == FactoryTest.FACTORY_TEST_OFF;
    760 
    761             if (uidRestricted && args.uidSpecified && (args.uid < Process.SYSTEM_UID)) {
    762                 throw new ZygoteSecurityException(
    763                         "System UID may not launch process with UID < "
    764                         + Process.SYSTEM_UID);
    765             }
    766         }
    767 
    768         // If not otherwise specified, uid and gid are inherited from peer
    769         if (!args.uidSpecified) {
    770             args.uid = peer.getUid();
    771             args.uidSpecified = true;
    772         }
    773         if (!args.gidSpecified) {
    774             args.gid = peer.getGid();
    775             args.gidSpecified = true;
    776         }
    777     }
    778 
    779     /**
    780      * Applies debugger system properties to the zygote arguments.
    781      *
    782      * If "ro.debuggable" is "1", all apps are debuggable. Otherwise,
    783      * the debugger state is specified via the "--enable-jdwp" flag
    784      * in the spawn request.
    785      *
    786      * @param args non-null; zygote spawner args
    787      */
    788     public static void applyDebuggerSystemProperty(Arguments args) {
    789         if (RoSystemProperties.DEBUGGABLE) {
    790             args.runtimeFlags |= Zygote.DEBUG_ENABLE_JDWP;
    791         }
    792     }
    793 
    794     /**
    795      * Applies zygote security policy.
    796      * Based on the credentials of the process issuing a zygote command:
    797      * <ol>
    798      * <li> uid 0 (root) may specify --invoke-with to launch Zygote with a
    799      * wrapper command.
    800      * <li> Any other uid may not specify any invoke-with argument.
    801      * </ul>
    802      *
    803      * @param args non-null; zygote spawner arguments
    804      * @param peer non-null; peer credentials
    805      * @throws ZygoteSecurityException
    806      */
    807     private static void applyInvokeWithSecurityPolicy(Arguments args, Credentials peer)
    808             throws ZygoteSecurityException {
    809         int peerUid = peer.getUid();
    810 
    811         if (args.invokeWith != null && peerUid != 0 &&
    812             (args.runtimeFlags & Zygote.DEBUG_ENABLE_JDWP) == 0) {
    813             throw new ZygoteSecurityException("Peer is permitted to specify an"
    814                     + "explicit invoke-with wrapper command only for debuggable"
    815                     + "applications.");
    816         }
    817     }
    818 
    819     /**
    820      * Applies invoke-with system properties to the zygote arguments.
    821      *
    822      * @param args non-null; zygote args
    823      */
    824     public static void applyInvokeWithSystemProperty(Arguments args) {
    825         if (args.invokeWith == null && args.niceName != null) {
    826             String property = "wrap." + args.niceName;
    827             args.invokeWith = SystemProperties.get(property);
    828             if (args.invokeWith != null && args.invokeWith.length() == 0) {
    829                 args.invokeWith = null;
    830             }
    831         }
    832     }
    833 
    834     /**
    835      * Handles post-fork setup of child proc, closing sockets as appropriate,
    836      * reopen stdio as appropriate, and ultimately throwing MethodAndArgsCaller
    837      * if successful or returning if failed.
    838      *
    839      * @param parsedArgs non-null; zygote args
    840      * @param descriptors null-ok; new file descriptors for stdio if available.
    841      * @param pipeFd null-ok; pipe for communication back to Zygote.
    842      * @param isZygote whether this new child process is itself a new Zygote.
    843      */
    844     private Runnable handleChildProc(Arguments parsedArgs, FileDescriptor[] descriptors,
    845             FileDescriptor pipeFd, boolean isZygote) {
    846         /**
    847          * By the time we get here, the native code has closed the two actual Zygote
    848          * socket connections, and substituted /dev/null in their place.  The LocalSocket
    849          * objects still need to be closed properly.
    850          */
    851 
    852         closeSocket();
    853         if (descriptors != null) {
    854             try {
    855                 Os.dup2(descriptors[0], STDIN_FILENO);
    856                 Os.dup2(descriptors[1], STDOUT_FILENO);
    857                 Os.dup2(descriptors[2], STDERR_FILENO);
    858 
    859                 for (FileDescriptor fd: descriptors) {
    860                     IoUtils.closeQuietly(fd);
    861                 }
    862             } catch (ErrnoException ex) {
    863                 Log.e(TAG, "Error reopening stdio", ex);
    864             }
    865         }
    866 
    867         if (parsedArgs.niceName != null) {
    868             Process.setArgV0(parsedArgs.niceName);
    869         }
    870 
    871         // End of the postFork event.
    872         Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
    873         if (parsedArgs.invokeWith != null) {
    874             WrapperInit.execApplication(parsedArgs.invokeWith,
    875                     parsedArgs.niceName, parsedArgs.targetSdkVersion,
    876                     VMRuntime.getCurrentInstructionSet(),
    877                     pipeFd, parsedArgs.remainingArgs);
    878 
    879             // Should not get here.
    880             throw new IllegalStateException("WrapperInit.execApplication unexpectedly returned");
    881         } else {
    882             if (!isZygote) {
    883                 return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs,
    884                         null /* classLoader */);
    885             } else {
    886                 return ZygoteInit.childZygoteInit(parsedArgs.targetSdkVersion,
    887                         parsedArgs.remainingArgs, null /* classLoader */);
    888             }
    889         }
    890     }
    891 
    892     /**
    893      * Handles post-fork cleanup of parent proc
    894      *
    895      * @param pid != 0; pid of child if &gt; 0 or indication of failed fork
    896      * if &lt; 0;
    897      * @param descriptors null-ok; file descriptors for child's new stdio if
    898      * specified.
    899      * @param pipeFd null-ok; pipe for communication with child.
    900      */
    901     private void handleParentProc(int pid, FileDescriptor[] descriptors, FileDescriptor pipeFd) {
    902         if (pid > 0) {
    903             setChildPgid(pid);
    904         }
    905 
    906         if (descriptors != null) {
    907             for (FileDescriptor fd: descriptors) {
    908                 IoUtils.closeQuietly(fd);
    909             }
    910         }
    911 
    912         boolean usingWrapper = false;
    913         if (pipeFd != null && pid > 0) {
    914             int innerPid = -1;
    915             try {
    916                 // Do a busy loop here. We can't guarantee that a failure (and thus an exception
    917                 // bail) happens in a timely manner.
    918                 final int BYTES_REQUIRED = 4;  // Bytes in an int.
    919 
    920                 StructPollfd fds[] = new StructPollfd[] {
    921                         new StructPollfd()
    922                 };
    923 
    924                 byte data[] = new byte[BYTES_REQUIRED];
    925 
    926                 int remainingSleepTime = WRAPPED_PID_TIMEOUT_MILLIS;
    927                 int dataIndex = 0;
    928                 long startTime = System.nanoTime();
    929 
    930                 while (dataIndex < data.length && remainingSleepTime > 0) {
    931                     fds[0].fd = pipeFd;
    932                     fds[0].events = (short) POLLIN;
    933                     fds[0].revents = 0;
    934                     fds[0].userData = null;
    935 
    936                     int res = android.system.Os.poll(fds, remainingSleepTime);
    937                     long endTime = System.nanoTime();
    938                     int elapsedTimeMs = (int)((endTime - startTime) / 1000000l);
    939                     remainingSleepTime = WRAPPED_PID_TIMEOUT_MILLIS - elapsedTimeMs;
    940 
    941                     if (res > 0) {
    942                         if ((fds[0].revents & POLLIN) != 0) {
    943                             // Only read one byte, so as not to block.
    944                             int readBytes = android.system.Os.read(pipeFd, data, dataIndex, 1);
    945                             if (readBytes < 0) {
    946                                 throw new RuntimeException("Some error");
    947                             }
    948                             dataIndex += readBytes;
    949                         } else {
    950                             // Error case. revents should contain one of the error bits.
    951                             break;
    952                         }
    953                     } else if (res == 0) {
    954                         Log.w(TAG, "Timed out waiting for child.");
    955                     }
    956                 }
    957 
    958                 if (dataIndex == data.length) {
    959                     DataInputStream is = new DataInputStream(new ByteArrayInputStream(data));
    960                     innerPid = is.readInt();
    961                 }
    962 
    963                 if (innerPid == -1) {
    964                     Log.w(TAG, "Error reading pid from wrapped process, child may have died");
    965                 }
    966             } catch (Exception ex) {
    967                 Log.w(TAG, "Error reading pid from wrapped process, child may have died", ex);
    968             }
    969 
    970             // Ensure that the pid reported by the wrapped process is either the
    971             // child process that we forked, or a descendant of it.
    972             if (innerPid > 0) {
    973                 int parentPid = innerPid;
    974                 while (parentPid > 0 && parentPid != pid) {
    975                     parentPid = Process.getParentPid(parentPid);
    976                 }
    977                 if (parentPid > 0) {
    978                     Log.i(TAG, "Wrapped process has pid " + innerPid);
    979                     pid = innerPid;
    980                     usingWrapper = true;
    981                 } else {
    982                     Log.w(TAG, "Wrapped process reported a pid that is not a child of "
    983                             + "the process that we forked: childPid=" + pid
    984                             + " innerPid=" + innerPid);
    985                 }
    986             }
    987         }
    988 
    989         try {
    990             mSocketOutStream.writeInt(pid);
    991             mSocketOutStream.writeBoolean(usingWrapper);
    992         } catch (IOException ex) {
    993             throw new IllegalStateException("Error writing to command socket", ex);
    994         }
    995     }
    996 
    997     private void setChildPgid(int pid) {
    998         // Try to move the new child into the peer's process group.
    999         try {
   1000             Os.setpgid(pid, Os.getpgid(peer.getPid()));
   1001         } catch (ErrnoException ex) {
   1002             // This exception is expected in the case where
   1003             // the peer is not in our session
   1004             // TODO get rid of this log message in the case where
   1005             // getsid(0) != getsid(peer.getPid())
   1006             Log.i(TAG, "Zygote: setpgid failed. This is "
   1007                 + "normal if peer is not in our session");
   1008         }
   1009     }
   1010 }
   1011