/**
   * Runs the zygote in accept-and-fork mode. In this mode, each peer gets its own zygote spawner
   * process. This code is retained for reference only.
   *
   * @throws MethodAndArgsCaller in a child process when a main() should be executed.
   */
  private static void runForkMode() throws MethodAndArgsCaller {
    while (true) {
      ZygoteConnection peer = acceptCommandPeer();

      int pid;

      pid = Zygote.fork();

      if (pid == 0) {
        // The child process should handle the peer requests

        // The child does not accept any more connections
        try {
          sServerSocket.close();
        } catch (IOException ex) {
          Log.e(TAG, "Zygote Child: error closing sockets", ex);
        } finally {
          sServerSocket = null;
        }

        peer.run();
        break;
      } else if (pid > 0) {
        peer.closeSocket();
      } else {
        throw new RuntimeException("Error invoking fork()");
      }
    }
  }
示例#2
0
  /**
   * Handles post-fork setup of child proc, closing sockets as appropriate, reopen stdio as
   * appropriate, and ultimately throwing MethodAndArgsCaller if successful or returning if failed.
   *
   * @param parsedArgs non-null; zygote args
   * @param descriptors null-ok; new file descriptors for stdio if available.
   * @param pipeFd null-ok; pipe for communication back to Zygote.
   * @param newStderr null-ok; stream to use for stderr until stdio is reopened.
   * @throws ZygoteInit.MethodAndArgsCaller on success to trampoline to code that invokes static
   *     main.
   */
  private void handleChildProc(
      Arguments parsedArgs,
      FileDescriptor[] descriptors,
      FileDescriptor pipeFd,
      PrintStream newStderr)
      throws ZygoteInit.MethodAndArgsCaller {

    /*
     * Close the socket, unless we're in "peer wait" mode, in which
     * case it's used to track the liveness of this process.
     */

    if (parsedArgs.peerWait) {
      try {
        ZygoteInit.setCloseOnExec(mSocket.getFileDescriptor(), true);
        sPeerWaitSocket = mSocket;
      } catch (IOException ex) {
        Log.e(TAG, "Zygote Child: error setting peer wait " + "socket to be close-on-exec", ex);
      }
    } else {
      closeSocket();
      ZygoteInit.closeServerSocket();
    }

    if (descriptors != null) {
      try {
        ZygoteInit.reopenStdio(descriptors[0], descriptors[1], descriptors[2]);

        for (FileDescriptor fd : descriptors) {
          IoUtils.closeQuietly(fd);
        }
        newStderr = System.err;
      } catch (IOException ex) {
        Log.e(TAG, "Error reopening stdio", ex);
      }
    }

    if (parsedArgs.niceName != null) {
      Process.setArgV0(parsedArgs.niceName);
    }

    if (parsedArgs.runtimeInit) {
      if (parsedArgs.invokeWith != null) {
        WrapperInit.execApplication(
            parsedArgs.invokeWith,
            parsedArgs.niceName,
            parsedArgs.targetSdkVersion,
            pipeFd,
            parsedArgs.remainingArgs);
      } else {
        RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs);
      }
    } else {
      String className;
      try {
        className = parsedArgs.remainingArgs[0];
      } catch (ArrayIndexOutOfBoundsException ex) {
        logAndPrintError(newStderr, "Missing required class name argument", null);
        return;
      }

      String[] mainArgs = new String[parsedArgs.remainingArgs.length - 1];
      System.arraycopy(parsedArgs.remainingArgs, 1, mainArgs, 0, mainArgs.length);

      if (parsedArgs.invokeWith != null) {
        WrapperInit.execStandalone(
            parsedArgs.invokeWith, parsedArgs.classpath, className, mainArgs);
      } else {
        ClassLoader cloader;
        if (parsedArgs.classpath != null) {
          cloader = new PathClassLoader(parsedArgs.classpath, ClassLoader.getSystemClassLoader());
        } else {
          cloader = ClassLoader.getSystemClassLoader();
        }

        try {
          ZygoteInit.invokeStaticMain(cloader, className, mainArgs);
        } catch (RuntimeException ex) {
          logAndPrintError(newStderr, "Error starting.", ex);
        }
      }
    }
  }
示例#3
0
  /**
   * Reads one start command from the command socket. If successful, a child is forked and a {@link
   * ZygoteInit.MethodAndArgsCaller} exception is thrown in that child while in the parent process,
   * the method returns normally. On failure, the child is not spawned and messages are printed to
   * the log and stderr. Returns a boolean status value indicating whether an end-of-file on the
   * command socket has been encountered.
   *
   * @return false if command socket should continue to be read from, or true if an end-of-file has
   *     been encountered.
   * @throws ZygoteInit.MethodAndArgsCaller trampoline to invoke main() method in child process
   */
  boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {

    String args[];
    Arguments parsedArgs = null;
    FileDescriptor[] descriptors;

    try {
      args = readArgumentList();
      descriptors = mSocket.getAncillaryFileDescriptors();
    } catch (IOException ex) {
      Log.w(TAG, "IOException on command socket " + ex.getMessage());
      closeSocket();
      return true;
    }

    if (args == null) {
      // EOF reached.
      closeSocket();
      return true;
    }

    /** the stderr of the most recent request, if avail */
    PrintStream newStderr = null;

    if (descriptors != null && descriptors.length >= 3) {
      newStderr = new PrintStream(new FileOutputStream(descriptors[2]));
    }

    int pid = -1;
    FileDescriptor childPipeFd = null;
    FileDescriptor serverPipeFd = null;

    try {
      parsedArgs = new Arguments(args);

      applyUidSecurityPolicy(parsedArgs, peer);
      applyRlimitSecurityPolicy(parsedArgs, peer);
      applyCapabilitiesSecurityPolicy(parsedArgs, peer);
      applyInvokeWithSecurityPolicy(parsedArgs, peer);

      applyDebuggerSystemProperty(parsedArgs);
      applyInvokeWithSystemProperty(parsedArgs);

      int[][] rlimits = null;

      if (parsedArgs.rlimits != null) {
        rlimits = parsedArgs.rlimits.toArray(intArray2d);
      }

      if (parsedArgs.runtimeInit && parsedArgs.invokeWith != null) {
        FileDescriptor[] pipeFds = Libcore.os.pipe();
        childPipeFd = pipeFds[1];
        serverPipeFd = pipeFds[0];
        ZygoteInit.setCloseOnExec(serverPipeFd, true);
      }

      pid =
          Zygote.forkAndSpecialize(
              parsedArgs.uid, parsedArgs.gid, parsedArgs.gids, parsedArgs.debugFlags, rlimits);
    } catch (IOException ex) {
      logAndPrintError(newStderr, "Exception creating pipe", ex);
    } catch (ErrnoException ex) {
      logAndPrintError(newStderr, "Exception creating pipe", ex);
    } catch (IllegalArgumentException ex) {
      logAndPrintError(newStderr, "Invalid zygote arguments", ex);
    } catch (ZygoteSecurityException ex) {
      logAndPrintError(newStderr, "Zygote security policy prevents request: ", ex);
    }

    try {
      if (pid == 0) {
        // in child
        IoUtils.closeQuietly(serverPipeFd);
        serverPipeFd = null;
        handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);

        // should never get here, the child is expected to either
        // throw ZygoteInit.MethodAndArgsCaller or exec().
        return true;
      } else {
        // in parent...pid of < 0 means failure
        IoUtils.closeQuietly(childPipeFd);
        childPipeFd = null;
        return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs);
      }
    } finally {
      IoUtils.closeQuietly(childPipeFd);
      IoUtils.closeQuietly(serverPipeFd);
    }
  }