michael@0: /* Any copyright is dedicated to the Public Domain. michael@0: http://creativecommons.org/publicdomain/zero/1.0/ */ michael@0: michael@0: "use strict"; michael@0: michael@0: const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; michael@0: michael@0: michael@0: let subscriptLoader = Cc["@mozilla.org/moz/jssubscript-loader;1"] michael@0: .getService(Ci.mozIJSSubScriptLoader); michael@0: michael@0: /** michael@0: * Start a new RIL worker. michael@0: * michael@0: * @param custom_ns michael@0: * Namespace with symbols to be injected into the new worker michael@0: * namespace. michael@0: * michael@0: * @return an object that represents the worker's namespace. michael@0: * michael@0: * @note that this does not start an actual worker thread. The worker michael@0: * is executed on the main thread, within a separate namespace object. michael@0: */ michael@0: function newWorker(custom_ns) { michael@0: let worker_ns = { michael@0: importScripts: function() { michael@0: Array.slice(arguments).forEach(function(script) { michael@0: if (!script.startsWith("resource:")) { michael@0: script = "resource://gre/modules/" + script; michael@0: } michael@0: subscriptLoader.loadSubScript(script, this); michael@0: }, this); michael@0: }, michael@0: michael@0: postRILMessage: function(message) { michael@0: }, michael@0: michael@0: postMessage: function(message) { michael@0: }, michael@0: michael@0: // Define these variables inside the worker scope so ES5 strict mode michael@0: // doesn't flip out. michael@0: onmessage: undefined, michael@0: onerror: undefined, michael@0: michael@0: DEBUG: true michael@0: }; michael@0: // The 'self' variable in a worker points to the worker's own namespace. michael@0: worker_ns.self = worker_ns; michael@0: michael@0: // Copy the custom definitions over. michael@0: for (let key in custom_ns) { michael@0: worker_ns[key] = custom_ns[key]; michael@0: } michael@0: michael@0: // fake require() for toolkit/components/workerloader/require.js michael@0: let require = (function() { michael@0: return function require(script) { michael@0: worker_ns.module = {}; michael@0: worker_ns.importScripts(script); michael@0: return worker_ns; michael@0: } michael@0: })(); michael@0: michael@0: Object.freeze(require); michael@0: Object.defineProperty(worker_ns, "require", { michael@0: value: require, michael@0: enumerable: true, michael@0: configurable: false michael@0: }); michael@0: michael@0: // Load the RIL worker itself. michael@0: worker_ns.importScripts("ril_worker.js"); michael@0: michael@0: // Register at least one client. michael@0: worker_ns.ContextPool.registerClient({ clientId: 0 }); michael@0: michael@0: return worker_ns; michael@0: } michael@0: michael@0: /** michael@0: * Create a parcel suitable for postRILMessage(). michael@0: * michael@0: * @param fakeParcelSize michael@0: * Value to be written to parcel size field for testing michael@0: * incorrect/incomplete parcel reading. Replaced with correct michael@0: * one determined length of data if negative. michael@0: * @param response michael@0: * Response code of the incoming parcel. michael@0: * @param request michael@0: * Request code of the incoming parcel. michael@0: * @param data michael@0: * Extra data to be appended. michael@0: * michael@0: * @return an Uint8Array carrying all parcel data. michael@0: */ michael@0: function newIncomingParcel(fakeParcelSize, response, request, data) { michael@0: const UINT32_SIZE = 4; michael@0: const PARCEL_SIZE_SIZE = 4; michael@0: michael@0: let realParcelSize = data.length + 2 * UINT32_SIZE; michael@0: let buffer = new ArrayBuffer(realParcelSize + PARCEL_SIZE_SIZE); michael@0: let bytes = new Uint8Array(buffer); michael@0: michael@0: let writeIndex = 0; michael@0: function writeUint8(value) { michael@0: bytes[writeIndex] = value; michael@0: ++writeIndex; michael@0: } michael@0: michael@0: function writeInt32(value) { michael@0: writeUint8(value & 0xff); michael@0: writeUint8((value >> 8) & 0xff); michael@0: writeUint8((value >> 16) & 0xff); michael@0: writeUint8((value >> 24) & 0xff); michael@0: } michael@0: michael@0: function writeParcelSize(value) { michael@0: writeUint8((value >> 24) & 0xff); michael@0: writeUint8((value >> 16) & 0xff); michael@0: writeUint8((value >> 8) & 0xff); michael@0: writeUint8(value & 0xff); michael@0: } michael@0: michael@0: if (fakeParcelSize < 0) { michael@0: fakeParcelSize = realParcelSize; michael@0: } michael@0: writeParcelSize(fakeParcelSize); michael@0: michael@0: writeInt32(response); michael@0: writeInt32(request); michael@0: michael@0: // write parcel data michael@0: for (let ii = 0; ii < data.length; ++ii) { michael@0: writeUint8(data[ii]); michael@0: } michael@0: michael@0: return bytes; michael@0: } michael@0: michael@0: /** michael@0: * michael@0: */ michael@0: let ril_ns; michael@0: function newRadioInterface() { michael@0: if (!ril_ns) { michael@0: ril_ns = {}; michael@0: subscriptLoader.loadSubScript("resource://gre/components/RadioInterfaceLayer.js", ril_ns); michael@0: } michael@0: michael@0: return { michael@0: __proto__: ril_ns.RadioInterface.prototype, michael@0: }; michael@0: } michael@0: michael@0: /** michael@0: * Test whether specified function throws exception with expected michael@0: * result. michael@0: * michael@0: * @param func michael@0: * Function to be tested. michael@0: * @param message michael@0: * Message of expected exception. null for no throws. michael@0: * @param stack michael@0: * Optional stack object to be printed. null for michael@0: * Components#stack#caller. michael@0: */ michael@0: function do_check_throws(func, message, stack) michael@0: { michael@0: if (!stack) michael@0: stack = Components.stack.caller; michael@0: michael@0: try { michael@0: func(); michael@0: } catch (exc) { michael@0: if (exc.message === message) { michael@0: return; michael@0: } michael@0: do_throw("expecting exception '" + message michael@0: + "', caught '" + exc.message + "'", stack); michael@0: } michael@0: michael@0: if (message) { michael@0: do_throw("expecting exception '" + message + "', none thrown", stack); michael@0: } michael@0: } michael@0: