Bug 1056136 - Get rid of SDK dependency for simulator addon. r=jryans, r=gps
authorAlexandre Poirot <poirot.alex@gmail.com>
Thu, 28 Aug 2014 04:58:00 -0400
changeset 223905 87ac83b75957344a0e97a4b6f41da4fd642b48e0
parent 223904 a0ce53c1cc7a32ac504e80a54477e88b00ba6ef1
child 223906 f41c1edabfe8e4c57caaca6d5b08660db3ad496d
push id3979
push userraliiev@mozilla.com
push dateMon, 13 Oct 2014 16:35:44 +0000
treeherdermozilla-beta@30f2cc610691 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjryans, gps
bugs1056136
milestone34.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1056136 - Get rid of SDK dependency for simulator addon. r=jryans, r=gps
b2g/simulator/bootstrap.js
b2g/simulator/build_xpi.py
b2g/simulator/defaults/preferences/prefs.js
b2g/simulator/install.rdf.in
b2g/simulator/lib/main.js
b2g/simulator/lib/simulator-process.js
b2g/simulator/options.xul.in
b2g/simulator/package-overload.json.in
b2g/simulator/package.json
b2g/simulator/packages/subprocess/README.md
b2g/simulator/packages/subprocess/lib/subprocess.js
b2g/simulator/packages/subprocess/lib/subprocess_worker_unix.js
b2g/simulator/packages/subprocess/lib/subprocess_worker_win.js
b2g/simulator/packages/subprocess/package.json
b2g/simulator/packages/subprocess/tests/test-subprocess.js
new file mode 100644
--- /dev/null
+++ b/b2g/simulator/bootstrap.js
@@ -0,0 +1,67 @@
+const Ci = Components.interfaces;
+const Cu = Components.utils;
+
+Cu.import("resource://gre/modules/Services.jsm");
+
+// Useful piece of code from :bent
+// http://mxr.mozilla.org/mozilla-central/source/dom/workers/test/extensions/bootstrap/bootstrap.js
+function registerAddonResourceHandler(data) {
+  let file = data.installPath;
+  let fileuri = file.isDirectory() ?
+                Services.io.newFileURI(file) :
+                Services.io.newURI("jar:" + file.path + "!/", null, null);
+  let resourceName = encodeURIComponent(data.id.replace("@", "at"));
+
+  Services.io.getProtocolHandler("resource").
+              QueryInterface(Ci.nsIResProtocolHandler).
+              setSubstitution(resourceName, fileuri);
+
+  return "resource://" + resourceName + "/";
+}
+
+let mainModule;
+
+function install(data, reason) {}
+function uninstall(data, reason) {}
+
+function startup(data, reason) {
+  let uri = registerAddonResourceHandler(data);
+
+  let loaderModule =
+    Cu.import('resource://gre/modules/commonjs/toolkit/loader.js').Loader;
+  let { Loader, Require, Main } = loaderModule;
+
+  const { ConsoleAPI } = Cu.import("resource://gre/modules/devtools/Console.jsm");
+
+  let loader = Loader({
+    paths: {
+      "./": uri + "lib/",
+      "": "resource://gre/modules/commonjs/"
+    },
+    globals: {
+      console: new ConsoleAPI({
+        prefix: data.id
+      })
+    },
+    modules: {
+      "toolkit/loader": loaderModule,
+      addon: {
+        id: data.id,
+        version: data.version,
+        uri: uri
+      }
+    }
+  });
+
+  let require_ = Require(loader, { id: "./addon" });
+  mainModule = require_("./main");
+}
+
+function shutdown(data, reason) {
+  if (mainModule && mainModule.shutdown) {
+    mainModule.shutdown();
+  }
+}
+
+function uninstall(data, reason) {}
+
--- a/b2g/simulator/build_xpi.py
+++ b/b2g/simulator/build_xpi.py
@@ -13,21 +13,21 @@
 #     * a small firefox addon registering to the app manager
 #     * b2g desktop runtime
 #     * gaia profile
 
 import sys, os, re, subprocess
 from mozbuild.preprocessor import Preprocessor
 from mozbuild.base import MozbuildObject
 from mozbuild.util import ensureParentDir
+from mozpack.mozjar import JarWriter
 from zipfile import ZipFile
 from distutils.version import LooseVersion
 
 ftp_root_path = "/pub/mozilla.org/labs/fxos-simulator"
-UPDATE_LINK = "https://ftp.mozilla.org" + ftp_root_path + "/%(update_path)s/%(xpi_name)s"
 UPDATE_URL = "https://ftp.mozilla.org" + ftp_root_path + "/%(update_path)s/update.rdf"
 XPI_NAME = "fxos-simulator-%(version)s-%(platform)s.xpi"
 
 class GaiaBuilder(object):
     def __init__(self, build, gaia_path):
         self.build = build
         self.gaia_path = gaia_path
 
@@ -38,48 +38,52 @@ class GaiaBuilder(object):
         self.build._run_make(target="profile", directory=self.gaia_path, num_jobs=1, silent=False, append_env=env)
 
     def override_prefs(self, srcfile):
         # Note that each time we call `make profile` in gaia, a fresh new pref file is created
         # cat srcfile >> profile/user.js
         with open(os.path.join(self.gaia_path, "profile", "user.js"), "a") as userJs:
             userJs.write(open(srcfile).read())
 
-def process_package_overload(src, dst, version, app_buildid):
+def preprocess_file(src, dst, version, app_buildid, update_url):
     ensureParentDir(dst)
-    # First replace numeric version like '1.3'
-    # Then replace with 'slashed' version like '1_4'
-    # Finally set the full length addon version like 1.3.20131230
-    # (reduce the app build id to only the build date
-    # as addon manager doesn't handle big ints in addon versions)
+
     defines = {
-        "NUM_VERSION": version,
-        "SLASH_VERSION": version.replace(".", "_"),
-        "FULL_VERSION": ("%s.%s" % (version, app_buildid[:8]))
+        "ADDON_ID": "fxos_" + version.replace(".", "_") + "_simulator@mozilla.org",
+        # (reduce the app build id to only the build date
+        # as addon manager doesn't handle big ints in addon versions)
+        "ADDON_VERSION": ("%s.%s" % (version, app_buildid[:8])),
+        "ADDON_NAME": "Firefox OS " + version + " Simulator",
+        "ADDON_DESCRIPTION": "a Firefox OS " + version + " simulator",
+        "ADDON_UPDATE_URL": update_url
     }
     pp = Preprocessor(defines=defines)
     pp.do_filter("substitution")
     with open(dst, "w") as output:
         with open(src, "r") as input:
             pp.processFile(input=input, output=output)
 
-def add_dir_to_zip(zip, top, pathInZip, blacklist=()):
-    zf = ZipFile(zip, "a")
+def add_dir_to_zip(jar, top, pathInZip, blacklist=()):
     for dirpath, subdirs, files in os.walk(top):
         dir_relpath = os.path.relpath(dirpath, top)
         if dir_relpath.startswith(blacklist):
             continue
-        zf.write(dirpath, os.path.join(pathInZip, dir_relpath))
         for filename in files:
             relpath = os.path.join(dir_relpath, filename)
             if relpath in blacklist:
                 continue
-            zf.write(os.path.join(dirpath, filename),
-                     os.path.join(pathInZip, relpath))
-    zf.close()
+            path = os.path.normpath(os.path.join(pathInZip, relpath))
+            file = open(os.path.join(dirpath, filename), "rb")
+            mode = os.stat(os.path.join(dirpath, filename)).st_mode
+            jar.add(path.encode("ascii"), file, mode=mode)
+
+def add_file_to_zip(jar, path, pathInZip):
+    file = open(path, "rb")
+    mode = os.stat(path).st_mode
+    jar.add(pathInZip.encode("ascii"), file, mode=mode)
 
 def main(platform):
     build = MozbuildObject.from_environment()
     topsrcdir = build.topsrcdir
     distdir = build.distdir
 
     srcdir = os.path.join(topsrcdir, "b2g", "simulator")
 
@@ -102,48 +106,51 @@ def main(platform):
     env = {
       "NOFTU": "1",
       "GAIA_APP_TARGET": "production",
       "SETTINGS_PATH": os.path.join(srcdir, "custom-settings.json")
     }
     builder.profile(env)
     builder.override_prefs(os.path.join(srcdir, "custom-prefs.js"))
 
-    # Substitute version strings in the package manifest overload file
-    manifest_overload = os.path.join(build.topobjdir, "b2g", "simulator", "package-overload.json")
-    process_package_overload(os.path.join(srcdir, "package-overload.json.in"),
-                             manifest_overload,
-                             version,
-                             app_buildid)
-
     # Build the simulator addon xpi
     xpi_name = XPI_NAME % {"version": version, "platform": platform}
     xpi_path = os.path.join(distdir, xpi_name)
 
     update_path = "%s/%s" % (version, platform)
-    update_link = UPDATE_LINK % {"update_path": update_path, "xpi_name": xpi_name}
     update_url = UPDATE_URL % {"update_path": update_path}
-    subprocess.check_call([
-      build.virtualenv_manager.python_path, os.path.join(topsrcdir, "addon-sdk", "source", "bin", "cfx"), "xpi", \
-      "--pkgdir", srcdir, \
-      "--manifest-overload", manifest_overload, \
-      "--strip-sdk", \
-      "--update-link", update_link, \
-      "--update-url", update_url, \
-      "--static-args", "{\"label\": \"Firefox OS %s\"}" % version, \
-      "--output-file", xpi_path \
-    ])
+
+    # Preprocess some files...
+    manifest = os.path.join(build.topobjdir, "b2g", "simulator", "install.rdf")
+    preprocess_file(os.path.join(srcdir, "install.rdf.in"),
+                    manifest,
+                    version,
+                    app_buildid,
+                    update_url)
 
-    # Ship b2g-desktop, but prevent its gaia profile to be shipped in the xpi
-    add_dir_to_zip(xpi_path, os.path.join(distdir, "b2g"), "b2g", ("gaia", "B2G.app/Contents/MacOS/gaia"))
-    # Then ship our own gaia profile
-    add_dir_to_zip(xpi_path, os.path.join(gaia_path, "profile"), "profile")
-    # Add "defaults" directory (required by add-on runner in Firefox 31 and
-    # earlier)
-    add_dir_to_zip(xpi_path, os.path.join(srcdir, "defaults"), "defaults")
+    options_file = os.path.join(build.topobjdir, "b2g", "simulator", "options.xul")
+    preprocess_file(os.path.join(srcdir, "options.xul.in"),
+                    options_file,
+                    version,
+                    app_buildid,
+                    update_url)
+
+    with JarWriter(xpi_path, optimize=False) as zip:
+        # Ship addon files into the .xpi
+        add_dir_to_zip(zip, os.path.join(srcdir, "lib"), "lib")
+        add_file_to_zip(zip, manifest, "install.rdf")
+        add_file_to_zip(zip, os.path.join(srcdir, "bootstrap.js"), "bootstrap.js")
+        add_file_to_zip(zip, options_file, "options.xul")
+        add_file_to_zip(zip, os.path.join(srcdir, "icon.png"), "icon.png")
+        add_file_to_zip(zip, os.path.join(srcdir, "icon64.png"), "icon64.png")
+
+        # Ship b2g-desktop, but prevent its gaia profile to be shipped in the xpi
+        add_dir_to_zip(zip, os.path.join(distdir, "b2g"), "b2g", ("gaia", "B2G.app/Contents/MacOS/gaia"))
+        # Then ship our own gaia profile
+        add_dir_to_zip(zip, os.path.join(gaia_path, "profile"), "profile")
 
 if __name__ == '__main__':
     if 2 != len(sys.argv):
         print("""Usage:
   python {0} MOZ_PKG_PLATFORM
 """.format(sys.argv[0]))
         sys.exit(1)
     main(*sys.argv[1:])
deleted file mode 100644
new file mode 100644
--- /dev/null
+++ b/b2g/simulator/install.rdf.in
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+   - License, v. 2.0. If a copy of the MPL was not distributed with this
+   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:em="http://www.mozilla.org/2004/em-rdf#">
+  <Description about="urn:mozilla:install-manifest">
+    <em:id>@ADDON_ID@</em:id>
+    <em:version>@ADDON_VERSION@</em:version>
+    <em:type>2</em:type>
+    <em:bootstrap>true</em:bootstrap>
+    <em:unpack>true</em:unpack>
+
+    <!-- Firefox -->
+    <em:targetApplication>
+      <Description>
+        <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
+        <em:minVersion>26.0</em:minVersion>
+        <em:maxVersion>30.0</em:maxVersion>
+      </Description>
+    </em:targetApplication>
+
+    <!-- Front End MetaData -->
+    <em:name>@ADDON_NAME@</em:name>
+    <em:description>@ADDON_DESCRIPTION@</em:description>
+    <em:creator>Myk Melez (https://github.com/mykmelez)</em:creator>
+
+    <em:optionsType>2</em:optionsType>
+
+    <em:updateURL>@ADDON_UPDATE_URL@</em:updateURL>
+
+    <em:contributor>Alexandre Poirot (https://github.com/ochameau)</em:contributor>
+    <em:contributor>Anant Narayanan (https://github.com/anantn)</em:contributor>
+    <em:contributor>Brandon Kase (https://github.com/bkase)</em:contributor>
+    <em:contributor>Breck Yunits (https://github.com/breck7)</em:contributor>
+    <em:contributor>César Carruitero (https://github.com/ccarruitero)</em:contributor>
+    <em:contributor>David Gomes (https://github.com/davidgomes)</em:contributor>
+    <em:contributor>Fabrice Desré (https://github.com/fabricedesre)</em:contributor>
+    <em:contributor>Fraser Tweedale (https://github.com/frasertweedale)</em:contributor>
+    <em:contributor>Harald Kirschner (https://github.com/digitarald)</em:contributor>
+    <em:contributor>Jérémie Patonnier (https://github.com/JeremiePat)</em:contributor>
+    <em:contributor>J. Ryan Stinnett (https://github.com/jryans)</em:contributor>
+    <em:contributor>Kan-Ru Chen (陳侃如) (https://github.com/kanru)</em:contributor>
+    <em:contributor>Louis Stowasser (https://github.com/louisstow)</em:contributor>
+    <em:contributor>Luca Greco (https://github.com/rpl)</em:contributor>
+    <em:contributor>Matthew Claypotch (https://github.com/potch)</em:contributor>
+    <em:contributor>Matthew Riley MacPherson (https://github.com/tofumatt)</em:contributor>
+    <em:contributor>Nick Desaulniers (https://github.com/nickdesaulniers)</em:contributor>
+    <em:contributor>Soumen Ganguly (https://github.com/SoumenG)</em:contributor>
+    <em:contributor>Sudheesh Singanamalla (https://github.com/sudheesh001)</em:contributor>
+    <em:contributor>Victor Bjelkholm (https://github.com/VictorBjelkholm)</em:contributor>
+  </Description>
+</RDF>
--- a/b2g/simulator/lib/main.js
+++ b/b2g/simulator/lib/main.js
@@ -2,19 +2,18 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  */
 
 const { Cc, Ci, Cu } = require("chrome");
 
 const { SimulatorProcess } = require("./simulator-process");
 const { Promise: promise } = Cu.import("resource://gre/modules/Promise.jsm", {});
-const Self = require("sdk/self");
-const System = require("sdk/system");
 const { Simulator } = Cu.import("resource://gre/modules/devtools/Simulator.jsm");
+const { AddonManager } = Cu.import("resource://gre/modules/AddonManager.jsm", {});
 
 let process;
 
 function launch({ port }) {
   // Close already opened simulation
   if (process) {
     return close().then(launch.bind(null, { port: port }));
   }
@@ -30,23 +29,25 @@ function close() {
   if (!process) {
     return promise.resolve();
   }
   let p = process;
   process = null;
   return p.kill();
 }
 
+let appinfo = {};
 
-// Load data generated at build time that
-// expose various information about the runtime we ship
-let appinfo = System.staticArgs;
+AddonManager.getAddonByID(require("addon").id, function (addon) {
+  appinfo.label = addon.name.replace(" Simulator", "");
 
-Simulator.register(appinfo.label, {
-  appinfo: appinfo,
-  launch: launch,
-  close: close
+  Simulator.register(appinfo.label, {
+    appinfo: appinfo,
+    launch: launch,
+    close: close
+  });
 });
 
-require("sdk/system/unload").when(function () {
+exports.shutdown = function () {
   Simulator.unregister(appinfo.label);
   close();
-});
+}
+
--- a/b2g/simulator/lib/simulator-process.js
+++ b/b2g/simulator/lib/simulator-process.js
@@ -9,23 +9,21 @@ const { Cc, Ci, Cu, ChromeWorker } = req
 
 Cu.import("resource://gre/modules/Services.jsm");
 
 const { EventTarget } = require("sdk/event/target");
 const { emit, off } = require("sdk/event/core");
 const { Class } = require("sdk/core/heritage");
 const Environment = require("sdk/system/environment").env;
 const Runtime = require("sdk/system/runtime");
-const Self = require("sdk/self");
 const URL = require("sdk/url");
-const Subprocess = require("subprocess");
+const Subprocess = require("sdk/system/child_process/subprocess");
 const { Promise: promise } = Cu.import("resource://gre/modules/Promise.jsm", {});
-const Prefs = require("sdk/simple-prefs").prefs;
 
-const { rootURI: ROOT_URI } = require('@loader/options');
+const ROOT_URI = require("addon").uri;
 const PROFILE_URL = ROOT_URI + "profile/";
 const BIN_URL = ROOT_URI + "b2g/";
 
 // Log subprocess error and debug messages to the console.  This logs messages
 // for all consumers of the API.  We trim the messages because they sometimes
 // have trailing newlines.  And note that registerLogHandler actually registers
 // an error handler, despite its name.
 Subprocess.registerLogHandler(
@@ -135,19 +133,24 @@ exports.SimulatorProcess = Class({
     return this._executable ? this._executableFilename : "B2G";
   },
 
   // compute current b2g file handle
   get b2gExecutable() {
     if (this._executable) {
       return this._executable;
     }
+    let customRuntime;
+    try {
+      let pref = "extensions." + require("addon").id + ".customRuntime";
+      customRuntime = Services.prefs.getComplexValue(pref, Ci.nsIFile);
+    } catch(e) {}
 
-    if (Prefs.customRuntime) {
-      this._executable = Prefs.customRuntime;
+    if (customRuntime) {
+      this._executable = customRuntime;
       this._executableFilename = "Custom runtime";
       return this._executable;
     }
 
     let bin = URL.toFilename(BIN_URL);
     let executables = {
       WINNT: "b2g-bin.exe",
       Darwin: "B2G.app/Contents/MacOS/b2g-bin",
@@ -172,17 +175,23 @@ exports.SimulatorProcess = Class({
 
     return executable;
   },
 
   // compute b2g CLI arguments
   get b2gArguments() {
     let args = [];
 
-    let profile = Prefs.gaiaProfile || URL.toFilename(PROFILE_URL);
+    let gaiaProfile;
+    try {
+      let pref = "extensions." + require("addon").id + ".gaiaProfile";
+      gaiaProfile = Services.prefs.getComplexValue(pref, Ci.nsIFile).path;
+    } catch(e) {}
+
+    let profile = gaiaProfile || URL.toFilename(PROFILE_URL);
     args.push("-profile", profile);
     console.log("profile", profile);
 
     // NOTE: push dbgport option on the b2g-desktop commandline
     args.push("-start-debugger-server", "" + this.remoteDebuggerPort);
 
     // Ignore eventual zombie instances of b2g that are left over
     args.push("-no-remote");
new file mode 100644
--- /dev/null
+++ b/b2g/simulator/options.xul.in
@@ -0,0 +1,5 @@
+<?xml version="1.0" ?>
+<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+  <setting pref="extensions.@ADDON_ID@.gaiaProfile" type="directory" title="Select a custom Gaia profile directory"/>
+  <setting pref="extensions.@ADDON_ID@.customRuntime" type="file" title="Select a custom runtime executable"/>
+</vbox>
deleted file mode 100644
--- a/b2g/simulator/package-overload.json.in
+++ /dev/null
@@ -1,7 +0,0 @@
-{
-  "id": "fxos_@SLASH_VERSION@_simulator@mozilla.org",
-  "name": "fxos_@SLASH_VERSION@_simulator",
-  "version": "@FULL_VERSION@",
-  "fullName": "Firefox OS @NUM_VERSION@ Simulator",
-  "description": "a Firefox OS @NUM_VERSION@ simulator"
-}
deleted file mode 100644
--- a/b2g/simulator/package.json
+++ /dev/null
@@ -1,46 +0,0 @@
-{
-  "id": "fxos_simulator@mozilla.org",
-  "name": "fxos_simulator",
-  "version": "1.0.dev",
-  "fullName": "Firefox OS Simulator",
-  "label": "Firefox OS",
-  "description": "a Firefox OS simulator",
-  "author": "Myk Melez (https://github.com/mykmelez)",
-  "contributors": [
-    "Alexandre Poirot (https://github.com/ochameau)",
-    "Anant Narayanan (https://github.com/anantn)",
-    "Brandon Kase (https://github.com/bkase)",
-    "Breck Yunits (https://github.com/breck7)",
-    "César Carruitero (https://github.com/ccarruitero)",
-    "David Gomes (https://github.com/davidgomes)",
-    "Fabrice Desré (https://github.com/fabricedesre)",
-    "Fraser Tweedale (https://github.com/frasertweedale)",
-    "Harald Kirschner (https://github.com/digitarald)",
-    "Jérémie Patonnier (https://github.com/JeremiePat)",
-    "J. Ryan Stinnett (https://github.com/jryans)",
-    "Kan-Ru Chen (陳侃如) (https://github.com/kanru)",
-    "Louis Stowasser (https://github.com/louisstow)",
-    "Luca Greco (https://github.com/rpl)",
-    "Matthew Claypotch (https://github.com/potch)",
-    "Matthew Riley MacPherson (https://github.com/tofumatt)",
-    "Nick Desaulniers (https://github.com/nickdesaulniers)",
-    "Soumen Ganguly (https://github.com/SoumenG)",
-    "Sudheesh Singanamalla (https://github.com/sudheesh001)",
-    "Victor Bjelkholm (https://github.com/VictorBjelkholm)"
-  ],
-  "permissions": {
-    "private-browsing": true
-  },
-  "preferences": [{
-    "type": "directory",
-    "name": "gaiaProfile",
-    "title": "Select a custom Gaia profile directory"
-  }, {
-    "type": "file",
-    "name": "customRuntime",
-    "title": "Select a custom runtime executable"
-  }],
-  "license": "MPL 2.0",
-  "unpack": true,
-  "dependencies": ["subprocess"]
-}
deleted file mode 100644
--- a/b2g/simulator/packages/subprocess/README.md
+++ /dev/null
@@ -1,124 +0,0 @@
-<h2>What's that?</h2>
-Simply package enigmail hard work on providing IPC feature in mozilla platform.
-So we are able to launch child proccesses from javascript,
-and in our case, from addon-sdk libraries :)
-
-<h2>Sample of code:</h2>
-  This object allows to start a process, and read/write data to/from it
-  using stdin/stdout/stderr streams.
-  Usage example:
-
-   const subprocess = require("subprocess");
-   var p = subprocess.call({
-     command:     '/bin/foo',
-     arguments:   ['-v', 'foo'],
-     environment: [ "XYZ=abc", "MYVAR=def" ],
-     charset: 'UTF-8',
-     workdir: '/home/foo',
-     //stdin: "some value to write to stdin\nfoobar",
-     stdin: function(stdin) {
-       stdin.write("some value to write to stdin\nfoobar");
-       stdin.close();
-     },
-     stdout: function(data) {
-       dump("got data on stdout:" + data + "\n");
-     },
-     stderr: function(data) {
-       dump("got data on stderr:" + data + "\n");
-     },
-     done: function(result) {
-       dump("process terminated with " + result.exitCode + "\n");
-     },
-     mergeStderr: false
-   });
-   p.wait(); // wait for the subprocess to terminate
-             // this will block the main thread,
-             // only do if you can wait that long
-
-
-  Description of parameters:
-  --------------------------
-  Apart from <command>, all arguments are optional.
-
-  command:     either a |nsIFile| object pointing to an executable file or a
-              String containing the platform-dependent path to an executable
-              file.
-
-  arguments:   optional string array containing the arguments to the command.
-
-  environment: optional string array containing environment variables to pass
-               to the command. The array elements must have the form
-               "VAR=data". Please note that if environment is defined, it
-               replaces any existing environment variables for the subprocess.
-
-  charset:     Output is decoded with given charset and a string is returned.
-               If charset is undefined, "UTF-8" is used as default.
-               To get binary data, set this to null and the returned string
-               is not decoded in any way.
-
-  workdir:     optional; String containing the platform-dependent path to a
-               directory to become the current working directory of the subprocess.
-
-  stdin:       optional input data for the process to be passed on standard
-               input. stdin can either be a string or a function.
-               A |string| gets written to stdin and stdin gets closed;
-               A |function| gets passed an object with write and close function.
-               Please note that the write() function will return almost immediately;
-               data is always written asynchronously on a separate thread.
-
-  stdout:      an optional function that can receive output data from the
-               process. The stdout-function is called asynchronously; it can be
-               called mutliple times during the execution of a process.
-               At a minimum at each occurance of \n or \r.
-               Please note that null-characters might need to be escaped
-               with something like 'data.replace(/\0/g, "\\0");'.
-
-  stderr:      an optional function that can receive stderr data from the
-               process. The stderr-function is called asynchronously; it can be
-               called mutliple times during the execution of a process. Please
-               note that null-characters might need to be escaped with
-               something like 'data.replace(/\0/g, "\\0");'.
-               (on windows it only gets called once right now)
-
-  done:        optional function that is called when the process has terminated.
-               The exit code from the process available via result.exitCode. If
-               stdout is not defined, then the output from stdout is available
-               via result.stdout. stderr data is in result.stderr
-
-  mergeStderr: optional boolean value. If true, stderr is merged with stdout;
-               no data will be provided to stderr.
-
-
-  Description of object returned by subprocess.call(...)
-  ------------------------------------------------------
-  The object returned by subprocess.call offers a few methods that can be
-  executed:
-
-  wait():         waits for the subprocess to terminate. It is not required to use
-                  wait; done will be called in any case when the subprocess terminated.
-
-  kill(hardKill): kill the subprocess. Any open pipes will be closed and
-                  done will be called.
-                  hardKill [ignored on Windows]:
-                   - false: signal the process terminate (SIGTERM)
-                   - true:  kill the process (SIGKILL)
-
-
-  Other methods in subprocess
-  ---------------------------
-
-  registerDebugHandler(functionRef):   register a handler that is called to get
-                                       debugging information
-  registerLogHandler(functionRef):     register a handler that is called to get error
-                                       messages
-
-  example:
-     subprocess.registerLogHandler( function(s) { dump(s); } );
-
-
-<h2>Credits:</h2>
-All enigmail team working on IPC component.
-  The Initial Developer of this code is Jan Gerber.
-  Portions created by Jan Gerber <j@mailb.org>,
-  Patrick Brunschwig (author of almost all code) <patrick@mozilla-enigmail.org>,
-  Ramalingam Saravanan (from enigmail team) <svn@xmlterm.org>
deleted file mode 100644
--- a/b2g/simulator/packages/subprocess/lib/subprocess.js
+++ /dev/null
@@ -1,1543 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/.
- */
-
-'use strict';
-
-const { Cc, Ci, Cu, ChromeWorker } = require("chrome");
-
-Cu.import("resource://gre/modules/ctypes.jsm");
-
-const NS_LOCAL_FILE = "@mozilla.org/file/local;1";
-
-const Runtime = require("sdk/system/runtime");
-const Environment = require("sdk/system/environment").env;
-const DEFAULT_ENVIRONMENT = [];
-if (Runtime.OS == "Linux" && "DISPLAY" in Environment) {
-  DEFAULT_ENVIRONMENT.push("DISPLAY=" + Environment.DISPLAY);
-}
-
-/*
-Fake require statements to ensure worker scripts are packaged:
-require("subprocess_worker_win.js");
-require("subprocess_worker_unix.js");
-*/
-const URL_PREFIX = module.uri.replace(/subprocess\.js/, "");
-const WORKER_URL_WIN = URL_PREFIX + "subprocess_worker_win.js";
-const WORKER_URL_UNIX = URL_PREFIX + "subprocess_worker_unix.js";
-
-//Windows API definitions
-if (ctypes.size_t.size == 8) {
-    var WinABI = ctypes.default_abi;
-} else {
-    var WinABI = ctypes.winapi_abi;
-}
-const WORD = ctypes.uint16_t;
-const DWORD = ctypes.uint32_t;
-const LPDWORD = DWORD.ptr;
-
-const UINT = ctypes.unsigned_int;
-const BOOL = ctypes.bool;
-const HANDLE = ctypes.size_t;
-const HWND = HANDLE;
-const HMODULE = HANDLE;
-const WPARAM = ctypes.size_t;
-const LPARAM = ctypes.size_t;
-const LRESULT = ctypes.size_t;
-const ULONG_PTR = ctypes.uintptr_t;
-const PVOID = ctypes.voidptr_t;
-const LPVOID = PVOID;
-const LPCTSTR = ctypes.jschar.ptr;
-const LPCWSTR = ctypes.jschar.ptr;
-const LPTSTR = ctypes.jschar.ptr;
-const LPSTR = ctypes.char.ptr;
-const LPCSTR = ctypes.char.ptr;
-const LPBYTE = ctypes.char.ptr;
-
-const CREATE_NEW_CONSOLE = 0x00000010;
-const CREATE_NO_WINDOW = 0x08000000;
-const CREATE_UNICODE_ENVIRONMENT = 0x00000400;
-const STARTF_USESHOWWINDOW = 0x00000001;
-const STARTF_USESTDHANDLES = 0x00000100;
-const SW_HIDE = 0;
-const DUPLICATE_SAME_ACCESS = 0x00000002;
-const STILL_ACTIVE = 259;
-const INFINITE = DWORD(0xFFFFFFFF);
-const WAIT_TIMEOUT = 0x00000102;
-
-/*
-typedef struct _SECURITY_ATTRIBUTES {
- DWORD  nLength;
- LPVOID lpSecurityDescriptor;
- BOOL   bInheritHandle;
-} SECURITY_ATTRIBUTES, *PSECURITY_ATTRIBUTES, *LPSECURITY_ATTRIBUTES;
-*/
-const SECURITY_ATTRIBUTES = new ctypes.StructType("SECURITY_ATTRIBUTES", [
-    {"nLength": DWORD},
-    {"lpSecurityDescriptor": LPVOID},
-    {"bInheritHandle": BOOL},
-]);
-
-/*
-typedef struct _STARTUPINFO {
-  DWORD  cb;
-  LPTSTR lpReserved;
-  LPTSTR lpDesktop;
-  LPTSTR lpTitle;
-  DWORD  dwX;
-  DWORD  dwY;
-  DWORD  dwXSize;
-  DWORD  dwYSize;
-  DWORD  dwXCountChars;
-  DWORD  dwYCountChars;
-  DWORD  dwFillAttribute;
-  DWORD  dwFlags;
-  WORD   wShowWindow;
-  WORD   cbReserved2;
-  LPBYTE lpReserved2;
-  HANDLE hStdInput;
-  HANDLE hStdOutput;
-  HANDLE hStdError;
-} STARTUPINFO, *LPSTARTUPINFO;
-*/
-const STARTUPINFO = new ctypes.StructType("STARTUPINFO", [
-    {"cb": DWORD},
-    {"lpReserved": LPTSTR},
-    {"lpDesktop": LPTSTR},
-    {"lpTitle": LPTSTR},
-    {"dwX": DWORD},
-    {"dwY": DWORD},
-    {"dwXSize": DWORD},
-    {"dwYSize": DWORD},
-    {"dwXCountChars": DWORD},
-    {"dwYCountChars": DWORD},
-    {"dwFillAttribute": DWORD},
-    {"dwFlags": DWORD},
-    {"wShowWindow": WORD},
-    {"cbReserved2": WORD},
-    {"lpReserved2": LPBYTE},
-    {"hStdInput": HANDLE},
-    {"hStdOutput": HANDLE},
-    {"hStdError": HANDLE},
-]);
-
-/*
-typedef struct _PROCESS_INFORMATION {
-  HANDLE hProcess;
-  HANDLE hThread;
-  DWORD  dwProcessId;
-  DWORD  dwThreadId;
-} PROCESS_INFORMATION, *LPPROCESS_INFORMATION;
-*/
-const PROCESS_INFORMATION = new ctypes.StructType("PROCESS_INFORMATION", [
-    {"hProcess": HANDLE},
-    {"hThread": HANDLE},
-    {"dwProcessId": DWORD},
-    {"dwThreadId": DWORD},
-]);
-
-/*
-typedef struct _OVERLAPPED {
-  ULONG_PTR Internal;
-  ULONG_PTR InternalHigh;
-  union {
-    struct {
-      DWORD Offset;
-      DWORD OffsetHigh;
-    };
-    PVOID  Pointer;
-  };
-  HANDLE    hEvent;
-} OVERLAPPED, *LPOVERLAPPED;
-*/
-const OVERLAPPED = new ctypes.StructType("OVERLAPPED");
-
-//UNIX definitions
-const pid_t = ctypes.int32_t;
-const WNOHANG = 1;
-const F_GETFD = 1;
-const F_SETFL = 4;
-
-const LIBNAME       = 0;
-const O_NONBLOCK    = 1;
-const RLIM_T        = 2;
-const RLIMIT_NOFILE = 3;
-
-function getPlatformValue(valueType) {
-
-    if (! gXulRuntime)
-        gXulRuntime = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime);
-
-    const platformDefaults = {
-        // Windows API:
-        'winnt':   [ 'kernel32.dll' ],
-
-        // Unix API:
-        //            library name   O_NONBLOCK RLIM_T                RLIMIT_NOFILE
-        'darwin':  [ 'libc.dylib',   0x04     , ctypes.uint64_t     , 8 ],
-        'linux':   [ 'libc.so.6',    2024     , ctypes.unsigned_long, 7 ],
-        'freebsd': [ 'libc.so.7',    0x04     , ctypes.int64_t      , 8 ],
-        'openbsd': [ 'libc.so.61.0', 0x04     , ctypes.int64_t      , 8 ],
-        'sunos':   [ 'libc.so',      0x80     , ctypes.unsigned_long, 5 ]
-    }
-
-    return platformDefaults[gXulRuntime.OS.toLowerCase()][valueType];
-}
-
-
-var gDebugFunc = null,
-    gLogFunc = null,
-    gXulRuntime = null;
-
-function LogError(s) {
-    if (gLogFunc)
-        gLogFunc(s);
-    else
-        dump(s);
-}
-
-function debugLog(s) {
-    if (gDebugFunc)
-        gDebugFunc(s);
-}
-
-function setTimeout(callback, timeout) {
-    var timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
-    timer.initWithCallback(callback, timeout, Ci.nsITimer.TYPE_ONE_SHOT);
-};
-
-function getBytes(data) {
-  var string = '';
-  data.forEach(function(x) { string += String.fromCharCode(x < 0 ? x + 256 : x) });
-  return string;
-}
-
-function readString(data, length, charset) {
-    var string = '', bytes = [];
-    for(var i = 0;i < length; i++) {
-        if(data[i] == 0 && charset !== null) // stop on NULL character for non-binary data
-           break
-        bytes.push(data[i]);
-    }
-    if (!bytes || bytes.length == 0)
-        return string;
-    if(charset === null) {
-        return bytes;
-    }
-    return convertBytes(bytes, charset);
-}
-
-function convertBytes(bytes, charset) {
-    var string = '';
-    charset = charset || 'UTF-8';
-    var unicodeConv = Cc["@mozilla.org/intl/scriptableunicodeconverter"]
-                        .getService(Ci.nsIScriptableUnicodeConverter);
-    try {
-        unicodeConv.charset = charset;
-        string = unicodeConv.convertFromByteArray(bytes, bytes.length);
-    } catch (ex) {
-        LogError("String conversion failed: "+ex.toString()+"\n")
-        string = '';
-    }
-    string += unicodeConv.Finish();
-    return string;
-}
-
-
-// temporary solution for removal of nsILocalFile
-function getLocalFileApi() {
-  if ("nsILocalFile" in Ci) {
-    return Ci.nsILocalFile;
-  }
-  else
-    return Ci.nsIFile;
-}
-
-function getCommandStr(command) {
-    let commandStr = null;
-    if (typeof(command) == "string") {
-        let file = Cc[NS_LOCAL_FILE].createInstance(getLocalFileApi());
-        file.initWithPath(command);
-        if (! (file.isExecutable() && file.isFile()))
-            throw("File '"+command+"' is not an executable file");
-        commandStr = command;
-    }
-    else {
-        if (! (command.isExecutable() && command.isFile()))
-            throw("File '"+command.path+"' is not an executable file");
-        commandStr = command.path;
-    }
-
-    return commandStr;
-}
-
-function getWorkDir(workdir) {
-    let workdirStr = null;
-    if (typeof(workdir) == "string") {
-        let file = Cc[NS_LOCAL_FILE].createInstance(getLocalFileApi());
-        file.initWithPath(workdir);
-        if (! (file.isDirectory()))
-            throw("Directory '"+workdir+"' does not exist");
-        workdirStr = workdir;
-    }
-    else if (workdir) {
-        if (! workdir.isDirectory())
-            throw("Directory '"+workdir.path+"' does not exist");
-        workdirStr = workdir.path;
-    }
-    return workdirStr;
-}
-
-
-var subprocess = {
-    call: function(options) {
-        options.mergeStderr = options.mergeStderr || false;
-        options.workdir = options.workdir ||  null;
-        options.environment = options.environment || DEFAULT_ENVIRONMENT;
-        if (options.arguments) {
-            var args = options.arguments;
-            options.arguments = [];
-            args.forEach(function(argument) {
-                options.arguments.push(argument);
-            });
-        } else {
-            options.arguments = [];
-        }
-
-        options.libc = getPlatformValue(LIBNAME);
-
-        if (gXulRuntime.OS.substring(0, 3) == "WIN") {
-            return subprocess_win32(options);
-        } else {
-            return subprocess_unix(options);
-        }
-
-    },
-    registerDebugHandler: function(func) {
-        gDebugFunc = func;
-    },
-    registerLogHandler: function(func) {
-        gLogFunc = func;
-    }
-};
-
-
-
-function subprocess_win32(options) {
-    var kernel32dll = ctypes.open(options.libc),
-        hChildProcess,
-        active = true,
-        done = false,
-        exitCode = -1,
-        child = {},
-        stdinWorker = null,
-        stdoutWorker = null,
-        stderrWorker = null,
-        pendingWriteCount = 0,
-        readers = options.mergeStderr ? 1 : 2,
-        stdinOpenState = 2,
-        error = '',
-        output = '';
-
-    // stdin pipe states
-    const OPEN = 2;
-    const CLOSEABLE = 1;
-    const CLOSED = 0;
-
-    //api declarations
-    /*
-    BOOL WINAPI CloseHandle(
-      __in  HANDLE hObject
-    );
-    */
-    var CloseHandle = kernel32dll.declare("CloseHandle",
-                                            WinABI,
-                                            BOOL,
-                                            HANDLE
-    );
-
-    /*
-    BOOL WINAPI CreateProcess(
-      __in_opt     LPCTSTR lpApplicationName,
-      __inout_opt  LPTSTR lpCommandLine,
-      __in_opt     LPSECURITY_ATTRIBUTES lpProcessAttributes,
-      __in_opt     LPSECURITY_ATTRIBUTES lpThreadAttributes,
-      __in         BOOL bInheritHandles,
-      __in         DWORD dwCreationFlags,
-      __in_opt     LPVOID lpEnvironment,
-      __in_opt     LPCTSTR lpCurrentDirectory,
-      __in         LPSTARTUPINFO lpStartupInfo,
-      __out        LPPROCESS_INFORMATION lpProcessInformation
-    );
-     */
-    var CreateProcessW = kernel32dll.declare("CreateProcessW",
-                                            WinABI,
-                                            BOOL,
-                                            LPCTSTR,
-                                            LPTSTR,
-                                            SECURITY_ATTRIBUTES.ptr,
-                                            SECURITY_ATTRIBUTES.ptr,
-                                            BOOL,
-                                            DWORD,
-                                            LPVOID,
-                                            LPCTSTR,
-                                            STARTUPINFO.ptr,
-                                            PROCESS_INFORMATION.ptr
-                                         );
-
-//     /*
-//     BOOL WINAPI ReadFile(
-//       __in         HANDLE hFile,
-//       __out        LPVOID ReadFileBuffer,
-//       __in         DWORD nNumberOfBytesToRead,
-//       __out_opt    LPDWORD lpNumberOfBytesRead,
-//       __inout_opt  LPOVERLAPPED lpOverlapped
-//     );
-//     */
-//     var ReadFileBufferSize = 1024,
-//         ReadFileBuffer = ctypes.char.array(ReadFileBufferSize),
-//         ReadFile = kernel32dll.declare("ReadFile",
-//                                         WinABI,
-//                                         BOOL,
-//                                         HANDLE,
-//                                         ReadFileBuffer,
-//                                         DWORD,
-//                                         LPDWORD,
-//                                         OVERLAPPED.ptr
-//     );
-//
-//     /*
-//     BOOL WINAPI PeekNamedPipe(
-//       __in       HANDLE hNamedPipe,
-//       __out_opt  LPVOID lpBuffer,
-//       __in       DWORD nBufferSize,
-//       __out_opt  LPDWORD lpBytesRead,
-//       __out_opt  LPDWORD lpTotalBytesAvail,
-//       __out_opt  LPDWORD lpBytesLeftThisMessage
-//     );
-//     */
-//     var PeekNamedPipe = kernel32dll.declare("PeekNamedPipe",
-//                                         WinABI,
-//                                         BOOL,
-//                                         HANDLE,
-//                                         ReadFileBuffer,
-//                                         DWORD,
-//                                         LPDWORD,
-//                                         LPDWORD,
-//                                         LPDWORD
-//     );
-//
-//     /*
-//     BOOL WINAPI WriteFile(
-//       __in         HANDLE hFile,
-//       __in         LPCVOID lpBuffer,
-//       __in         DWORD nNumberOfBytesToWrite,
-//       __out_opt    LPDWORD lpNumberOfBytesWritten,
-//       __inout_opt  LPOVERLAPPED lpOverlapped
-//     );
-//     */
-//     var WriteFile = kernel32dll.declare("WriteFile",
-//                                         WinABI,
-//                                         BOOL,
-//                                         HANDLE,
-//                                         ctypes.char.ptr,
-//                                         DWORD,
-//                                         LPDWORD,
-//                                         OVERLAPPED.ptr
-//     );
-
-    /*
-    BOOL WINAPI CreatePipe(
-      __out     PHANDLE hReadPipe,
-      __out     PHANDLE hWritePipe,
-      __in_opt  LPSECURITY_ATTRIBUTES lpPipeAttributes,
-      __in      DWORD nSize
-    );
-    */
-    var CreatePipe = kernel32dll.declare("CreatePipe",
-                                        WinABI,
-                                        BOOL,
-                                        HANDLE.ptr,
-                                        HANDLE.ptr,
-                                        SECURITY_ATTRIBUTES.ptr,
-                                        DWORD
-    );
-
-    /*
-    HANDLE WINAPI GetCurrentProcess(void);
-    */
-    var GetCurrentProcess = kernel32dll.declare("GetCurrentProcess",
-                                        WinABI,
-                                        HANDLE
-    );
-
-    /*
-    DWORD WINAPI GetLastError(void);
-    */
-    var GetLastError = kernel32dll.declare("GetLastError",
-                                        WinABI,
-                                        DWORD
-    );
-
-    /*
-    BOOL WINAPI DuplicateHandle(
-      __in   HANDLE hSourceProcessHandle,
-      __in   HANDLE hSourceHandle,
-      __in   HANDLE hTargetProcessHandle,
-      __out  LPHANDLE lpTargetHandle,
-      __in   DWORD dwDesiredAccess,
-      __in   BOOL bInheritHandle,
-      __in   DWORD dwOptions
-    );
-    */
-    var DuplicateHandle = kernel32dll.declare("DuplicateHandle",
-                                        WinABI,
-                                        BOOL,
-                                        HANDLE,
-                                        HANDLE,
-                                        HANDLE,
-                                        HANDLE.ptr,
-                                        DWORD,
-                                        BOOL,
-                                        DWORD
-    );
-
-
-    /*
-    BOOL WINAPI GetExitCodeProcess(
-      __in   HANDLE hProcess,
-      __out  LPDWORD lpExitCode
-    );
-    */
-    var GetExitCodeProcess = kernel32dll.declare("GetExitCodeProcess",
-                                        WinABI,
-                                        BOOL,
-                                        HANDLE,
-                                        LPDWORD
-    );
-
-    /*
-    DWORD WINAPI WaitForSingleObject(
-      __in  HANDLE hHandle,
-      __in  DWORD dwMilliseconds
-    );
-    */
-    var WaitForSingleObject = kernel32dll.declare("WaitForSingleObject",
-                                        WinABI,
-                                        DWORD,
-                                        HANDLE,
-                                        DWORD
-    );
-
-    /*
-    BOOL WINAPI TerminateProcess(
-      __in  HANDLE hProcess,
-      __in  UINT uExitCode
-    );
-    */
-    var TerminateProcess = kernel32dll.declare("TerminateProcess",
-                                        WinABI,
-                                        BOOL,
-                                        HANDLE,
-                                        UINT
-    );
-
-    //functions
-    function popen(command, workdir, args, environment, child) {
-        //escape arguments
-        args.unshift(command);
-        for (var i = 0; i < args.length; i++) {
-          if (typeof args[i] != "string") { args[i] = args[i].toString(); }
-          /* quote arguments with spaces */
-          if (args[i].match(/\s/)) {
-            args[i] = "\"" + args[i] + "\"";
-          }
-          /* If backslash is followed by a quote, double it */
-          args[i] = args[i].replace(/\\\"/g, "\\\\\"");
-        }
-        command = args.join(' ');
-
-        environment = environment || [];
-        if(environment.length) {
-            //An environment block consists of
-            //a null-terminated block of null-terminated strings.
-            //Using CREATE_UNICODE_ENVIRONMENT so needs to be jschar
-            environment = ctypes.jschar.array()(environment.join('\0') + '\0');
-        } else {
-            environment = null;
-        }
-
-        var hOutputReadTmp = new HANDLE(),
-            hOutputRead = new HANDLE(),
-            hOutputWrite = new HANDLE();
-
-        var hErrorRead = new HANDLE(),
-            hErrorReadTmp = new HANDLE(),
-            hErrorWrite = new HANDLE();
-
-        var hInputRead = new HANDLE(),
-            hInputWriteTmp = new HANDLE(),
-            hInputWrite = new HANDLE();
-
-        // Set up the security attributes struct.
-        var sa = new SECURITY_ATTRIBUTES();
-        sa.nLength = SECURITY_ATTRIBUTES.size;
-        sa.lpSecurityDescriptor = null;
-        sa.bInheritHandle = true;
-
-        // Create output pipe.
-
-        if(!CreatePipe(hOutputReadTmp.address(), hOutputWrite.address(), sa.address(), 0))
-            LogError('CreatePipe hOutputReadTmp failed');
-
-        if(options.mergeStderr) {
-          // Create a duplicate of the output write handle for the std error
-          // write handle. This is necessary in case the child application
-          // closes one of its std output handles.
-          if (!DuplicateHandle(GetCurrentProcess(), hOutputWrite,
-                               GetCurrentProcess(), hErrorWrite.address(), 0,
-                               true, DUPLICATE_SAME_ACCESS))
-             LogError("DuplicateHandle hOutputWrite failed");
-        } else {
-            // Create error pipe.
-            if(!CreatePipe(hErrorReadTmp.address(), hErrorWrite.address(), sa.address(), 0))
-                LogError('CreatePipe hErrorReadTmp failed');
-        }
-
-        // Create input pipe.
-        if (!CreatePipe(hInputRead.address(),hInputWriteTmp.address(),sa.address(), 0))
-            LogError("CreatePipe hInputRead failed");
-
-        // Create new output/error read handle and the input write handles. Set
-        // the Properties to FALSE. Otherwise, the child inherits the
-        // properties and, as a result, non-closeable handles to the pipes
-        // are created.
-        if (!DuplicateHandle(GetCurrentProcess(), hOutputReadTmp,
-                             GetCurrentProcess(),
-                             hOutputRead.address(), // Address of new handle.
-                             0, false, // Make it uninheritable.
-                             DUPLICATE_SAME_ACCESS))
-             LogError("DupliateHandle hOutputReadTmp failed");
-
-        if(!options.mergeStderr) {
-            if (!DuplicateHandle(GetCurrentProcess(), hErrorReadTmp,
-                             GetCurrentProcess(),
-                             hErrorRead.address(), // Address of new handle.
-                             0, false, // Make it uninheritable.
-                             DUPLICATE_SAME_ACCESS))
-             LogError("DupliateHandle hErrorReadTmp failed");
-        }
-        if (!DuplicateHandle(GetCurrentProcess(), hInputWriteTmp,
-                             GetCurrentProcess(),
-                             hInputWrite.address(), // Address of new handle.
-                             0, false, // Make it uninheritable.
-                             DUPLICATE_SAME_ACCESS))
-          LogError("DupliateHandle hInputWriteTmp failed");
-
-        // Close inheritable copies of the handles.
-        if (!CloseHandle(hOutputReadTmp)) LogError("CloseHandle hOutputReadTmp failed");
-        if(!options.mergeStderr)
-            if (!CloseHandle(hErrorReadTmp)) LogError("CloseHandle hErrorReadTmp failed");
-        if (!CloseHandle(hInputWriteTmp)) LogError("CloseHandle failed");
-
-        var pi = new PROCESS_INFORMATION();
-        var si = new STARTUPINFO();
-
-        si.cb = STARTUPINFO.size;
-        si.dwFlags = STARTF_USESTDHANDLES;
-        si.hStdInput  = hInputRead;
-        si.hStdOutput = hOutputWrite;
-        si.hStdError  = hErrorWrite;
-
-        // Launch the process
-        if(!CreateProcessW(null,            // executable name
-                           command,         // command buffer
-                           null,            // process security attribute
-                           null,            // thread security attribute
-                           true,            // inherits system handles
-                           CREATE_UNICODE_ENVIRONMENT|CREATE_NO_WINDOW, // process flags
-                           environment,     // envrionment block
-                           workdir,          // set as current directory
-                           si.address(),    // (in) startup information
-                           pi.address()     // (out) process information
-        ))
-            throw("Fatal - Could not launch subprocess '"+command+"'");
-
-        // Close any unnecessary handles.
-        if (!CloseHandle(pi.hThread))
-            LogError("CloseHandle pi.hThread failed");
-
-        // Close pipe handles (do not continue to modify the parent).
-        // You need to make sure that no handles to the write end of the
-        // output pipe are maintained in this process or else the pipe will
-        // not close when the child process exits and the ReadFile will hang.
-        if (!CloseHandle(hInputRead)) LogError("CloseHandle hInputRead failed");
-        if (!CloseHandle(hOutputWrite)) LogError("CloseHandle hOutputWrite failed");
-        if (!CloseHandle(hErrorWrite)) LogError("CloseHandle hErrorWrite failed");
-
-        //return values
-        child.stdin = hInputWrite;
-        child.stdout = hOutputRead;
-        child.stderr = options.mergeStderr ? undefined : hErrorRead;
-        child.process = pi.hProcess;
-        return pi.hProcess;
-    }
-
-    /*
-     * createStdinWriter ()
-     *
-     * Create a ChromeWorker object for writing data to the subprocess' stdin
-     * pipe. The ChromeWorker object lives on a separate thread; this avoids
-     * internal deadlocks.
-     */
-    function createStdinWriter() {
-        debugLog("Creating new stdin worker\n");
-        stdinWorker = new ChromeWorker(WORKER_URL_WIN);
-        stdinWorker.onmessage = function(event) {
-            switch(event.data) {
-            case "WriteOK":
-                pendingWriteCount--;
-                debugLog("got OK from stdinWorker - remaining count: "+pendingWriteCount+"\n");
-                break;
-            case "ClosedOK":
-                stdinOpenState = CLOSED;
-                debugLog("Stdin pipe closed\n");
-                break;
-            default:
-                debugLog("got msg from stdinWorker: "+event.data+"\n");
-            }
-        }
-        stdinWorker.onerror = function(error) {
-            pendingWriteCount--;
-            LogError("got error from stdinWorker: "+error.message+"\n");
-        }
-
-        stdinWorker.postMessage({msg: "init", libc: options.libc});
-    }
-
-    /*
-     * writeStdin()
-     * @data: String containing the data to write
-     *
-     * Write data to the subprocess' stdin (equals to sending a request to the
-     * ChromeWorker object to write the data).
-     */
-    function writeStdin(data) {
-        ++pendingWriteCount;
-        debugLog("sending "+data.length+" bytes to stdinWorker\n");
-        var pipePtr = parseInt(ctypes.cast(child.stdin.address(), ctypes.uintptr_t).value);
-
-        stdinWorker.postMessage({
-                msg: 'write',
-                pipe: pipePtr,
-                data: data
-            });
-    }
-
-    /*
-     * closeStdinHandle()
-     *
-     * Close the stdin pipe, either directly or by requesting the ChromeWorker to
-     * close the pipe. The ChromeWorker will only close the pipe after the last write
-     * request process is done.
-     */
-
-    function closeStdinHandle() {
-        debugLog("trying to close stdin\n");
-        if (stdinOpenState != OPEN) return;
-        stdinOpenState = CLOSEABLE;
-
-        if (stdinWorker) {
-            debugLog("sending close stdin to worker\n");
-            var pipePtr = parseInt(ctypes.cast(child.stdin.address(), ctypes.uintptr_t).value);
-            stdinWorker.postMessage({
-                msg: 'close',
-                pipe: pipePtr
-            });
-        }
-        else {
-            stdinOpenState = CLOSED;
-            debugLog("Closing Stdin\n");
-            CloseHandle(child.stdin) || LogError("CloseHandle hInputWrite failed");
-        }
-    }
-
-
-    /*
-     * createReader(pipe, name)
-     *
-     * @pipe: handle to the pipe
-     * @name: String containing the pipe name (stdout or stderr)
-     *
-     * Create a ChromeWorker object for reading data asynchronously from
-     * the pipe (i.e. on a separate thread), and passing the result back to
-     * the caller.
-     */
-    function createReader(pipe, name, callbackFunc) {
-        var worker = new ChromeWorker(WORKER_URL_WIN);
-        worker.onmessage = function(event) {
-            switch(event.data.msg) {
-            case "data":
-                debugLog("got "+event.data.count+" bytes from "+name+"\n");
-                var data = '';
-                if (options.charset === null) {
-                    data = getBytes(event.data.data);
-                }
-                else {
-                    try {
-                        data = convertBytes(event.data.data, options.charset);
-                    }
-                    catch(ex) {
-                        console.warn("error decoding output: " + ex);
-                        data = getBytes(event.data.data);
-                    }
-                }
-
-                callbackFunc(data);
-                break;
-            case "done":
-                debugLog("Pipe "+name+" closed\n");
-                --readers;
-                if (readers == 0) cleanup();
-                break;
-            default:
-                debugLog("Got msg from "+name+": "+event.data.data+"\n");
-            }
-        }
-
-        worker.onerror = function(errorMsg) {
-            LogError("Got error from "+name+": "+errorMsg.message);
-        }
-
-        var pipePtr = parseInt(ctypes.cast(pipe.address(), ctypes.uintptr_t).value);
-
-        worker.postMessage({
-                msg: 'read',
-                pipe: pipePtr,
-                libc: options.libc,
-                charset: options.charset === null ? "null" : options.charset,
-                name: name
-            });
-
-        return worker;
-    }
-
-    /*
-     * readPipes()
-     *
-     * Open the pipes for reading from stdout and stderr
-     */
-    function readPipes() {
-
-        stdoutWorker = createReader(child.stdout, "stdout", function (data) {
-            if(options.stdout) {
-                setTimeout(function() {
-                    options.stdout(data);
-                }, 0);
-            } else {
-                output += data;
-            }
-        });
-
-
-        if (!options.mergeStderr) stderrWorker = createReader(child.stderr, "stderr", function (data) {
-            if(options.stderr) {
-                setTimeout(function() {
-                    options.stderr(data);
-                }, 0);
-            } else {
-                error += data;
-            }
-        });
-    }
-
-    /*
-     * cleanup()
-     *
-     * close stdin if needed, get the exit code from the subprocess and invoke
-     * the caller's done() function.
-     *
-     * Note: because stdout() and stderr() are called using setTimeout, we need to
-     * do the same here in order to guarantee the message sequence.
-     */
-    function cleanup() {
-        debugLog("Cleanup called\n");
-        if(active) {
-            active = false;
-
-            closeStdinHandle(); // should only be required in case of errors
-
-            var exit = new DWORD();
-            GetExitCodeProcess(child.process, exit.address());
-            exitCode = exit.value;
-
-            if (stdinWorker)
-                stdinWorker.postMessage({msg: 'stop'})
-
-            setTimeout(function _done() {
-                if (options.done) {
-                    try {
-                        options.done({
-                            exitCode: exitCode,
-                            stdout: output,
-                            stderr: error,
-                        });
-                    }
-                    catch (ex) {
-                        // prevent from blocking if options.done() throws an error
-                        done = true;
-                        throw ex;
-                    }
-                }
-                done = true;
-            }, 0);
-            kernel32dll.close();
-        }
-    }
-
-    var cmdStr = getCommandStr(options.command);
-    var workDir = getWorkDir(options.workdir);
-
-    //main
-    hChildProcess = popen(cmdStr, workDir, options.arguments, options.environment, child);
-
-    readPipes();
-
-    if (options.stdin) {
-       createStdinWriter();
-
-        if(typeof(options.stdin) == 'function') {
-            try {
-                options.stdin({
-                    write: function(data) {
-                        writeStdin(data);
-                    },
-                    close: function() {
-                        closeStdinHandle();
-                    }
-                });
-            }
-            catch (ex) {
-                // prevent from failing if options.stdin() throws an exception
-                closeStdinHandle();
-                throw ex;
-            }
-        } else {
-            writeStdin(options.stdin);
-            closeStdinHandle();
-        }
-    }
-    else
-        closeStdinHandle();
-
-    return {
-        kill: function(hardKill) {
-            // hardKill is currently ignored on Windows
-            var r = !!TerminateProcess(child.process, 255);
-            cleanup(-1);
-            return r;
-        },
-        wait: function() {
-            // wait for async operations to complete
-            var thread = Cc['@mozilla.org/thread-manager;1'].getService(Ci.nsIThreadManager).currentThread;
-            while (!done) thread.processNextEvent(true);
-
-            return exitCode;
-        }
-    }
-}
-
-
-function subprocess_unix(options) {
-    // stdin pipe states
-    const OPEN = 2;
-    const CLOSEABLE = 1;
-    const CLOSED = 0;
-
-    var libc = ctypes.open(options.libc),
-        active = true,
-        done = false,
-        exitCode = -1,
-        workerExitCode = 0,
-        child = {},
-        pid = -1,
-        stdinWorker = null,
-        stdoutWorker = null,
-        stderrWorker = null,
-        pendingWriteCount = 0,
-        readers = options.mergeStderr ? 1 : 2,
-        stdinOpenState = OPEN,
-        error = '',
-        output = '';
-
-    //api declarations
-
-    //pid_t fork(void);
-    var fork = libc.declare("fork",
-                         ctypes.default_abi,
-                         pid_t
-    );
-
-    //NULL terminated array of strings, argv[0] will be command >> + 2
-    var argv = ctypes.char.ptr.array(options.arguments.length + 2);
-    var envp = ctypes.char.ptr.array(options.environment.length + 1);
-
-    // posix_spawn_file_actions_t is a complex struct that may be different on
-    // each platform. We do not care about its attributes, we don't need to
-    // get access to them, but we do need to allocate the right amount
-    // of memory for it.
-    // Bug 936297 - Use OS.File internals to fetch
-    // sizeof(posix_spawn_file_actions_t)
-    var { OS } = Cu.import("resource://gre/modules/osfile.jsm", {});
-    var sizeof_file_actions_t = OS.Constants.libc.OSFILE_SIZEOF_DIRENT;
-    var posix_spawn_file_actions_t = ctypes.uint8_t.array(sizeof_file_actions_t);
-
-    //int posix_spawn(pid_t *restrict pid, const char *restrict path,
-    //   const posix_spawn_file_actions_t *file_actions,
-    //   const posix_spawnattr_t *restrict attrp,
-    //   char *const argv[restrict], char *const envp[restrict]);
-    var posix_spawn = libc.declare("posix_spawn",
-                         ctypes.default_abi,
-                         ctypes.int,
-                         pid_t.ptr,
-                         ctypes.char.ptr,
-                         posix_spawn_file_actions_t.ptr,
-                         ctypes.voidptr_t,
-                         argv,
-                         envp
-    );
-
-    //int posix_spawn_file_actions_init(posix_spawn_file_actions_t *file_actions);
-    var posix_spawn_file_actions_init = libc.declare("posix_spawn_file_actions_init",
-                         ctypes.default_abi,
-                         ctypes.int,
-                         posix_spawn_file_actions_t.ptr
-    );
-
-    //int posix_spawn_file_actions_destroy(posix_spawn_file_actions_t *file_actions);
-    var posix_spawn_file_actions_destroy = libc.declare("posix_spawn_file_actions_destroy",
-                         ctypes.default_abi,
-                         ctypes.int,
-                         posix_spawn_file_actions_t.ptr
-    );
-
-    // int posix_spawn_file_actions_adddup2(posix_spawn_file_actions_t *
-    //                                      file_actions, int fildes, int newfildes);
-    var posix_spawn_file_actions_adddup2 = libc.declare("posix_spawn_file_actions_adddup2",
-                         ctypes.default_abi,
-                         ctypes.int,
-                         posix_spawn_file_actions_t.ptr,
-                         ctypes.int,
-                         ctypes.int
-    );
-
-    // int posix_spawn_file_actions_addclose(posix_spawn_file_actions_t *
-    //                                       file_actions, int fildes);
-    var posix_spawn_file_actions_addclose = libc.declare("posix_spawn_file_actions_addclose",
-                         ctypes.default_abi,
-                         ctypes.int,
-                         posix_spawn_file_actions_t.ptr,
-                         ctypes.int
-    );
-
-    //int pipe(int pipefd[2]);
-    var pipefd = ctypes.int.array(2);
-    var pipe = libc.declare("pipe",
-                         ctypes.default_abi,
-                         ctypes.int,
-                         pipefd
-    );
-
-    //int close(int fd);
-    var close = libc.declare("close",
-                          ctypes.default_abi,
-                          ctypes.int,
-                          ctypes.int
-    );
-
-    //pid_t waitpid(pid_t pid, int *status, int options);
-    var waitpid = libc.declare("waitpid",
-                          ctypes.default_abi,
-                          pid_t,
-                          pid_t,
-                          ctypes.int.ptr,
-                          ctypes.int
-    );
-
-    //int kill(pid_t pid, int sig);
-    var kill = libc.declare("kill",
-                          ctypes.default_abi,
-                          ctypes.int,
-                          pid_t,
-                          ctypes.int
-    );
-
-    //int read(int fd, void *buf, size_t count);
-    var bufferSize = 1024;
-    var buffer = ctypes.char.array(bufferSize);
-    var read = libc.declare("read",
-                          ctypes.default_abi,
-                          ctypes.int,
-                          ctypes.int,
-                          buffer,
-                          ctypes.int
-    );
-
-    //ssize_t write(int fd, const void *buf, size_t count);
-    var write = libc.declare("write",
-                          ctypes.default_abi,
-                          ctypes.int,
-                          ctypes.int,
-                          ctypes.char.ptr,
-                          ctypes.int
-    );
-
-    //int chdir(const char *path);
-    var chdir = libc.declare("chdir",
-                          ctypes.default_abi,
-                          ctypes.int,
-                          ctypes.char.ptr
-    );
-
-    //int fcntl(int fd, int cmd, ... /* arg */ );
-    var fcntl = libc.declare("fcntl",
-                          ctypes.default_abi,
-                          ctypes.int,
-                          ctypes.int,
-                          ctypes.int,
-                          ctypes.int
-    );
-
-    function popen(command, workdir, args, environment, child) {
-        var _in,
-            _out,
-            _err,
-            pid,
-            rc;
-        _in = new pipefd();
-        _out = new pipefd();
-        if(!options.mergeStderr)
-            _err = new pipefd();
-
-        var _args = argv();
-        args.unshift(command);
-        for(var i=0;i<args.length;i++) {
-            _args[i] = ctypes.char.array()(args[i]);
-        }
-        var _envp = envp();
-        for(var i=0;i<environment.length;i++) {
-            _envp[i] = ctypes.char.array()(environment[i]);
-            // LogError(_envp);
-        }
-
-        rc = pipe(_in);
-        if (rc < 0) {
-            return -1;
-        }
-        rc = pipe(_out);
-        fcntl(_out[0], F_SETFL, getPlatformValue(O_NONBLOCK));
-        if (rc < 0) {
-            close(_in[0]);
-            close(_in[1]);
-            return -1
-        }
-        if(!options.mergeStderr) {
-            rc = pipe(_err);
-            fcntl(_err[0], F_SETFL, getPlatformValue(O_NONBLOCK));
-            if (rc < 0) {
-                close(_in[0]);
-                close(_in[1]);
-                close(_out[0]);
-                close(_out[1]);
-                return -1
-            }
-        }
-
-        let STDIN_FILENO = 0;
-        let STDOUT_FILENO = 1;
-        let STDERR_FILENO = 2;
-
-        let action = posix_spawn_file_actions_t();
-        posix_spawn_file_actions_init(action.address());
-
-        posix_spawn_file_actions_adddup2(action.address(), _in[0], STDIN_FILENO);
-        posix_spawn_file_actions_addclose(action.address(), _in[1]);
-        posix_spawn_file_actions_addclose(action.address(), _in[0]);
-
-        posix_spawn_file_actions_adddup2(action.address(), _out[1], STDOUT_FILENO);
-        posix_spawn_file_actions_addclose(action.address(), _out[1]);
-        posix_spawn_file_actions_addclose(action.address(), _out[0]);
-
-        if (!options.mergeStderr) {
-          posix_spawn_file_actions_adddup2(action.address(), _err[1], STDERR_FILENO);
-          posix_spawn_file_actions_addclose(action.address(), _err[1]);
-          posix_spawn_file_actions_addclose(action.address(), _err[0]);
-        }
-
-        // posix_spawn doesn't support setting a custom workdir for the child,
-        // so change the cwd in the parent process before launching the child process.
-        if (workdir) {
-          if (chdir(workdir) < 0) {
-            throw new Error("Unable to change workdir before launching child process");
-          }
-        }
-
-        closeOtherFds(action, _in[1], _out[0], options.mergeStderr ? undefined : _err[0]);
-
-        let id = pid_t(0);
-        let rv = posix_spawn(id.address(), command, action.address(), null, _args, _envp);
-        posix_spawn_file_actions_destroy(action.address());
-        if (rv != 0) {
-          // we should not really end up here
-          if(!options.mergeStderr) {
-            close(_err[0]);
-            close(_err[1]);
-          }
-          close(_out[0]);
-          close(_out[1]);
-          close(_in[0]);
-          close(_in[1]);
-          throw new Error("Fatal - failed to create subprocess '"+command+"'");
-        }
-        pid = id.value;
-
-        close(_in[0]);
-        close(_out[1]);
-        if (!options.mergeStderr)
-          close(_err[1]);
-        child.stdin  = _in[1];
-        child.stdout = _out[0];
-        child.stderr = options.mergeStderr ? undefined : _err[0];
-        child.pid = pid;
-
-        return pid;
-    }
-
-
-    // close any file descriptors that are not required for the process
-    function closeOtherFds(action, fdIn, fdOut, fdErr) {
-        // Unfortunately on mac, any fd registered in posix_spawn_file_actions_addclose
-        // that can't be closed correctly will make posix_spawn fail...
-        // Even if we ensure registering only still opened fds.
-        if (gXulRuntime.OS == "Darwin")
-            return;
-
-        var maxFD = 256; // arbitrary max
-
-
-        var rlim_t = getPlatformValue(RLIM_T);
-
-        const RLIMITS = new ctypes.StructType("RLIMITS", [
-            {"rlim_cur": rlim_t},
-            {"rlim_max": rlim_t}
-        ]);
-
-        try {
-            var getrlimit = libc.declare("getrlimit",
-                                  ctypes.default_abi,
-                                  ctypes.int,
-                                  ctypes.int,
-                                  RLIMITS.ptr
-            );
-
-            var rl = new RLIMITS();
-            if (getrlimit(getPlatformValue(RLIMIT_NOFILE), rl.address()) == 0) {
-                maxFD = rl.rlim_cur;
-            }
-            debugLog("getlimit: maxFD="+maxFD+"\n");
-
-        }
-        catch(ex) {
-            debugLog("getrlimit: no such function on this OS\n");
-            debugLog(ex.toString());
-        }
-
-        // close any file descriptors
-        // fd's 0-2 are already closed
-        for (var i = 3; i < maxFD; i++) {
-            if (i != fdIn && i != fdOut && i != fdErr && fcntl(i, F_GETFD, -1) >= 0) {
-                posix_spawn_file_actions_addclose(action.address(), i);
-            }
-        }
-    }
-
-    /*
-     * createStdinWriter ()
-     *
-     * Create a ChromeWorker object for writing data to the subprocess' stdin
-     * pipe. The ChromeWorker object lives on a separate thread; this avoids
-     * internal deadlocks.
-     */
-    function createStdinWriter() {
-        debugLog("Creating new stdin worker\n");
-        stdinWorker = new ChromeWorker(WORKER_URL_UNIX);
-        stdinWorker.onmessage = function(event) {
-            switch (event.data.msg) {
-            case "info":
-                switch(event.data.data) {
-                case "WriteOK":
-                    pendingWriteCount--;
-                    debugLog("got OK from stdinWorker - remaining count: "+pendingWriteCount+"\n");
-                    break;
-                case "ClosedOK":
-                    stdinOpenState = CLOSED;
-                    debugLog("Stdin pipe closed\n");
-                    break;
-                default:
-                    debugLog("got msg from stdinWorker: "+event.data.data+"\n");
-                }
-                break;
-            case "debug":
-                debugLog("stdinWorker: "+event.data.data+"\n");
-                break;
-            case "error":
-                LogError("got error from stdinWorker: "+event.data.data+"\n");
-                pendingWriteCount = 0;
-                stdinOpenState = CLOSED;
-            }
-        }
-        stdinWorker.onerror = function(error) {
-            pendingWriteCount = 0;
-            closeStdinHandle();
-            LogError("got error from stdinWorker: "+error.message+"\n");
-        }
-        stdinWorker.postMessage({msg: "init", libc: options.libc});
-    }
-
-    /*
-     * writeStdin()
-     * @data: String containing the data to write
-     *
-     * Write data to the subprocess' stdin (equals to sending a request to the
-     * ChromeWorker object to write the data).
-     */
-    function writeStdin(data) {
-        if (stdinOpenState == CLOSED) return; // do not write to closed pipes
-
-        ++pendingWriteCount;
-        debugLog("sending "+data.length+" bytes to stdinWorker\n");
-        var pipe = parseInt(child.stdin);
-
-        stdinWorker.postMessage({
-            msg: 'write',
-            pipe: pipe,
-            data: data
-        });
-    }
-
-
-    /*
-     * closeStdinHandle()
-     *
-     * Close the stdin pipe, either directly or by requesting the ChromeWorker to
-     * close the pipe. The ChromeWorker will only close the pipe after the last write
-     * request process is done.
-     */
-
-    function closeStdinHandle() {
-        debugLog("trying to close stdin\n");
-        if (stdinOpenState != OPEN) return;
-        stdinOpenState = CLOSEABLE;
-
-        if (stdinWorker) {
-            debugLog("sending close stdin to worker\n");
-            var pipePtr = parseInt(child.stdin);
-
-            stdinWorker.postMessage({
-                msg: 'close',
-                pipe: pipePtr
-            });
-        }
-        else {
-            stdinOpenState = CLOSED;
-            debugLog("Closing Stdin\n");
-            close(child.stdin) && LogError("CloseHandle stdin failed");
-        }
-    }
-
-
-    /*
-     * createReader(pipe, name)
-     *
-     * @pipe: handle to the pipe
-     * @name: String containing the pipe name (stdout or stderr)
-     * @callbackFunc: function to be called with the read data
-     *
-     * Create a ChromeWorker object for reading data asynchronously from
-     * the pipe (i.e. on a separate thread), and passing the result back to
-     * the caller.
-     *
-     */
-    function createReader(pipe, name, callbackFunc) {
-        var worker = new ChromeWorker(WORKER_URL_UNIX);
-        worker.onmessage = function(event) {
-            switch(event.data.msg) {
-            case "data":
-                debugLog("got "+event.data.count+" bytes from "+name+"\n");
-                var data = '';
-                if (options.charset === null) {
-                    data = getBytes(event.data.data);
-                }
-                else {
-                    try {
-                        data = convertBytes(event.data.data, options.charset);
-                    }
-                    catch(ex) {
-                        console.warn("error decoding output: " + ex);
-                        data = getBytes(event.data.data);
-                    }
-                }
-
-                callbackFunc(data);
-                break;
-            case "done":
-                debugLog("Pipe "+name+" closed\n");
-                if (event.data.data != 0) workerExitCode = event.data.data;
-                --readers;
-                if (readers == 0) cleanup();
-                break;
-            default:
-                debugLog("Got msg from "+name+": "+event.data.data+"\n");
-            }
-        }
-        worker.onerror = function(error) {
-            LogError("Got error from "+name+": "+error.message);
-        }
-
-        worker.postMessage({
-                msg: 'read',
-                pipe: pipe,
-                pid: pid,
-                libc: options.libc,
-                charset: options.charset === null ? "null" : options.charset,
-                name: name
-            });
-
-        return worker;
-    }
-
-    /*
-     * readPipes()
-     *
-     * Open the pipes for reading from stdout and stderr
-     */
-    function readPipes() {
-
-        stdoutWorker = createReader(child.stdout, "stdout", function (data) {
-            if(options.stdout) {
-                setTimeout(function() {
-                    options.stdout(data);
-                }, 0);
-            } else {
-                output += data;
-            }
-        });
-
-        if (!options.mergeStderr) stderrWorker = createReader(child.stderr, "stderr", function (data) {
-            if(options.stderr) {
-                setTimeout(function() {
-                    options.stderr(data);
-                 }, 0);
-            } else {
-                error += data;
-            }
-        });
-    }
-
-    function cleanup() {
-        debugLog("Cleanup called\n");
-        if(active) {
-            active = false;
-
-            closeStdinHandle(); // should only be required in case of errors
-
-            var result, status = ctypes.int();
-            result = waitpid(child.pid, status.address(), 0);
-            if (result > 0)
-                exitCode = status.value
-            else
-                if (workerExitCode >= 0)
-                    exitCode = workerExitCode
-                else
-                    exitCode = status.value;
-
-            if (stdinWorker)
-                stdinWorker.postMessage({msg: 'stop'})
-
-            setTimeout(function _done() {
-                if (options.done) {
-                    try {
-                        options.done({
-                            exitCode: exitCode,
-                            stdout: output,
-                            stderr: error,
-                        });
-                    }
-                    catch(ex) {
-                        // prevent from blocking if options.done() throws an error
-                        done = true;
-                        throw ex;
-                    }
-
-                }
-                done = true;
-            }, 0);
-
-            libc.close();
-        }
-    }
-
-    //main
-
-    var cmdStr = getCommandStr(options.command);
-    var workDir = getWorkDir(options.workdir);
-
-    child = {};
-    pid = popen(cmdStr, workDir, options.arguments, options.environment, child);
-
-    debugLog("subprocess started; got PID "+pid+"\n");
-
-    readPipes();
-
-    if (options.stdin) {
-        createStdinWriter();
-        if(typeof(options.stdin) == 'function') {
-            try {
-                options.stdin({
-                    write: function(data) {
-                        writeStdin(data);
-                    },
-                    close: function() {
-                        closeStdinHandle();
-                    }
-                });
-            }
-            catch(ex) {
-                // prevent from failing if options.stdin() throws an exception
-                closeStdinHandle();
-                throw ex;
-            }
-        } else {
-            writeStdin(options.stdin);
-            closeStdinHandle();
-        }
-    }
-
-    return {
-        wait: function() {
-            // wait for async operations to complete
-            var thread = Cc['@mozilla.org/thread-manager;1'].getService(Ci.nsIThreadManager).currentThread;
-            while (! done) thread.processNextEvent(true)
-            return exitCode;
-        },
-        kill: function(hardKill) {
-            var rv = kill(pid, (hardKill ? 9: 15));
-            cleanup(-1);
-            return rv;
-        }
-    }
-}
-
-
-module.exports = subprocess;
deleted file mode 100644
--- a/b2g/simulator/packages/subprocess/lib/subprocess_worker_unix.js
+++ /dev/null
@@ -1,248 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/.
- */
-
-/*
- * ChromeWorker Object subprocess.jsm on Unix-like systems (Linux, Mac OS X, ...)
- * to process stdin/stdout/stderr on separate threads.
- *
- */
-
-// Being a ChromeWorker object, implicitly uses the following:
-// Components.utils.import("resource://gre/modules/ctypes.jsm");
-
-'use strict';
-
-const BufferSize = 1024;
-
-var libc = null;
-var libcFunc = {};
-
-
-/*
-    struct pollfd {
-         int    fd;       // file descriptor
-         short  events;   // events to look for
-         short  revents;  // events returned
-     };
-*/
-
-var pollfd = new ctypes.StructType("pollfd",
-                        [   {'fd': ctypes.int},
-                            {'events': ctypes.short},
-                            {'revents': ctypes.short}
-                        ]);
-
-var WriteBuffer = ctypes.uint8_t.array(BufferSize);
-var ReadBuffer = ctypes.char.array(BufferSize);
-
-
-const POLLIN     = 0x0001;
-const POLLOUT    = 0x0004;
-
-const POLLERR    = 0x0008;         // some poll error occurred
-const POLLHUP    = 0x0010;         // file descriptor was "hung up"
-const POLLNVAL   = 0x0020;         // requested events "invalid"
-
-const WNOHANG    = 0x01;
-
-const pid_t = ctypes.int32_t;
-
-const INDEFINITE = -1;
-const NOWAIT     = 0;
-const WAITTIME   = 200  // wait time for poll() in ms
-
-function initLibc(libName) {
-    postMessage({msg: "debug", data: "initialising library with "+ libName});
-
-    libc = ctypes.open(libName);
-
-    libcFunc.pollFds = pollfd.array(1);
-
-    // int poll(struct pollfd fds[], nfds_t nfds, int timeout);
-    libcFunc.poll = libc.declare("poll",
-                                  ctypes.default_abi,
-                                  ctypes.int,
-                                  libcFunc.pollFds,
-                                  ctypes.unsigned_int,
-                                  ctypes.int);
-
-    //ssize_t write(int fd, const void *buf, size_t count);
-    // NOTE: buf is declared as array of unsigned int8 instead of char to avoid
-    // implicit charset conversion
-    libcFunc.write = libc.declare("write",
-                                  ctypes.default_abi,
-                                  ctypes.int,
-                                  ctypes.int,
-                                  WriteBuffer,
-                                  ctypes.int);
-
-    //int read(int fd, void *buf, size_t count);
-    libcFunc.read = libc.declare("read",
-                                  ctypes.default_abi,
-                                  ctypes.int,
-                                  ctypes.int,
-                                  ReadBuffer,
-                                  ctypes.int);
-
-    //int pipe(int pipefd[2]);
-    libcFunc.pipefd = ctypes.int.array(2);
-
-    //int close(int fd);
-    libcFunc.close = libc.declare("close",
-                                  ctypes.default_abi,
-                                  ctypes.int,
-                                  ctypes.int);
-
-    //pid_t waitpid(pid_t pid, int *status, int options);
-    libcFunc.waitpid = libc.declare("waitpid",
-                                  ctypes.default_abi,
-                                  pid_t,
-                                  pid_t,
-                                  ctypes.int.ptr,
-                                  ctypes.int);
-}
-
-function closePipe(pipe) {
-    libcFunc.close(pipe);
-}
-
-function writePipe(pipe, data) {
-
-    postMessage({msg: "debug", data: "trying to write to "+pipe});
-
-    let numChunks = Math.floor(data.length / BufferSize);
-    let pData = new WriteBuffer();
-
-    for (var chunk = 0; chunk <= numChunks; chunk ++) {
-        let numBytes = chunk < numChunks ? BufferSize : data.length - chunk * BufferSize;
-        for (var i=0; i < numBytes; i++) {
-            pData[i] = data.charCodeAt(chunk * BufferSize + i) % 256;
-        }
-
-        let bytesWritten = libcFunc.write(pipe, pData, numBytes);
-        if (bytesWritten != numBytes) {
-            closePipe();
-            libc.close();
-            postMessage({ msg: "error", data: "error: wrote "+bytesWritten+" instead of "+numBytes+" bytes"});
-            close();
-        }
-    }
-    postMessage({msg: "info", data: "wrote "+data.length+" bytes of data"});
-}
-
-
-function readString(data, length, charset) {
-    var string = '', bytes = [];
-    for(var i = 0;i < length; i++) {
-        if(data[i] == 0 && charset != "null") // stop on NULL character for non-binary data
-           break;
-
-        bytes.push(data[i]);
-    }
-
-    return bytes;
-}
-
-function readPipe(pipe, charset, pid) {
-    var p = new libcFunc.pollFds;
-    p[0].fd = pipe;
-    p[0].events = POLLIN | POLLERR | POLLHUP;
-    p[0].revents = 0;
-    var pollTimeout = WAITTIME;
-    var exitCode = -1;
-    var readCount = 0;
-    var result, status = ctypes.int();
-    result = 0;
-
-
-    const i=0;
-    while (true) {
-        if (result == 0) {
-            result = libcFunc.waitpid(pid, status.address(), WNOHANG);
-            if (result > 0) {
-                pollTimeout = NOWAIT;
-                exitCode = parseInt(status.value);
-                postMessage({msg: "debug", data: "waitpid signaled subprocess stop, exitcode="+status.value });
-            }
-        }
-        var r = libcFunc.poll(p, 1, pollTimeout);
-        if (r > 0) {
-            if (p[i].revents & POLLIN) {
-                postMessage({msg: "debug", data: "reading next chunk"});
-                readCount = readPolledFd(p[i].fd, charset);
-                if (readCount == 0) break;
-            }
-
-            if (p[i].revents & POLLHUP) {
-                postMessage({msg: "debug", data: "poll returned HUP"});
-                break;
-            }
-            else if (p[i].revents & POLLERR) {
-                postMessage({msg: "error", data: "poll returned error"});
-                break;
-            }
-            else if (p[i].revents != POLLIN) {
-                postMessage({msg: "error", data: "poll returned "+p[i]});
-                break;
-            }
-        }
-        else
-            if (pollTimeout == 0 || r < 0) break;
-    }
-
-    // continue reading until the buffer is empty
-    while (readCount > 0) {
-      readCount = readPolledFd(pipe, charset);
-    }
-
-    libcFunc.close(pipe);
-    postMessage({msg: "done", data: exitCode });
-    libc.close();
-    close();
-}
-
-function readPolledFd(pipe, charset) {
-    var line = new ReadBuffer();
-    var r = libcFunc.read(pipe, line, BufferSize);
-
-    if (r > 0) {
-        var c = readString(line, r, charset);
-        postMessage({msg: "data", data: c, count: c.length});
-    }
-    return r;
-}
-
-onmessage = function (event) {
-    switch (event.data.msg) {
-    case "init":
-        initLibc(event.data.libc);
-        break;
-    case "read":
-        initLibc(event.data.libc);
-        readPipe(event.data.pipe, event.data.charset, event.data.pid);
-        break;
-    case "write":
-        // data contents:
-        //   msg: 'write'
-        //   data: the data (string) to write
-        //   pipe: ptr to pipe
-        writePipe(event.data.pipe, event.data.data);
-        postMessage({msg: "info", data: "WriteOK"});
-        break;
-    case "close":
-        postMessage({msg: "debug", data: "closing stdin\n"});
-
-        closePipe(event.data.pipe);
-        postMessage({msg: "info", data: "ClosedOK"});
-        break;
-    case "stop":
-        libc.close(); // do not use libc after this point
-        close();
-        break;
-    default:
-        throw("error: Unknown command"+event.data.msg+"\n");
-    }
-    return;
-};
deleted file mode 100644
--- a/b2g/simulator/packages/subprocess/lib/subprocess_worker_win.js
+++ /dev/null
@@ -1,206 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/.
- */
-
-/*
- * ChromeWorker Object subprocess.jsm on Windows to process stdin/stdout/stderr
- * on separate threads.
- *
- */
-
-// Being a ChromeWorker object, implicitly uses the following:
-// Components.utils.import("resource://gre/modules/ctypes.jsm");
-
-'use strict';
-
-const BufferSize = 1024;
-
-const BOOL = ctypes.bool;
-const HANDLE = ctypes.size_t;
-const DWORD = ctypes.uint32_t;
-const LPDWORD = DWORD.ptr;
-const PVOID = ctypes.voidptr_t;
-const LPVOID = PVOID;
-
-/*
-typedef struct _OVERLAPPED {
-  ULONG_PTR Internal;
-  ULONG_PTR InternalHigh;
-  union {
-    struct {
-      DWORD Offset;
-      DWORD OffsetHigh;
-    };
-    PVOID  Pointer;
-  };
-  HANDLE    hEvent;
-} OVERLAPPED, *LPOVERLAPPED;
-*/
-const OVERLAPPED = new ctypes.StructType("OVERLAPPED");
-
-var ReadFileBuffer = ctypes.char.array(BufferSize);
-var WriteFileBuffer = ctypes.uint8_t.array(BufferSize);
-
-var kernel32dll = null;
-var libFunc = {};
-
-function initLib(libName) {
-    if (ctypes.size_t.size == 8) {
-        var WinABI = ctypes.default_abi;
-    } else {
-        var WinABI = ctypes.winapi_abi;
-    }
-
-    kernel32dll = ctypes.open(libName);
-
-    /*
-    BOOL WINAPI WriteFile(
-      __in         HANDLE hFile,
-      __in         LPCVOID lpBuffer,
-      __in         DWORD nNumberOfBytesToWrite,
-      __out_opt    LPDWORD lpNumberOfBytesWritten,
-      __inout_opt  LPOVERLAPPED lpOverlapped
-    );
-
-    NOTE: lpBuffer is declared as array of unsigned int8 instead of char to avoid
-           implicit charset conversion
-    */
-    libFunc.WriteFile = kernel32dll.declare("WriteFile",
-                                        WinABI,
-                                        BOOL,
-                                        HANDLE,
-                                        WriteFileBuffer,
-                                        DWORD,
-                                        LPDWORD,
-                                        OVERLAPPED.ptr
-    );
-
-    /*
-    BOOL WINAPI ReadFile(
-      __in         HANDLE hFile,
-      __out        LPVOID ReadFileBuffer,
-      __in         DWORD nNumberOfBytesToRead,
-      __out_opt    LPDWORD lpNumberOfBytesRead,
-      __inout_opt  LPOVERLAPPED lpOverlapped
-    );
-    */
-    libFunc.ReadFile = kernel32dll.declare("ReadFile",
-                                        WinABI,
-                                        BOOL,
-                                        HANDLE,
-                                        ReadFileBuffer,
-                                        DWORD,
-                                        LPDWORD,
-                                        OVERLAPPED.ptr
-    );
-
-    /*
-    BOOL WINAPI CloseHandle(
-      __in  HANDLE hObject
-    );
-    */
-    libFunc.CloseHandle = kernel32dll.declare("CloseHandle",
-                                            WinABI,
-                                            BOOL,
-                                            HANDLE
-    );
-}
-
-
-function writePipe(pipe, data) {
-    var bytesWritten = DWORD(0);
-
-    var pData = new WriteFileBuffer();
-
-    var numChunks = Math.floor(data.length / BufferSize);
-    for (var chunk = 0; chunk <= numChunks; chunk ++) {
-        var numBytes = chunk < numChunks ? BufferSize : data.length - chunk * BufferSize;
-        for (var i=0; i < numBytes; i++) {
-            pData[i] = data.charCodeAt(chunk * BufferSize + i) % 256;
-        }
-
-      var r = libFunc.WriteFile(pipe, pData, numBytes, bytesWritten.address(), null);
-      if (bytesWritten.value != numBytes)
-          throw("error: wrote "+bytesWritten.value+" instead of "+numBytes+" bytes");
-    }
-    postMessage("wrote "+data.length+" bytes of data");
-}
-
-function readString(data, length, charset) {
-    var string = '', bytes = [];
-    for(var i = 0;i < length; i++) {
-        if(data[i] == 0 && charset != "null") // stop on NULL character for non-binary data
-           break;
-
-        bytes.push(data[i]);
-    }
-
-    return bytes;
-}
-
-function readPipe(pipe, charset) {
-    while (true) {
-        var bytesRead = DWORD(0);
-        var line = new ReadFileBuffer();
-        var r = libFunc.ReadFile(pipe, line, BufferSize, bytesRead.address(), null);
-
-        if (!r) {
-            // stop if we get an error (such as EOF reached)
-            postMessage({msg: "info", data: "ReadFile failed"});
-            break;
-        }
-
-        if (bytesRead.value > 0) {
-            var c = readString(line, bytesRead.value, charset);
-            postMessage({msg: "data", data: c, count: c.length});
-        }
-        else {
-            break;
-        }
-    }
-    libFunc.CloseHandle(pipe);
-    postMessage({msg: "done"});
-    kernel32dll.close();
-    close();
-}
-
-onmessage = function (event) {
-    let pipePtr;
-    switch (event.data.msg) {
-    case "init":
-        initLib(event.data.libc);
-        break;
-    case "write":
-        // data contents:
-        //   msg: 'write'
-        //   data: the data (string) to write
-        //   pipe: ptr to pipe
-        pipePtr = HANDLE.ptr(event.data.pipe);
-        writePipe(pipePtr.contents, event.data.data);
-        postMessage("WriteOK");
-        break;
-    case "read":
-        initLib(event.data.libc);
-        pipePtr = HANDLE.ptr(event.data.pipe);
-        readPipe(pipePtr.contents, event.data.charset);
-        break;
-    case "close":
-        pipePtr = HANDLE.ptr(event.data.pipe);
-        postMessage("closing stdin\n");
-
-        if (libFunc.CloseHandle(pipePtr.contents)) {
-            postMessage("ClosedOK");
-        }
-        else
-            postMessage("Could not close stdin handle");
-        break;
-    case "stop":
-        kernel32dll.close();
-        close();
-        break;
-    default:
-        throw("error: Unknown command"+event.data.msg+"\n");
-    }
-    return;
-};
deleted file mode 100644
--- a/b2g/simulator/packages/subprocess/package.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
-    "name": "subprocess",
-    "license": "MPL 1.1/GPL 2.0/LGPL 2.1",
-    "author": "Alexandre Poirot",
-    "contributors": [
-      "Jan Gerber (original creator) <j@mailb.org>",
-      "Patrick Brunschwig (author of almost all code) <patrick@mozilla-enigmail.org>",
-      "Ramalingam Saravanan (from enigmail team) <svn@xmlterm.org>"
-    ],
-    "version": "0.1.1",
-    "dependencies": [
-      "api-utils"
-    ],
-    "description": "Addon-sdk package for subprocess xpcom components from enigmail. Allow to run process, manipulate stdin/out and kill it."
-}
deleted file mode 100644
--- a/b2g/simulator/packages/subprocess/tests/test-subprocess.js
+++ /dev/null
@@ -1,144 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/.
- */
-
-const { Cc, Ci } = require("chrome");
-const subprocess = require("subprocess");
-const env = Cc["@mozilla.org/process/environment;1"].getService(Ci.nsIEnvironment);
-
-// For now, only test on windows
-if (env.get('OS') && env.get('OS').match(/Windows/)) {
-
-exports.testWindows = function (test) {
-  test.waitUntilDone();
-  let envTestValue = "OK";
-  let gotStdout = false;
-
-  var p = subprocess.call({
-    // Retrieve windows cmd.exe path from env
-    command:     env.get('ComSpec'),
-    // In order to execute a simple "echo" function
-    arguments:   ['/C', 'echo %ENV_TEST%'], // ' & type CON' should display stdin, but doesn't work
-    // Printing an environnement variable set here by the parent process
-    environment: ['ENV_TEST='+envTestValue],
-
-    stdin: function(stdin) {
-      // Win32 command line is not really made for stdin
-      // So it doesn't seems to work as it's hard to retrieve stdin
-      stdin.write("stdin");
-      stdin.close();
-    },
-    stdout: function(data) {
-      test.assert(!gotStdout,"don't get stdout twice");
-      test.assertEqual(data,envTestValue+"\r\n","stdout contains the environment variable");
-      gotStdout = true;
-    },
-    stderr: function(data) {
-      test.fail("shouldn't get stderr");
-    },
-    done: function() {
-      test.assert(gotStdout, "got stdout before finished");
-      test.done();
-    },
-    mergeStderr: false
-  });
-
-}
-
-exports.testWindowsStderr = function (test) {
-  test.waitUntilDone();
-  let gotStderr = false;
-
-  var p = subprocess.call({
-    command:     env.get('ComSpec'),
-    arguments:   ['/C', 'nonexistent'],
-
-    stdout: function(data) {
-      test.fail("shouldn't get stdout");
-    },
-    stderr: function(data) {
-      test.assert(!gotStderr,"don't get stderr twice");
-      test.assertEqual(
-        data,
-        "'nonexistent' is not recognized as an internal or external command,\r\n" +
-        "operable program or batch file.\r\n",
-        "stderr contains the error message"
-      );
-      gotStderr = true;
-    },
-    done: function() {
-      test.assert(gotStderr, "got stderr before finished");
-      test.done();
-    },
-    mergeStderr: false
-  });
-
-}
-
-}
-
-if (env.get('USER') && env.get('SHELL')) {
-
-exports.testUnix = function (test) {
-  test.waitUntilDone();
-  let envTestValue = "OK";
-  let gotStdout = false;
-
-  var p = subprocess.call({
-    command:     '/bin/sh',
-    // Print stdin and our env variable
-    //arguments:   ['-c', 'echo $@ $ENV_TEST'],
-    environment: ['ENV_TEST='+envTestValue],
-
-    stdin: function(stdin) {
-      stdin.write("echo $ENV_TEST");
-      stdin.close();
-    },
-    stdout: function(data) {
-      test.assert(!gotStdout,"don't get stdout twice");
-      test.assertEqual(data,envTestValue+"\n","stdout contains the environment variable");
-      gotStdout = true;
-    },
-    stderr: function(data) {
-      test.fail("shouldn't get stderr");
-    },
-    done: function() {
-      test.assert(gotStdout, "got stdout before finished");
-      test.done();
-    },
-    mergeStderr: false
-  });
-}
-
-exports.testUnixStderr = function (test) {
-  test.waitUntilDone();
-  let gotStderr = false;
-
-  var p = subprocess.call({
-    // Hope that we don't have to give absolute path on linux ...
-    command:     '/bin/sh',
-    arguments:   ['nonexistent'],
-
-    stdout: function(data) {
-      test.fail("shouldn't get stdout");
-    },
-    stderr: function(data) {
-      test.assert(!gotStderr,"don't get stderr twice");
-      // There is two variant of error message
-      if (data == "/bin/sh: 0: Can't open nonexistent\n")
-        test.pass("stderr containes the expected error message");
-      else
-        test.assertEqual(data, "/bin/sh: nonexistent: No such file or directory\n",
-                         "stderr contains the error message");
-      gotStderr = true;
-    },
-    done: function() {
-      test.assert(gotStderr, "got stderr before finished");
-      test.done();
-    },
-    mergeStderr: false
-  });
-}
-
-}