public DaemonStartupInfo startDaemon() {
    String daemonUid = UUID.randomUUID().toString();

    GradleInstallation gradleInstallation = CurrentGradleInstallation.get();
    ModuleRegistry registry = new DefaultModuleRegistry(gradleInstallation);
    ClassPath classpath;
    List<File> searchClassPath;
    if (gradleInstallation == null) {
      // When not running from a Gradle distro, need runtime impl for launcher plus the search path
      // to look for other modules
      classpath = new DefaultClassPath();
      for (Module module : registry.getModule("gradle-launcher").getAllRequiredModules()) {
        classpath = classpath.plus(module.getClasspath());
      }
      searchClassPath = registry.getAdditionalClassPath().getAsFiles();
    } else {
      // When running from a Gradle distro, only need launcher jar. The daemon can find everything
      // from there.
      classpath = registry.getModule("gradle-launcher").getImplementationClasspath();
      searchClassPath = Collections.emptyList();
    }
    if (classpath.isEmpty()) {
      throw new IllegalStateException(
          "Unable to construct a bootstrap classpath when starting the daemon");
    }

    versionValidator.validate(daemonParameters);

    List<String> daemonArgs = new ArrayList<String>();
    daemonArgs.add(daemonParameters.getEffectiveJvm().getJavaExecutable().getAbsolutePath());

    List<String> daemonOpts = daemonParameters.getEffectiveJvmArgs();
    daemonArgs.addAll(daemonOpts);
    daemonArgs.add("-cp");
    daemonArgs.add(CollectionUtils.join(File.pathSeparator, classpath.getAsFiles()));

    if (Boolean.getBoolean("org.gradle.daemon.debug")) {
      daemonArgs.add("-Xdebug");
      daemonArgs.add("-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5005");
    }
    LOGGER.debug("Using daemon args: {}", daemonArgs);

    daemonArgs.add(GradleDaemon.class.getName());
    // Version isn't used, except by a human looking at the output of jps.
    daemonArgs.add(GradleVersion.current().getVersion());

    // Serialize configuration to daemon via the process' stdin
    ByteArrayOutputStream serializedConfig = new ByteArrayOutputStream();
    FlushableEncoder encoder =
        new KryoBackedEncoder(new EncodedStream.EncodedOutput(serializedConfig));
    try {
      encoder.writeString(daemonParameters.getGradleUserHomeDir().getAbsolutePath());
      encoder.writeString(daemonDir.getBaseDir().getAbsolutePath());
      encoder.writeSmallInt(daemonParameters.getIdleTimeout());
      encoder.writeString(daemonUid);
      encoder.writeSmallInt(daemonOpts.size());
      for (String daemonOpt : daemonOpts) {
        encoder.writeString(daemonOpt);
      }
      encoder.writeSmallInt(searchClassPath.size());
      for (File file : searchClassPath) {
        encoder.writeString(file.getAbsolutePath());
      }
      encoder.flush();
    } catch (IOException e) {
      throw new UncheckedIOException(e);
    }
    ByteArrayInputStream stdInput = new ByteArrayInputStream(serializedConfig.toByteArray());

    DaemonStartupInfo daemonInfo = startProcess(daemonArgs, daemonDir.getVersionedDir(), stdInput);
    listener.daemonStarted(daemonInfo);
    return daemonInfo;
  }