/**
   * 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()");
      }
    }
  }
  /** Prepare the arguments and fork for the system server process. */
  private static boolean startSystemServer() throws MethodAndArgsCaller, RuntimeException {
    /* Hardcoded command line to start the system server */
    String args[] = {
      "--setuid=1000",
      "--setgid=1000",
      "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,3001,3002,3003",
      "--capabilities=130104352,130104352",
      "--runtime-init",
      "--nice-name=system_server",
      "com.android.server.SystemServer",
    };
    ZygoteConnection.Arguments parsedArgs = null;

    int pid;

    try {
      parsedArgs = new ZygoteConnection.Arguments(args);

      /*
       * Enable debugging of the system process if *either* the command line flags
       * indicate it should be debuggable or the ro.debuggable system property
       * is set to "1"
       */
      int debugFlags = parsedArgs.debugFlags;
      if ("1".equals(SystemProperties.get("ro.debuggable")))
        debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;

      /* Request to fork the system server process */
      pid =
          Zygote.forkSystemServer(
              parsedArgs.uid, parsedArgs.gid, parsedArgs.gids, debugFlags, null);
    } catch (IllegalArgumentException ex) {
      throw new RuntimeException(ex);
    }

    /* For child process */
    if (pid == 0) {
      handleSystemServerProcess(parsedArgs);
    }

    return true;
  }
  /** Prepare the arguments and fork for the system server process. */
  private static boolean startSystemServer() throws MethodAndArgsCaller, RuntimeException {
    /* Hardcoded command line to start the system server */
    String args[] = {
      "--setuid=1000",
      "--setgid=1000",
      "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,3001,3002,3003,3006,3007",
      "--capabilities=130104352,130104352",
      "--runtime-init",
      "--nice-name=system_server",
      "com.android.server.SystemServer",
    };
    ZygoteConnection.Arguments parsedArgs = null;

    int pid;

    try {
      parsedArgs = new ZygoteConnection.Arguments(args);
      ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
      ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);

      /* Request to fork the system server process */
      pid =
          Zygote.forkSystemServer(
              parsedArgs.uid,
              parsedArgs.gid,
              parsedArgs.gids,
              parsedArgs.debugFlags,
              null,
              parsedArgs.permittedCapabilities,
              parsedArgs.effectiveCapabilities);
    } catch (IllegalArgumentException ex) {
      throw new RuntimeException(ex);
    }

    /* For child process */
    if (pid == 0) {
      handleSystemServerProcess(parsedArgs);
    }

    return true;
  }
  /**
   * 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);
    }
  }