1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/b2g/simulator/lib/simulator-process.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,193 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. 1.7 + */ 1.8 + 1.9 +'use strict'; 1.10 + 1.11 +const { Cc, Ci, Cu, ChromeWorker } = require("chrome"); 1.12 + 1.13 +Cu.import("resource://gre/modules/Services.jsm"); 1.14 + 1.15 +const { EventTarget } = require("sdk/event/target"); 1.16 +const { emit, off } = require("sdk/event/core"); 1.17 +const { Class } = require("sdk/core/heritage"); 1.18 +const Environment = require("sdk/system/environment").env; 1.19 +const Runtime = require("sdk/system/runtime"); 1.20 +const Self = require("sdk/self"); 1.21 +const URL = require("sdk/url"); 1.22 +const Subprocess = require("subprocess"); 1.23 +const { Promise: promise } = Cu.import("resource://gre/modules/Promise.jsm", {}); 1.24 +const Prefs = require("sdk/simple-prefs").prefs; 1.25 + 1.26 +const { rootURI: ROOT_URI } = require('@loader/options'); 1.27 +const PROFILE_URL = ROOT_URI + "profile/"; 1.28 +const BIN_URL = ROOT_URI + "b2g/"; 1.29 + 1.30 +// Log subprocess error and debug messages to the console. This logs messages 1.31 +// for all consumers of the API. We trim the messages because they sometimes 1.32 +// have trailing newlines. And note that registerLogHandler actually registers 1.33 +// an error handler, despite its name. 1.34 +Subprocess.registerLogHandler( 1.35 + function(s) console.error("subprocess: " + s.trim()) 1.36 +); 1.37 +Subprocess.registerDebugHandler( 1.38 + function(s) console.debug("subprocess: " + s.trim()) 1.39 +); 1.40 + 1.41 +exports.SimulatorProcess = Class({ 1.42 + extends: EventTarget, 1.43 + initialize: function initialize(options) { 1.44 + EventTarget.prototype.initialize.call(this, options); 1.45 + 1.46 + this.on("stdout", function onStdout(data) console.log(data.trim())); 1.47 + this.on("stderr", function onStderr(data) console.error(data.trim())); 1.48 + }, 1.49 + 1.50 + // check if b2g is running 1.51 + get isRunning() !!this.process, 1.52 + 1.53 + /** 1.54 + * Start the process and connect the debugger client. 1.55 + */ 1.56 + run: function() { 1.57 + // kill before start if already running 1.58 + if (this.process != null) { 1.59 + this.process 1.60 + .kill() 1.61 + .then(this.run.bind(this)); 1.62 + return; 1.63 + } 1.64 + 1.65 + // resolve b2g binaries path (raise exception if not found) 1.66 + let b2gExecutable = this.b2gExecutable; 1.67 + 1.68 + this.once("stdout", function () { 1.69 + if (Runtime.OS == "Darwin") { 1.70 + console.debug("WORKAROUND run osascript to show b2g-desktop window"+ 1.71 + " on Runtime.OS=='Darwin'"); 1.72 + // Escape double quotes and escape characters for use in AppleScript. 1.73 + let path = b2gExecutable.path 1.74 + .replace(/\\/g, "\\\\").replace(/\"/g, '\\"'); 1.75 + 1.76 + Subprocess.call({ 1.77 + command: "/usr/bin/osascript", 1.78 + arguments: ["-e", 'tell application "' + path + '" to activate'], 1.79 + }); 1.80 + } 1.81 + }); 1.82 + 1.83 + let environment; 1.84 + if (Runtime.OS == "Linux") { 1.85 + environment = ["TMPDIR=" + Services.dirsvc.get("TmpD",Ci.nsIFile).path]; 1.86 + if ("DISPLAY" in Environment) { 1.87 + environment.push("DISPLAY=" + Environment.DISPLAY); 1.88 + } 1.89 + } 1.90 + 1.91 + // spawn a b2g instance 1.92 + this.process = Subprocess.call({ 1.93 + command: b2gExecutable, 1.94 + arguments: this.b2gArguments, 1.95 + environment: environment, 1.96 + 1.97 + // emit stdout event 1.98 + stdout: (function(data) { 1.99 + emit(this, "stdout", data); 1.100 + }).bind(this), 1.101 + 1.102 + // emit stderr event 1.103 + stderr: (function(data) { 1.104 + emit(this, "stderr", data); 1.105 + }).bind(this), 1.106 + 1.107 + // on b2g instance exit, reset tracked process, remoteDebuggerPort and 1.108 + // shuttingDown flag, then finally emit an exit event 1.109 + done: (function(result) { 1.110 + console.log(this.b2gFilename + " terminated with " + result.exitCode); 1.111 + this.process = null; 1.112 + emit(this, "exit", result.exitCode); 1.113 + }).bind(this) 1.114 + }); 1.115 + }, 1.116 + 1.117 + // request a b2g instance kill 1.118 + kill: function() { 1.119 + let deferred = promise.defer(); 1.120 + if (this.process) { 1.121 + this.once("exit", (exitCode) => { 1.122 + this.shuttingDown = false; 1.123 + deferred.resolve(exitCode); 1.124 + }); 1.125 + if (!this.shuttingDown) { 1.126 + this.shuttingDown = true; 1.127 + emit(this, "kill", null); 1.128 + this.process.kill(); 1.129 + } 1.130 + return deferred.promise; 1.131 + } else { 1.132 + return promise.resolve(undefined); 1.133 + } 1.134 + }, 1.135 + 1.136 + // compute current b2g filename 1.137 + get b2gFilename() { 1.138 + return this._executable ? this._executableFilename : "B2G"; 1.139 + }, 1.140 + 1.141 + // compute current b2g file handle 1.142 + get b2gExecutable() { 1.143 + if (this._executable) { 1.144 + return this._executable; 1.145 + } 1.146 + 1.147 + if (Prefs.customRuntime) { 1.148 + this._executable = Prefs.customRuntime; 1.149 + this._executableFilename = "Custom runtime"; 1.150 + return this._executable; 1.151 + } 1.152 + 1.153 + let bin = URL.toFilename(BIN_URL); 1.154 + let executables = { 1.155 + WINNT: "b2g-bin.exe", 1.156 + Darwin: "B2G.app/Contents/MacOS/b2g-bin", 1.157 + Linux: "b2g-bin", 1.158 + }; 1.159 + 1.160 + let path = bin; 1.161 + path += Runtime.OS == "WINNT" ? "\\" : "/"; 1.162 + path += executables[Runtime.OS]; 1.163 + console.log("simulator path: " + path); 1.164 + 1.165 + let executable = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile); 1.166 + executable.initWithPath(path); 1.167 + 1.168 + if (!executable.exists()) { 1.169 + // B2G binaries not found 1.170 + throw Error("b2g-desktop Executable not found."); 1.171 + } 1.172 + 1.173 + this._executable = executable; 1.174 + this._executableFilename = "b2g-bin"; 1.175 + 1.176 + return executable; 1.177 + }, 1.178 + 1.179 + // compute b2g CLI arguments 1.180 + get b2gArguments() { 1.181 + let args = []; 1.182 + 1.183 + let profile = Prefs.gaiaProfile || URL.toFilename(PROFILE_URL); 1.184 + args.push("-profile", profile); 1.185 + console.log("profile", profile); 1.186 + 1.187 + // NOTE: push dbgport option on the b2g-desktop commandline 1.188 + args.push("-start-debugger-server", "" + this.remoteDebuggerPort); 1.189 + 1.190 + // Ignore eventual zombie instances of b2g that are left over 1.191 + args.push("-no-remote"); 1.192 + 1.193 + return args; 1.194 + }, 1.195 +}); 1.196 +