Use the subprocess factory that uses the Win32 API on Windows.

We should really do something about the mess that is loading our JNI libraries -- io.bazel.EnableJNI is mentioned eight times in the code in various diverse contexts. This change is not the right place to do it, though.

--
MOS_MIGRATED_REVID=126570481
diff --git a/src/main/java/com/google/devtools/build/lib/BUILD b/src/main/java/com/google/devtools/build/lib/BUILD
index 567a65b..f56f688 100644
--- a/src/main/java/com/google/devtools/build/lib/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/BUILD
@@ -864,6 +864,7 @@
         ":unix",
         ":util",
         ":vfs",
+        ":windows",
         "//src/main/java/com/google/devtools/build/docgen:docgen_javalib",
         "//src/main/java/com/google/devtools/build/lib/actions",
         "//src/main/java/com/google/devtools/build/lib/query2",
diff --git a/src/main/java/com/google/devtools/build/lib/runtime/BlazeRuntime.java b/src/main/java/com/google/devtools/build/lib/runtime/BlazeRuntime.java
index f11b51a..f95aecd 100644
--- a/src/main/java/com/google/devtools/build/lib/runtime/BlazeRuntime.java
+++ b/src/main/java/com/google/devtools/build/lib/runtime/BlazeRuntime.java
@@ -71,6 +71,9 @@
 import com.google.devtools.build.lib.server.AfUnixServer;
 import com.google.devtools.build.lib.server.RPCServer;
 import com.google.devtools.build.lib.server.signal.InterruptSignalHandler;
+import com.google.devtools.build.lib.shell.JavaSubprocessFactory;
+import com.google.devtools.build.lib.shell.Subprocess;
+import com.google.devtools.build.lib.shell.SubprocessBuilder;
 import com.google.devtools.build.lib.skyframe.DiffAwareness;
 import com.google.devtools.build.lib.skyframe.PrecomputedValue;
 import com.google.devtools.build.lib.skyframe.SequencedSkyframeExecutorFactory;
@@ -93,6 +96,7 @@
 import com.google.devtools.build.lib.vfs.PathFragment;
 import com.google.devtools.build.lib.vfs.UnixFileSystem;
 import com.google.devtools.build.lib.vfs.WindowsFileSystem;
+import com.google.devtools.build.lib.windows.WindowsSubprocessFactory;
 import com.google.devtools.build.skyframe.SkyFunction;
 import com.google.devtools.build.skyframe.SkyFunctionName;
 import com.google.devtools.common.options.Option;
@@ -893,6 +897,14 @@
     return OS.getCurrent() == OS.WINDOWS ? new WindowsFileSystem() : new UnixFileSystem();
   }
 
+  private static Subprocess.Factory subprocessFactoryImplementation() {
+    if (!"0".equals(System.getProperty("io.bazel.EnableJni")) && OS.getCurrent() == OS.WINDOWS) {
+      return WindowsSubprocessFactory.INSTANCE;
+    } else {
+      return JavaSubprocessFactory.INSTANCE;
+    }
+  }
+
   /**
    * Creates and returns a new Blaze RPCServer. Call {@link RPCServer#serve()} to start the server.
    */
@@ -1028,7 +1040,9 @@
     if (fs == null) {
       fs = fileSystemImplementation();
     }
+
     Path.setFileSystemForSerialization(fs);
+    SubprocessBuilder.setSubprocessFactory(subprocessFactoryImplementation());
 
     Path installBasePath = fs.getPath(installBase);
     Path outputBasePath = fs.getPath(outputBase);
diff --git a/src/main/java/com/google/devtools/build/lib/shell/SubprocessBuilder.java b/src/main/java/com/google/devtools/build/lib/shell/SubprocessBuilder.java
index 0b6ecfb..b89cf96 100644
--- a/src/main/java/com/google/devtools/build/lib/shell/SubprocessBuilder.java
+++ b/src/main/java/com/google/devtools/build/lib/shell/SubprocessBuilder.java
@@ -46,6 +46,12 @@
   private File stderrFile;
   private File workingDirectory;
 
+  private static Subprocess.Factory factory = JavaSubprocessFactory.INSTANCE;
+
+  public static void setSubprocessFactory(Subprocess.Factory factory) {
+    SubprocessBuilder.factory = factory;
+  }
+
   public SubprocessBuilder() {
     stdoutAction = StreamAction.STREAM;
     stderrAction = StreamAction.STREAM;
@@ -154,6 +160,6 @@
   }
 
   public Subprocess start() throws IOException {
-    return JavaSubprocessFactory.INSTANCE.create(this);
+    return factory.create(this);
   }
 }
diff --git a/src/main/java/com/google/devtools/build/lib/windows/WindowsJniLoader.java b/src/main/java/com/google/devtools/build/lib/windows/WindowsJniLoader.java
index b95aa61..2fe564e 100644
--- a/src/main/java/com/google/devtools/build/lib/windows/WindowsJniLoader.java
+++ b/src/main/java/com/google/devtools/build/lib/windows/WindowsJniLoader.java
@@ -18,11 +18,22 @@
  * Loads native code under Windows.
  */
 public class WindowsJniLoader {
-  public static void loadJni() {
+  private static boolean jniLoaded = false;
+  public static synchronized void loadJni() {
+    if (jniLoaded) {
+      return;
+    }
+
     System.loadLibrary("windows_jni");
+    jniLoaded = true;
   }
 
-  public static void loadJniForTesting(String jniDll) {
+  public static synchronized void loadJniForTesting(String jniDll) {
+    if (jniLoaded) {
+      return;
+    }
+
     System.load(jniDll);
+    jniLoaded = true;
   }
 }
diff --git a/src/main/java/com/google/devtools/build/lib/windows/WindowsSubprocessFactory.java b/src/main/java/com/google/devtools/build/lib/windows/WindowsSubprocessFactory.java
index 3a79477..6e7f529 100644
--- a/src/main/java/com/google/devtools/build/lib/windows/WindowsSubprocessFactory.java
+++ b/src/main/java/com/google/devtools/build/lib/windows/WindowsSubprocessFactory.java
@@ -36,6 +36,8 @@
 
   @Override
   public Subprocess create(SubprocessBuilder builder) throws IOException {
+    WindowsJniLoader.loadJni();
+    
     String commandLine = WindowsProcesses.quoteCommandLine(builder.getArgv());
     byte[] env = builder.getEnv() == null ? null : convertEnvToNative(builder.getEnv());