This commit is contained in:
Ryan VanderMeulen 2015-08-27 21:44:52 -04:00
Родитель 451891bfbb b5b68e3ea5
Коммит 84b872d09e
143 изменённых файлов: 4094 добавлений и 1425 удалений

Просмотреть файл

@ -366,18 +366,33 @@ Target.prototype = {
} else {
let histogramName = CUSTOM_HISTOGRAM_PREFIX + metricAppName + '_'
+ metricName;
if (!developerHUD._customHistograms.has(histogramName)) {
try {
Services.telemetry.registerAddonHistogram(metricAppName,
CUSTOM_HISTOGRAM_PREFIX + metricName,
Services.telemetry.HISTOGRAM_LINEAR, 1, 10000, 10);
developerHUD._customHistograms.add(histogramName);
} catch(err) {
console.error('Histogram error: ' + err);
}
// This is a call to add a value to an existing histogram.
if (typeof metric.value !== 'undefined') {
Services.telemetry.getAddonHistogram(metricAppName,
CUSTOM_HISTOGRAM_PREFIX + metricName).add(parseInt(metric.value, 10));
return;
}
// The histogram already exists and are not adding data to it.
if (developerHUD._customHistograms.has(histogramName)) {
return;
}
// This is a call to create a new histogram.
try {
let metricType = parseInt(metric.type, 10);
if (metricType === Services.telemetry.HISTOGRAM_COUNT) {
Services.telemetry.registerAddonHistogram(metricAppName,
CUSTOM_HISTOGRAM_PREFIX + metricName, metricType);
} else {
Services.telemetry.registerAddonHistogram(metricAppName,
CUSTOM_HISTOGRAM_PREFIX + metricName, metricType, metric.min,
metric.max, metric.buckets);
}
developerHUD._customHistograms.add(histogramName);
} catch (err) {
console.error('Histogram error: ' + err);
}
Services.telemetry.getAddonHistogram(metricAppName,
CUSTOM_HISTOGRAM_PREFIX + metricName).add(parseInt(metric.value, 10));
}
}
};
@ -588,24 +603,40 @@ let consoleWatcher = {
let TELEMETRY_IDENTIFIER_IDX = 0;
let NAME_IDX = 1;
let VALUE_IDX = 2;
let TYPE_IDX = 2;
let MIN_IDX = 3;
let MAX_IDX = 4;
let BUCKETS_IDX = 5;
let MAX_CUSTOM_ARGS = 6;
let MIN_CUSTOM_ARGS = 3;
if (telemetryData[TELEMETRY_IDENTIFIER_IDX] != 'telemetry' ||
telemetryData.length < 3 || telemetryData.length > 4) {
telemetryData.length < MIN_CUSTOM_ARGS ||
telemetryData.length > MAX_CUSTOM_ARGS) {
return;
}
let metric = {
name: telemetryData[NAME_IDX],
value: telemetryData[VALUE_IDX]
name: telemetryData[NAME_IDX]
};
if (metric.name == 'MGMT') {
if (metric.value == 'TIMETOSHIP') {
if (metric.name === 'MGMT') {
metric.value = telemetryData[VALUE_IDX];
if (metric.value === 'TIMETOSHIP') {
telemetryDebug('Received a Ship event');
target._sendTelemetryData();
} else if (metric.value == 'CLEARMETRICS') {
} else if (metric.value === 'CLEARMETRICS') {
target._clearTelemetryData();
}
} else {
if (telemetryData.length === MIN_CUSTOM_ARGS) {
metric.value = telemetryData[VALUE_IDX];
} else if (telemetryData.length === MAX_CUSTOM_ARGS) {
metric.type = telemetryData[TYPE_IDX];
metric.min = telemetryData[MIN_IDX];
metric.max = telemetryData[MAX_IDX];
metric.buckets = telemetryData[BUCKETS_IDX];
}
metric.custom = true;
target._logHistogram(metric);
}

Просмотреть файл

@ -23,6 +23,7 @@ Cu.import('resource://gre/modules/SystemUpdateService.jsm');
Cu.import('resource://gre/modules/NetworkStatsService.jsm');
Cu.import('resource://gre/modules/ResourceStatsService.jsm');
#endif
Cu.import('resource://gre/modules/KillSwitchMain.jsm');
// Identity
Cu.import('resource://gre/modules/SignInToWebsite.jsm');

Просмотреть файл

@ -128,3 +128,7 @@ contract @mozilla.org/presentation-device/prompt;1 {4a300c26-e99b-4018-ab9b-c48c
# PresentationRequestUIGlue.js
component {ccc8a839-0b64-422b-8a60-fb2af0e376d0} PresentationRequestUIGlue.js
contract @mozilla.org/presentation/requestuiglue;1 {ccc8a839-0b64-422b-8a60-fb2af0e376d0}
# KillSwitch.js
component {b6eae5c6-971c-4772-89e5-5df626bf3f09} KillSwitch.js
contract @mozilla.org/moz-kill-switch;1 {b6eae5c6-971c-4772-89e5-5df626bf3f09}

Просмотреть файл

@ -0,0 +1,116 @@
/* 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 DEBUG = false;
function debug(s) {
dump("-*- KillSwitch.js: " + s + "\n");
}
const {interfaces: Ci, utils: Cu} = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/DOMRequestHelper.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Services",
"resource://gre/modules/Services.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
"@mozilla.org/childprocessmessagemanager;1",
"nsIMessageSender");
const KILLSWITCH_CID = "{b6eae5c6-971c-4772-89e5-5df626bf3f09}";
const KILLSWITCH_CONTRACTID = "@mozilla.org/moz-kill-switch;1";
const kEnableKillSwitch = "KillSwitch:Enable";
const kEnableKillSwitchOK = "KillSwitch:Enable:OK";
const kEnableKillSwitchKO = "KillSwitch:Enable:KO";
const kDisableKillSwitch = "KillSwitch:Disable";
const kDisableKillSwitchOK = "KillSwitch:Disable:OK";
const kDisableKillSwitchKO = "KillSwitch:Disable:KO";
function KillSwitch() {
this._window = null;
}
KillSwitch.prototype = {
__proto__: DOMRequestIpcHelper.prototype,
init: function(aWindow) {
DEBUG && debug("init");
this._window = aWindow;
this.initDOMRequestHelper(this._window);
},
enable: function() {
DEBUG && debug("KillSwitch: enable");
cpmm.addMessageListener(kEnableKillSwitchOK, this);
cpmm.addMessageListener(kEnableKillSwitchKO, this);
return this.createPromise((aResolve, aReject) => {
cpmm.sendAsyncMessage(kEnableKillSwitch, {
requestID: this.getPromiseResolverId({
resolve: aResolve,
reject: aReject
})
});
});
},
disable: function() {
DEBUG && debug("KillSwitch: disable");
cpmm.addMessageListener(kDisableKillSwitchOK, this);
cpmm.addMessageListener(kDisableKillSwitchKO, this);
return this.createPromise((aResolve, aReject) => {
cpmm.sendAsyncMessage(kDisableKillSwitch, {
requestID: this.getPromiseResolverId({
resolve: aResolve,
reject: aReject
})
});
});
},
receiveMessage: function(message) {
DEBUG && debug("Received: " + message.name);
cpmm.removeMessageListener(kEnableKillSwitchOK, this);
cpmm.removeMessageListener(kEnableKillSwitchKO, this);
cpmm.removeMessageListener(kDisableKillSwitchOK, this);
cpmm.removeMessageListener(kDisableKillSwitchKO, this);
let req = this.takePromiseResolver(message.data.requestID);
switch (message.name) {
case kEnableKillSwitchKO:
case kDisableKillSwitchKO:
req.reject(false);
break;
case kEnableKillSwitchOK:
case kDisableKillSwitchOK:
req.resolve(true);
break;
default:
DEBUG && debug("Unrecognized message: " + message.name);
break;
}
},
classID : Components.ID(KILLSWITCH_CID),
contractID : KILLSWITCH_CONTRACTID,
QueryInterface: XPCOMUtils.generateQI([Ci.nsIKillSwitch,
Ci.nsIDOMGlobalPropertyInitializer,
Ci.nsIObserver,
Ci.nsIMessageListener,
Ci.nsISupportsWeakReference]),
};
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([KillSwitch]);

Просмотреть файл

@ -0,0 +1,505 @@
/* 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";
this.EXPORTED_SYMBOLS = [ "KillSwitchMain" ];
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "OS", "resource://gre/modules/osfile.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Promise", "resource://gre/modules/Promise.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "settings",
"@mozilla.org/settingsService;1",
"nsISettingsService");
XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
"@mozilla.org/parentprocessmessagemanager;1",
"nsIMessageBroadcaster");
XPCOMUtils.defineLazyGetter(this, "permMgr", function() {
return Cc["@mozilla.org/permissionmanager;1"]
.getService(Ci.nsIPermissionManager);
});
#ifdef MOZ_WIDGET_GONK
XPCOMUtils.defineLazyGetter(this, "libcutils", function () {
Cu.import("resource://gre/modules/systemlibs.js");
return libcutils;
});
#else
this.libcutils = null;
#endif
const DEBUG = false;
const kEnableKillSwitch = "KillSwitch:Enable";
const kEnableKillSwitchOK = "KillSwitch:Enable:OK";
const kEnableKillSwitchKO = "KillSwitch:Enable:KO";
const kDisableKillSwitch = "KillSwitch:Disable";
const kDisableKillSwitchOK = "KillSwitch:Disable:OK";
const kDisableKillSwitchKO = "KillSwitch:Disable:KO";
const kMessages = [kEnableKillSwitch, kDisableKillSwitch];
const kXpcomShutdownObserverTopic = "xpcom-shutdown";
const kProperty = "persist.moz.killswitch";
const kUserValues =
OS.Path.join(OS.Constants.Path.profileDir, "killswitch.json");
let inParent = Cc["@mozilla.org/xre/app-info;1"]
.getService(Ci.nsIXULRuntime)
.processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT;
function debug(aStr) {
dump("--*-- KillSwitchMain: " + aStr + "\n");
}
this.KillSwitchMain = {
_ksState: null,
_libcutils: null,
_enabledValues: {
// List of settings to set to a specific value
settings: {
"debugger.remote-mode": "disabled",
"developer.menu.enabled": false,
"devtools.unrestricted": false,
"lockscreen.enabled": true,
"lockscreen.locked": true,
"lockscreen.lock-immediately": true,
"tethering.usb.enabled": false,
"tethering.wifi.enabled": false,
"ums.enabled": false
},
// List of preferences to set to a specific value
prefs: {
"b2g.killswitch.test": true
},
// List of Android properties to set to a specific value
properties: {
"persist.sys.usb.config": "none" // will change sys.usb.config and sys.usb.state
},
// List of Android services to control
services: {
"adbd": "stop"
}
},
init: function() {
DEBUG && debug("init");
if (libcutils) {
this._libcutils = libcutils;
}
kMessages.forEach(m => {
ppmm.addMessageListener(m, this);
});
Services.obs.addObserver(this, kXpcomShutdownObserverTopic, false);
this.readStateProperty();
},
uninit: function() {
kMessages.forEach(m => {
ppmm.removeMessageListener(m, this);
});
Services.obs.removeObserver(this, kXpcomShutdownObserverTopic);
},
checkLibcUtils: function() {
DEBUG && debug("checkLibcUtils");
if (!this._libcutils) {
debug("No proper libcutils binding, aborting.");
throw Cr.NS_ERROR_NO_INTERFACE;
}
return true;
},
readStateProperty: function() {
DEBUG && debug("readStateProperty");
try {
this.checkLibcUtils();
} catch (ex) {
return;
}
this._ksState =
this._libcutils.property_get(kProperty, "false") === "true";
},
writeStateProperty: function() {
DEBUG && debug("writeStateProperty");
try {
this.checkLibcUtils();
} catch (ex) {
return;
}
this._libcutils.property_set(kProperty, this._ksState.toString());
},
getPref(name, value) {
let rv = undefined;
try {
switch (typeof value) {
case "boolean":
rv = Services.prefs.getBoolPref(name, value);
break;
case "number":
rv = Services.prefs.getIntPref(name, value);
break;
case "string":
rv = Services.prefs.getCharPref(name, value);
break;
default:
debug("Unexpected pref type " + value);
break;
}
} catch (ex) {
}
return rv;
},
setPref(name, value) {
switch (typeof value) {
case "boolean":
Services.prefs.setBoolPref(name, value);
break;
case "number":
Services.prefs.setIntPref(name, value);
break;
case "string":
Services.prefs.setCharPref(name, value);
break;
default:
debug("Unexpected pref type " + value);
break;
}
},
doEnable: function() {
return new Promise((resolve, reject) => {
// Make sure that the API cannot do a new |enable()| call once the
// feature has been enabled, otherwise we will overwrite the user values.
if (this._ksState) {
reject(true);
return;
}
this.saveUserValues().then(() => {
DEBUG && debug("Toggling settings: " +
JSON.stringify(this._enabledValues.settings));
let lock = settings.createLock();
for (let key of Object.keys(this._enabledValues.settings)) {
lock.set(key, this._enabledValues.settings[key], this);
}
DEBUG && debug("Toggling prefs: " +
JSON.stringify(this._enabledValues.prefs));
for (let key of Object.keys(this._enabledValues.prefs)) {
this.setPref(key, this._enabledValues.prefs[key]);
}
DEBUG && debug("Toggling properties: " +
JSON.stringify(this._enabledValues.properties));
for (let key of Object.keys(this._enabledValues.properties)) {
this._libcutils.property_set(key, this._enabledValues.properties[key]);
}
DEBUG && debug("Toggling services: " +
JSON.stringify(this._enabledValues.services));
for (let key of Object.keys(this._enabledValues.services)) {
let value = this._enabledValues.services[key];
if (value !== "start" && value !== "stop") {
debug("Unexpected service " + key + " value:" + value);
}
this._libcutils.property_set("ctl." + value, key);
}
this._ksState = true;
this.writeStateProperty();
resolve(true);
}).catch(err => {
DEBUG && debug("doEnable: " + err);
reject(false);
});
});
},
saveUserValues: function() {
return new Promise((resolve, reject) => {
try {
this.checkLibcUtils();
} catch (ex) {
reject("nolibcutils");
}
let _userValues = {
settings: { },
prefs: { },
properties: { }
};
// Those will be sync calls
for (let key of Object.keys(this._enabledValues.prefs)) {
_userValues.prefs[key] =
this.getPref(key, this._enabledValues.prefs[key]);
}
for (let key of Object.keys(this._enabledValues.properties)) {
_userValues.properties[key] = this._libcutils.property_get(key);
}
let self = this;
let getCallback = {
handleAbort: function(m) {
DEBUG && debug("getCallback: handleAbort: m=" + m);
reject(m);
},
handleError: function(m) {
DEBUG && debug("getCallback: handleError: m=" + m);
reject(m);
},
handle: function(n, v) {
DEBUG && debug("getCallback: handle: n=" + n + " ; v=" + v);
if (self._pendingSettingsGet) {
// We have received a settings callback value for saving user data
let pending = self._pendingSettingsGet.indexOf(n);
if (pending !== -1) {
_userValues.settings[n] = v;
self._pendingSettingsGet.splice(pending, 1);
}
if (self._pendingSettingsGet.length === 0) {
delete self._pendingSettingsGet;
let payload = JSON.stringify(_userValues);
DEBUG && debug("Dumping to " + kUserValues + ": " + payload);
OS.File.writeAtomic(kUserValues, payload).then(
function writeOk() {
resolve(true);
},
function writeNok(err) {
reject("write error");
}
);
}
}
}
};
// For settings we have to wait all the callbacks to come back before
// we can resolve or reject
this._pendingSettingsGet = [];
let lock = settings.createLock();
for (let key of Object.keys(this._enabledValues.settings)) {
this._pendingSettingsGet.push(key);
lock.get(key, getCallback);
}
});
},
doDisable: function() {
return new Promise((resolve, reject) => {
this.restoreUserValues().then(() => {
this._ksState = false;
this.writeStateProperty();
resolve(true);
}).catch(err => {
DEBUG && debug("doDisable: " + err);
reject(false);
});
});
},
restoreUserValues: function() {
return new Promise((resolve, reject) => {
try {
this.checkLibcUtils();
} catch (ex) {
reject("nolibcutils");
}
OS.File.read(kUserValues, { encoding: "utf-8" }).then(content => {
let values = JSON.parse(content);
for (let key of Object.keys(values.prefs)) {
this.setPref(key, values.prefs[key]);
}
for (let key of Object.keys(values.properties)) {
this._libcutils.property_set(key, values.properties[key]);
}
let self = this;
let saveCallback = {
handleAbort: function(m) {
DEBUG && debug("saveCallback: handleAbort: m=" + m);
reject(m);
},
handleError: function(m) {
DEBUG && debug("saveCallback: handleError: m=" + m);
reject(m);
},
handle: function(n, v) {
DEBUG && debug("saveCallback: handle: n=" + n + " ; v=" + v);
if (self._pendingSettingsSet) {
// We have received a settings callback value for setting user data
let pending = self._pendingSettingsSet.indexOf(n);
if (pending !== -1) {
self._pendingSettingsSet.splice(pending, 1);
}
if (self._pendingSettingsSet.length === 0) {
delete self._pendingSettingsSet;
DEBUG && debug("Restored from " + kUserValues + ": " + JSON.stringify(values));
resolve(values);
}
}
}
};
// For settings we have to wait all the callbacks to come back before
// we can resolve or reject
this._pendingSettingsSet = [];
let lock = settings.createLock();
for (let key of Object.keys(values.settings)) {
this._pendingSettingsSet.push(key);
lock.set(key, values.settings[key], saveCallback);
}
}).catch(err => {
reject(err);
});
});
},
// Settings Callbacks
handle: function(aName, aValue) {
DEBUG && debug("handle: aName=" + aName + " ; aValue=" + aValue);
// We don't have to do anything for now.
},
handleAbort: function(aMessage) {
debug("handleAbort: " + JSON.stringify(aMessage));
throw Cr.NS_ERROR_ABORT;
},
handleError: function(aMessage) {
debug("handleError: " + JSON.stringify(aMessage));
throw Cr.NS_ERROR_FAILURE;
},
// addObserver
observe: function(aSubject, aTopic, aData) {
switch (aTopic) {
case kXpcomShutdownObserverTopic:
this.uninit();
break;
default:
DEBUG && debug("Wrong observer topic: " + aTopic);
break;
}
},
// addMessageListener
receiveMessage: function(aMessage) {
let hasPermission = aMessage.target.assertPermission("killswitch");
DEBUG && debug("hasPermission: " + hasPermission);
if (!hasPermission) {
debug("Message " + aMessage.name + " from a process with no killswitch perm.");
aMessage.target.killChild();
throw Cr.NS_ERROR_NOT_AVAILABLE;
return;
}
function returnMessage(name, data) {
if (aMessage.target) {
data.requestID = aMessage.data.requestID;
try {
aMessage.target.sendAsyncMessage(name, data);
} catch (e) {
if (DEBUG) debug("Return message failed, " + name + ": " + e);
}
}
}
switch (aMessage.name) {
case kEnableKillSwitch:
this.doEnable().then(
() => {
returnMessage(kEnableKillSwitchOK, {});
},
err => {
debug("doEnable failed: " + err);
returnMessage(kEnableKillSwitchKO, {});
}
);
break;
case kDisableKillSwitch:
this.doDisable().then(
() => {
returnMessage(kDisableKillSwitchOK, {});
},
err => {
debug("doDisable failed: " + err);
returnMessage(kDisableKillSwitchKO, {});
}
);
break;
default:
debug("Unsupported message: " + aMessage.name);
aMessage.target && aMessage.target.killChild();
throw Cr.NS_ERROR_ILLEGAL_VALUE;
return;
break;
}
}
};
// This code should ALWAYS be living only on the parent side.
if (!inParent) {
debug("KillSwitchMain should only be living on parent side.");
throw Cr.NS_ERROR_ABORT;
} else {
this.KillSwitchMain.init();
}

Просмотреть файл

@ -18,6 +18,7 @@ EXTRA_COMPONENTS += [
'FxAccountsUIGlue.js',
'HelperAppDialog.js',
'InterAppCommUIGlue.js',
'KillSwitch.js',
'MailtoProtocolHandler.js',
'MobileIdentityUIGlue.js',
'OMAContentHandler.js',
@ -74,6 +75,10 @@ EXTRA_JS_MODULES += [
'WebappsUpdater.jsm',
]
EXTRA_PP_JS_MODULES += [
'KillSwitchMain.jsm'
]
if CONFIG['MOZ_WIDGET_TOOLKIT'] != 'gonk':
EXTRA_JS_MODULES += [
'GlobalSimulatorScreen.jsm'

Просмотреть файл

@ -0,0 +1,67 @@
let Ci = Components.interfaces;
let Cc = Components.classes;
let Cu = Components.utils;
// Stolen from SpecialPowers, since at this point we don't know we're in a test.
let isMainProcess = function() {
try {
return Cc["@mozilla.org/xre/app-info;1"]
.getService(Ci.nsIXULRuntime)
.processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT;
} catch (e) { }
return true;
};
var fakeLibcUtils = {
_props_: {},
property_set: function(name, value) {
dump("property_set('" + name + "', '" + value+ "' [" + (typeof value) + "]);\n");
this._props_[name] = value;
},
property_get: function(name, defaultValue) {
dump("property_get('" + name + "', '" + defaultValue+ "');\n");
if (Object.keys(this._props_).indexOf(name) !== -1) {
return this._props_[name];
} else {
return defaultValue;
}
}
};
var kUserValues;
function installUserValues(next) {
var fakeValues = {
settings: {
"lockscreen.locked": false,
"lockscreen.lock-immediately": false
},
prefs: {
"b2g.killswitch.test": false
},
properties: {
"dalvik.vm.heapmaxfree": "32m",
"dalvik.vm.isa.arm.features": "fdiv",
"dalvik.vm.lockprof.threshold": "5000",
"net.bt.name": "BTAndroid",
"dalvik.vm.stack-trace-file": "/data/anr/stack-traces.txt"
}
};
OS.File.writeAtomic(kUserValues,
JSON.stringify(fakeValues)).then(() => {
next();
});
}
if (isMainProcess()) {
Cu.import("resource://gre/modules/SettingsRequestManager.jsm");
Cu.import("resource://gre/modules/osfile.jsm");
Cu.import("resource://gre/modules/KillSwitchMain.jsm");
kUserValues = OS.Path.join(OS.Constants.Path.profileDir, "killswitch.json");
installUserValues(() => {
KillSwitchMain._libcutils = fakeLibcUtils;
});
}

Просмотреть файл

@ -0,0 +1,149 @@
/* 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";
function setupSettings(target) {
ok((Object.keys(initialSettingsValues).length > 0), "Has at least one setting");
Object.keys(initialSettingsValues).forEach(k => {
ok(Object.keys(target).indexOf(k) !== -1, "Same settings set");
});
var lock = navigator.mozSettings.createLock();
lock.set(initialSettingsValues);
}
function testSettingsInitial(next) {
var promises = [];
for (var setting in initialSettingsValues) {
promises.push(navigator.mozSettings.createLock().get(setting));
}
Promise.all(promises).then(values => {
values.forEach(set => {
var key = Object.keys(set)[0];
var value = set[key];
is(value, initialSettingsValues[key], "Value of " + key + " is initial one");
});
next();
});
}
function testSettingsExpected(target, next) {
var promises = [];
for (var setting in initialSettingsValues) {
promises.push(navigator.mozSettings.createLock().get(setting));
}
Promise.all(promises).then(values => {
values.forEach(set => {
var key = Object.keys(set)[0];
var value = set[key];
is(value, target[key], "Value of " + key + " is expected one");
});
next();
});
}
function testSetPrefValue(prefName, prefValue) {
switch (typeof prefValue) {
case "boolean":
SpecialPowers.setBoolPref(prefName, prefValue);
break;
case "number":
SpecialPowers.setIntPref(prefName, prefValue);
break;
case "string":
SpecialPowers.setCharPref(prefName, prefValue);
break;
default:
is(false, "Unexpected pref type");
break;
}
}
function testGetPrefValue(prefName, prefValue) {
var rv = undefined;
switch (typeof prefValue) {
case "boolean":
rv = SpecialPowers.getBoolPref(prefName);
break;
case "number":
rv = SpecialPowers.getIntPref(prefName);
break;
case "string":
rv = SpecialPowers.getCharPref(prefName);
break;
default:
is(false, "Unexpected pref type");
break;
}
return rv;
}
function setupPrefs(target) {
ok((Object.keys(initialPrefsValues).length > 0), "Has at least one pref");
Object.keys(initialPrefsValues).forEach(k => {
ok(Object.keys(target).indexOf(k) !== -1, "Same pref set");
});
Object.keys(initialPrefsValues).forEach(key => {
testSetPrefValue(key, initialPrefsValues[key]);
});
}
function testPrefsInitial() {
Object.keys(initialPrefsValues).forEach(key => {
var value = testGetPrefValue(key, initialPrefsValues[key]);
is(value, initialPrefsValues[key], "Value of " + key + " is initial one");
});
}
function testPrefsExpected(target) {
Object.keys(target).forEach(key => {
var value = testGetPrefValue(key, target[key]);
is(value, target[key], "Value of " + key + " is initial one");
});
}
function finish() {
SpecialPowers.removePermission("killswitch", document);
SimpleTest.finish();
}
function addPermissions() {
if (SpecialPowers.hasPermission("killswitch", document)) {
startTests();
} else {
var allow = SpecialPowers.Ci.nsIPermissionManager.ALLOW_ACTION;
[ "killswitch", "settings-api-read", "settings-api-write",
"settings-read", "settings-write", "settings-clear"
].forEach(perm => {
SpecialPowers.addPermission(perm, allow, document);
});
window.location.reload();
}
}
function loadSettings() {
var url = SimpleTest.getTestFileURL("file_loadserver.js");
var script = SpecialPowers.loadChromeScript(url);
}
function addPrefs() {
SpecialPowers.pushPrefEnv({"set": [
["dom.ignore_webidl_scope_checks", true],
["dom.mozKillSwitch.enabled", true],
]}, addPermissions);
}

Просмотреть файл

@ -1,5 +1,4 @@
[DEFAULT]
skip-if = toolkit != "gonk"
support-files =
permission_handler_chrome.js
SandboxPromptTest.html
@ -8,14 +7,27 @@ support-files =
systemapp_helper.js
presentation_prompt_handler_chrome.js
presentation_ui_glue_handler_chrome.js
file_loadserver.js
killswitch.js
[test_filepicker_path.html]
skip-if = toolkit != "gonk"
[test_permission_deny.html]
skip-if = toolkit != "gonk"
[test_permission_gum_remember.html]
skip-if = true # Bug 1019572 - frequent timeouts
[test_sandbox_permission.html]
skip-if = toolkit != "gonk"
[test_screenshot.html]
skip-if = toolkit != "gonk"
[test_systemapp.html]
skip-if = toolkit != "gonk"
[test_presentation_device_prompt.html]
skip-if = toolkit != "gonk"
[test_permission_visibilitychange.html]
skip-if = toolkit != "gonk"
[test_presentation_request_ui_glue.html]
skip-if = toolkit != "gonk"
[test_killswitch_basics.html]
[test_killswitch_disable.html]
[test_killswitch_enable.html]

Просмотреть файл

@ -0,0 +1,92 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Enabling of killswitch feature</title>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js">
</script>
</head>
<body>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test">
<script type="application/javascript">
"use strict";
function testNotExposed(check) {
ok(!("mozKillSwitch" in navigator),
"mozKillSwitch not exposed in navigator: " + check);
}
function testIsExposed() {
ok(("mozKillSwitch" in navigator), "mozKillSwitch is exposed in navigator");
ok(("enable" in navigator.mozKillSwitch), "mozKillSwitch has |enable|");
ok(("disable" in navigator.mozKillSwitch), "mozKillSwitch has |disable|");
}
function continueTests() {
// Now we should have it!
testIsExposed();
finish();
}
function finish() {
SpecialPowers.removePermission("killswitch", document);
SimpleTest.finish();
}
function alreadyHasPermission() {
return SpecialPowers.hasPermission("killswitch", document);
}
function addPermission() {
var allow = SpecialPowers.Ci.nsIPermissionManager.ALLOW_ACTION;
SpecialPowers.addPermission("killswitch", allow, document);
window.location.reload();
}
function addPrefIgnoreWebIDL(next) {
SpecialPowers.pushPrefEnv({"set": [
["dom.ignore_webidl_scope_checks", true],
]}, next);
}
function addPrefKillSwitch(next) {
SpecialPowers.pushPrefEnv({"set": [
["dom.mozKillSwitch.enabled", true],
]}, next);
}
function startTests() {
if (alreadyHasPermission()) {
continueTests();
} else {
// Make sure it's not exposed
testNotExposed("webidl, pref, perm");
// Expose certified APIs
addPrefIgnoreWebIDL(() => {
// Still not exposed because not perm and pref
testNotExposed("pref, perm");
// Add the kill switch pref
addPrefKillSwitch(() => {
// Still not exposed because not perm
testNotExposed("perm");
// Will reload the page
addPermission();
});
});
}
}
SimpleTest.waitForExplicitFinish();
startTests();
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -0,0 +1,65 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Disabling of killswitch feature</title>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js">
</script>
<script type="application/javascript" src="killswitch.js"></script>
</head>
<body>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test">
<script type="application/javascript">
"use strict";
var initialSettingsValues = {
"lockscreen.locked": true,
"lockscreen.lock-immediately": true
};
var initialPrefsValues = {
"b2g.killswitch.test": true
};
var disabledSettingsExpected = {
"lockscreen.locked": false,
"lockscreen.lock-immediately": false
};
var disabledPrefsExpected = {
"b2g.killswitch.test": false
};
function testDoAction() {
return navigator.mozKillSwitch.disable();
}
function startTests() {
setupSettings(disabledSettingsExpected);
setupPrefs(initialPrefsValues);
testSettingsInitial(() => {
testPrefsInitial();
testDoAction().then(() => {
testSettingsExpected(disabledSettingsExpected, () => {
testPrefsExpected(disabledPrefsExpected);
finish();
});
}).catch(() => {
ok(false, "KillSwitch promise failed");
finish();
});
});
}
SimpleTest.waitForExplicitFinish();
loadSettings();
addPrefs();
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -0,0 +1,65 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Enabling of killswitch feature</title>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js">
</script>
<script type="application/javascript" src="killswitch.js"></script>
</head>
<body>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test">
<script type="application/javascript">
"use strict";
var initialSettingsValues = {
"lockscreen.locked": false,
"lockscreen.lock-immediately": false
};
var initialPrefsValues = {
"b2g.killswitch.test": false
};
var enabledSettingsExpected = {
"lockscreen.locked": true,
"lockscreen.lock-immediately": true
};
var enabledPrefsExpected = {
"b2g.killswitch.test": true
};
function testDoAction() {
return navigator.mozKillSwitch.enable();
}
function startTests() {
setupSettings(enabledSettingsExpected);
setupPrefs(initialPrefsValues);
testSettingsInitial(() => {
testPrefsInitial();
testDoAction().then(() => {
testSettingsExpected(enabledSettingsExpected, () => {
testPrefsExpected(enabledPrefsExpected);
finish();
});
}).catch(() => {
ok(false, "KillSwitch promise failed");
finish();
});
});
}
SimpleTest.waitForExplicitFinish();
loadSettings();
addPrefs();
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -0,0 +1,425 @@
/* 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 {classes: Cc, interfaces: Ci, utils: Cu} = Components;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/NetUtil.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "OS", "resource://gre/modules/osfile.jsm");
let kUserValues;
function run_test() {
do_get_profile();
Cu.import("resource://gre/modules/KillSwitchMain.jsm");
check_enabledValues();
run_next_test();
}
function check_enabledValues() {
let expected = {
settings: {
"debugger.remote-mode": "disabled",
"developer.menu.enabled": false,
"devtools.unrestricted": false,
"lockscreen.enabled": true,
"lockscreen.locked": true,
"lockscreen.lock-immediately": true,
"tethering.usb.enabled": false,
"tethering.wifi.enabled": false,
"ums.enabled": false
},
prefs: {
"b2g.killswitch.test": true
},
properties: {
"persist.sys.usb.config": "none"
},
services: {
"adbd": "stop"
}
};
for (let key of Object.keys(KillSwitchMain._enabledValues.settings)) {
strictEqual(expected.settings[key],
KillSwitchMain._enabledValues.settings[key],
"setting " + key);
}
for (let key of Object.keys(KillSwitchMain._enabledValues.prefs)) {
strictEqual(expected.prefs[key],
KillSwitchMain._enabledValues.prefs[key],
"pref " + key);
}
for (let key of Object.keys(KillSwitchMain._enabledValues.properties)) {
strictEqual(expected.properties[key],
KillSwitchMain._enabledValues.properties[key],
"proprety " + key);
}
for (let key of Object.keys(KillSwitchMain._enabledValues.services)) {
strictEqual(expected.services[key],
KillSwitchMain._enabledValues.services[key],
"service " + key);
}
}
add_test(function test_prepareTestValues() {
if (("adbd" in KillSwitchMain._enabledValues.services)) {
strictEqual(KillSwitchMain._enabledValues.services["adbd"], "stop");
// We replace those for the test because on Gonk we will loose the control
KillSwitchMain._enabledValues.settings = {
"lockscreen.locked": true,
"lockscreen.lock-immediately": true
};
KillSwitchMain._enabledValues.services = {};
KillSwitchMain._enabledValues.properties = {
"dalvik.vm.heapmaxfree": "8m",
"dalvik.vm.isa.arm.features": "div",
"dalvik.vm.lockprof.threshold": "500",
"net.bt.name": "Android",
"dalvik.vm.stack-trace-file": "/data/anr/traces.txt"
}
}
kUserValues = OS.Path.join(OS.Constants.Path.profileDir, "killswitch.json");
run_next_test();
});
function reset_status() {
KillSwitchMain._ksState = undefined;
KillSwitchMain._libcutils.property_set("persist.moz.killswitch", "undefined");
}
function install_common_tests() {
add_test(function test_readStateProperty() {
KillSwitchMain._libcutils.property_set("persist.moz.killswitch", "false");
KillSwitchMain.readStateProperty();
strictEqual(KillSwitchMain._ksState, false);
KillSwitchMain._libcutils.property_set("persist.moz.killswitch", "true");
KillSwitchMain.readStateProperty();
strictEqual(KillSwitchMain._ksState, true);
run_next_test();
});
add_test(function test_writeStateProperty() {
KillSwitchMain._ksState = false;
KillSwitchMain.writeStateProperty();
let state = KillSwitchMain._libcutils.property_get("persist.moz.killswitch");
strictEqual(state, "false");
KillSwitchMain._ksState = true;
KillSwitchMain.writeStateProperty();
state = KillSwitchMain._libcutils.property_get("persist.moz.killswitch");
strictEqual(state, "true");
run_next_test();
});
add_test(function test_doEnable() {
reset_status();
let enable = KillSwitchMain.doEnable();
ok(enable, "should have a Promise");
enable.then(() => {
strictEqual(KillSwitchMain._ksState, true);
let state = KillSwitchMain._libcutils.property_get("persist.moz.killswitch");
strictEqual(state, "true");
run_next_test();
}).catch(err => {
ok(false, "should have succeeded");
run_next_test();
});
});
add_test(function test_enableMessage() {
reset_status();
let listener = {
assertPermission: function() {
return true;
},
sendAsyncMessage: function(name, data) {
strictEqual(name, "KillSwitch:Enable:OK");
strictEqual(data.requestID, 1);
let state = KillSwitchMain._libcutils.property_get("persist.moz.killswitch");
strictEqual(state, "true");
run_next_test();
}
};
KillSwitchMain.receiveMessage({
name: "KillSwitch:Enable",
target: listener,
data: {
requestID: 1
}
});
});
add_test(function test_saveUserValues_prepare() {
reset_status();
OS.File.exists(kUserValues).then(e => {
if (e) {
OS.File.remove(kUserValues).then(() => {
run_next_test();
}).catch(err => {
ok(false, "should have succeeded");
run_next_test();
});
} else {
run_next_test();
}
}).catch(err => {
ok(false, "should have succeeded");
run_next_test();
});
});
add_test(function test_saveUserValues() {
reset_status();
let expectedValues = Object.assign({}, KillSwitchMain._enabledValues);
// Reset _enabledValues so we check properly that the dumped state
// is the current device state
KillSwitchMain._enabledValues = {
settings: {
"lockscreen.locked": false,
"lockscreen.lock-immediately": false
},
prefs: {
"b2g.killswitch.test": false
},
properties: {
"dalvik.vm.heapmaxfree": "32m",
"dalvik.vm.isa.arm.features": "fdiv",
"dalvik.vm.lockprof.threshold": "5000",
"net.bt.name": "BTAndroid",
"dalvik.vm.stack-trace-file": "/data/anr/stack-traces.txt"
},
services: {}
};
KillSwitchMain.saveUserValues().then(e => {
ok(e, "should have succeeded");
OS.File.read(kUserValues, { encoding: "utf-8" }).then(content => {
let obj = JSON.parse(content);
deepEqual(obj.settings, expectedValues.settings);
notDeepEqual(obj.settings, KillSwitchMain._enabledValues.settings);
deepEqual(obj.prefs, expectedValues.prefs);
notDeepEqual(obj.prefs, KillSwitchMain._enabledValues.prefs);
deepEqual(obj.properties, expectedValues.properties);
notDeepEqual(obj.properties, KillSwitchMain._enabledValues.properties);
run_next_test();
}).catch(err => {
ok(false, "should have succeeded");
run_next_test();
});
}).catch(err => {
ok(false, "should have succeeded");
run_next_test();
});
});
add_test(function test_saveUserValues_cleaup() {
reset_status();
OS.File.exists(kUserValues).then(e => {
if (e) {
OS.File.remove(kUserValues).then(() => {
ok(true, "should have had a file");
run_next_test();
}).catch(err => {
ok(false, "should have succeeded");
run_next_test();
});
} else {
ok(false, "should have had a file");
run_next_test();
}
}).catch(err => {
ok(false, "should have succeeded");
run_next_test();
});
});
add_test(function test_restoreUserValues_prepare() {
reset_status();
let fakeValues = {
settings: {
"lockscreen.locked": false,
"lockscreen.lock-immediately": false
},
prefs: {
"b2g.killswitch.test": false
},
properties: {
"dalvik.vm.heapmaxfree": "32m",
"dalvik.vm.isa.arm.features": "fdiv",
"dalvik.vm.lockprof.threshold": "5000",
"net.bt.name": "BTAndroid",
"dalvik.vm.stack-trace-file": "/data/anr/stack-traces.txt"
}
};
OS.File.exists(kUserValues).then(e => {
if (!e) {
OS.File.writeAtomic(kUserValues,
JSON.stringify(fakeValues)).then(() => {
ok(true, "success writing file");
run_next_test();
}, err => {
ok(false, "error writing file");
run_next_test();
});
} else {
ok(false, "file should not have been there");
run_next_test();
}
}).catch(err => {
ok(false, "should have succeeded");
run_next_test();
});
});
add_test(function test_restoreUserValues() {
reset_status();
KillSwitchMain.restoreUserValues().then(e => {
ok(e, "should have succeeded");
strictEqual(e.settings["lockscreen.locked"], false);
strictEqual(e.settings["lockscreen.lock-immediately"], false);
strictEqual(e.prefs["b2g.killswitch.test"], false);
strictEqual(
e.properties["dalvik.vm.heapmaxfree"],
"32m");
strictEqual(
e.properties["dalvik.vm.isa.arm.features"],
"fdiv");
strictEqual(
e.properties["dalvik.vm.lockprof.threshold"],
"5000");
strictEqual(
e.properties["net.bt.name"],
"BTAndroid");
strictEqual(
e.properties["dalvik.vm.stack-trace-file"],
"/data/anr/stack-traces.txt");
strictEqual(
KillSwitchMain._libcutils.property_get("dalvik.vm.heapmaxfree"),
"32m");
strictEqual(
KillSwitchMain._libcutils.property_get("dalvik.vm.isa.arm.features"),
"fdiv");
strictEqual(
KillSwitchMain._libcutils.property_get("dalvik.vm.lockprof.threshold"),
"5000");
strictEqual(
KillSwitchMain._libcutils.property_get("net.bt.name"),
"BTAndroid");
strictEqual(
KillSwitchMain._libcutils.property_get("dalvik.vm.stack-trace-file"),
"/data/anr/stack-traces.txt");
run_next_test();
}).catch(err => {
ok(false, "should not have had an error");
run_next_test();
});
});
add_test(function test_doDisable() {
reset_status();
let disable = KillSwitchMain.doDisable()
ok(disable, "should have a Promise");
disable.then(() => {
strictEqual(KillSwitchMain._ksState, false);
let state = KillSwitchMain._libcutils.property_get("persist.moz.killswitch");
strictEqual(state, "false");
run_next_test();
}).catch(err => {
ok(false, "should have succeeded");
run_next_test();
});
});
add_test(function test_disableMessage() {
reset_status();
let listener = {
assertPermission: function() {
return true;
},
sendAsyncMessage: function(name, data) {
strictEqual(name, "KillSwitch:Disable:OK");
strictEqual(data.requestID, 2);
let state = KillSwitchMain._libcutils.property_get("persist.moz.killswitch");
strictEqual(state, "false");
run_next_test();
}
};
KillSwitchMain.receiveMessage({
name: "KillSwitch:Disable",
target: listener,
data: {
requestID: 2
}
});
});
add_test(function test_doEnable_only_once() {
reset_status();
let firstEnable = KillSwitchMain.doEnable();
ok(firstEnable, "should have a first Promise");
firstEnable.then(() => {
let secondEnable = KillSwitchMain.doEnable();
ok(secondEnable, "should have a second Promise");
secondEnable.then(() => {
ok(false, "second enable should have not succeeded");
run_next_test();
}).catch(err => {
strictEqual(err, true, "second enable should reject(true);");
run_next_test();
});
}).catch(err => {
ok(false, "first enable should have succeeded");
run_next_test();
});
});
}

Просмотреть файл

@ -0,0 +1,108 @@
/* 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 {results: Cr} = Components;
// Trivial test just to make sure we have no syntax error
add_test(function test_ksm_ok() {
ok(KillSwitchMain, "KillSwitchMain object exists");
run_next_test();
});
let aMessageNoPerm = {
name: "KillSwitch:Enable",
target: {
assertPermission: function() {
return false;
},
killChild: function() { }
}
};
let aMessageWithPerm = {
name: "KillSwitch:Enable",
target: {
assertPermission: function() {
return true;
}
},
data: {
requestID: 0
}
};
add_test(function test_sendMessageWithoutPerm() {
try {
KillSwitchMain.receiveMessage(aMessageNoPerm);
ok(false, "Should have failed");
} catch (ex) {
// strictEqual(ex, Cr.NS_ERROR_NOT_AVAILABLE);
}
run_next_test();
});
add_test(function test_sendMessageWithPerm() {
let rv = KillSwitchMain.receiveMessage(aMessageWithPerm);
strictEqual(rv, undefined);
run_next_test();
});
let uMessage = {
name: "KillSwitch:WTF",
target: {
assertPermission: function() {
return true;
},
killChild: function() { }
}
};
add_test(function test_sendUnknownMessage() {
try {
KillSwitchMain.receiveMessage(uMessage);
ok(false, "Should have failed");
} catch (ex) {
strictEqual(ex, Cr.NS_ERROR_ILLEGAL_VALUE);
}
run_next_test();
});
let fakeLibcUtils = {
_props_: {},
property_set: function(name, value) {
dump("property_set('" + name + "', '" + value+ "' [" + (typeof value) + "]);\n");
this._props_[name] = value;
},
property_get: function(name, defaultValue) {
dump("property_get('" + name + "', '" + defaultValue+ "');\n");
if (Object.keys(this._props_).indexOf(name) !== -1) {
return this._props_[name];
} else {
return defaultValue;
}
}
};
add_test(function test_nolibcutils() {
KillSwitchMain._libcutils = null;
try {
KillSwitchMain.checkLibcUtils();
ok(false, "Should have failed");
} catch (ex) {
strictEqual(ex, Cr.NS_ERROR_NO_INTERFACE);
}
run_next_test();
});
add_test(function test_install_fakelibcutils() {
KillSwitchMain._libcutils = fakeLibcUtils;
let rv = KillSwitchMain.checkLibcUtils();
strictEqual(rv, true);
run_next_test();
});
install_common_tests();

Просмотреть файл

@ -0,0 +1,42 @@
/* 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/. */
Cu.import("resource://gre/modules/NetUtil.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyGetter(this, "libcutils", function () {
Cu.import("resource://gre/modules/systemlibs.js");
return libcutils;
});
// Trivial test just to make sure we have no syntax error
add_test(function test_ksm_ok() {
ok(KillSwitchMain, "KillSwitchMain object exists");
run_next_test();
});
add_test(function test_has_libcutils() {
let rv = KillSwitchMain.checkLibcUtils();
strictEqual(rv, true);
run_next_test();
});
add_test(function test_libcutils_works() {
KillSwitchMain._libcutils.property_set("ro.moz.ks_test", "wesh");
let rv_ks_get = KillSwitchMain._libcutils.property_get("ro.moz.ks_test");
strictEqual(rv_ks_get, "wesh")
let rv_sys_get = libcutils.property_get("ro.moz.ks_test")
strictEqual(rv_sys_get, "wesh")
KillSwitchMain._libcutils.property_set("ro.moz.ks_test2", "123456789");
rv_ks_get = KillSwitchMain._libcutils.property_get("ro.moz.ks_test2");
strictEqual(rv_ks_get, "123456789")
rv_sys_get = libcutils.property_get("ro.moz.ks_test2")
strictEqual(rv_sys_get, "123456789")
run_next_test();
});
install_common_tests();

Просмотреть файл

@ -41,3 +41,12 @@ head = head_logshake_gonk.js
skip-if = (toolkit != "gonk")
[test_aboutserviceworkers.js]
[test_killswitch.js]
head = file_killswitch.js
skip-if = (toolkit == "gonk")
[test_killswitch_gonk.js]
head = file_killswitch.js
# Bug 1193677: disable on B2G ICS Emulator for intermittent failures with IndexedDB
skip-if = ((toolkit != "gonk") || (toolkit == "gonk" && debug))

Просмотреть файл

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="e935894ef5f27e2f04b9e929a45a958e6288a223">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="d784c81961d82cbe9e111405468c590a8345856c"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="b69c16798ddd7154207f56d983721a327522f5d1"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
@ -23,7 +23,7 @@
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="6641107c83e718d9896f90a9529ad0c252ddc271"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="b4f6fd4afd03161f53c7d2a663750f94762bd238"/>
<!-- Stock Android things -->
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="ebdad82e61c16772f6cd47e9f11936bf6ebe9aa0"/>
@ -73,7 +73,7 @@
<project name="platform/external/libselinux" path="external/libselinux" revision="1e2cf2c4a2d15a9b1ca2d353b99fb6884413ffe1"/>
<project name="platform/external/libsepol" path="external/libsepol" revision="edc447a138ec77236f1cbfd36c1211a38ba21418"/>
<project name="platform/external/libvpx" path="external/libvpx" revision="ca9281af0bfe816f1ae2fc3e8771524164a0a03c"/>
<project name="platform/external/mdnsresponder" path="external/mdnsresponder" revision="c46f53f5e072f23051c4eedef730386f7634dc11"/>
<project name="platform/external/mdnsresponder" path="external/mdnsresponder" remote="caf" revision="dd17df3f6775c4366a5c1d21865370d60a3b1295"/>
<project name="platform/external/mksh" path="external/mksh" revision="f8c396c4d446a038358106a301b329607a04633d"/>
<project name="platform/external/netcat" path="external/netcat" revision="444644cfa9a2f3002863caa168fb2d6b34dfd1e8"/>
<project name="platform/external/openssl" path="external/openssl" revision="bb8428f762b3632f493572c4f73957e1281ade79"/>

Просмотреть файл

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="e935894ef5f27e2f04b9e929a45a958e6288a223">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="d784c81961d82cbe9e111405468c590a8345856c"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="b69c16798ddd7154207f56d983721a327522f5d1"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
@ -23,7 +23,7 @@
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="6641107c83e718d9896f90a9529ad0c252ddc271"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="b4f6fd4afd03161f53c7d2a663750f94762bd238"/>
<!-- Stock Android things -->
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="ebdad82e61c16772f6cd47e9f11936bf6ebe9aa0"/>
@ -74,7 +74,7 @@
<project name="platform/external/libselinux" path="external/libselinux" revision="1e2cf2c4a2d15a9b1ca2d353b99fb6884413ffe1"/>
<project name="platform/external/libsepol" path="external/libsepol" revision="8fd7c65a336d45d5225f32363a9f26c1e3e60c3c"/>
<project name="platform/external/libvpx" path="external/libvpx" revision="5e563eddf3e143a4b670766b49f676ce39023322"/>
<project name="platform/external/mdnsresponder" path="external/mdnsresponder" revision="c46f53f5e072f23051c4eedef730386f7634dc11"/>
<project name="platform/external/mdnsresponder" path="external/mdnsresponder" remote="caf" revision="dd17df3f6775c4366a5c1d21865370d60a3b1295"/>
<project name="platform/external/mksh" path="external/mksh" revision="f8c396c4d446a038358106a301b329607a04633d"/>
<project name="platform/external/netcat" path="external/netcat" revision="444644cfa9a2f3002863caa168fb2d6b34dfd1e8"/>
<project name="platform/external/openssl" path="external/openssl" revision="bb8428f762b3632f493572c4f73957e1281ade79"/>

Просмотреть файл

@ -19,7 +19,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="d784c81961d82cbe9e111405468c590a8345856c"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="b69c16798ddd7154207f56d983721a327522f5d1"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="2d58f4b9206b50b8fda0d5036da6f0c62608db7c"/>

Просмотреть файл

@ -17,10 +17,10 @@
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="d784c81961d82cbe9e111405468c590a8345856c"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="b69c16798ddd7154207f56d983721a327522f5d1"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="51ebaf824cc634665c5efcae95b8301ad1758c5e"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="6641107c83e718d9896f90a9529ad0c252ddc271"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="b4f6fd4afd03161f53c7d2a663750f94762bd238"/>
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
<!-- Stock Android things -->

Просмотреть файл

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="e935894ef5f27e2f04b9e929a45a958e6288a223">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="d784c81961d82cbe9e111405468c590a8345856c"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="b69c16798ddd7154207f56d983721a327522f5d1"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
@ -23,7 +23,7 @@
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="6641107c83e718d9896f90a9529ad0c252ddc271"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="b4f6fd4afd03161f53c7d2a663750f94762bd238"/>
<!-- Stock Android things -->
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="f92a936f2aa97526d4593386754bdbf02db07a12"/>
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="6e47ff2790f5656b5b074407829ceecf3e6188c4"/>
@ -74,7 +74,7 @@
<project name="platform/external/libselinux" path="external/libselinux" revision="f2a93748f1974a76f1676f66049b3a29f1b4e532"/>
<project name="platform/external/libsepol" path="external/libsepol" revision="cf9b75ee1949969c6620fcbec854e67a305dbbc7"/>
<project name="platform/external/libvpx" path="external/libvpx" revision="11e4fb71a745e7d0f76099f8861d7e6083c104fa"/>
<project name="platform/external/mdnsresponder" path="external/mdnsresponder" revision="dcea77d81cd32b7874b1e26a6474e34917326472"/>
<project name="platform/external/mdnsresponder" path="external/mdnsresponder" remote="caf" revision="dd17df3f6775c4366a5c1d21865370d60a3b1295"/>
<project name="platform/external/mksh" path="external/mksh" revision="221fb0e62a39d4cedd6469a048cadb28fbf01a96"/>
<project name="platform/external/netcat" path="external/netcat" revision="0c2bf20f00ca9d74080a75eda76d0a5550702eaa"/>
<project name="platform/external/openssl" path="external/openssl" revision="aa09f63881e72abb398d301c8c19c56583790c84"/>

Просмотреть файл

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="05a36844c1046a1eb07d5b1325f85ed741f961ea">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="d784c81961d82cbe9e111405468c590a8345856c"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="b69c16798ddd7154207f56d983721a327522f5d1"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
@ -23,7 +23,7 @@
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="6641107c83e718d9896f90a9529ad0c252ddc271"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="b4f6fd4afd03161f53c7d2a663750f94762bd238"/>
<!-- Stock Android things -->
<project groups="pdk,linux" name="platform/prebuilts/clang/linux-x86/host/3.5" path="prebuilts/clang/linux-x86/host/3.5" revision="ffc05a232799fe8fcb3e47b7440b52b1fb4244c0"/>
<project groups="pdk,linux,arm" name="platform/prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.8" path="prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.8" revision="337e0ef5e40f02a1ae59b90db0548976c70a7226"/>

Просмотреть файл

@ -19,7 +19,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="d784c81961d82cbe9e111405468c590a8345856c"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="b69c16798ddd7154207f56d983721a327522f5d1"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="2d58f4b9206b50b8fda0d5036da6f0c62608db7c"/>

Просмотреть файл

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="e935894ef5f27e2f04b9e929a45a958e6288a223">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="d784c81961d82cbe9e111405468c590a8345856c"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="b69c16798ddd7154207f56d983721a327522f5d1"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
@ -23,7 +23,7 @@
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="6641107c83e718d9896f90a9529ad0c252ddc271"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="b4f6fd4afd03161f53c7d2a663750f94762bd238"/>
<!-- Stock Android things -->
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="ebdad82e61c16772f6cd47e9f11936bf6ebe9aa0"/>
@ -72,7 +72,7 @@
<project name="platform/external/libselinux" path="external/libselinux" revision="1e2cf2c4a2d15a9b1ca2d353b99fb6884413ffe1"/>
<project name="platform/external/libsepol" path="external/libsepol" revision="edc447a138ec77236f1cbfd36c1211a38ba21418"/>
<project name="platform/external/libvpx" path="external/libvpx" revision="ca9281af0bfe816f1ae2fc3e8771524164a0a03c"/>
<project name="platform/external/mdnsresponder" path="external/mdnsresponder" revision="c46f53f5e072f23051c4eedef730386f7634dc11"/>
<project name="platform/external/mdnsresponder" path="external/mdnsresponder" remote="caf" revision="dd17df3f6775c4366a5c1d21865370d60a3b1295"/>
<project name="platform/external/mksh" path="external/mksh" revision="f8c396c4d446a038358106a301b329607a04633d"/>
<project name="platform/external/netcat" path="external/netcat" revision="444644cfa9a2f3002863caa168fb2d6b34dfd1e8"/>
<project name="platform/external/openssl" path="external/openssl" revision="bb8428f762b3632f493572c4f73957e1281ade79"/>

Просмотреть файл

@ -1,9 +1,9 @@
{
"git": {
"git_revision": "d784c81961d82cbe9e111405468c590a8345856c",
"git_revision": "b69c16798ddd7154207f56d983721a327522f5d1",
"remote": "https://git.mozilla.org/releases/gaia.git",
"branch": ""
},
"revision": "34464a3c3dc438c500b48f2b7ff54025f46ce1fd",
"revision": "27d2127a81f03614541bfd148daa3002a9010e57",
"repo_path": "integration/gaia-central"
}

Просмотреть файл

@ -17,10 +17,10 @@
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="d784c81961d82cbe9e111405468c590a8345856c"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="b69c16798ddd7154207f56d983721a327522f5d1"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="51ebaf824cc634665c5efcae95b8301ad1758c5e"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="6641107c83e718d9896f90a9529ad0c252ddc271"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="b4f6fd4afd03161f53c7d2a663750f94762bd238"/>
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
<!-- Stock Android things -->

Просмотреть файл

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="05a36844c1046a1eb07d5b1325f85ed741f961ea">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="d784c81961d82cbe9e111405468c590a8345856c"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="b69c16798ddd7154207f56d983721a327522f5d1"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
@ -23,7 +23,7 @@
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="6641107c83e718d9896f90a9529ad0c252ddc271"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="b4f6fd4afd03161f53c7d2a663750f94762bd238"/>
<!-- Stock Android things -->
<project groups="pdk,linux" name="platform/prebuilts/clang/linux-x86/host/3.5" path="prebuilts/clang/linux-x86/host/3.5" revision="ffc05a232799fe8fcb3e47b7440b52b1fb4244c0"/>
<project groups="pdk,linux,arm" name="platform/prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.8" path="prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.8" revision="337e0ef5e40f02a1ae59b90db0548976c70a7226"/>

Просмотреть файл

@ -85,6 +85,13 @@ endif
DEFINES += -DBINPATH=$(BINPATH)
DEFINES += -DRESPATH=$(RESPATH)
LPROJ_ROOT = $(firstword $(subst -, ,$(AB_CD)))
ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT))
ifeq (zh-TW,$(AB_CD))
LPROJ_ROOT := $(subst -,_,$(AB_CD))
endif
endif
DEFINES += -DLPROJ_ROOT=$(LPROJ_ROOT)
ifneq (,$(filter WINNT Darwin Android,$(OS_TARGET)))
DEFINES += -DMOZ_SHARED_MOZGLUE=1

Просмотреть файл

@ -32,7 +32,8 @@
@APPNAME@/Contents/Info.plist
@APPNAME@/Contents/PkgInfo
@APPNAME@/Contents/Plug-Ins/
@RESPATH@
@RESPATH@/b2g.icns
@RESPATH@/@LPROJ_ROOT@.lproj/*
#endif
[@AB_CD@]
@ -961,6 +962,7 @@ bin/libfreebl_32int64_3.so
@RESPATH@/components/B2GAppMigrator.js
@RESPATH@/components/B2GPresentationDevicePrompt.js
@RESPATH@/components/PresentationRequestUIGlue.js
@RESPATH@/components/KillSwitch.js
#ifndef MOZ_WIDGET_GONK
@RESPATH@/components/SimulatorScreen.js

Просмотреть файл

@ -382,7 +382,7 @@
label="&viewPageSourceCmd.label;"
accesskey="&viewPageSourceCmd.accesskey;"
oncommand="BrowserViewSource(gContextMenu.browser);"
observes="isImage"/>
observes="canViewSource"/>
<menuitem id="context-viewinfo"
label="&viewPageInfoCmd.label;"
accesskey="&viewPageInfoCmd.accesskey;"

Просмотреть файл

@ -39,7 +39,7 @@
<commandset id="editMenuCommands"/>
<command id="View:PageSource" oncommand="BrowserViewSource(window.gBrowser.selectedBrowser);" observes="isImage"/>
<command id="View:PageSource" oncommand="BrowserViewSource(window.gBrowser.selectedBrowser);" observes="canViewSource"/>
<command id="View:PageInfo" oncommand="BrowserPageInfo();"/>
<command id="View:FullScreen" oncommand="BrowserFullScreen();"/>
<command id="View:ReaderView" oncommand="ReaderParent.toggleReaderMode(event);"/>
@ -174,6 +174,7 @@
oncommand="gPopupBlockerObserver.dontShowMessage();"/>
<broadcaster id="blockedPopupsSeparator"/>
<broadcaster id="isImage"/>
<broadcaster id="canViewSource"/>
<broadcaster id="isFrameImage"/>
<broadcaster id="singleFeedMenuitemState" disabled="true"/>
<broadcaster id="multipleFeedsMenuState" hidden="true"/>
@ -231,7 +232,9 @@
<broadcaster id="devtoolsMenuBroadcaster_PageSource"
label="&pageSourceCmd.label;"
key="key_viewSource"
command="View:PageSource"/>
command="View:PageSource">
<observes element="canViewSource" attribute="disabled"/>
</broadcaster>
<broadcaster id="devtoolsMenuBroadcaster_ErrorConsole"
label="&errorConsoleCmd.label;"
command="Tools:ErrorConsole"/>

Просмотреть файл

@ -4049,6 +4049,10 @@ var XULBrowserWindow = {
delete this.isImage;
return this.isImage = document.getElementById("isImage");
},
get canViewSource () {
delete this.canViewSource;
return this.canViewSource = document.getElementById("canViewSource");
},
init: function () {
// Initialize the security button's state and tooltip text.
@ -4206,6 +4210,7 @@ var XULBrowserWindow = {
if (aRequest) {
let msg = "";
let location;
let canViewSource = true;
// Get the URI either from a channel or a pseudo-object
if (aRequest instanceof nsIChannel || "URI" in aRequest) {
location = aRequest.URI;
@ -4214,6 +4219,9 @@ var XULBrowserWindow = {
if (location.scheme == "keyword" && aWebProgress.isTopLevel)
gBrowser.userTypedValue = null;
canViewSource = !Services.prefs.getBoolPref("view_source.tab") ||
location.scheme != "view-source";
if (location.spec != "about:blank") {
switch (aStatus) {
case Components.results.NS_ERROR_NET_TIMEOUT:
@ -4227,10 +4235,18 @@ var XULBrowserWindow = {
this.setDefaultStatus(msg);
// Disable menu entries for images, enable otherwise
if (browser.documentContentType && BrowserUtils.mimeTypeIsTextBased(browser.documentContentType))
if (browser.documentContentType && BrowserUtils.mimeTypeIsTextBased(browser.documentContentType)) {
this.isImage.removeAttribute('disabled');
else
} else {
canViewSource = false;
this.isImage.setAttribute('disabled', 'true');
}
if (canViewSource) {
this.canViewSource.removeAttribute('disabled');
} else {
this.canViewSource.setAttribute('disabled', 'true');
}
}
this.isBusy = false;

Просмотреть файл

@ -474,6 +474,7 @@ skip-if = os == "linux" || e10s # Bug 1073339 - Investigate autocomplete test un
[browser_urlbar_search_healthreport.js]
[browser_urlbar_searchsettings.js]
[browser_utilityOverlay.js]
[browser_viewSourceInTabOnViewSource.js]
[browser_visibleFindSelection.js]
[browser_visibleLabel.js]
[browser_visibleTabs.js]

Просмотреть файл

@ -0,0 +1,55 @@
function wait_while_tab_is_busy() {
return new Promise(resolve => {
let progressListener = {
onStateChange: function(aWebProgress, aRequest, aStateFlags, aStatus) {
if (aStateFlags & Ci.nsIWebProgressListener.STATE_STOP) {
gBrowser.removeProgressListener(this);
setTimeout(resolve, 0);
}
}
};
gBrowser.addProgressListener(progressListener);
});
}
// This function waits for the tab to stop being busy instead of waiting for it
// to load, since the canViewSource change happens at that time.
let with_new_tab_opened = Task.async(function* (options, taskFn) {
let busyPromise = wait_while_tab_is_busy();
let tab = yield BrowserTestUtils.openNewForegroundTab(options.gBrowser, options.url, false);
yield busyPromise;
yield taskFn(tab.linkedBrowser);
gBrowser.removeTab(tab);
});
add_task(function*() {
yield new Promise((resolve) => {
SpecialPowers.pushPrefEnv({"set": [
["view_source.tab", true],
]}, resolve);
});
});
add_task(function* test_regular_page() {
function* test_expect_view_source_enabled(browser) {
ok(!XULBrowserWindow.canViewSource.hasAttribute("disabled"),
"View Source should be enabled");
}
yield with_new_tab_opened({
gBrowser,
url: "http://example.com",
}, test_expect_view_source_enabled);
});
add_task(function* test_view_source_page() {
function* test_expect_view_source_disabled(browser) {
ok(XULBrowserWindow.canViewSource.hasAttribute("disabled"),
"View Source should be disabled");
}
yield with_new_tab_opened({
gBrowser,
url: "view-source:http://example.com",
}, test_expect_view_source_disabled);
});

Просмотреть файл

@ -37,12 +37,22 @@ AppValidator.prototype._getPackagedManifestFile = function () {
this.error(strings.GetStringFromName("validator.expectProjectFolder"));
return null;
}
manifestFile.append("manifest.webapp");
if (!manifestFile.exists() || !manifestFile.isFile()) {
let appManifestFile = manifestFile.clone();
appManifestFile.append("manifest.webapp");
let jsonManifestFile = manifestFile.clone();
jsonManifestFile.append("manifest.json");
let hasAppManifest = appManifestFile.exists() && appManifestFile.isFile();
let hasJsonManifest = jsonManifestFile.exists() && jsonManifestFile.isFile();
if (!hasAppManifest && !hasJsonManifest) {
this.error(strings.GetStringFromName("validator.wrongManifestFileName"));
return null;
}
return manifestFile;
return hasAppManifest ? appManifestFile : jsonManifestFile;
};
AppValidator.prototype._getPackagedManifestURL = function () {
@ -191,10 +201,6 @@ AppValidator.prototype._getOriginURL = function () {
};
AppValidator.prototype.validateLaunchPath = function (manifest) {
// Addons don't use index page (yet?)
if (manifest.role && manifest.role === "addon") {
return promise.resolve();
}
let deferred = promise.defer();
// The launch_path field has to start with a `/`
if (manifest.launch_path && manifest.launch_path[0] !== "/") {
@ -267,14 +273,20 @@ AppValidator.prototype.validate = function () {
this.errors = [];
this.warnings = [];
return this._getManifest().
then((function (manifest) {
then((manifest) => {
if (manifest) {
this.manifest = manifest;
// Skip validations for add-ons
if (manifest.role === "addon" || manifest.manifest_version) {
return promise.resolve();
}
this.validateManifest(manifest);
this.validateType(manifest);
return this.validateLaunchPath(manifest);
}
}).bind(this));
});
};
exports.AppValidator = AppValidator;

Просмотреть файл

@ -659,7 +659,7 @@ let AppManager = exports.AppManager = {
// Addons don't have any document to load (yet?)
// So that there is no need to run them, installing is enough
if (project.manifest.role && project.manifest.role === "addon") {
if (project.manifest.manifest_version || project.manifest.role === "addon") {
return;
}

Просмотреть файл

@ -18,7 +18,7 @@ project.installing=Installing…
project.installed=Installed!
validator.nonExistingFolder=The project folder doesn't exists
validator.expectProjectFolder=The project folder ends up being a file
validator.wrongManifestFileName=Packaged apps require a manifest file that can only be named 'manifest.webapp' at project root folder
validator.wrongManifestFileName=A manifest file is required at project root folder, named either 'manifest.webapp' for packaged apps or 'manifest.json' for addons.
validator.invalidManifestURL=Invalid manifest URL '%S'
# LOCALIZATION NOTE (validator.invalidManifestJSON, validator.noAccessManifestURL):
# %1$S is the error message, %2$S is the URI of the manifest.

Просмотреть файл

@ -287,8 +287,8 @@ class RemoteAutomation(Automation):
self.procName = app
# Setting timeout at 1 hour since on a remote device this takes much longer.
# Temporarily increased to 75 minutes because no more chunks can be created.
self.timeout = 4500
# Temporarily increased to 90 minutes because no more chunks can be created.
self.timeout = 5400
# The benefit of the following sleep is unclear; it was formerly 15 seconds
time.sleep(1)

Просмотреть файл

@ -497,6 +497,12 @@ this.PermissionsTable = { geolocation: {
trusted: DENY_ACTION,
privileged: ALLOW_ACTION,
certified: ALLOW_ACTION
},
"killswitch": {
app: DENY_ACTION,
trusted: DENY_ACTION,
privileged: DENY_ACTION,
certified: ALLOW_ACTION
}
};

Просмотреть файл

@ -12,6 +12,7 @@ this.EXPORTED_SYMBOLS = ["UserCustomizations"];
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/AppsUtils.jsm");
Cu.import("resource://gre/modules/Extension.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "ValueExtractor",
@ -47,7 +48,7 @@ this.UserCustomizations = {
debug("Starting customization registration for " + aApp.manifestURL + "\n");
let extension = new Extension({
id: aApp.manifestURL,
id: AppsUtils.computeHash(aApp.manifestURL),
resourceURI: Services.io.newURI(aApp.origin + "/", null, null)
});
@ -150,6 +151,9 @@ this.UserCustomizations = {
},
init: function() {
// XXX : For testing purposes. Will not commit.
AppsUtils.allowUnsignedAddons = true;
this._enabled = false;
try {
this._enabled = Services.prefs.getBoolPref("dom.apps.customization.enabled");

Просмотреть файл

@ -861,9 +861,13 @@ this.DOMApplicationRegistry = {
root = aManifest.entry_points[aEntryPoint];
}
if (!root.messages || !Array.isArray(root.messages) ||
root.messages.length == 0) {
dump("Could not register invalid system message entry\n");
if (!root.messages) {
// This application just doesn't use system messages.
return;
}
if (!Array.isArray(root.messages) || root.messages.length == 0) {
dump("Could not register invalid system message entry for " + aApp.manifestURL + "\n");
try {
dump(JSON.stringify(root.messages) + "\n");
} catch(e) {}
@ -877,7 +881,7 @@ this.DOMApplicationRegistry = {
let handlerPageURI = launchPathURI;
let messageName;
if (typeof(aMessage) !== "object" || Object.keys(aMessage).length !== 1) {
dump("Could not register invalid system message entry\n");
dump("Could not register invalid system message entry for " + aApp.manifestURL + "\n");
try {
dump(JSON.stringify(aMessage) + "\n");
} catch(e) {}

Просмотреть файл

@ -2468,24 +2468,6 @@ Navigator::HasUserMediaSupport(JSContext* /* unused */,
}
#endif // MOZ_MEDIA_NAVIGATOR
/* static */
bool
Navigator::HasInputMethodSupport(JSContext* /* unused */,
JSObject* aGlobal)
{
nsCOMPtr<nsPIDOMWindow> win = GetWindowFromGlobal(aGlobal);
if (!win || !Preferences::GetBool("dom.mozInputMethod.enabled", false)) {
return false;
}
if (Preferences::GetBool("dom.mozInputMethod.testing", false)) {
return true;
}
return CheckPermission(win, "input") ||
CheckPermission(win, "input-manage");
}
/* static */
bool
Navigator::HasDataStoreSupport(nsIPrincipal* aPrincipal)

Просмотреть файл

@ -323,8 +323,6 @@ public:
JSObject* /* unused */);
#endif // MOZ_MEDIA_NAVIGATOR
static bool HasInputMethodSupport(JSContext* /* unused */, JSObject* aGlobal);
static bool HasDataStoreSupport(nsIPrincipal* aPrincipal);
static bool HasDataStoreSupport(JSContext* cx, JSObject* aGlobal);

Просмотреть файл

@ -113,8 +113,11 @@ PostMessageEvent::Run()
false /*cancelable */, messageData, mCallerOrigin,
EmptyString(), mSource);
nsTArray<nsRefPtr<MessagePortBase>> ports;
TakeTransferredPorts(ports);
event->SetPorts(new MessagePortList(static_cast<dom::Event*>(event.get()),
GetTransferredPorts()));
ports));
// We can't simply call dispatchEvent on the window because doing so ends
// up flipping the trusted bit on the event, and we don't want that to

Просмотреть файл

@ -14,11 +14,24 @@
#include "mozilla/dom/FileListBinding.h"
#include "mozilla/dom/ImageBitmap.h"
#include "mozilla/dom/ImageBitmapBinding.h"
#include "mozilla/dom/ImageData.h"
#include "mozilla/dom/ImageDataBinding.h"
#include "mozilla/dom/ipc/BlobChild.h"
#include "mozilla/dom/StructuredClone.h"
#include "mozilla/dom/MessagePort.h"
#include "mozilla/dom/MessagePortBinding.h"
#include "mozilla/dom/PMessagePort.h"
#include "mozilla/dom/StructuredCloneTags.h"
#include "mozilla/dom/ToJSValue.h"
#include "mozilla/dom/WebCryptoCommon.h"
#include "mozilla/ipc/BackgroundChild.h"
#include "mozilla/ipc/BackgroundUtils.h"
#include "MultipartBlobImpl.h"
#include "nsFormData.h"
#include "nsIRemoteBlob.h"
#include "nsQueryObject.h"
using namespace mozilla::ipc;
namespace mozilla {
namespace dom {
@ -142,11 +155,7 @@ bool
StructuredCloneHelperInternal::Write(JSContext* aCx,
JS::Handle<JS::Value> aValue)
{
MOZ_ASSERT(!mBuffer, "Double Write is not allowed");
MOZ_ASSERT(!mShutdownCalled, "This method cannot be called after Shutdown.");
mBuffer = new JSAutoStructuredCloneBuffer(&gCallbacks, this);
return mBuffer->write(aCx, aValue, &gCallbacks, this);
return Write(aCx, aValue, JS::UndefinedHandleValue);
}
bool
@ -217,24 +226,37 @@ StructuredCloneHelper::StructuredCloneHelper(CloningSupport aSupportsCloning,
StructuredCloneHelper::~StructuredCloneHelper()
{
Shutdown();
MOZ_ASSERT(mTransferredPorts.IsEmpty());
}
void
StructuredCloneHelper::Write(JSContext* aCx,
JS::Handle<JS::Value> aValue,
bool aMaybeToDifferentThread,
ErrorResult& aRv)
{
Write(aCx, aValue, JS::UndefinedHandleValue, aRv);
Write(aCx, aValue, JS::UndefinedHandleValue, aMaybeToDifferentThread, aRv);
}
void
StructuredCloneHelper::Write(JSContext* aCx,
JS::Handle<JS::Value> aValue,
JS::Handle<JS::Value> aTransfer,
bool aMaybeToDifferentThread,
ErrorResult& aRv)
{
if (!StructuredCloneHelperInternal::Write(aCx, aValue, aTransfer)) {
aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
return;
}
if (aMaybeToDifferentThread) {
for (uint32_t i = 0, len = mBlobImplArray.Length(); i < len; ++i) {
if (!mBlobImplArray[i]->MayBeClonedToOtherThreads()) {
aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
return;
}
}
}
}
@ -324,6 +346,346 @@ StructuredCloneHelper::FreeBuffer(uint64_t* aBuffer,
JS_ClearStructuredClone(aBuffer, aBufferLength, &gCallbacks, this, false);
}
namespace {
// Recursive!
already_AddRefed<BlobImpl>
EnsureBlobForBackgroundManager(BlobImpl* aBlobImpl,
PBackgroundChild* aManager = nullptr)
{
MOZ_ASSERT(aBlobImpl);
if (!aManager) {
aManager = BackgroundChild::GetForCurrentThread();
MOZ_ASSERT(aManager);
}
nsRefPtr<BlobImpl> blobImpl = aBlobImpl;
const nsTArray<nsRefPtr<BlobImpl>>* subBlobImpls =
aBlobImpl->GetSubBlobImpls();
if (!subBlobImpls || !subBlobImpls->Length()) {
if (nsCOMPtr<nsIRemoteBlob> remoteBlob = do_QueryObject(blobImpl)) {
// Always make sure we have a blob from an actor we can use on this
// thread.
BlobChild* blobChild = BlobChild::GetOrCreate(aManager, blobImpl);
MOZ_ASSERT(blobChild);
blobImpl = blobChild->GetBlobImpl();
MOZ_ASSERT(blobImpl);
DebugOnly<bool> isMutable;
MOZ_ASSERT(NS_SUCCEEDED(blobImpl->GetMutable(&isMutable)));
MOZ_ASSERT(!isMutable);
} else {
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(blobImpl->SetMutable(false)));
}
return blobImpl.forget();
}
const uint32_t subBlobCount = subBlobImpls->Length();
MOZ_ASSERT(subBlobCount);
nsTArray<nsRefPtr<BlobImpl>> newSubBlobImpls;
newSubBlobImpls.SetLength(subBlobCount);
bool newBlobImplNeeded = false;
for (uint32_t index = 0; index < subBlobCount; index++) {
const nsRefPtr<BlobImpl>& subBlobImpl = subBlobImpls->ElementAt(index);
MOZ_ASSERT(subBlobImpl);
nsRefPtr<BlobImpl>& newSubBlobImpl = newSubBlobImpls[index];
newSubBlobImpl = EnsureBlobForBackgroundManager(subBlobImpl, aManager);
MOZ_ASSERT(newSubBlobImpl);
if (subBlobImpl != newSubBlobImpl) {
newBlobImplNeeded = true;
}
}
if (newBlobImplNeeded) {
nsString contentType;
blobImpl->GetType(contentType);
if (blobImpl->IsFile()) {
nsString name;
blobImpl->GetName(name);
blobImpl = new MultipartBlobImpl(newSubBlobImpls, name, contentType);
} else {
blobImpl = new MultipartBlobImpl(newSubBlobImpls, contentType);
}
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(blobImpl->SetMutable(false)));
}
return blobImpl.forget();
}
JSObject*
ReadBlob(JSContext* aCx,
uint32_t aIndex,
StructuredCloneHelper* aHelper)
{
MOZ_ASSERT(aHelper);
MOZ_ASSERT(aIndex < aHelper->BlobImpls().Length());
nsRefPtr<BlobImpl> blobImpl = aHelper->BlobImpls()[aIndex];
blobImpl = EnsureBlobForBackgroundManager(blobImpl);
MOZ_ASSERT(blobImpl);
// nsRefPtr<File> needs to go out of scope before toObjectOrNull() is
// called because the static analysis thinks dereferencing XPCOM objects
// can GC (because in some cases it can!), and a return statement with a
// JSObject* type means that JSObject* is on the stack as a raw pointer
// while destructors are running.
JS::Rooted<JS::Value> val(aCx);
{
nsRefPtr<Blob> blob = Blob::Create(aHelper->ParentDuringRead(), blobImpl);
if (!ToJSValue(aCx, blob, &val)) {
return nullptr;
}
}
return &val.toObject();
}
bool
WriteBlob(JSStructuredCloneWriter* aWriter,
Blob* aBlob,
StructuredCloneHelper* aHelper)
{
MOZ_ASSERT(aWriter);
MOZ_ASSERT(aBlob);
MOZ_ASSERT(aHelper);
nsRefPtr<BlobImpl> blobImpl = EnsureBlobForBackgroundManager(aBlob->Impl());
MOZ_ASSERT(blobImpl);
// We store the position of the blobImpl in the array as index.
if (JS_WriteUint32Pair(aWriter, SCTAG_DOM_BLOB,
aHelper->BlobImpls().Length())) {
aHelper->BlobImpls().AppendElement(blobImpl);
return true;
}
return false;
}
// Read the WriteFileList for the format.
JSObject*
ReadFileList(JSContext* aCx,
JSStructuredCloneReader* aReader,
uint32_t aCount,
StructuredCloneHelper* aHelper)
{
MOZ_ASSERT(aCx);
MOZ_ASSERT(aReader);
JS::Rooted<JS::Value> val(aCx);
{
nsRefPtr<FileList> fileList = new FileList(aHelper->ParentDuringRead());
uint32_t tag, offset;
// Offset is the index of the blobImpl from which we can find the blobImpl
// for this FileList.
if (!JS_ReadUint32Pair(aReader, &tag, &offset)) {
return nullptr;
}
MOZ_ASSERT(tag == 0);
// |aCount| is the number of BlobImpls to use from the |offset|.
for (uint32_t i = 0; i < aCount; ++i) {
uint32_t index = offset + i;
MOZ_ASSERT(index < aHelper->BlobImpls().Length());
nsRefPtr<BlobImpl> blobImpl = aHelper->BlobImpls()[index];
MOZ_ASSERT(blobImpl->IsFile());
nsRefPtr<File> file = File::Create(aHelper->ParentDuringRead(), blobImpl);
if (!fileList->Append(file)) {
return nullptr;
}
}
if (!ToJSValue(aCx, fileList, &val)) {
return nullptr;
}
}
return &val.toObject();
}
// The format of the FileList serialization is:
// - pair of ints: SCTAG_DOM_FILELIST, Length of the FileList
// - pair of ints: 0, The offset of the BlobImpl array
bool
WriteFileList(JSStructuredCloneWriter* aWriter,
FileList* aFileList,
StructuredCloneHelper* aHelper)
{
MOZ_ASSERT(aWriter);
MOZ_ASSERT(aFileList);
MOZ_ASSERT(aHelper);
// A FileList is serialized writing the X number of elements and the offset
// from mBlobImplArray. The Read will take X elements from mBlobImplArray
// starting from the offset.
if (!JS_WriteUint32Pair(aWriter, SCTAG_DOM_FILELIST,
aFileList->Length()) ||
!JS_WriteUint32Pair(aWriter, 0,
aHelper->BlobImpls().Length())) {
return false;
}
for (uint32_t i = 0; i < aFileList->Length(); ++i) {
aHelper->BlobImpls().AppendElement(aFileList->Item(i)->Impl());
}
return true;
}
// Read the WriteFormData for the format.
JSObject*
ReadFormData(JSContext* aCx,
JSStructuredCloneReader* aReader,
uint32_t aCount,
StructuredCloneHelper* aHelper)
{
MOZ_ASSERT(aCx);
MOZ_ASSERT(aReader);
MOZ_ASSERT(aHelper);
// See the serialization of the FormData for the format.
JS::Rooted<JS::Value> val(aCx);
{
nsRefPtr<nsFormData> formData =
new nsFormData(aHelper->ParentDuringRead());
Optional<nsAString> thirdArg;
for (uint32_t i = 0; i < aCount; ++i) {
nsAutoString name;
if (!ReadString(aReader, name)) {
return nullptr;
}
uint32_t tag, indexOrLengthOfString;
if (!JS_ReadUint32Pair(aReader, &tag, &indexOrLengthOfString)) {
return nullptr;
}
if (tag == SCTAG_DOM_BLOB) {
MOZ_ASSERT(indexOrLengthOfString < aHelper->BlobImpls().Length());
nsRefPtr<BlobImpl> blobImpl =
aHelper->BlobImpls()[indexOrLengthOfString];
MOZ_ASSERT(blobImpl->IsFile());
nsRefPtr<File> file =
File::Create(aHelper->ParentDuringRead(), blobImpl);
MOZ_ASSERT(file);
formData->Append(name, *file, thirdArg);
} else {
MOZ_ASSERT(tag == 0);
nsAutoString value;
value.SetLength(indexOrLengthOfString);
size_t charSize = sizeof(nsString::char_type);
if (!JS_ReadBytes(aReader, (void*) value.BeginWriting(),
indexOrLengthOfString * charSize)) {
return nullptr;
}
formData->Append(name, value);
}
}
if (!ToJSValue(aCx, formData, &val)) {
return nullptr;
}
}
return &val.toObject();
}
// The format of the FormData serialization is:
// - pair of ints: SCTAG_DOM_FORMDATA, Length of the FormData elements
// - for each Element element:
// - name string
// - if it's a blob:
// - pair of ints: SCTAG_DOM_BLOB, index of the BlobImpl in the array
// mBlobImplArray.
// - else:
// - pair of ints: 0, string length
// - value string
bool
WriteFormData(JSStructuredCloneWriter* aWriter,
nsFormData* aFormData,
StructuredCloneHelper* aHelper)
{
MOZ_ASSERT(aWriter);
MOZ_ASSERT(aFormData);
MOZ_ASSERT(aHelper);
if (!JS_WriteUint32Pair(aWriter, SCTAG_DOM_FORMDATA,
aFormData->Length())) {
return false;
}
class MOZ_STACK_CLASS Closure final
{
JSStructuredCloneWriter* mWriter;
StructuredCloneHelper* mHelper;
public:
Closure(JSStructuredCloneWriter* aWriter,
StructuredCloneHelper* aHelper)
: mWriter(aWriter),
mHelper(aHelper)
{ }
static bool
Write(const nsString& aName, bool isFile, const nsString& aValue,
File* aFile, void* aClosure)
{
Closure* closure = static_cast<Closure*>(aClosure);
if (!WriteString(closure->mWriter, aName)) {
return false;
}
if (isFile) {
BlobImpl* blobImpl = aFile->Impl();
if (!JS_WriteUint32Pair(closure->mWriter, SCTAG_DOM_BLOB,
closure->mHelper->BlobImpls().Length())) {
return false;
}
closure->mHelper->BlobImpls().AppendElement(blobImpl);
return true;
}
size_t charSize = sizeof(nsString::char_type);
if (!JS_WriteUint32Pair(closure->mWriter, 0, aValue.Length()) ||
!JS_WriteBytes(closure->mWriter, aValue.get(),
aValue.Length() * charSize)) {
return false;
}
return true;
}
};
Closure closure(aWriter, aHelper);
return aFormData->ForEach(Closure::Write, &closure);
}
} // anonymous namespace
JSObject*
StructuredCloneHelper::ReadCallback(JSContext* aCx,
JSStructuredCloneReader* aReader,
@ -333,56 +695,19 @@ StructuredCloneHelper::ReadCallback(JSContext* aCx,
MOZ_ASSERT(mSupportsCloning);
if (aTag == SCTAG_DOM_BLOB) {
MOZ_ASSERT(aIndex < mBlobImplArray.Length());
nsRefPtr<BlobImpl> blobImpl = mBlobImplArray[aIndex];
// nsRefPtr<File> needs to go out of scope before toObjectOrNull() is
// called because the static analysis thinks dereferencing XPCOM objects
// can GC (because in some cases it can!), and a return statement with a
// JSObject* type means that JSObject* is on the stack as a raw pointer
// while destructors are running.
JS::Rooted<JS::Value> val(aCx);
{
nsRefPtr<Blob> blob = Blob::Create(mParent, blobImpl);
if (!ToJSValue(aCx, blob, &val)) {
return nullptr;
}
}
return &val.toObject();
return ReadBlob(aCx, aIndex, this);
}
if (aTag == SCTAG_DOM_FILELIST) {
JS::Rooted<JS::Value> val(aCx);
{
nsRefPtr<FileList> fileList = new FileList(mParent);
return ReadFileList(aCx, aReader, aIndex, this);
}
// |aIndex| is the number of BlobImpls to use from |offset|.
uint32_t tag, offset;
if (!JS_ReadUint32Pair(aReader, &tag, &offset)) {
return nullptr;
}
MOZ_ASSERT(tag == 0);
if (aTag == SCTAG_DOM_IMAGEDATA) {
return ReadStructuredCloneImageData(aCx, aReader);
}
for (uint32_t i = 0; i < aIndex; ++i) {
uint32_t index = offset + i;
MOZ_ASSERT(index < mBlobImplArray.Length());
nsRefPtr<BlobImpl> blobImpl = mBlobImplArray[index];
MOZ_ASSERT(blobImpl->IsFile());
nsRefPtr<File> file = File::Create(mParent, blobImpl);
if (!fileList->Append(file)) {
return nullptr;
}
}
if (!ToJSValue(aCx, fileList, &val)) {
return nullptr;
}
}
return &val.toObject();
if (aTag == SCTAG_DOM_FORMDATA) {
return ReadFormData(aCx, aReader, aIndex, this);
}
if (aTag == SCTAG_DOM_IMAGEBITMAP) {
@ -410,35 +735,31 @@ StructuredCloneHelper::WriteCallback(JSContext* aCx,
{
Blob* blob = nullptr;
if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, aObj, blob))) {
BlobImpl* blobImpl = blob->Impl();
if (JS_WriteUint32Pair(aWriter, SCTAG_DOM_BLOB,
mBlobImplArray.Length())) {
mBlobImplArray.AppendElement(blobImpl);
return true;
}
return false;
return WriteBlob(aWriter, blob, this);
}
}
// See if this is a FileList object.
{
FileList* fileList = nullptr;
if (NS_SUCCEEDED(UNWRAP_OBJECT(FileList, aObj, fileList))) {
// A FileList is serialized writing the X number of elements and the offset
// from mBlobImplArray. The Read will take X elements from mBlobImplArray
// starting from the offset.
if (!JS_WriteUint32Pair(aWriter, SCTAG_DOM_FILELIST,
fileList->Length()) ||
!JS_WriteUint32Pair(aWriter, 0,
mBlobImplArray.Length())) {
return false;
}
return WriteFileList(aWriter, fileList, this);
}
}
for (uint32_t i = 0; i < fileList->Length(); ++i) {
mBlobImplArray.AppendElement(fileList->Item(i)->Impl());
}
// See if this is a ImageData object.
{
ImageData* imageData = nullptr;
if (NS_SUCCEEDED(UNWRAP_OBJECT(ImageData, aObj, imageData))) {
return WriteStructuredCloneImageData(aCx, aWriter, imageData);
}
}
return true;
// See if this is a FormData object.
{
nsFormData* formData = nullptr;
if (NS_SUCCEEDED(UNWRAP_OBJECT(FormData, aObj, formData))) {
return WriteFormData(aWriter, formData, this);
}
}

Просмотреть файл

@ -81,6 +81,11 @@ public:
bool Read(JSContext* aCx,
JS::MutableHandle<JS::Value> aValue);
bool HasBeenWritten() const
{
return !!mBuffer;
}
uint64_t* BufferData() const
{
MOZ_ASSERT(mBuffer, "Write() has never been called.");
@ -132,11 +137,13 @@ public:
void Write(JSContext* aCx,
JS::Handle<JS::Value> aValue,
bool aMaybeToDifferentThread,
ErrorResult &aRv);
void Write(JSContext* aCx,
JS::Handle<JS::Value> aValue,
JS::Handle<JS::Value> aTransfer,
bool aMaybeToDifferentThread,
ErrorResult &aRv);
void Read(nsISupports* aParent,
@ -184,10 +191,19 @@ public:
return mBlobImplArray;
}
const nsTArray<nsRefPtr<MessagePortBase>>& GetTransferredPorts() const
nsISupports* ParentDuringRead() const
{
return mParent;
}
// This must be called if the transferring has ports generated by Read().
// MessagePorts are not thread-safe and they must be retrieved in the thread
// where they are created.
void TakeTransferredPorts(nsTArray<nsRefPtr<MessagePortBase>>& aPorts)
{
MOZ_ASSERT(mSupportsTransferring);
return mTransferredPorts;
MOZ_ASSERT(aPorts.IsEmpty());
aPorts.SwapElements(mTransferredPorts);
}
nsTArray<MessagePortIdentifier>& PortIdentifiers()

Просмотреть файл

@ -46,6 +46,8 @@ enum StructuredCloneTags {
SCTAG_DOM_RTC_CERTIFICATE,
SCTAG_DOM_FORMDATA,
SCTAG_DOM_MAX
};

Просмотреть файл

@ -3205,6 +3205,93 @@ nsDOMWindowUtils::RemoteFrameFullscreenReverted()
return NS_OK;
}
class MOZ_STACK_CLASS FullscreenChangePrepare
{
public:
FullscreenChangePrepare(nsIPresShell* aPresShell,
const nsSize& aSize, nsSize* aOldSize = nullptr)
: mPresShell(aPresShell)
{
if (mPresShell) {
mPresShell->SetIsInFullscreenChange(true);
}
if (aSize.IsEmpty()) {
return;
}
if (nsViewManager* viewManager = mPresShell->GetViewManager()) {
if (aOldSize) {
viewManager->GetWindowDimensions(&aOldSize->width, &aOldSize->height);
}
viewManager->SetWindowDimensions(aSize.width, aSize.height);
}
}
~FullscreenChangePrepare()
{
if (mPresShell) {
mPresShell->SetIsInFullscreenChange(false);
}
}
private:
nsCOMPtr<nsIPresShell> mPresShell;
};
class OldWindowSize : public LinkedListElement<OldWindowSize>
{
public:
static void Set(nsPIDOMWindow* aWindow, const nsSize& aSize)
{
OldWindowSize* item = GetItem(aWindow);
if (item) {
item->mSize = aSize;
} else if (aWindow) {
item = new OldWindowSize(do_GetWeakReference(aWindow), aSize);
sList.insertBack(item);
}
}
static nsSize GetAndRemove(nsPIDOMWindow* aWindow)
{
nsSize result;
if (OldWindowSize* item = GetItem(aWindow)) {
result = item->mSize;
delete item;
}
return result;
}
private:
explicit OldWindowSize(already_AddRefed<nsIWeakReference>&& aWindow,
const nsSize& aSize)
: mWindow(Move(aWindow)), mSize(aSize) { }
~OldWindowSize() { };
static OldWindowSize* GetItem(nsPIDOMWindow* aWindow)
{
OldWindowSize* item = sList.getFirst();
while (item) {
nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(item->mWindow);
if (!window) {
OldWindowSize* thisItem = item;
item = thisItem->getNext();
delete thisItem;
continue;
}
if (window == aWindow) {
break;
}
}
return item;
}
static LinkedList<OldWindowSize> sList;
nsWeakPtr mWindow;
nsSize mSize;
};
LinkedList<OldWindowSize> OldWindowSize::sList;
NS_IMETHODIMP
nsDOMWindowUtils::HandleFullscreenRequests(bool* aRetVal)
{
@ -3213,6 +3300,18 @@ nsDOMWindowUtils::HandleFullscreenRequests(bool* aRetVal)
nsCOMPtr<nsIDocument> doc = GetDocument();
NS_ENSURE_STATE(doc);
// Notify the pres shell that we are starting fullscreen change, and
// set the window dimensions in advance. Since the resize message
// comes after the fullscreen change call, doing so could avoid an
// extra resize reflow after this point.
nsRect screenRect;
if (nsPresContext* presContext = GetPresContext()) {
presContext->DeviceContext()->GetRect(screenRect);
}
nsSize oldSize;
FullscreenChangePrepare prepare(GetPresShell(), screenRect.Size(), &oldSize);
OldWindowSize::Set(doc->GetWindow(), oldSize);
*aRetVal = nsIDocument::HandlePendingFullscreenRequests(doc);
return NS_OK;
}
@ -3224,6 +3323,16 @@ nsDOMWindowUtils::ExitFullscreen()
nsCOMPtr<nsIDocument> doc = GetDocument();
NS_ENSURE_STATE(doc);
if (!doc->IsFullScreenDoc()) {
return NS_OK;
}
// Notify the pres shell that we are starting fullscreen change, and
// set the window dimensions in advance. Since the resize message
// comes after the fullscreen change call, doing so could avoid an
// extra resize reflow after this point.
FullscreenChangePrepare prepare(
GetPresShell(), OldWindowSize::GetAndRemove(doc->GetWindow()));
nsIDocument::ExitFullscreenInDocTree(doc);
return NS_OK;

Просмотреть файл

@ -1763,12 +1763,18 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsGlobalWindow)
cb.NoteNativeChild(timeout, NS_CYCLE_COLLECTION_PARTICIPANT(nsTimeout));
}
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocation)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mHistory)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocalStorage)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSessionStorage)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mApplicationCache)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSuspendedDoc)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIndexedDB)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentPrincipal)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDoc)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIdleService)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWakeLock)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPendingStorageEvents)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIdleObservers)
@ -1827,15 +1833,20 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGlobalWindow)
tmp->mListenerManager->Disconnect();
NS_IMPL_CYCLE_COLLECTION_UNLINK(mListenerManager)
}
NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocation)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mHistory)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocalStorage)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mSessionStorage)
if (tmp->mApplicationCache) {
static_cast<nsDOMOfflineResourceList*>(tmp->mApplicationCache.get())->Disconnect();
NS_IMPL_CYCLE_COLLECTION_UNLINK(mApplicationCache)
}
NS_IMPL_CYCLE_COLLECTION_UNLINK(mSuspendedDoc)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mIndexedDB)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentPrincipal)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDoc)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mIdleService)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mWakeLock)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mPendingStorageEvents)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mIdleObservers)
@ -6385,7 +6396,8 @@ FullscreenTransitionTask::Run()
mWindow->mFullScreen = mFullscreen;
}
// Toggle the fullscreen state on the widget
mWidget->MakeFullScreen(mFullscreen, mScreen);
mWindow->SetWidgetFullscreen(nsPIDOMWindow::eForFullscreenAPI,
mFullscreen, mWidget, mScreen);
// Set observer for the next content paint.
nsCOMPtr<nsIObserver> observer = new Observer(this);
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
@ -6464,13 +6476,7 @@ MakeWidgetFullscreen(nsGlobalWindow* aWindow, gfx::VRHMDInfo* aHMD,
}
nsCOMPtr<nsIScreen> screen = aHMD ? aHMD->GetScreen() : nullptr;
if (!performTransition) {
if (aReason == nsPIDOMWindow::eForFullscreenMode) {
// If we enter fullscreen for fullscreen mode, we want
// the native system behavior.
widget->MakeFullScreenWithNativeTransition(aFullscreen, screen);
} else {
widget->MakeFullScreen(aFullscreen, screen);
}
aWindow->SetWidgetFullscreen(aReason, aFullscreen, widget, screen);
} else {
nsCOMPtr<nsIRunnable> task =
new FullscreenTransitionTask(duration, aWindow, aFullscreen,
@ -6574,6 +6580,27 @@ nsGlobalWindow::SetFullscreenInternal(FullscreenReason aReason,
return NS_OK;
}
void
nsGlobalWindow::SetWidgetFullscreen(FullscreenReason aReason, bool aIsFullscreen,
nsIWidget* aWidget, nsIScreen* aScreen)
{
MOZ_ASSERT(IsOuterWindow());
MOZ_ASSERT(this == GetTop(), "Only topmost window should call this");
MOZ_ASSERT(!GetFrameElementInternal(), "Content window should not call this");
MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
if (nsCOMPtr<nsIPresShell> presShell = mDocShell->GetPresShell()) {
presShell->SetIsInFullscreenChange(true);
}
if (aReason == nsPIDOMWindow::eForFullscreenMode) {
// If we enter fullscreen for fullscreen mode, we want
// the native system behavior.
aWidget->MakeFullScreenWithNativeTransition(aIsFullscreen, aScreen);
} else {
aWidget->MakeFullScreen(aIsFullscreen, aScreen);
}
}
/* virtual */ void
nsGlobalWindow::FinishFullscreenChange(bool aIsFullscreen)
{
@ -6606,6 +6633,11 @@ nsGlobalWindow::FinishFullscreenChange(bool aIsFullscreen)
// respond visually if we are kicked into full screen mode
DispatchCustomEvent(NS_LITERAL_STRING("fullscreen"));
if (nsCOMPtr<nsIPresShell> presShell = mDocShell->GetPresShell()) {
MOZ_ASSERT(presShell->IsInFullscreenChange());
presShell->SetIsInFullscreenChange(false);
}
if (!mWakeLock && mFullScreen) {
nsRefPtr<power::PowerManagerService> pmService =
power::PowerManagerService::GetInstance();
@ -8614,7 +8646,7 @@ nsGlobalWindow::PostMessageMozOuter(JSContext* aCx, JS::Handle<JS::Value> aMessa
JS::Rooted<JS::Value> message(aCx, aMessage);
JS::Rooted<JS::Value> transfer(aCx, aTransfer);
event->Write(aCx, message, transfer, aError);
event->Write(aCx, message, transfer, false, aError);
if (NS_WARN_IF(aError.Failed())) {
return;
}

Просмотреть файл

@ -498,6 +498,8 @@ public:
FullscreenReason aReason, bool aIsFullscreen,
mozilla::gfx::VRHMDInfo *aHMD = nullptr) override final;
virtual void FinishFullscreenChange(bool aIsFullscreen) override final;
void SetWidgetFullscreen(FullscreenReason aReason, bool aIsFullscreen,
nsIWidget* aWidget, nsIScreen* aScreen);
bool FullScreen() const;
// Inner windows only.
@ -1631,13 +1633,6 @@ private:
void DisconnectEventTargetObjects();
protected:
// When adding new member variables, be careful not to create cycles
// through JavaScript. If there is any chance that a member variable
// could own objects that are implemented in JavaScript, then those
// objects will keep the global object (this object) alive. To prevent
// these cycles, ownership of such members must be released in
// |CleanUp| and |DetachFromDocShell|.
// This member is also used on both inner and outer windows, but
// for slightly different purposes. On inner windows it means the
// inner window is held onto by session history and should not

Просмотреть файл

@ -52,7 +52,7 @@ nsStructuredCloneContainer::InitFromJSVal(JS::Handle<JS::Value> aData,
}
ErrorResult rv;
Write(aCx, aData, rv);
Write(aCx, aData, true, rv);
if (NS_WARN_IF(rv.Failed())) {
return rv.StealNSResult();
}

Просмотреть файл

@ -2875,26 +2875,22 @@ nsXMLHttpRequest::Send(nsIVariant* aVariant, const Nullable<RequestBody>& aBody)
NS_ASSERTION(listener != this,
"Using an object as a listener that can't be exposed to JS");
// Bypass the network cache in cases where it makes no sense:
// POST responses are always unique, and we provide no API that would
// allow our consumers to specify a "cache key" to access old POST
// responses, so they are not worth caching.
if (method.EqualsLiteral("POST")) {
AddLoadFlags(mChannel,
nsIRequest::LOAD_BYPASS_CACHE | nsIRequest::INHIBIT_CACHING);
} else {
// When we are sync loading, we need to bypass the local cache when it would
// otherwise block us waiting for exclusive access to the cache. If we don't
// do this, then we could dead lock in some cases (see bug 309424).
//
// Also don't block on the cache entry on async if it is busy - favoring parallelism
// over cache hit rate for xhr. This does not disable the cache everywhere -
// only in cases where more than one channel for the same URI is accessed
// simultanously.
// When we are sync loading, we need to bypass the local cache when it would
// otherwise block us waiting for exclusive access to the cache. If we don't
// do this, then we could dead lock in some cases (see bug 309424).
//
// Also don't block on the cache entry on async if it is busy - favoring parallelism
// over cache hit rate for xhr. This does not disable the cache everywhere -
// only in cases where more than one channel for the same URI is accessed
// simultanously.
AddLoadFlags(mChannel,
nsICachingChannel::LOAD_BYPASS_LOCAL_CACHE_IF_BUSY);
}
AddLoadFlags(mChannel,
nsICachingChannel::LOAD_BYPASS_LOCAL_CACHE_IF_BUSY);
// While it would be optimal to bypass the cache in case of POST requests
// since they are never cached, our ServiceWorker interception implementation
// on single-process systems is implemented via the HTTP cache, so DO NOT
// bypass the cache based on method!
// Since we expect XML data, set the type hint accordingly
// if the channel doesn't know any content type.

Просмотреть файл

@ -836,4 +836,5 @@ skip-if = buildapp == 'mulet' || buildapp == 'b2g'
[test_window_element_enumeration.html]
[test_referrer_redirect.html]
[test_postMessages.html]
support-files = worker_postMessages.js
[test_window_proto.html]

Просмотреть файл

@ -278,6 +278,51 @@ function test_windowToIframeURL(url) {
document.body.appendChild(ifr);
}
// PostMessage for Workers
function test_workers() {
info("Testing Workers");
var resolve;
var w = new Worker('worker_postMessages.js');
w.postMessage('workers');
w.onmessage = function(e) {
is(e.data, 'ok', "Worker ready!");
w.onmessage = function(e) {
if (!resolve) {
ok(false, "Unexpected message!");
return;
}
let tmp = resolve;
resolve = null;
tmp({ data: e.data, ports: e.ports });
}
runTests({
clonableObjects: true,
transferableObjects: true,
send: function(what, ports) {
return new Promise(function(r, rr) {
resolve = r;
try {
w.postMessage(what, ports);
} catch(e) {
resolve = null;
rr();
}
});
},
finished: function() {
onmessage = null;
next();
}
});
}
}
// PostMessage for BroadcastChannel
function test_broadcastChannel() {
info("Testing broadcastChannel");
@ -320,6 +365,52 @@ function test_broadcastChannel() {
});
}
// PostMessage for BroadcastChannel in workers
function test_broadcastChannel_inWorkers() {
info("Testing broadcastChannel in Workers");
var bc = new BroadcastChannel('postMessagesTest_inWorkers');
var resolve;
var w = new Worker('worker_postMessages.js');
w.postMessage('broadcastChannel');
w.onmessage = function(e) {
is(e.data, 'ok', "Worker ready!");
w.onmessage = function(e) {
if (!resolve) {
ok(false, "Unexpected message!");
return;
}
let tmp = resolve;
resolve = null;
tmp({ data: e.data, ports: e.ports });
}
runTests({
clonableObjects: true,
transferableObjects: false,
send: function(what, ports) {
return new Promise(function(r, rr) {
if (ports.length) {
rr();
return;
}
resolve = r;
bc.postMessage(what);
});
},
finished: function() {
onmessage = null;
next();
}
});
}
}
// PostMessage for MessagePort
function test_messagePort() {
info("Testing messagePort");
@ -360,6 +451,52 @@ function test_messagePort() {
});
}
// PostMessage for MessagePort in Workers
function test_messagePort_inWorkers() {
info("Testing messagePort in workers");
var mc = new MessageChannel();
var resolve;
var w = new Worker('worker_postMessages.js');
w.postMessage('messagePort', [ mc.port2 ]);
w.onmessage = function(e) {
is(e.data, 'ok', "Worker ready!");
w.onmessage = function(e) {
if (!resolve) {
ok(false, "Unexpected message!");
return;
}
let tmp = resolve;
resolve = null;
tmp({ data: e.data, ports: e.ports });
}
runTests({
clonableObjects: true,
transferableObjects: true,
send: function(what, ports) {
return new Promise(function(r, rr) {
resolve = r;
try {
mc.port1.postMessage(what, ports);
} catch(e) {
resolve = null;
rr();
}
});
},
finished: function() {
onmessage = null;
next();
}
});
}
}
var tests = [
create_fileList,
@ -367,11 +504,13 @@ var tests = [
test_windowToIframe,
test_windowToCrossOriginIframe,
test_workers,
test_broadcastChannel,
// TODO BroadcastChannel in worker
test_broadcastChannel_inWorkers,
test_messagePort,
// TODO MessagePort in worker
test_messagePort_inWorkers,
];
function next() {

Просмотреть файл

@ -0,0 +1,33 @@
function test_workers() {
onmessage = function(e) {
postMessage(e.data, e.ports);
}
}
function test_broadcastChannel() {
var bc = new BroadcastChannel('postMessagesTest_inWorkers');
bc.onmessage = function(e) {
postMessage(e.data);
}
}
function test_messagePort(port) {
port.onmessage = function(e) {
postMessage(e.data, e.ports);
}
}
onmessage = function(e) {
if (e.data == 'workers') {
test_workers();
postMessage('ok');
} else if (e.data == 'broadcastChannel') {
test_broadcastChannel();
postMessage('ok');
} else if (e.data == 'messagePort') {
test_messagePort(e.ports[0]);
postMessage('ok');
} else {
postMessage('ko');
}
}

Просмотреть файл

@ -454,19 +454,11 @@ BroadcastChannel::PostMessageInternal(JSContext* aCx,
{
nsRefPtr<BroadcastChannelMessage> data = new BroadcastChannelMessage();
data->Write(aCx, aMessage, aRv);
data->Write(aCx, aMessage, true, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
const nsTArray<nsRefPtr<BlobImpl>>& blobImpls = data->BlobImpls();
for (uint32_t i = 0, len = blobImpls.Length(); i < len; ++i) {
if (!blobImpls[i]->MayBeClonedToOtherThreads()) {
aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
return;
}
}
PostMessageData(data);
}

Просмотреть файл

@ -17,13 +17,11 @@ function setup() {
}
SpecialPowers.setBoolPref("dom.mozInputMethod.enabled", true);
SpecialPowers.setBoolPref("dom.mozInputMethod.testing", true);
SpecialPowers.addPermission('input-manage', true, document);
}
function tearDown() {
SpecialPowers.setBoolPref("dom.mozInputMethod.enabled", false);
SpecialPowers.setBoolPref("dom.mozInputMethod.testing", false);
SpecialPowers.removePermission('input-manage', document);
SimpleTest.finish();
}

Просмотреть файл

@ -86,7 +86,7 @@ skip-if = toolkit == 'android' || (toolkit == 'gonk' && !debug) #TIMED_OUT, bug
skip-if = (toolkit == 'gonk') # Disabled on b2g due to bug 1097419
[test_browserElement_oop_SendEvent.html]
[test_browserElement_oop_SetInputMethodActive.html]
skip-if = (os == "android")
skip-if = (os == "android") || (toolkit == 'gonk') # Disabled on B2G Emulator bug 1198163
[test_browserElement_oop_SetVisible.html]
[test_browserElement_oop_SetVisibleFrames.html]
[test_browserElement_oop_SetVisibleFrames2.html]

Просмотреть файл

@ -209,7 +209,7 @@ skip-if = (toolkit == 'gonk') # Disabled on b2g due to bug 1097419
[test_browserElement_inproc_SendEvent.html]
# The setInputMethodActive() tests will timed out on Android
[test_browserElement_inproc_SetInputMethodActive.html]
skip-if = (os == "android")
skip-if = (os == "android") || (toolkit == 'gonk') # Disabled on B2G Emulator bug 1198163
[test_browserElement_inproc_SetVisible.html]
[test_browserElement_inproc_SetVisibleFrames.html]
[test_browserElement_inproc_SetVisibleFrames2.html]

Просмотреть файл

@ -7,11 +7,11 @@
#include "mozilla/dom/ImageBitmap.h"
#include "mozilla/dom/ImageBitmapBinding.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/StructuredCloneTags.h"
#include "mozilla/dom/WorkerPrivate.h"
#include "mozilla/dom/WorkerRunnable.h"
#include "mozilla/gfx/2D.h"
#include "imgTools.h"
#include "js/StructuredClone.h"
#include "libyuv.h"
#include "nsLayoutUtils.h"

Просмотреть файл

@ -36,15 +36,6 @@ let Utils = {
return mm;
},
checkPermissionForMM: function u_checkPermissionForMM(mm, permName) {
let testing = false;
try {
testing = Services.prefs.getBoolPref("dom.mozInputMethod.testing");
} catch (e) { }
if (testing) {
return true;
}
return mm.assertPermission(permName);
}
};

Просмотреть файл

@ -213,14 +213,8 @@ MozInputMethod.prototype = {
this._isSystem = true;
}
// Check if we can use keyboard related APIs.
let testing = false;
try {
testing = Services.prefs.getBoolPref("dom.mozInputMethod.testing");
} catch (e) {
}
perm = Services.perms.testExactPermissionFromPrincipal(principal, "input");
if (!testing && perm !== Ci.nsIPermissionManager.ALLOW_ACTION) {
if (perm !== Ci.nsIPermissionManager.ALLOW_ACTION) {
this._isKeyboard = false;
return;
}

Просмотреть файл

@ -8,7 +8,7 @@ function inputmethod_setup(callback) {
}
let permissions = [];
['input-manage', 'browser'].forEach(function(name) {
['input', 'input-manage', 'browser'].forEach(function(name) {
permissions.push({
type: name,
allow: true,
@ -20,9 +20,7 @@ function inputmethod_setup(callback) {
let prefs = [
['dom.mozBrowserFramesEnabled', true],
// Enable navigator.mozInputMethod.
['dom.mozInputMethod.enabled', true],
// Bypass the permission check for mozInputMethod API.
['dom.mozInputMethod.testing', true]
['dom.mozInputMethod.enabled', true]
];
SpecialPowers.pushPrefEnv({set: prefs}, function() {
SimpleTest.waitForFocus(callback);

Просмотреть файл

@ -89,7 +89,11 @@ function runTest() {
SpecialPowers.pushPermissions([{
type: 'input',
allow: true,
context: imeUrl
context: {
url: imeUrl,
appId: SpecialPowers.Ci.nsIScriptSecurityManager.NO_APP_ID,
isInBrowserElement: true
}
}], function() {
keyboardA.src = imeUrl;
keyboardB.src = imeUrl;

Просмотреть файл

@ -76,7 +76,11 @@ function runTest() {
SpecialPowers.pushPermissions([{
type: 'input',
allow: true,
context: imeUrl
context: {
url: imeUrl,
appId: SpecialPowers.Ci.nsIScriptSecurityManager.NO_APP_ID,
isInBrowserElement: true
}
}], function() {
// STEP 2c: Tell Gecko to use this iframe as its keyboard app
let req = keyboard.setInputMethodActive(true);

Просмотреть файл

@ -66,6 +66,9 @@
#include "nsIWidget.h"
#include "nsIWindowMediator.h"
#include "nsIWindowWatcher.h"
#ifndef XP_WIN
#include "nsJARProtocolHandler.h"
#endif
#include "nsOpenURIInFrameParams.h"
#include "nsPIDOMWindow.h"
#include "nsPIWindowWatcher.h"
@ -898,9 +901,21 @@ TabParent::LoadURL(nsIURI* aURI)
rv = packageFile->GetPath(path);
NS_ENSURE_SUCCESS_VOID(rv);
nsRefPtr<OpenFileAndSendFDRunnable> openFileRunnable =
new OpenFileAndSendFDRunnable(path, this);
openFileRunnable->Dispatch();
#ifndef XP_WIN
PRFileDesc* cachedFd = nullptr;
gJarHandler->JarCache()->GetFd(packageFile, &cachedFd);
if (cachedFd) {
FileDescriptor::PlatformHandleType handle =
FileDescriptor::PlatformHandleType(PR_FileDesc2NativeHandle(cachedFd));
unused << SendCacheFileDescriptor(path, FileDescriptor(handle));
} else
#endif
{
nsRefPtr<OpenFileAndSendFDRunnable> openFileRunnable =
new OpenFileAndSendFDRunnable(path, this);
openFileRunnable->Dispatch();
}
}
}
}

Просмотреть файл

@ -161,6 +161,11 @@ if CONFIG['MOZ_SANDBOX'] and CONFIG['OS_ARCH'] == 'WINNT':
'/security/sandbox/chromium-shim',
]
if CONFIG['OS_ARCH'] != 'WINNT':
LOCAL_INCLUDES += [
'/modules/libjar',
]
DEFINES['BIN_SUFFIX'] = '"%s"' % CONFIG['BIN_SUFFIX']
if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('android', 'gtk2', 'gonk', 'qt'):

Просмотреть файл

@ -10,10 +10,6 @@
#include "nsMimeTypes.h"
#include "mozilla/Preferences.h"
#ifdef MOZ_ANDROID_OMX
#include "AndroidMediaPluginHost.h"
#endif
#include "OggDecoder.h"
#include "OggReader.h"
#ifdef MOZ_WAVE
@ -34,7 +30,6 @@
#include "GStreamerReader.h"
#endif
#ifdef MOZ_ANDROID_OMX
#include "AndroidMediaPluginHost.h"
#include "AndroidMediaDecoder.h"
#include "AndroidMediaReader.h"
#include "AndroidMediaPluginHost.h"

Просмотреть файл

@ -2353,12 +2353,12 @@ nsresult MediaDecoderStateMachine::RunStateMachine()
// Play the remaining media. We want to run AdvanceFrame() at least
// once to ensure the current playback position is advanced to the
// end of the media, and so that we update the readyState.
MaybeStartPlayback();
if (VideoQueue().GetSize() > 1 ||
(HasAudio() && !mAudioCompleted) ||
(mAudioCaptured && !mDecodedStream->IsFinished()))
{
// Start playback if necessary to play the remaining media.
MaybeStartPlayback();
UpdateRenderedVideoFrames();
NS_ASSERTION(!IsPlaying() ||
mLogicallySeeking ||

Просмотреть файл

@ -10,7 +10,6 @@
#include "AndroidMediaPluginHost.h"
#include "nsXPCOMStrings.h"
#include "nsISeekableStream.h"
#include "AndroidMediaReader.h"
#include "nsIGfxInfo.h"
#include "gfxCrashReporterUtils.h"
#include "prmem.h"
@ -288,7 +287,6 @@ MPAPI::Decoder *AndroidMediaPluginHost::CreateDecoder(MediaResource *aResource,
decoder->mResource = strdup(url.get());
if (plugin->CreateDecoder(&sPluginHost, decoder, chars, len)) {
aResource->AddRef();
return decoder.forget();
}
}

Просмотреть файл

@ -461,7 +461,7 @@ AndroidMediaResourceServer::AddResource(mozilla::MediaResource* aResource, nsCSt
MutexAutoLock lock(mMutex);
// Adding a resource URL that already exists is considered an error.
if (mResources.find(aUrl) != mResources.end()) return NS_ERROR_FAILURE;
if (mResources.find(url) != mResources.end()) return NS_ERROR_FAILURE;
mResources[url] = aResource;
}

Просмотреть файл

@ -38,7 +38,6 @@ support-files =
[test_BufferedSeek_mp4.html]
skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac")) # Only supported on osx and vista+
[test_BufferingWait.html]
skip-if = true # bug 1190776
[test_BufferingWait_mp4.html]
skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac") || (os == "win" && os_version == "6.1")) # Only supported on osx and vista+, disabling on win7 bug 1191138
[test_EndOfStream.html]

Просмотреть файл

@ -33,6 +33,7 @@
#include "mozilla/SharedThreadPool.h"
#include "MediaInfo.h"
#include "FuzzingWrapper.h"
#include "H264Converter.h"
#include "OpusDecoder.h"
@ -50,6 +51,9 @@ bool PlatformDecoderModule::sGonkDecoderEnabled = false;
bool PlatformDecoderModule::sAndroidMCDecoderEnabled = false;
bool PlatformDecoderModule::sAndroidMCDecoderPreferred = false;
bool PlatformDecoderModule::sGMPDecoderEnabled = false;
bool PlatformDecoderModule::sEnableFuzzingWrapper = false;
uint32_t PlatformDecoderModule::sVideoOutputMinimumInterval_ms = 0;
bool PlatformDecoderModule::sDontDelayInputExhausted = false;
/* static */
void
@ -81,6 +85,13 @@ PlatformDecoderModule::Init()
Preferences::AddBoolVarCache(&sGMPDecoderEnabled,
"media.fragmented-mp4.gmp.enabled", false);
Preferences::AddBoolVarCache(&sEnableFuzzingWrapper,
"media.decoder.fuzzing.enabled", false);
Preferences::AddUintVarCache(&sVideoOutputMinimumInterval_ms,
"media.decoder.fuzzing.video-output-minimum-interval-ms", 0);
Preferences::AddBoolVarCache(&sDontDelayInputExhausted,
"media.decoder.fuzzing.dont-delay-inputexhausted", false);
#ifdef XP_WIN
WMFDecoderModule::Init();
#endif
@ -212,25 +223,40 @@ PlatformDecoderModule::CreateDecoder(const TrackInfo& aConfig,
return nullptr;
}
MediaDataDecoderCallback* callback = aCallback;
nsRefPtr<DecoderCallbackFuzzingWrapper> callbackWrapper;
if (sEnableFuzzingWrapper) {
callbackWrapper = new DecoderCallbackFuzzingWrapper(aCallback);
callbackWrapper->SetVideoOutputMinimumInterval(
TimeDuration::FromMilliseconds(sVideoOutputMinimumInterval_ms));
callbackWrapper->SetDontDelayInputExhausted(sDontDelayInputExhausted);
callback = callbackWrapper.get();
}
if (H264Converter::IsH264(aConfig)) {
m = new H264Converter(this,
*aConfig.GetAsVideoInfo(),
aLayersBackend,
aImageContainer,
aTaskQueue,
aCallback);
callback);
} else if (!hasPlatformDecoder && VPXDecoder::IsVPX(aConfig.mMimeType)) {
m = new VPXDecoder(*aConfig.GetAsVideoInfo(),
aImageContainer,
aTaskQueue,
aCallback);
callback);
} else {
m = CreateVideoDecoder(*aConfig.GetAsVideoInfo(),
aLayersBackend,
aImageContainer,
aTaskQueue,
aCallback);
callback);
}
if (callbackWrapper && m) {
m = new DecoderFuzzingWrapper(m.forget(), callbackWrapper.forget());
}
return m.forget();
}

Просмотреть файл

@ -159,6 +159,9 @@ protected:
static bool sAndroidMCDecoderPreferred;
static bool sAndroidMCDecoderEnabled;
static bool sGMPDecoderEnabled;
static bool sEnableFuzzingWrapper;
static uint32_t sVideoOutputMinimumInterval_ms;
static bool sDontDelayInputExhausted;
};
// A callback used by MediaDataDecoder to return output/errors to the

Просмотреть файл

@ -25,6 +25,7 @@
#include "GonkNativeWindowClient.h"
#include "mozilla/layers/GrallocTextureClient.h"
#include "mozilla/layers/TextureClient.h"
#include <cutils/properties.h>
#define READ_OUTPUT_BUFFER_TIMEOUT_US 3000
@ -78,6 +79,19 @@ GonkVideoDecoderManager::Init(MediaDataDecoderCallback* aCallback)
{
nsIntSize displaySize(mDisplayWidth, mDisplayHeight);
nsIntRect pictureRect(0, 0, mVideoWidth, mVideoHeight);
uint32_t maxWidth, maxHeight;
char propValue[PROPERTY_VALUE_MAX];
property_get("ro.moz.omx.hw.max_width", propValue, "-1");
maxWidth = -1 == atoi(propValue) ? MAX_VIDEO_WIDTH : atoi(propValue);
property_get("ro.moz.omx.hw.max_height", propValue, "-1");
maxHeight = -1 == atoi(propValue) ? MAX_VIDEO_HEIGHT : atoi(propValue) ;
if (mVideoWidth * mVideoHeight > maxWidth * maxHeight) {
GVDM_LOG("Video resolution exceeds hw codec capability");
return InitPromise::CreateAndReject(DecoderFailureReason::INIT_ERROR, __func__);
}
// Validate the container-reported frame and pictureRect sizes. This ensures
// that our video frame creation code doesn't overflow.
nsIntSize frameSize(mVideoWidth, mVideoHeight);
@ -355,6 +369,10 @@ GonkVideoDecoderManager::SetVideoFormat()
nsresult
GonkVideoDecoderManager::Flush()
{
if (mDecoder == nullptr) {
GVDM_LOG("Decoder is not inited");
return NS_ERROR_UNEXPECTED;
}
{
MonitorAutoLock mon(mMonitor);
mQueueSample.Clear();

Просмотреть файл

@ -10,6 +10,7 @@ EXPORTS += [
'agnostic/VPXDecoder.h',
'PlatformDecoderModule.h',
'SharedDecoderManager.h',
'wrappers/FuzzingWrapper.h',
'wrappers/H264Converter.h'
]
@ -20,6 +21,7 @@ UNIFIED_SOURCES += [
'agnostic/VPXDecoder.cpp',
'PlatformDecoderModule.cpp',
'SharedDecoderManager.cpp',
'wrappers/FuzzingWrapper.cpp',
'wrappers/H264Converter.cpp'
]

Просмотреть файл

@ -0,0 +1,324 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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/. */
#include "FuzzingWrapper.h"
PRLogModuleInfo* GetFuzzingWrapperLog() {
static PRLogModuleInfo* log = nullptr;
if (!log) {
log = PR_NewLogModule("MediaFuzzingWrapper");
}
return log;
}
#define DFW_LOGD(arg, ...) MOZ_LOG(GetFuzzingWrapperLog(), mozilla::LogLevel::Debug, ("DecoderFuzzingWrapper(%p)::%s: " arg, this, __func__, ##__VA_ARGS__))
#define DFW_LOGV(arg, ...) MOZ_LOG(GetFuzzingWrapperLog(), mozilla::LogLevel::Verbose, ("DecoderFuzzingWrapper(%p)::%s: " arg, this, __func__, ##__VA_ARGS__))
#define CFW_LOGD(arg, ...) MOZ_LOG(GetFuzzingWrapperLog(), mozilla::LogLevel::Debug, ("DecoderCallbackFuzzingWrapper(%p)::%s: " arg, this, __func__, ##__VA_ARGS__))
#define CFW_LOGV(arg, ...) MOZ_LOG(GetFuzzingWrapperLog(), mozilla::LogLevel::Verbose, ("DecoderCallbackFuzzingWrapper(%p)::%s: " arg, this, __func__, ##__VA_ARGS__))
namespace mozilla {
DecoderFuzzingWrapper::DecoderFuzzingWrapper(
already_AddRefed<MediaDataDecoder> aDecoder,
already_AddRefed<DecoderCallbackFuzzingWrapper> aCallbackWrapper)
: mDecoder(aDecoder)
, mCallbackWrapper(aCallbackWrapper)
{
DFW_LOGV("aDecoder=%p aCallbackWrapper=%p", mDecoder.get(), mCallbackWrapper.get());
}
DecoderFuzzingWrapper::~DecoderFuzzingWrapper()
{
DFW_LOGV("");
}
nsRefPtr<MediaDataDecoder::InitPromise>
DecoderFuzzingWrapper::Init()
{
DFW_LOGV("");
MOZ_ASSERT(mDecoder);
return mDecoder->Init();
}
nsresult
DecoderFuzzingWrapper::Input(MediaRawData* aData)
{
DFW_LOGV("aData.mTime=%lld", aData->mTime);
MOZ_ASSERT(mDecoder);
return mDecoder->Input(aData);
}
nsresult
DecoderFuzzingWrapper::Flush()
{
DFW_LOGV("");
MOZ_ASSERT(mDecoder);
// Flush may output some frames (though unlikely).
// Flush may block a bit, it's ok if we output some frames in the meantime.
nsresult result = mDecoder->Flush();
// Clear any delayed output we may have.
mCallbackWrapper->ClearDelayedOutput();
return result;
}
nsresult
DecoderFuzzingWrapper::Drain()
{
DFW_LOGV("");
MOZ_ASSERT(mDecoder);
// Note: The decoder should callback DrainComplete(), we'll drain the
// delayed output (if any) then.
return mDecoder->Drain();
}
nsresult
DecoderFuzzingWrapper::Shutdown()
{
DFW_LOGV("");
MOZ_ASSERT(mDecoder);
// Both shutdowns below may block a bit.
nsresult result = mDecoder->Shutdown();
mCallbackWrapper->Shutdown();
return result;
}
bool
DecoderFuzzingWrapper::IsHardwareAccelerated(nsACString& aFailureReason) const
{
DFW_LOGV("");
MOZ_ASSERT(mDecoder);
return mDecoder->IsHardwareAccelerated(aFailureReason);
}
nsresult
DecoderFuzzingWrapper::ConfigurationChanged(const TrackInfo& aConfig)
{
DFW_LOGV("");
MOZ_ASSERT(mDecoder);
return mDecoder->ConfigurationChanged(aConfig);
}
DecoderCallbackFuzzingWrapper::DecoderCallbackFuzzingWrapper(MediaDataDecoderCallback* aCallback)
: mCallback(aCallback)
, mDontDelayInputExhausted(false)
, mDraining(false)
, mTaskQueue(new TaskQueue(SharedThreadPool::Get(NS_LITERAL_CSTRING("MediaFuzzingWrapper"), 1)))
{
CFW_LOGV("aCallback=%p", aCallback);
}
DecoderCallbackFuzzingWrapper::~DecoderCallbackFuzzingWrapper()
{
CFW_LOGV("");
}
void
DecoderCallbackFuzzingWrapper::SetVideoOutputMinimumInterval(
TimeDuration aFrameOutputMinimumInterval)
{
CFW_LOGD("aFrameOutputMinimumInterval=%fms",
aFrameOutputMinimumInterval.ToMilliseconds());
mFrameOutputMinimumInterval = aFrameOutputMinimumInterval;
}
void
DecoderCallbackFuzzingWrapper::SetDontDelayInputExhausted(
bool aDontDelayInputExhausted)
{
CFW_LOGD("aDontDelayInputExhausted=%d",
aDontDelayInputExhausted);
mDontDelayInputExhausted = aDontDelayInputExhausted;
}
void
DecoderCallbackFuzzingWrapper::Output(MediaData* aData)
{
if (!mTaskQueue->IsCurrentThreadIn()) {
nsCOMPtr<nsIRunnable> task =
NS_NewRunnableMethodWithArg<StorensRefPtrPassByPtr<MediaData>>(
this, &DecoderCallbackFuzzingWrapper::Output, aData);
mTaskQueue->Dispatch(task.forget());
return;
}
CFW_LOGV("aData.mTime=%lld", aData->mTime);
MOZ_ASSERT(mCallback);
if (mFrameOutputMinimumInterval) {
if (!mPreviousOutput.IsNull()) {
if (!mDelayedOutput.empty()) {
// We already have some delayed frames, just add this one to the queue.
mDelayedOutput.push_back(MakePair<nsRefPtr<MediaData>, bool>(aData, false));
CFW_LOGD("delaying output of sample@%lld, total queued:%d",
aData->mTime, int(mDelayedOutput.size()));
return;
}
if (TimeStamp::Now() < mPreviousOutput + mFrameOutputMinimumInterval) {
// Frame arriving too soon after the previous one, start queuing.
mDelayedOutput.push_back(MakePair<nsRefPtr<MediaData>, bool>(aData, false));
CFW_LOGD("delaying output of sample@%lld, first queued", aData->mTime);
if (!mDelayedOutputTimer) {
mDelayedOutputTimer = new MediaTimer();
}
ScheduleOutputDelayedFrame();
return;
}
}
// If we're here, we're going to actually output a frame -> Record time.
mPreviousOutput = TimeStamp::Now();
}
// Passing the data straight through, no need to dispatch to another queue,
// callback should deal with that.
mCallback->Output(aData);
}
void
DecoderCallbackFuzzingWrapper::Error()
{
if (!mTaskQueue->IsCurrentThreadIn()) {
nsCOMPtr<nsIRunnable> task =
NS_NewRunnableMethod(this, &DecoderCallbackFuzzingWrapper::Error);
mTaskQueue->Dispatch(task.forget());
return;
}
CFW_LOGV("");
MOZ_ASSERT(mCallback);
ClearDelayedOutput();
mCallback->Error();
}
void
DecoderCallbackFuzzingWrapper::InputExhausted()
{
if (!mTaskQueue->IsCurrentThreadIn()) {
nsCOMPtr<nsIRunnable> task =
NS_NewRunnableMethod(this, &DecoderCallbackFuzzingWrapper::InputExhausted);
mTaskQueue->Dispatch(task.forget());
return;
}
if (!mDontDelayInputExhausted && !mDelayedOutput.empty()) {
MediaDataAndInputExhausted& last = mDelayedOutput.back();
CFW_LOGD("InputExhausted delayed until after output of sample@%lld",
last.first()->mTime);
last.second() = true;
return;
}
CFW_LOGV("");
MOZ_ASSERT(mCallback);
mCallback->InputExhausted();
}
void
DecoderCallbackFuzzingWrapper::DrainComplete()
{
if (!mTaskQueue->IsCurrentThreadIn()) {
nsCOMPtr<nsIRunnable> task =
NS_NewRunnableMethod(this, &DecoderCallbackFuzzingWrapper::DrainComplete);
mTaskQueue->Dispatch(task.forget());
return;
}
MOZ_ASSERT(mCallback);
if (mDelayedOutput.empty()) {
// No queued output -> Draining is complete now.
CFW_LOGV("No delayed output -> DrainComplete now");
mCallback->DrainComplete();
} else {
// Queued output waiting -> Make sure we call DrainComplete when it's empty.
CFW_LOGD("Delayed output -> DrainComplete later");
mDraining = true;
}
}
void
DecoderCallbackFuzzingWrapper::ReleaseMediaResources()
{
if (!mTaskQueue->IsCurrentThreadIn()) {
nsCOMPtr<nsIRunnable> task =
NS_NewRunnableMethod(this, &DecoderCallbackFuzzingWrapper::ReleaseMediaResources);
mTaskQueue->Dispatch(task.forget());
return;
}
CFW_LOGV("");
MOZ_ASSERT(mCallback);
mCallback->ReleaseMediaResources();
}
bool
DecoderCallbackFuzzingWrapper::OnReaderTaskQueue()
{
CFW_LOGV("");
MOZ_ASSERT(mCallback);
return mCallback->OnReaderTaskQueue();
}
void
DecoderCallbackFuzzingWrapper::ScheduleOutputDelayedFrame()
{
MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
nsRefPtr<DecoderCallbackFuzzingWrapper> self = this;
mDelayedOutputTimer->WaitUntil(
mPreviousOutput + mFrameOutputMinimumInterval,
__func__)
->Then(mTaskQueue, __func__,
[self] () -> void { self->OutputDelayedFrame(); },
[self] () -> void { self->OutputDelayedFrame(); });
}
void
DecoderCallbackFuzzingWrapper::OutputDelayedFrame()
{
MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
if (mDelayedOutput.empty()) {
if (mDraining) {
// No more output, and we were draining -> Send DrainComplete.
mDraining = false;
mCallback->DrainComplete();
}
return;
}
MediaDataAndInputExhausted& data = mDelayedOutput.front();
CFW_LOGD("Outputting delayed sample@%lld, remaining:%d",
data.first()->mTime, int(mDelayedOutput.size() - 1));
mPreviousOutput = TimeStamp::Now();
mCallback->Output(data.first());
if (data.second()) {
CFW_LOGD("InputExhausted after delayed sample@%lld", data.first()->mTime);
mCallback->InputExhausted();
}
mDelayedOutput.pop_front();
if (!mDelayedOutput.empty()) {
// More output -> Send it later.
ScheduleOutputDelayedFrame();
} else if (mDraining) {
// No more output, and we were draining -> Send DrainComplete.
CFW_LOGD("DrainComplete");
mDraining = false;
mCallback->DrainComplete();
}
}
void
DecoderCallbackFuzzingWrapper::ClearDelayedOutput()
{
if (!mTaskQueue->IsCurrentThreadIn()) {
nsCOMPtr<nsIRunnable> task =
NS_NewRunnableMethod(this, &DecoderCallbackFuzzingWrapper::ClearDelayedOutput);
mTaskQueue->Dispatch(task.forget());
return;
}
mDelayedOutputTimer = nullptr;
mDelayedOutput.clear();
}
void
DecoderCallbackFuzzingWrapper::Shutdown()
{
DFW_LOGV("Shutting down mTaskQueue");
mTaskQueue->BeginShutdown();
mTaskQueue->AwaitIdle();
DFW_LOGV("mTaskQueue shut down");
}
} // namespace mozilla

Просмотреть файл

@ -0,0 +1,120 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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/. */
#if !defined(FuzzingWrapper_h_)
#define FuzzingWrapper_h_
#include "mozilla/Pair.h"
#include "PlatformDecoderModule.h"
#include <deque>
namespace mozilla {
// Fuzzing wrapper for media decoders.
//
// DecoderFuzzingWrapper owns the DecoderCallbackFuzzingWrapper, and inserts
// itself between the reader and the decoder.
// DecoderCallbackFuzzingWrapper inserts itself between a decoder and its
// callback.
// Together they are used to introduce some fuzzing, (e.g. delay output).
//
// Normally:
// ====================================>
// reader decoder
// <------------------------------------
//
// With fuzzing:
// ======> DecoderFuzzingWrapper ======>
// reader v decoder
// <-- DecoderCallbackFuzzingWrapper <--
//
// Creation order should be:
// 1. Create DecoderCallbackFuzzingWrapper, give the expected callback target.
// 2. Create actual decoder, give DecoderCallbackFuzzingWrapper as callback.
// 3. Create DecoderFuzzingWrapper, give decoder and DecoderCallbackFuzzingWrapper.
// DecoderFuzzingWrapper is what the reader sees as decoder, it owns the
// real decoder and the DecoderCallbackFuzzingWrapper.
class DecoderCallbackFuzzingWrapper : public MediaDataDecoderCallback
{
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DecoderCallbackFuzzingWrapper)
explicit DecoderCallbackFuzzingWrapper(MediaDataDecoderCallback* aCallback);
// Enforce a minimum interval between output frames (i.e., limit frame rate).
// Of course, if the decoder is even slower, this won't have any effect.
void SetVideoOutputMinimumInterval(TimeDuration aFrameOutputMinimumInterval);
// If false (default), if frames are delayed, any InputExhausted is delayed to
// be later sent after the corresponding delayed frame.
// If true, InputExhausted are passed through immediately; This could result
// in lots of frames being decoded and queued for delayed output!
void SetDontDelayInputExhausted(bool aDontDelayInputExhausted);
private:
virtual ~DecoderCallbackFuzzingWrapper();
// MediaDataDecoderCallback implementation.
void Output(MediaData* aData) override;
void Error() override;
void InputExhausted() override;
void DrainComplete() override;
void ReleaseMediaResources() override;
bool OnReaderTaskQueue() override;
MediaDataDecoderCallback* mCallback;
// Settings for minimum frame output interval & InputExhausted,
// should be set during init and then only read on mTaskQueue.
TimeDuration mFrameOutputMinimumInterval;
bool mDontDelayInputExhausted;
// Members for minimum frame output interval & InputExhausted,
// should only be accessed on mTaskQueue.
TimeStamp mPreviousOutput;
// First member is the frame to be delayed.
// Second member is true if an 'InputExhausted' arrived after that frame; in
// which case an InputExhausted will be sent after finally outputting the frame.
typedef Pair<nsRefPtr<MediaData>, bool> MediaDataAndInputExhausted;
std::deque<MediaDataAndInputExhausted> mDelayedOutput;
nsRefPtr<MediaTimer> mDelayedOutputTimer;
// If draining, a 'DrainComplete' will be sent after all delayed frames have
// been output.
bool mDraining;
// All callbacks are redirected through this task queue, both to avoid locking
// and to have a consistent sequencing of callbacks.
nsRefPtr<TaskQueue> mTaskQueue;
void ScheduleOutputDelayedFrame();
void OutputDelayedFrame();
public: // public for the benefit of DecoderFuzzingWrapper.
void ClearDelayedOutput();
void Shutdown();
};
class DecoderFuzzingWrapper : public MediaDataDecoder
{
public:
DecoderFuzzingWrapper(already_AddRefed<MediaDataDecoder> aDecoder,
already_AddRefed<DecoderCallbackFuzzingWrapper> aCallbackWrapper);
virtual ~DecoderFuzzingWrapper();
private:
// MediaDataDecoder implementation.
nsRefPtr<InitPromise> Init() override;
nsresult Input(MediaRawData* aSample) override;
nsresult Flush() override;
nsresult Drain() override;
nsresult Shutdown() override;
bool IsHardwareAccelerated(nsACString& aFailureReason) const override;
nsresult ConfigurationChanged(const TrackInfo& aConfig) override;
nsRefPtr<MediaDataDecoder> mDecoder;
nsRefPtr<DecoderCallbackFuzzingWrapper> mCallbackWrapper;
};
} // namespace mozilla
#endif

Просмотреть файл

@ -1,7 +1,7 @@
[DEFAULT]
# strictContentSandbox - bug 1042735, Android 2.3 - bug 981881
tags = msg webrtc
skip-if = (os == 'win' && strictContentSandbox) || android_version == '10' || android_version == '18' || (buildapp == 'mulet') || (toolkit == 'gonk' && debug) # b2g(Either bug 1171118 or bug 1169838, take your pick)
skip-if = (os == 'win' && strictContentSandbox) || android_version == '10' || (buildapp == 'mulet') || (toolkit == 'gonk' && debug) # b2g(Either bug 1171118 or bug 1169838, take your pick)
support-files =
head.js
dataChannel.js
@ -17,21 +17,21 @@ support-files =
[test_dataChannel_basicAudio.html]
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # Bug 962984 for debug, bug 963244 for opt
[test_dataChannel_basicAudioVideo.html]
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || android_version == '18' # b2g(Bug 960442, video support for WebRTC is disabled on b2g), android(Bug 1189784, timeouts on 4.3 emulator)
[test_dataChannel_basicAudioVideoNoBundle.html]
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || android_version == '18' # b2g(Bug 960442, video support for WebRTC is disabled on b2g) FAILS WHEN RUN MANUALLY ON AWS, android(Bug 1189784, timeouts on 4.3 emulator)
[test_dataChannel_basicAudioVideoCombined.html]
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || android_version == '18' # b2g(Bug 960442, video support for WebRTC is disabled on b2g), android(Bug 1189784, timeouts on 4.3 emulator)
[test_dataChannel_basicDataOnly.html]
[test_dataChannel_basicVideo.html]
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || (android_version == '18' && debug) # b2g(Bug 960442, video support for WebRTC is disabled on b2g), android(Bug 1189784, timeouts on 4.3 emulator)
[test_dataChannel_bug1013809.html]
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g emulator seems to be too slow (Bug 1016498 and 1008080)
[test_dataChannel_noOffer.html]
[test_enumerateDevices.html]
skip-if = buildapp == 'mulet'
[test_getUserMedia_audioCapture.html]
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g emulator seems to be too slow (Bug 1016498 and 1008080)
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || android_version == '18' # b2g emulator seems to be too slow (Bug 1016498 and 1008080), android(Bug 1189784, timeouts on 4.3 emulator)
[test_getUserMedia_basicAudio.html]
skip-if = (toolkit == 'gonk' || buildapp == 'mulet' && debug) # debug-only failure
[test_getUserMedia_basicVideo.html]
@ -46,7 +46,7 @@ skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' # no
skip-if = (toolkit == 'gonk' || buildapp == 'mulet' && debug) # debug-only failure, turned an intermittent (bug 962579) into a permanant orange
[test_getUserMedia_constraints.html]
[test_getUserMedia_callbacks.html]
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || toolkit == 'android' || buildapp == 'mulet' # Bug 1063290, intermittent timeout # TC: Bug 1144079 - Re-enable Mulet mochitests and reftests taskcluster-specific disables.
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || buildapp == 'mulet' # Bug 1063290, intermittent timeout # TC: Bug 1144079 - Re-enable Mulet mochitests and reftests taskcluster-specific disables.
[test_getUserMedia_gumWithinGum.html]
[test_getUserMedia_playAudioTwice.html]
[test_getUserMedia_playVideoAudioTwice.html]
@ -63,11 +63,11 @@ skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 1021776, too --ing
[test_peerConnection_basicAudio.html]
skip-if = toolkit == 'gonk' # B2G emulator is too slow to handle a two-way audio call reliably
[test_peerConnection_basicAudioVideo.html]
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || (android_version == '18' && debug) # b2g(Bug 960442, video support for WebRTC is disabled on b2g), android(Bug 1189784, timeouts on 4.3 emulator)
[test_peerConnection_basicAudioVideoCombined.html]
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || (android_version == '18' && debug) # b2g(Bug 960442, video support for WebRTC is disabled on b2g), android(Bug 1189784, timeouts on 4.3 emulator)
[test_peerConnection_basicAudioVideoNoBundle.html]
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || (android_version == '18' && debug) # b2g(Bug 960442, video support for WebRTC is disabled on b2g), android(Bug 1189784, timeouts on 4.3 emulator)
[test_peerConnection_basicVideo.html]
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
[test_peerConnection_basicScreenshare.html]
@ -92,7 +92,7 @@ skip-if = buildapp == 'b2g' || buildapp == 'mulet' || os == 'android' # bug 1043
[test_peerConnection_bug1064223.html]
[test_peerConnection_capturedVideo.html]
tags=capturestream
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || android_version == '18' # b2g(Bug 960442, video support for WebRTC is disabled on b2g), android(Bug 1189784, timeouts on 4.3 emulator)
[test_peerConnection_captureStream_canvas_2d.html]
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
[test_peerConnection_captureStream_canvas_webgl.html]
@ -103,9 +103,9 @@ skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video suppo
[test_peerConnection_closeDuringIce.html]
[test_peerConnection_errorCallbacks.html]
[test_peerConnection_iceFailure.html]
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || os == 'linux' || os == 'mac' || os == 'win' # Disabling because of test failures on B2G emulator (Bug 1180388 for win, mac and linux)
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || os == 'linux' || os == 'mac' || os == 'win' || android_version == '18' # Disabling because of test failures on B2G emulator (Bug 1180388 for win, mac and linux), android(Bug 1189784, timeouts on 4.3 emulator)
[test_peerConnection_forwarding_basicAudioVideoCombined.html]
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || android_version == '18' # b2g(Bug 960442, video support for WebRTC is disabled on b2g), android(Bug 1189784, timeouts on 4.3 emulator)
[test_peerConnection_noTrickleAnswer.html]
skip-if = toolkit == 'gonk' # B2G emulator is too slow to handle a two-way audio call reliably
[test_peerConnection_noTrickleOffer.html]
@ -116,17 +116,17 @@ skip-if = toolkit == 'gonk' # B2G emulator is too slow to handle a two-way audio
[test_peerConnection_offerRequiresReceiveVideo.html]
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
[test_peerConnection_offerRequiresReceiveVideoAudio.html]
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || (android_version == '18' && debug) # b2g(Bug 960442, video support for WebRTC is disabled on b2g), android(Bug 1189784, timeouts on 4.3 emulator)
[test_peerConnection_promiseSendOnly.html]
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || (android_version == '18' && debug) # b2g(Bug 960442, video support for WebRTC is disabled on b2g), android(Bug 1189784, timeouts on 4.3 emulator)
[test_peerConnection_relayOnly.html]
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
[test_peerConnection_callbacks.html]
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || (android_version == '18' && debug) # b2g(Bug 960442, video support for WebRTC is disabled on b2g), android(Bug 1189784, timeouts on 4.3 emulator)
[test_peerConnection_replaceTrack.html]
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || android_version == '18' # b2g(Bug 960442, video support for WebRTC is disabled on b2g), android(Bug 1189784, timeouts on 4.3 emulator)
[test_peerConnection_syncSetDescription.html]
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || (android_version == '18' && debug) # b2g(Bug 960442, video support for WebRTC is disabled on b2g), android(Bug 1189784, timeouts on 4.3 emulator)
[test_peerConnection_setLocalAnswerInHaveLocalOffer.html]
[test_peerConnection_setLocalAnswerInStable.html]
[test_peerConnection_setLocalOfferInHaveRemoteOffer.html]
@ -138,51 +138,51 @@ skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video suppo
[test_peerConnection_toJSON.html]
[test_peerConnection_twoAudioStreams.html]
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || (android_version == '18' && debug) # b2g (Bug 1059867), android(Bug 1189784, timeouts on 4.3 emulator)
[test_peerConnection_twoAudioTracksInOneStream.html]
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || (android_version == '18' && debug) # b2g (Bug 1059867), android(Bug 1189784, timeouts on 4.3 emulator)
[test_peerConnection_twoAudioVideoStreams.html]
# b2g(Bug 960442, video support for WebRTC is disabled on b2g), Bug 1180000 for Linux debug e10s
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || (os == 'linux' && debug && e10s)
# b2g(Bug 960442, video support for WebRTC is disabled on b2g), Bug 1180000 for Linux debug e10s, android(Bug 1189784, timeouts on 4.3 emulator)
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || (os == 'linux' && debug && e10s) || android_version == '18'
[test_peerConnection_twoAudioVideoStreamsCombined.html]
# b2g(Bug 960442, video support for WebRTC is disabled on b2g), Bug 1180000 for Linux debug e10s
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || (os == 'linux' && debug && e10s)
# b2g(Bug 960442, video support for WebRTC is disabled on b2g), Bug 1180000 for Linux debug e10s, android(Bug 1189784, timeouts on 4.3 emulator)
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || (os == 'linux' && debug && e10s) || android_version == '18'
[test_peerConnection_twoVideoStreams.html]
# b2g(Bug 960442, video support for WebRTC is disabled on b2g), Bug 1180000 for Linux debug e10s
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || (os == 'linux' && debug && e10s)
# b2g(Bug 960442, video support for WebRTC is disabled on b2g), Bug 1180000 for Linux debug e10s, android(Bug 1189784, timeouts on 4.3 emulator)
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || (os == 'linux' && debug && e10s) || android_version == '18'
[test_peerConnection_twoVideoTracksInOneStream.html]
# b2g(Bug 960442, video support for WebRTC is disabled on b2g), Bug 1180000 for Linux debug e10s
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || (os == 'linux' && debug && e10s)
# b2g(Bug 960442, video support for WebRTC is disabled on b2g), Bug 1180000 for Linux debug e10s, android(Bug 1189784, timeouts on 4.3 emulator)
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || (os == 'linux' && debug && e10s) || (android_version == '18' && debug)
[test_peerConnection_addSecondAudioStream.html]
skip-if = toolkit == 'gonk' # B2G emulator is too slow to finish a renegotiation test in under 5 minutes
[test_peerConnection_answererAddSecondAudioStream.html]
skip-if = toolkit == 'gonk' # B2G emulator is too slow to finish a renegotiation test in under 5 minutes
[test_peerConnection_removeAudioTrack.html]
skip-if = toolkit == 'gonk' # B2G emulator is too slow to finish a renegotiation test in under 5 minutes
skip-if = toolkit == 'gonk' || (android_version == '18' && debug) # B2G emulator is too slow to finish a renegotiation test in under 5 minutes, android(Bug 1189784, timeouts on 4.3 emulator)
[test_peerConnection_removeThenAddAudioTrack.html]
skip-if = toolkit == 'gonk' # B2G emulator is too slow to finish a renegotiation test in under 5 minutes
skip-if = toolkit == 'gonk' || (android_version == '18' && debug) # B2G emulator is too slow to finish a renegotiation test in under 5 minutes, android(Bug 1189784, timeouts on 4.3 emulator)
[test_peerConnection_addSecondVideoStream.html]
# B2G emulator is too slow to finish a renegotiation test in under 5 minutes, Bug 1180000 for Linux debug e10s
skip-if = toolkit == 'gonk' || (os == 'linux' && debug && e10s)
# B2G emulator is too slow to finish a renegotiation test in under 5 minutes, Bug 1180000 for Linux debug e10s, android(Bug 1189784, timeouts on 4.3 emulator)
skip-if = toolkit == 'gonk' || (os == 'linux' && debug && e10s) || (android_version == '18' && debug)
[test_peerConnection_removeVideoTrack.html]
# B2G emulator is too slow to finish a renegotiation test in under 5 minutes, Bug 1180000 for Linux debug e10s
skip-if = toolkit == 'gonk' || (os == 'linux' && debug && e10s)
# B2G emulator is too slow to finish a renegotiation test in under 5 minutes, Bug 1180000 for Linux debug e10s, android(Bug 1189784, timeouts on 4.3 emulator)
skip-if = toolkit == 'gonk' || (os == 'linux' && debug && e10s) || (android_version == '18' && debug)
[test_peerConnection_removeThenAddVideoTrack.html]
# B2G emulator is too slow to finish a renegotiation test in under 5 minutes, Bug 1180000 for Linux debug e10s
skip-if = toolkit == 'gonk' || (os == 'linux' && debug && e10s)
# B2G emulator is too slow to finish a renegotiation test in under 5 minutes, Bug 1180000 for Linux debug e10s, android(Bug 1189784, timeouts on 4.3 emulator)
skip-if = toolkit == 'gonk' || (os == 'linux' && debug && e10s) || (android_version == '18' && debug)
[test_peerConnection_replaceVideoThenRenegotiate.html]
# B2G emulator is too slow to finish a renegotiation test in under 5 minutes, Bug 1180000 for Linux debug e10s
skip-if = toolkit == 'gonk' || (os == 'linux' && debug && e10s)
# B2G emulator is too slow to finish a renegotiation test in under 5 minutes, Bug 1180000 for Linux debug e10s, android(Bug 1189784, timeouts on 4.3 emulator)
skip-if = toolkit == 'gonk' || (os == 'linux' && debug && e10s) || (android_version == '18' && debug)
[test_peerConnection_addSecondAudioStreamNoBundle.html]
skip-if = toolkit == 'gonk' # B2G emulator is too slow to finish a renegotiation test in under 5 minutes
skip-if = toolkit == 'gonk' || (android_version == '18' && debug) # B2G emulator is too slow to finish a renegotiation test in under 5 minutes, android(Bug 1189784, timeouts on 4.3 emulator)
[test_peerConnection_removeThenAddAudioTrackNoBundle.html]
skip-if = toolkit == 'gonk' # B2G emulator is too slow to finish a renegotiation test in under 5 minutes
skip-if = toolkit == 'gonk' || (android_version == '18' && debug) # B2G emulator is too slow to finish a renegotiation test in under 5 minutes, android(Bug 1189784, timeouts on 4.3 emulator)
[test_peerConnection_addSecondVideoStreamNoBundle.html]
# B2G emulator is too slow to finish a renegotiation test in under 5 minutes, Bug 1180000 for Linux debug e10s
skip-if = toolkit == 'gonk' || (os == 'linux' && debug && e10s)
# B2G emulator is too slow to finish a renegotiation test in under 5 minutes, Bug 1180000 for Linux debug e10s, android(Bug 1189784, timeouts on 4.3 emulator)
skip-if = toolkit == 'gonk' || (os == 'linux' && debug && e10s) || android_version == '18'
[test_peerConnection_removeThenAddVideoTrackNoBundle.html]
# B2G emulator is too slow to finish a renegotiation test in under 5 minutes, Bug 1180000 for Linux debug e10s
skip-if = toolkit == 'gonk' || (os == 'linux' && debug && e10s)
# B2G emulator is too slow to finish a renegotiation test in under 5 minutes, Bug 1180000 for Linux debug e10s, android(Bug 1189784, timeouts on 4.3 emulator)
skip-if = toolkit == 'gonk' || (os == 'linux' && debug && e10s) || android_version == '18'
[test_peerConnection_addDataChannel.html]
skip-if = toolkit == 'gonk' # B2G emulator seems to be so slow that DTLS cannot establish properly
[test_peerConnection_addDataChannelNoBundle.html]
@ -195,7 +195,7 @@ skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
[test_peerConnection_localReofferRollback.html]
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
[test_peerConnection_remoteRollback.html]
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
skip-if = toolkit == 'gonk' || buildapp == 'mulet' || (android_version == '18' && debug) # b2g (Bug 1059867), android(Bug 1189784, timeouts on 4.3 emulator)
[test_peerConnection_remoteReofferRollback.html]
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)

Просмотреть файл

@ -140,9 +140,12 @@ public:
event->SetTrusted(true);
event->SetSource(mPort);
nsTArray<nsRefPtr<MessagePortBase>> ports;
mData->TakeTransferredPorts(ports);
nsRefPtr<MessagePortList> portList =
new MessagePortList(static_cast<dom::Event*>(event.get()),
mData->GetTransferredPorts());
ports);
event->SetPorts(portList);
bool dummy;

Просмотреть файл

@ -46,19 +46,11 @@ SharedMessagePortMessage::Write(JSContext* aCx,
JS::Handle<JS::Value> aTransfer,
ErrorResult& aRv)
{
StructuredCloneHelper::Write(aCx, aValue, aTransfer, aRv);
StructuredCloneHelper::Write(aCx, aValue, aTransfer, true, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
const nsTArray<nsRefPtr<BlobImpl>>& blobImpls = BlobImpls();
for (uint32_t i = 0, len = blobImpls.Length(); i < len; ++i) {
if (!blobImpls[i]->MayBeClonedToOtherThreads()) {
aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
return;
}
}
FallibleTArray<uint8_t> cloneData;
MoveBufferDataToArray(cloneData, aRv);

Просмотреть файл

@ -6,7 +6,8 @@
[JSImplementation="@mozilla.org/b2g-inputmethod;1",
NavigatorProperty="mozInputMethod",
Func="Navigator::HasInputMethodSupport"]
Pref="dom.mozInputMethod.enabled",
CheckAnyPermissions="input input-manage"]
interface MozInputMethod : EventTarget {
// Input Method Manager contain a few global methods expose to apps
readonly attribute MozInputMethodManager mgmt;

Просмотреть файл

@ -0,0 +1,24 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/.
*/
/**
* This API is intended to lock the device in a way that it has no value
* anymore for a thief. A side effect is also protecting user's data. This
* means that we expect the device to be:
* - locked so that only the legitimate user can unlock it
* - unable to communitate via ADB, Devtools, MTP and/or UMS, ...
* - unable to go into recovery or fastboot mode to avoid flashing anything
*/
[JSImplementation="@mozilla.org/moz-kill-switch;1",
NavigatorProperty="mozKillSwitch",
AvailableIn="CertifiedApps",
CheckAnyPermissions="killswitch",
Pref="dom.mozKillSwitch.enabled"]
interface KillSwitch {
Promise<any> enable();
Promise<any> disable();
};

Просмотреть файл

@ -276,6 +276,7 @@ WEBIDL_FILES = [
'KeyboardEvent.webidl',
'KeyEvent.webidl',
'KeyframeEffect.webidl',
'KillSwitch.webidl',
'LegacyQueryInterface.webidl',
'LinkStyle.webidl',
'ListBoxObject.webidl',

Просмотреть файл

@ -233,7 +233,7 @@ public:
aWorkerPrivate->AssertIsOnWorkerThread();
// This needs to be structured cloned while it's still on the worker thread.
Write(aCx, aObj, mRv);
Write(aCx, aObj, true, mRv);
NS_WARN_IF(mRv.Failed());
}
@ -294,7 +294,7 @@ public:
aWorkerPrivate->AssertIsOnWorkerThread();
// This needs to be structured cloned while it's still on the worker thread.
Write(aCx, aObj, mRv);
Write(aCx, aObj, true, mRv);
NS_WARN_IF(mRv.Failed());
}

Просмотреть файл

@ -13,7 +13,6 @@
#include "nsGlobalWindow.h"
#include "nsIDocument.h"
#include "WorkerPrivate.h"
#include "WorkerStructuredClone.h"
using namespace mozilla;
using namespace mozilla::dom;
@ -73,24 +72,17 @@ ServiceWorkerClient::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProt
namespace {
class ServiceWorkerClientPostMessageRunnable final : public nsRunnable
class ServiceWorkerClientPostMessageRunnable final
: public nsRunnable
, public StructuredCloneHelper
{
uint64_t mWindowId;
JSAutoStructuredCloneBuffer mBuffer;
WorkerStructuredCloneClosure mClosure;
public:
ServiceWorkerClientPostMessageRunnable(uint64_t aWindowId,
JSAutoStructuredCloneBuffer&& aData,
WorkerStructuredCloneClosure& aClosure)
: mWindowId(aWindowId),
mBuffer(Move(aData))
{
mClosure.mClonedObjects.SwapElements(aClosure.mClonedObjects);
mClosure.mClonedImages.SwapElements(aClosure.mClonedImages);
MOZ_ASSERT(aClosure.mMessagePorts.IsEmpty());
mClosure.mMessagePortIdentifiers.SwapElements(aClosure.mMessagePortIdentifiers);
}
explicit ServiceWorkerClientPostMessageRunnable(uint64_t aWindowId)
: StructuredCloneHelper(CloningSupported, TransferringSupported)
, mWindowId(aWindowId)
{}
NS_IMETHOD
Run()
@ -123,40 +115,40 @@ private:
{
AssertIsOnMainThread();
// Release reference to objects that were AddRef'd for
// cloning into worker when array goes out of scope.
WorkerStructuredCloneClosure closure;
closure.mClonedObjects.SwapElements(mClosure.mClonedObjects);
closure.mClonedImages.SwapElements(mClosure.mClonedImages);
MOZ_ASSERT(mClosure.mMessagePorts.IsEmpty());
closure.mMessagePortIdentifiers.SwapElements(mClosure.mMessagePortIdentifiers);
closure.mParentWindow = do_QueryInterface(aTargetContainer->GetParentObject());
JS::Rooted<JS::Value> messageData(aCx);
if (!mBuffer.read(aCx, &messageData,
WorkerStructuredCloneCallbacks(), &closure)) {
xpc::Throw(aCx, NS_ERROR_DOM_DATA_CLONE_ERR);
ErrorResult rv;
Read(aTargetContainer->GetParentObject(), aCx, &messageData, rv);
if (NS_WARN_IF(rv.Failed())) {
xpc::Throw(aCx, rv.StealNSResult());
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIDOMMessageEvent> event = new MessageEvent(aTargetContainer,
nullptr, nullptr);
nsresult rv =
event->InitMessageEvent(NS_LITERAL_STRING("message"),
false /* non-bubbling */,
false /* not cancelable */,
messageData,
EmptyString(),
EmptyString(),
nullptr);
if (NS_FAILED(rv)) {
xpc::Throw(aCx, rv);
nsRefPtr<MessageEvent> event = new MessageEvent(aTargetContainer,
nullptr, nullptr);
rv = event->InitMessageEvent(NS_LITERAL_STRING("message"),
false /* non-bubbling */,
false /* not cancelable */,
messageData,
EmptyString(),
EmptyString(),
nullptr);
if (NS_WARN_IF(rv.Failed())) {
xpc::Throw(aCx, rv.StealNSResult());
return NS_ERROR_FAILURE;
}
nsTArray<nsRefPtr<MessagePortBase>> ports;
TakeTransferredPorts(ports);
nsRefPtr<MessagePortList> portList =
new MessagePortList(static_cast<dom::Event*>(event.get()),
ports);
event->SetPorts(portList);
event->SetTrusted(true);
bool status = false;
aTargetContainer->DispatchEvent(event, &status);
aTargetContainer->DispatchEvent(static_cast<dom::Event*>(event.get()),
&status);
if (!status) {
return NS_ERROR_FAILURE;
@ -194,22 +186,17 @@ ServiceWorkerClient::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
transferable.setObject(*array);
}
const JSStructuredCloneCallbacks* callbacks = WorkerStructuredCloneCallbacks();
nsRefPtr<ServiceWorkerClientPostMessageRunnable> runnable =
new ServiceWorkerClientPostMessageRunnable(mWindowId);
WorkerStructuredCloneClosure closure;
JSAutoStructuredCloneBuffer buffer;
if (!buffer.write(aCx, aMessage, transferable, callbacks, &closure)) {
aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
runnable->Write(aCx, aMessage, transferable, true, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
nsRefPtr<ServiceWorkerClientPostMessageRunnable> runnable =
new ServiceWorkerClientPostMessageRunnable(mWindowId, Move(buffer),
closure);
nsresult rv = NS_DispatchToMainThread(runnable);
if (NS_FAILED(rv)) {
aRv.Throw(NS_ERROR_FAILURE);
aRv = NS_DispatchToMainThread(runnable);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
}

Просмотреть файл

@ -45,15 +45,10 @@
#include "mozilla/Likely.h"
#include "mozilla/LoadContext.h"
#include "mozilla/dom/BindingUtils.h"
#include "mozilla/dom/BlobBinding.h"
#include "mozilla/dom/ErrorEvent.h"
#include "mozilla/dom/ErrorEventBinding.h"
#include "mozilla/dom/Exceptions.h"
#include "mozilla/dom/FunctionBinding.h"
#include "mozilla/dom/ImageBitmap.h"
#include "mozilla/dom/ImageBitmapBinding.h"
#include "mozilla/dom/ImageData.h"
#include "mozilla/dom/ImageDataBinding.h"
#include "mozilla/dom/MessageEvent.h"
#include "mozilla/dom/MessageEventBinding.h"
#include "mozilla/dom/MessagePort.h"
@ -62,26 +57,18 @@
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/PromiseDebugging.h"
#include "mozilla/dom/ScriptSettings.h"
#include "mozilla/dom/StructuredClone.h"
#include "mozilla/dom/StructuredCloneHelper.h"
#include "mozilla/dom/TabChild.h"
#include "mozilla/dom/WebCryptoCommon.h"
#include "mozilla/dom/WorkerBinding.h"
#include "mozilla/dom/WorkerDebuggerGlobalScopeBinding.h"
#include "mozilla/dom/WorkerGlobalScopeBinding.h"
#include "mozilla/dom/indexedDB/IDBFactory.h"
#include "mozilla/dom/ipc/BlobChild.h"
#include "mozilla/dom/ipc/nsIRemoteBlob.h"
#include "mozilla/ipc/BackgroundChild.h"
#include "mozilla/ipc/BackgroundUtils.h"
#include "mozilla/ipc/PBackgroundSharedTypes.h"
#include "mozilla/Preferences.h"
#include "MultipartBlobImpl.h"
#include "nsAlgorithm.h"
#include "nsContentUtils.h"
#include "nsCycleCollector.h"
#include "nsError.h"
#include "nsDOMJSUtils.h"
#include "nsFormData.h"
#include "nsHostObjectProtocolHandler.h"
#include "nsJSEnvironment.h"
#include "nsJSUtils.h"
@ -113,7 +100,6 @@
#include "WorkerFeature.h"
#include "WorkerRunnable.h"
#include "WorkerScope.h"
#include "WorkerStructuredClone.h"
#include "WorkerThread.h"
#ifdef XP_WIN
@ -327,481 +313,6 @@ LogErrorToConsole(const nsAString& aMessage,
fflush(stderr);
}
// Recursive!
already_AddRefed<BlobImpl>
EnsureBlobForBackgroundManager(BlobImpl* aBlobImpl,
PBackgroundChild* aManager = nullptr)
{
MOZ_ASSERT(aBlobImpl);
if (!aManager) {
aManager = BackgroundChild::GetForCurrentThread();
MOZ_ASSERT(aManager);
}
nsRefPtr<BlobImpl> blobImpl = aBlobImpl;
const nsTArray<nsRefPtr<BlobImpl>>* subBlobImpls =
aBlobImpl->GetSubBlobImpls();
if (!subBlobImpls) {
if (nsCOMPtr<nsIRemoteBlob> remoteBlob = do_QueryObject(blobImpl)) {
// Always make sure we have a blob from an actor we can use on this
// thread.
BlobChild* blobChild = BlobChild::GetOrCreate(aManager, blobImpl);
MOZ_ASSERT(blobChild);
blobImpl = blobChild->GetBlobImpl();
MOZ_ASSERT(blobImpl);
DebugOnly<bool> isMutable;
MOZ_ASSERT(NS_SUCCEEDED(blobImpl->GetMutable(&isMutable)));
MOZ_ASSERT(!isMutable);
} else {
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(blobImpl->SetMutable(false)));
}
return blobImpl.forget();
}
const uint32_t subBlobCount = subBlobImpls->Length();
MOZ_ASSERT(subBlobCount);
nsTArray<nsRefPtr<BlobImpl>> newSubBlobImpls;
newSubBlobImpls.SetLength(subBlobCount);
bool newBlobImplNeeded = false;
for (uint32_t index = 0; index < subBlobCount; index++) {
const nsRefPtr<BlobImpl>& subBlobImpl = subBlobImpls->ElementAt(index);
MOZ_ASSERT(subBlobImpl);
nsRefPtr<BlobImpl>& newSubBlobImpl = newSubBlobImpls[index];
newSubBlobImpl = EnsureBlobForBackgroundManager(subBlobImpl, aManager);
MOZ_ASSERT(newSubBlobImpl);
if (subBlobImpl != newSubBlobImpl) {
newBlobImplNeeded = true;
}
}
if (newBlobImplNeeded) {
nsString contentType;
blobImpl->GetType(contentType);
if (blobImpl->IsFile()) {
nsString name;
blobImpl->GetName(name);
blobImpl = new MultipartBlobImpl(newSubBlobImpls, name, contentType);
} else {
blobImpl = new MultipartBlobImpl(newSubBlobImpls, contentType);
}
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(blobImpl->SetMutable(false)));
}
return blobImpl.forget();
}
already_AddRefed<Blob>
ReadBlobOrFileNoWrap(JSContext* aCx,
JSStructuredCloneReader* aReader)
{
MOZ_ASSERT(aCx);
MOZ_ASSERT(aReader);
nsRefPtr<BlobImpl> blobImpl;
{
BlobImpl* rawBlobImpl;
MOZ_ALWAYS_TRUE(JS_ReadBytes(aReader, &rawBlobImpl, sizeof(rawBlobImpl)));
MOZ_ASSERT(rawBlobImpl);
blobImpl = rawBlobImpl;
}
blobImpl = EnsureBlobForBackgroundManager(blobImpl);
MOZ_ASSERT(blobImpl);
nsCOMPtr<nsISupports> parent;
if (NS_IsMainThread()) {
nsCOMPtr<nsIScriptGlobalObject> scriptGlobal =
nsJSUtils::GetStaticScriptGlobal(JS::CurrentGlobalOrNull(aCx));
parent = do_QueryInterface(scriptGlobal);
} else {
WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx);
MOZ_ASSERT(workerPrivate);
WorkerGlobalScope* globalScope = workerPrivate->GlobalScope();
MOZ_ASSERT(globalScope);
parent = do_QueryObject(globalScope);
}
nsRefPtr<Blob> blob = Blob::Create(parent, blobImpl);
return blob.forget();
}
void
ReadBlobOrFile(JSContext* aCx,
JSStructuredCloneReader* aReader,
JS::MutableHandle<JSObject*> aBlobOrFile)
{
nsRefPtr<Blob> blob = ReadBlobOrFileNoWrap(aCx, aReader);
aBlobOrFile.set(blob->WrapObject(aCx, nullptr));
}
// See WriteFormData for serialization format.
void
ReadFormData(JSContext* aCx,
JSStructuredCloneReader* aReader,
uint32_t aCount,
JS::MutableHandle<JSObject*> aFormData)
{
MOZ_ASSERT(aCx);
MOZ_ASSERT(aReader);
MOZ_ASSERT(!aFormData);
nsCOMPtr<nsISupports> parent;
if (NS_IsMainThread()) {
nsCOMPtr<nsIScriptGlobalObject> scriptGlobal =
nsJSUtils::GetStaticScriptGlobal(JS::CurrentGlobalOrNull(aCx));
parent = do_QueryInterface(scriptGlobal);
} else {
WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx);
MOZ_ASSERT(workerPrivate);
workerPrivate->AssertIsOnWorkerThread();
WorkerGlobalScope* globalScope = workerPrivate->GlobalScope();
MOZ_ASSERT(globalScope);
parent = do_QueryObject(globalScope);
}
nsRefPtr<nsFormData> formData = new nsFormData(parent);
MOZ_ASSERT(formData);
Optional<nsAString> thirdArg;
uint32_t isFile;
uint32_t dummy;
for (uint32_t i = 0; i < aCount; ++i) {
MOZ_ALWAYS_TRUE(JS_ReadUint32Pair(aReader, &isFile, &dummy));
nsAutoString name;
MOZ_ALWAYS_TRUE(ReadString(aReader, name));
if (isFile) {
// Read out the tag since the blob reader isn't expecting it.
MOZ_ALWAYS_TRUE(JS_ReadUint32Pair(aReader, &dummy, &dummy));
nsRefPtr<Blob> blob = ReadBlobOrFileNoWrap(aCx, aReader);
MOZ_ASSERT(blob);
formData->Append(name, *blob, thirdArg);
} else {
nsAutoString value;
MOZ_ALWAYS_TRUE(ReadString(aReader, value));
formData->Append(name, value);
}
}
aFormData.set(formData->WrapObject(aCx, nullptr));
}
bool
WriteBlobOrFile(JSStructuredCloneWriter* aWriter,
BlobImpl* aBlobImpl,
WorkerStructuredCloneClosure& aClosure)
{
MOZ_ASSERT(aWriter);
MOZ_ASSERT(aBlobImpl);
if (!aBlobImpl->MayBeClonedToOtherThreads()) {
NS_WARNING("Not all the blob implementations can be sent between threads.");
return false;
}
nsRefPtr<BlobImpl> blobImpl = EnsureBlobForBackgroundManager(aBlobImpl);
MOZ_ASSERT(blobImpl);
aBlobImpl = blobImpl;
if (NS_WARN_IF(!JS_WriteUint32Pair(aWriter, DOMWORKER_SCTAG_BLOB, 0)) ||
NS_WARN_IF(!JS_WriteBytes(aWriter, &aBlobImpl, sizeof(aBlobImpl)))) {
return false;
}
aClosure.mClonedObjects.AppendElement(aBlobImpl);
return true;
}
// A FormData is serialized as:
// - A pair of ints (tag identifying it as a FormData, number of elements in
// the FormData)
// - for each (key, value) pair:
// - pair of ints (is value a file?, 0). If not a file, value is a string.
// - string name
// - if value is a file:
// - write the file/blob
// - else:
// - string value
bool
WriteFormData(JSStructuredCloneWriter* aWriter,
nsFormData* aFormData,
WorkerStructuredCloneClosure& aClosure)
{
MOZ_ASSERT(aWriter);
MOZ_ASSERT(aFormData);
if (NS_WARN_IF(!JS_WriteUint32Pair(aWriter, DOMWORKER_SCTAG_FORMDATA, aFormData->Length()))) {
return false;
}
class MOZ_STACK_CLASS Closure final
{
JSStructuredCloneWriter* mWriter;
WorkerStructuredCloneClosure& mClones;
public:
Closure(JSStructuredCloneWriter* aWriter,
WorkerStructuredCloneClosure& aClones)
: mWriter(aWriter), mClones(aClones)
{ }
static bool
Write(const nsString& aName, bool isFile, const nsString& aValue,
File* aFile, void* aClosure)
{
Closure* closure = static_cast<Closure*>(aClosure);
if (!JS_WriteUint32Pair(closure->mWriter, /* a file? */ (uint32_t) isFile, 0)) {
return false;
}
if (!WriteString(closure->mWriter, aName)) {
return false;
}
if (isFile) {
if (!WriteBlobOrFile(closure->mWriter, aFile->Impl(),
closure->mClones)) {
return false;
}
} else {
if (!WriteString(closure->mWriter, aValue)) {
return false;
}
}
return true;
}
};
Closure closure(aWriter, aClosure);
return aFormData->ForEach(Closure::Write, &closure);
}
struct WorkerStructuredCloneCallbacks
{
static JSObject*
Read(JSContext* aCx, JSStructuredCloneReader* aReader, uint32_t aTag,
uint32_t aData, void* aClosure)
{
// See if object is a nsIDOMBlob pointer.
if (aTag == DOMWORKER_SCTAG_BLOB) {
MOZ_ASSERT(!aData);
JS::Rooted<JSObject*> blobOrFile(aCx);
ReadBlobOrFile(aCx, aReader, &blobOrFile);
return blobOrFile;
}
// See if the object is an ImageData.
if (aTag == SCTAG_DOM_IMAGEDATA) {
MOZ_ASSERT(!aData);
return ReadStructuredCloneImageData(aCx, aReader);
}
// See if the object is a FormData.
if (aTag == DOMWORKER_SCTAG_FORMDATA) {
JS::Rooted<JSObject*> formData(aCx);
// aData is the entry count.
ReadFormData(aCx, aReader, aData, &formData);
return formData;
}
// See if the object is an ImageBitmap.
if (aTag == SCTAG_DOM_IMAGEBITMAP) {
NS_ASSERTION(aClosure, "Null pointer!");
// Get the current global object.
auto* closure = static_cast<WorkerStructuredCloneClosure*>(aClosure);
nsCOMPtr<nsIGlobalObject> parent = do_QueryInterface(closure->mParentWindow);
// aData is the index of the cloned image.
return ImageBitmap::ReadStructuredClone(aCx, aReader, parent,
closure->mClonedImages, aData);
}
return NS_DOMReadStructuredClone(aCx, aReader, aTag, aData, nullptr);
}
static bool
Write(JSContext* aCx, JSStructuredCloneWriter* aWriter,
JS::Handle<JSObject*> aObj, void* aClosure)
{
NS_ASSERTION(aClosure, "Null pointer!");
auto* closure = static_cast<WorkerStructuredCloneClosure*>(aClosure);
// See if this is a Blob/File object.
{
nsRefPtr<Blob> blob;
if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, aObj, blob))) {
BlobImpl* blobImpl = blob->Impl();
MOZ_ASSERT(blobImpl);
if (WriteBlobOrFile(aWriter, blobImpl, *closure)) {
return true;
}
}
}
// See if this is an ImageData object.
{
ImageData* imageData = nullptr;
if (NS_SUCCEEDED(UNWRAP_OBJECT(ImageData, aObj, imageData))) {
return WriteStructuredCloneImageData(aCx, aWriter, imageData);
}
}
// See if this is a FormData object.
{
nsFormData* formData = nullptr;
if (NS_SUCCEEDED(UNWRAP_OBJECT(FormData, aObj, formData))) {
if (WriteFormData(aWriter, formData, *closure)) {
return true;
}
}
}
// See if this is an ImageBitmap object.
{
ImageBitmap* imageBitmap = nullptr;
if (NS_SUCCEEDED(UNWRAP_OBJECT(ImageBitmap, aObj, imageBitmap))) {
return ImageBitmap::WriteStructuredClone(aWriter,
closure->mClonedImages,
imageBitmap);
}
}
return NS_DOMWriteStructuredClone(aCx, aWriter, aObj, nullptr);
}
static void
Error(JSContext* aCx, uint32_t /* aErrorId */)
{
Throw(aCx, NS_ERROR_DOM_DATA_CLONE_ERR);
}
static bool
ReadTransfer(JSContext* aCx, JSStructuredCloneReader* aReader,
uint32_t aTag, void* aContent, uint64_t aExtraData,
void* aClosure, JS::MutableHandle<JSObject*> aReturnObject)
{
MOZ_ASSERT(aClosure);
auto* closure = static_cast<WorkerStructuredCloneClosure*>(aClosure);
if (aTag == SCTAG_DOM_MAP_MESSAGEPORT) {
MOZ_ASSERT(!aContent);
MOZ_ASSERT(aExtraData < closure->mMessagePortIdentifiers.Length());
ErrorResult rv;
nsRefPtr<MessagePortBase> port =
dom::MessagePort::Create(closure->mParentWindow,
closure->mMessagePortIdentifiers[aExtraData],
rv);
if (NS_WARN_IF(rv.Failed())) {
return false;
}
closure->mMessagePorts.AppendElement(port);
JS::Rooted<JS::Value> value(aCx);
if (!GetOrCreateDOMReflector(aCx, port, &value)) {
JS_ClearPendingException(aCx);
return false;
}
aReturnObject.set(&value.toObject());
return true;
}
return false;
}
static bool
Transfer(JSContext* aCx, JS::Handle<JSObject*> aObj, void* aClosure,
uint32_t* aTag, JS::TransferableOwnership* aOwnership,
void** aContent, uint64_t *aExtraData)
{
MOZ_ASSERT(aClosure);
auto* closure = static_cast<WorkerStructuredCloneClosure*>(aClosure);
MessagePortBase* port;
nsresult rv = UNWRAP_OBJECT(MessagePort, aObj, port);
if (NS_SUCCEEDED(rv)) {
if (NS_WARN_IF(closure->mTransferredPorts.Contains(port))) {
// No duplicates.
return false;
}
MessagePortIdentifier identifier;
if (!port->CloneAndDisentangle(identifier)) {
return false;
}
closure->mMessagePortIdentifiers.AppendElement(identifier);
closure->mTransferredPorts.AppendElement(port);
*aTag = SCTAG_DOM_MAP_MESSAGEPORT;
*aOwnership = JS::SCTAG_TMO_CUSTOM;
*aContent = nullptr;
*aExtraData = closure->mMessagePortIdentifiers.Length() - 1;
return true;
}
return false;
}
static void
FreeTransfer(uint32_t aTag, JS::TransferableOwnership aOwnership,
void *aContent, uint64_t aExtraData, void* aClosure)
{
if (aTag == SCTAG_DOM_MAP_MESSAGEPORT) {
MOZ_ASSERT(aClosure);
MOZ_ASSERT(!aContent);
auto* closure = static_cast<WorkerStructuredCloneClosure*>(aClosure);
MOZ_ASSERT(aExtraData < closure->mMessagePortIdentifiers.Length());
dom::MessagePort::ForceClose(closure->mMessagePortIdentifiers[aExtraData]);
}
}
};
const JSStructuredCloneCallbacks gWorkerStructuredCloneCallbacks = {
WorkerStructuredCloneCallbacks::Read,
WorkerStructuredCloneCallbacks::Write,
WorkerStructuredCloneCallbacks::Error,
WorkerStructuredCloneCallbacks::ReadTransfer,
WorkerStructuredCloneCallbacks::Transfer,
WorkerStructuredCloneCallbacks::FreeTransfer
};
class MainThreadReleaseRunnable final : public nsRunnable
{
nsTArray<nsCOMPtr<nsISupports>> mDoomed;
@ -1081,9 +592,8 @@ private:
};
class MessageEventRunnable final : public WorkerRunnable
, public StructuredCloneHelper
{
JSAutoStructuredCloneBuffer mBuffer;
WorkerStructuredCloneClosure mClosure;
uint64_t mMessagePortSerial;
bool mToMessagePort;
@ -1095,24 +605,12 @@ public:
TargetAndBusyBehavior aBehavior,
bool aToMessagePort, uint64_t aMessagePortSerial)
: WorkerRunnable(aWorkerPrivate, aBehavior)
, StructuredCloneHelper(CloningSupported, TransferringSupported)
, mMessagePortSerial(aMessagePortSerial)
, mToMessagePort(aToMessagePort)
{
}
bool
Write(JSContext* aCx, JS::Handle<JS::Value> aValue,
JS::Handle<JS::Value> aTransferredValue,
const JSStructuredCloneCallbacks *aCallbacks)
{
bool ok = mBuffer.write(aCx, aValue, aTransferredValue, aCallbacks,
&mClosure);
// This hashtable has to be empty because it could contain MessagePort
// objects that cannot be freed on a different thread.
mClosure.mTransferredPorts.Clear();
return ok;
}
void
SetMessageSource(ServiceWorkerClientInfo* aSource)
{
@ -1123,49 +621,44 @@ public:
DispatchDOMEvent(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
DOMEventTargetHelper* aTarget, bool aIsMainThread)
{
// Release reference to objects that were AddRef'd for
// cloning into worker when array goes out of scope.
WorkerStructuredCloneClosure closure;
closure.mClonedObjects.SwapElements(mClosure.mClonedObjects);
closure.mClonedImages.SwapElements(mClosure.mClonedImages);
MOZ_ASSERT(mClosure.mMessagePorts.IsEmpty());
closure.mMessagePortIdentifiers.SwapElements(mClosure.mMessagePortIdentifiers);
nsCOMPtr<nsPIDOMWindow> parent;
if (aIsMainThread) {
closure.mParentWindow = do_QueryInterface(aTarget->GetParentObject());
parent = do_QueryInterface(aTarget->GetParentObject());
}
JS::Rooted<JS::Value> messageData(aCx);
if (!mBuffer.read(aCx, &messageData,
workers::WorkerStructuredCloneCallbacks(),
&closure)) {
xpc::Throw(aCx, NS_ERROR_DOM_DATA_CLONE_ERR);
ErrorResult rv;
Read(parent, aCx, &messageData, rv);
if (NS_WARN_IF(rv.Failed())) {
xpc::Throw(aCx, rv.StealNSResult());
return false;
}
nsRefPtr<MessageEvent> event = new MessageEvent(aTarget, nullptr, nullptr);
nsresult rv =
event->InitMessageEvent(NS_LITERAL_STRING("message"),
false /* non-bubbling */,
false /* non-cancelable */,
messageData,
EmptyString(),
EmptyString(),
nullptr);
rv = event->InitMessageEvent(NS_LITERAL_STRING("message"),
false /* non-bubbling */,
false /* cancelable */,
messageData,
EmptyString(),
EmptyString(),
nullptr);
if (mEventSource) {
nsRefPtr<ServiceWorkerClient> client =
new ServiceWorkerWindowClient(aTarget, *mEventSource);
event->SetSource(client);
}
if (NS_FAILED(rv)) {
xpc::Throw(aCx, rv);
if (NS_WARN_IF(rv.Failed())) {
xpc::Throw(aCx, rv.StealNSResult());
return false;
}
nsTArray<nsRefPtr<MessagePortBase>> ports;
TakeTransferredPorts(ports);
event->SetTrusted(true);
event->SetPorts(new MessagePortList(static_cast<dom::Event*>(event.get()),
closure.mMessagePorts));
ports));
nsCOMPtr<nsIDOMEvent> domEvent = do_QueryObject(event);
nsEventStatus dummy = nsEventStatus_eIgnore;
@ -1190,8 +683,7 @@ private:
return
aWorkerPrivate->DispatchMessageEventToMessagePort(aCx,
mMessagePortSerial,
Move(mBuffer),
mClosure);
*this);
}
if (aWorkerPrivate->IsFrozen()) {
@ -3307,9 +2799,8 @@ WorkerPrivateParent<Derived>::PostMessageInternal(
WorkerRunnable::WorkerThreadModifyBusyCount,
aToMessagePort, aMessagePortSerial);
if (!runnable->Write(aCx, aMessage, transferable,
&gWorkerStructuredCloneCallbacks)) {
aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
runnable->Write(aCx, aMessage, transferable, true, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
@ -3352,45 +2843,10 @@ template <class Derived>
bool
WorkerPrivateParent<Derived>::DispatchMessageEventToMessagePort(
JSContext* aCx, uint64_t aMessagePortSerial,
JSAutoStructuredCloneBuffer&& aBuffer,
WorkerStructuredCloneClosure& aClosure)
StructuredCloneHelper& aHelper)
{
AssertIsOnMainThread();
JSAutoStructuredCloneBuffer buffer(Move(aBuffer));
class MOZ_STACK_CLASS AutoCloneBufferCleaner final
{
public:
AutoCloneBufferCleaner(JSAutoStructuredCloneBuffer& aBuffer,
const JSStructuredCloneCallbacks* aCallbacks,
WorkerStructuredCloneClosure& aClosure)
: mBuffer(aBuffer)
, mCallbacks(aCallbacks)
, mClosure(aClosure)
{}
~AutoCloneBufferCleaner()
{
mBuffer.clear(mCallbacks, &mClosure);
}
private:
JSAutoStructuredCloneBuffer& mBuffer;
const JSStructuredCloneCallbacks* mCallbacks;
WorkerStructuredCloneClosure& mClosure;
};
WorkerStructuredCloneClosure closure;
closure.mClonedObjects.SwapElements(aClosure.mClonedObjects);
closure.mClonedImages.SwapElements(aClosure.mClonedImages);
MOZ_ASSERT(aClosure.mMessagePorts.IsEmpty());
closure.mMessagePortIdentifiers.SwapElements(aClosure.mMessagePortIdentifiers);
AutoCloneBufferCleaner bufferCleaner(buffer,
&gWorkerStructuredCloneCallbacks,
closure);
SharedWorker* sharedWorker;
if (!mSharedWorkers.Get(aMessagePortSerial, &sharedWorker)) {
// SharedWorker has already been unregistered?
@ -3404,7 +2860,7 @@ WorkerPrivateParent<Derived>::DispatchMessageEventToMessagePort(
return true;
}
closure.mParentWindow = do_QueryInterface(port->GetParentObject());
nsCOMPtr<nsISupports> parent = do_QueryInterface(port->GetParentObject());
AutoJSAPI jsapi;
if (NS_WARN_IF(!jsapi.InitWithLegacyErrorReporting(port->GetParentObject()))) {
@ -3412,24 +2868,27 @@ WorkerPrivateParent<Derived>::DispatchMessageEventToMessagePort(
}
JSContext* cx = jsapi.cx();
ErrorResult rv;
JS::Rooted<JS::Value> data(cx);
if (!buffer.read(cx, &data, &gWorkerStructuredCloneCallbacks,
&closure)) {
aHelper.Read(parent, cx, &data, rv);
if (NS_WARN_IF(rv.Failed())) {
xpc::Throw(cx, rv.StealNSResult());
return false;
}
nsRefPtr<MessageEvent> event = new MessageEvent(port, nullptr, nullptr);
nsresult rv =
event->InitMessageEvent(NS_LITERAL_STRING("message"), false, false, data,
EmptyString(), EmptyString(), nullptr);
if (NS_FAILED(rv)) {
xpc::Throw(cx, rv);
rv = event->InitMessageEvent(NS_LITERAL_STRING("message"), false, false, data,
EmptyString(), EmptyString(), nullptr);
if (NS_WARN_IF(rv.Failed())) {
xpc::Throw(cx, rv.StealNSResult());
return false;
}
event->SetTrusted(true);
nsTArray<nsRefPtr<MessagePortBase>> ports;
aHelper.TakeTransferredPorts(ports);
event->SetPorts(new MessagePortList(port, closure.mMessagePorts));
event->SetTrusted(true);
event->SetPorts(new MessagePortList(port, ports));
nsCOMPtr<nsIDOMEvent> domEvent;
CallQueryInterface(event.get(), getter_AddRefs(domEvent));
@ -3437,8 +2896,8 @@ WorkerPrivateParent<Derived>::DispatchMessageEventToMessagePort(
bool ignored;
rv = port->DispatchEvent(domEvent, &ignored);
if (NS_FAILED(rv)) {
xpc::Throw(cx, rv);
if (NS_WARN_IF(rv.Failed())) {
xpc::Throw(cx, rv.StealNSResult());
return false;
}
@ -6091,9 +5550,8 @@ WorkerPrivate::PostMessageToParentInternal(
WorkerRunnable::ParentThreadUnchangedBusyCount,
aToMessagePort, aMessagePortSerial);
if (!runnable->Write(aCx, aMessage, transferable,
&gWorkerStructuredCloneCallbacks)) {
aRv = NS_ERROR_DOM_DATA_CLONE_ERR;
runnable->Write(aCx, aMessage, transferable, true, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
@ -7244,30 +6702,7 @@ GetWorkerCrossThreadDispatcher(JSContext* aCx, JS::Value aWorker)
return w->GetCrossThreadDispatcher();
}
const JSStructuredCloneCallbacks*
WorkerStructuredCloneCallbacks()
{
return &gWorkerStructuredCloneCallbacks;
}
// Force instantiation.
template class WorkerPrivateParent<WorkerPrivate>;
WorkerStructuredCloneClosure::WorkerStructuredCloneClosure()
{}
WorkerStructuredCloneClosure::~WorkerStructuredCloneClosure()
{}
void
WorkerStructuredCloneClosure::Clear()
{
mParentWindow = nullptr;
mClonedObjects.Clear();
mClonedImages.Clear();
mMessagePorts.Clear();
mMessagePortIdentifiers.Clear();
mTransferredPorts.Clear();
}
END_WORKERS_NAMESPACE

Просмотреть файл

@ -28,12 +28,10 @@
#include "nsTArray.h"
#include "nsThreadUtils.h"
#include "nsTObserverArray.h"
#include "mozilla/dom/StructuredCloneTags.h"
#include "Queue.h"
#include "WorkerFeature.h"
class JSAutoStructuredCloneBuffer;
class nsIChannel;
class nsIDocument;
class nsIEventTarget;
@ -52,6 +50,7 @@ struct RuntimeStats;
namespace mozilla {
namespace dom {
class Function;
class StructuredCloneHelper;
} // namespace dom
namespace ipc {
class PrincipalInfo;
@ -74,7 +73,6 @@ class WorkerDebuggerGlobalScope;
class WorkerGlobalScope;
class WorkerPrivate;
class WorkerRunnable;
class WorkerStructuredCloneClosure;
class WorkerThread;
// SharedMutex is a small wrapper around an (internal) reference-counted Mutex
@ -350,8 +348,7 @@ public:
DispatchMessageEventToMessagePort(
JSContext* aCx,
uint64_t aMessagePortSerial,
JSAutoStructuredCloneBuffer&& aBuffer,
WorkerStructuredCloneClosure& aClosure);
StructuredCloneHelper& aHelper);
void
UpdateRuntimeOptions(JSContext* aCx,
@ -1509,17 +1506,6 @@ IsCurrentThreadRunningChromeWorker();
JSContext*
GetCurrentThreadJSContext();
enum WorkerStructuredDataType
{
DOMWORKER_SCTAG_BLOB = SCTAG_DOM_MAX,
DOMWORKER_SCTAG_FORMDATA = SCTAG_DOM_MAX + 1,
DOMWORKER_SCTAG_END
};
const JSStructuredCloneCallbacks*
WorkerStructuredCloneCallbacks();
class AutoSyncLoopHolder
{
WorkerPrivate* mWorkerPrivate;

Просмотреть файл

@ -1,63 +0,0 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* 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/. */
#ifndef mozilla_dom_workers_WorkerStructuredClone_h
#define mozilla_dom_workers_WorkerStructuredClone_h
#include "Workers.h"
#include "mozilla/dom/PMessagePort.h"
class nsPIDOMWindow;
namespace mozilla {
namespace layers {
class Image;
}
namespace dom {
class MessagePortBase;
namespace workers {
// This class is implemented in WorkerPrivate.cpp
class WorkerStructuredCloneClosure final
{
private:
WorkerStructuredCloneClosure(const WorkerStructuredCloneClosure&) = delete;
WorkerStructuredCloneClosure & operator=(const WorkerStructuredCloneClosure&) = delete;
public:
WorkerStructuredCloneClosure();
~WorkerStructuredCloneClosure();
void Clear();
// This can be null if the MessagePort is created in a worker.
nsCOMPtr<nsPIDOMWindow> mParentWindow;
nsTArray<nsCOMPtr<nsISupports>> mClonedObjects;
// This is used for sharing the backend of ImageBitmaps.
// The layers::Image object must be thread-safely reference-counted.
// The layers::Image object will not be written ever via any ImageBitmap
// instance, so no race condition will occur.
nsTArray<nsRefPtr<layers::Image>> mClonedImages;
// The transferred ports.
nsTArray<nsRefPtr<MessagePortBase>> mMessagePorts;
// Information for the transferring.
nsTArray<MessagePortIdentifier> mMessagePortIdentifiers;
// To avoid duplicates in the transferred ports.
nsTArray<nsRefPtr<MessagePortBase>> mTransferredPorts;
};
} // namespace workers
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_workers_WorkerStructuredClone_h

Просмотреть файл

@ -18,6 +18,7 @@
#include "mozilla/dom/Exceptions.h"
#include "mozilla/dom/File.h"
#include "mozilla/dom/ProgressEvent.h"
#include "mozilla/dom/StructuredCloneHelper.h"
#include "nsComponentManagerUtils.h"
#include "nsContentUtils.h"
#include "nsFormData.h"
@ -27,7 +28,6 @@
#include "RuntimeService.h"
#include "WorkerPrivate.h"
#include "WorkerRunnable.h"
#include "WorkerStructuredClone.h"
#include "XMLHttpRequestUpload.h"
using namespace mozilla;
@ -175,6 +175,116 @@ private:
}
};
class WorkerThreadProxySyncRunnable : public nsRunnable
{
protected:
WorkerPrivate* mWorkerPrivate;
nsRefPtr<Proxy> mProxy;
nsCOMPtr<nsIEventTarget> mSyncLoopTarget;
private:
class ResponseRunnable final: public MainThreadStopSyncLoopRunnable
{
nsRefPtr<Proxy> mProxy;
nsresult mErrorCode;
public:
ResponseRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy,
nsresult aErrorCode)
: MainThreadStopSyncLoopRunnable(aWorkerPrivate, aProxy->GetEventTarget(),
NS_SUCCEEDED(aErrorCode)),
mProxy(aProxy), mErrorCode(aErrorCode)
{
MOZ_ASSERT(aProxy);
}
private:
~ResponseRunnable()
{ }
virtual void
MaybeSetException(JSContext* aCx) override
{
MOZ_ASSERT(NS_FAILED(mErrorCode));
Throw(aCx, mErrorCode);
}
};
public:
WorkerThreadProxySyncRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy)
: mWorkerPrivate(aWorkerPrivate), mProxy(aProxy)
{
MOZ_ASSERT(aWorkerPrivate);
MOZ_ASSERT(aProxy);
aWorkerPrivate->AssertIsOnWorkerThread();
}
NS_DECL_ISUPPORTS_INHERITED
bool
Dispatch(JSContext* aCx)
{
mWorkerPrivate->AssertIsOnWorkerThread();
AutoSyncLoopHolder syncLoop(mWorkerPrivate);
mSyncLoopTarget = syncLoop.EventTarget();
if (NS_FAILED(NS_DispatchToMainThread(this))) {
JS_ReportError(aCx, "Failed to dispatch to main thread!");
return false;
}
return syncLoop.Run();
}
protected:
virtual ~WorkerThreadProxySyncRunnable()
{ }
virtual nsresult
MainThreadRun() = 0;
private:
NS_DECL_NSIRUNNABLE
};
class SendRunnable final
: public WorkerThreadProxySyncRunnable
, public StructuredCloneHelper
{
nsString mStringBody;
nsCOMPtr<nsIEventTarget> mSyncLoopTarget;
bool mHasUploadListeners;
public:
SendRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy,
const nsAString& aStringBody)
: WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy)
, StructuredCloneHelper(CloningSupported, TransferringNotSupported)
, mStringBody(aStringBody)
, mHasUploadListeners(false)
{
}
void SetHaveUploadListeners(bool aHasUploadListeners)
{
mHasUploadListeners = aHasUploadListeners;
}
void SetSyncLoopTarget(nsIEventTarget* aSyncLoopTarget)
{
mSyncLoopTarget = aSyncLoopTarget;
}
private:
~SendRunnable()
{ }
virtual nsresult
MainThreadRun() override;
};
END_WORKERS_NAMESPACE
namespace {
@ -410,11 +520,10 @@ private:
};
class EventRunnable final : public MainThreadProxyRunnable
, public StructuredCloneHelper
{
nsString mType;
nsString mResponseType;
JSAutoStructuredCloneBuffer mResponseBuffer;
WorkerStructuredCloneClosure mResponseClosure;
JS::Heap<JS::Value> mResponse;
nsString mResponseText;
nsString mResponseURL;
@ -456,17 +565,19 @@ public:
EventRunnable(Proxy* aProxy, bool aUploadEvent, const nsString& aType,
bool aLengthComputable, uint64_t aLoaded, uint64_t aTotal)
: MainThreadProxyRunnable(aProxy->mWorkerPrivate, aProxy), mType(aType),
mResponse(JS::UndefinedValue()), mLoaded(aLoaded), mTotal(aTotal),
mEventStreamId(aProxy->mInnerEventStreamId), mStatus(0), mReadyState(0),
mUploadEvent(aUploadEvent), mProgressEvent(true),
: MainThreadProxyRunnable(aProxy->mWorkerPrivate, aProxy),
StructuredCloneHelper(CloningSupported, TransferringNotSupported),
mType(aType), mResponse(JS::UndefinedValue()), mLoaded(aLoaded),
mTotal(aTotal), mEventStreamId(aProxy->mInnerEventStreamId), mStatus(0),
mReadyState(0), mUploadEvent(aUploadEvent), mProgressEvent(true),
mLengthComputable(aLengthComputable), mUseCachedArrayBufferResponse(false),
mResponseTextResult(NS_OK), mStatusResult(NS_OK), mResponseResult(NS_OK)
{ }
EventRunnable(Proxy* aProxy, bool aUploadEvent, const nsString& aType)
: MainThreadProxyRunnable(aProxy->mWorkerPrivate, aProxy), mType(aType),
mResponse(JS::UndefinedValue()), mLoaded(0), mTotal(0),
: MainThreadProxyRunnable(aProxy->mWorkerPrivate, aProxy),
StructuredCloneHelper(CloningSupported, TransferringNotSupported),
mType(aType), mResponse(JS::UndefinedValue()), mLoaded(0), mTotal(0),
mEventStreamId(aProxy->mInnerEventStreamId), mStatus(0), mReadyState(0),
mUploadEvent(aUploadEvent), mProgressEvent(false), mLengthComputable(0),
mUseCachedArrayBufferResponse(false), mResponseTextResult(NS_OK),
@ -484,80 +595,6 @@ private:
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override;
};
class WorkerThreadProxySyncRunnable : public nsRunnable
{
protected:
WorkerPrivate* mWorkerPrivate;
nsRefPtr<Proxy> mProxy;
nsCOMPtr<nsIEventTarget> mSyncLoopTarget;
private:
class ResponseRunnable final: public MainThreadStopSyncLoopRunnable
{
nsRefPtr<Proxy> mProxy;
nsresult mErrorCode;
public:
ResponseRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy,
nsresult aErrorCode)
: MainThreadStopSyncLoopRunnable(aWorkerPrivate, aProxy->GetEventTarget(),
NS_SUCCEEDED(aErrorCode)),
mProxy(aProxy), mErrorCode(aErrorCode)
{
MOZ_ASSERT(aProxy);
}
private:
~ResponseRunnable()
{ }
virtual void
MaybeSetException(JSContext* aCx) override
{
MOZ_ASSERT(NS_FAILED(mErrorCode));
Throw(aCx, mErrorCode);
}
};
public:
WorkerThreadProxySyncRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy)
: mWorkerPrivate(aWorkerPrivate), mProxy(aProxy)
{
MOZ_ASSERT(aWorkerPrivate);
MOZ_ASSERT(aProxy);
aWorkerPrivate->AssertIsOnWorkerThread();
}
NS_DECL_ISUPPORTS_INHERITED
bool
Dispatch(JSContext* aCx)
{
mWorkerPrivate->AssertIsOnWorkerThread();
AutoSyncLoopHolder syncLoop(mWorkerPrivate);
mSyncLoopTarget = syncLoop.EventTarget();
if (NS_FAILED(NS_DispatchToMainThread(this))) {
JS_ReportError(aCx, "Failed to dispatch to main thread!");
return false;
}
return syncLoop.Run();
}
protected:
virtual ~WorkerThreadProxySyncRunnable()
{ }
virtual nsresult
MainThreadRun() = 0;
private:
NS_DECL_NSIRUNNABLE
};
class SyncTeardownRunnable final : public WorkerThreadProxySyncRunnable
{
public:
@ -791,39 +828,6 @@ private:
MainThreadRunInternal();
};
class SendRunnable final : public WorkerThreadProxySyncRunnable
{
nsString mStringBody;
JSAutoStructuredCloneBuffer mBody;
WorkerStructuredCloneClosure mClosure;
nsCOMPtr<nsIEventTarget> mSyncLoopTarget;
bool mHasUploadListeners;
public:
SendRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy,
const nsAString& aStringBody, JSAutoStructuredCloneBuffer&& aBody,
WorkerStructuredCloneClosure& aClosure,
nsIEventTarget* aSyncLoopTarget, bool aHasUploadListeners)
: WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy)
, mStringBody(aStringBody)
, mBody(Move(aBody))
, mSyncLoopTarget(aSyncLoopTarget)
, mHasUploadListeners(aHasUploadListeners)
{
mClosure.mClonedObjects.SwapElements(aClosure.mClonedObjects);
mClosure.mClonedImages.SwapElements(aClosure.mClonedImages);
MOZ_ASSERT(aClosure.mMessagePorts.IsEmpty());
MOZ_ASSERT(aClosure.mMessagePortIdentifiers.IsEmpty());
}
private:
~SendRunnable()
{ }
virtual nsresult
MainThreadRun() override;
};
class SetRequestHeaderRunnable final : public WorkerThreadProxySyncRunnable
{
nsCString mHeader;
@ -1227,21 +1231,11 @@ EventRunnable::PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
}
if (doClone) {
// Anything subject to GC must be cloned.
const JSStructuredCloneCallbacks* callbacks =
workers::WorkerStructuredCloneCallbacks();
WorkerStructuredCloneClosure closure;
if (mResponseBuffer.write(aCx, response, transferable, callbacks,
&closure)) {
mResponseClosure.mClonedObjects.SwapElements(closure.mClonedObjects);
mResponseClosure.mClonedImages.SwapElements(closure.mClonedImages);
MOZ_ASSERT(mResponseClosure.mMessagePorts.IsEmpty());
MOZ_ASSERT(mResponseClosure.mMessagePortIdentifiers.IsEmpty());
} else {
ErrorResult rv;
Write(aCx, response, transferable, false, rv);
if (NS_WARN_IF(rv.Failed())) {
NS_WARNING("Failed to clone response!");
mResponseResult = NS_ERROR_DOM_DATA_CLONE_ERR;
mResponseResult = rv.StealNSResult();
mProxy->mArrayBufferResponseWasTransferred = false;
}
}
@ -1336,22 +1330,14 @@ EventRunnable::WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
state->mResponseResult = mResponseResult;
if (NS_SUCCEEDED(mResponseResult)) {
if (mResponseBuffer.data()) {
if (HasBeenWritten()) {
MOZ_ASSERT(mResponse.isUndefined());
JSAutoStructuredCloneBuffer responseBuffer(Move(mResponseBuffer));
const JSStructuredCloneCallbacks* callbacks =
workers::WorkerStructuredCloneCallbacks();
WorkerStructuredCloneClosure closure;
closure.mClonedObjects.SwapElements(mResponseClosure.mClonedObjects);
closure.mClonedImages.SwapElements(mResponseClosure.mClonedImages);
MOZ_ASSERT(mResponseClosure.mMessagePorts.IsEmpty());
MOZ_ASSERT(mResponseClosure.mMessagePortIdentifiers.IsEmpty());
ErrorResult rv;
JS::Rooted<JS::Value> response(aCx);
if (!responseBuffer.read(aCx, &response, callbacks, &closure)) {
Read(nullptr, aCx, &response, rv);
if (NS_WARN_IF(rv.Failed())) {
rv.SuppressException();
return false;
}
@ -1517,32 +1503,25 @@ SendRunnable::MainThreadRun()
{
nsCOMPtr<nsIVariant> variant;
if (mBody.data()) {
if (HasBeenWritten()) {
AutoSafeJSContext cx;
JSAutoRequest ar(cx);
nsIXPConnect* xpc = nsContentUtils::XPConnect();
MOZ_ASSERT(xpc);
nsresult rv = NS_OK;
const JSStructuredCloneCallbacks* callbacks =
workers::WorkerStructuredCloneCallbacks();
ErrorResult rv;
JS::Rooted<JS::Value> body(cx);
if (mBody.read(cx, &body, callbacks, &mClosure)) {
if (NS_FAILED(xpc->JSValToVariant(cx, body, getter_AddRefs(variant)))) {
rv = NS_ERROR_DOM_INVALID_STATE_ERR;
}
}
else {
rv = NS_ERROR_DOM_DATA_CLONE_ERR;
Read(nullptr, cx, &body, rv);
if (NS_WARN_IF(rv.Failed())) {
return rv.StealNSResult();
}
mBody.clear();
mClosure.Clear();
NS_ENSURE_SUCCESS(rv, rv);
rv = xpc->JSValToVariant(cx, body, getter_AddRefs(variant));
if (NS_WARN_IF(rv.Failed())) {
return rv.StealNSResult();
}
}
else {
nsCOMPtr<nsIWritableVariant> wvariant =
@ -1845,11 +1824,10 @@ XMLHttpRequest::Unpin()
}
void
XMLHttpRequest::SendInternal(const nsAString& aStringBody,
JSAutoStructuredCloneBuffer&& aBody,
WorkerStructuredCloneClosure& aClosure,
XMLHttpRequest::SendInternal(SendRunnable* aRunnable,
ErrorResult& aRv)
{
MOZ_ASSERT(aRunnable);
mWorkerPrivate->AssertIsOnWorkerThread();
// No send() calls when open is running.
@ -1879,10 +1857,10 @@ XMLHttpRequest::SendInternal(const nsAString& aStringBody,
JSContext* cx = mWorkerPrivate->GetJSContext();
nsRefPtr<SendRunnable> runnable =
new SendRunnable(mWorkerPrivate, mProxy, aStringBody, Move(aBody),
aClosure, syncLoopTarget, hasUploadListeners);
if (!runnable->Dispatch(cx)) {
aRunnable->SetSyncLoopTarget(syncLoopTarget);
aRunnable->SetHaveUploadListeners(hasUploadListeners);
if (!aRunnable->Dispatch(cx)) {
// Dispatch() may have spun the event loop and we may have already unrooted.
// If so we don't want autoUnpin to try again.
if (!mRooted) {
@ -2109,11 +2087,11 @@ XMLHttpRequest::Send(ErrorResult& aRv)
return;
}
// Nothing to clone.
JSAutoStructuredCloneBuffer buffer;
WorkerStructuredCloneClosure closure;
nsRefPtr<SendRunnable> sendRunnable =
new SendRunnable(mWorkerPrivate, mProxy, NullString());
SendInternal(NullString(), Move(buffer), closure, aRv);
// Nothing to clone.
SendInternal(sendRunnable, aRv);
}
void
@ -2131,11 +2109,11 @@ XMLHttpRequest::Send(const nsAString& aBody, ErrorResult& aRv)
return;
}
// Nothing to clone.
JSAutoStructuredCloneBuffer buffer;
WorkerStructuredCloneClosure closure;
nsRefPtr<SendRunnable> sendRunnable =
new SendRunnable(mWorkerPrivate, mProxy, aBody);
SendInternal(aBody, Move(buffer), closure, aRv);
// Nothing to clone.
SendInternal(sendRunnable, aRv);
}
void
@ -2171,18 +2149,15 @@ XMLHttpRequest::Send(JS::Handle<JSObject*> aBody, ErrorResult& aRv)
valToClone.setString(bodyStr);
}
const JSStructuredCloneCallbacks* callbacks =
WorkerStructuredCloneCallbacks();
nsRefPtr<SendRunnable> sendRunnable =
new SendRunnable(mWorkerPrivate, mProxy, EmptyString());
WorkerStructuredCloneClosure closure;
JSAutoStructuredCloneBuffer buffer;
if (!buffer.write(cx, valToClone, callbacks, &closure)) {
aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
sendRunnable->Write(cx, valToClone, false, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
SendInternal(EmptyString(), Move(buffer), closure, aRv);
SendInternal(sendRunnable, aRv);
}
void
@ -2215,18 +2190,15 @@ XMLHttpRequest::Send(Blob& aBody, ErrorResult& aRv)
return;
}
const JSStructuredCloneCallbacks* callbacks =
WorkerStructuredCloneCallbacks();
nsRefPtr<SendRunnable> sendRunnable =
new SendRunnable(mWorkerPrivate, mProxy, EmptyString());
WorkerStructuredCloneClosure closure;
JSAutoStructuredCloneBuffer buffer;
if (!buffer.write(cx, value, callbacks, &closure)) {
aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
sendRunnable->Write(cx, value, false, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
SendInternal(EmptyString(), Move(buffer), closure, aRv);
SendInternal(sendRunnable, aRv);
}
void
@ -2251,17 +2223,15 @@ XMLHttpRequest::Send(nsFormData& aBody, ErrorResult& aRv)
return;
}
const JSStructuredCloneCallbacks* callbacks =
WorkerStructuredCloneCallbacks();
nsRefPtr<SendRunnable> sendRunnable =
new SendRunnable(mWorkerPrivate, mProxy, EmptyString());
JSAutoStructuredCloneBuffer buffer;
WorkerStructuredCloneClosure closure;
if (!buffer.write(cx, value, callbacks, &closure)) {
aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
sendRunnable->Write(cx, value, false, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
SendInternal(EmptyString(), Move(buffer), closure, aRv);
SendInternal(sendRunnable, aRv);
}
void

Просмотреть файл

@ -14,7 +14,6 @@
#include "mozilla/dom/TypedArray.h"
#include "js/StructuredClone.h"
#include "nsXMLHttpRequest.h"
namespace mozilla {
@ -26,9 +25,9 @@ class Blob;
BEGIN_WORKERS_NAMESPACE
class Proxy;
class SendRunnable;
class XMLHttpRequestUpload;
class WorkerPrivate;
class WorkerStructuredCloneClosure;
class XMLHttpRequest final: public nsXHREventTarget,
public WorkerFeature
@ -291,9 +290,7 @@ private:
ErrorResult& aRv);
void
SendInternal(const nsAString& aStringBody,
JSAutoStructuredCloneBuffer&& aBody,
WorkerStructuredCloneClosure& aClosure,
SendInternal(SendRunnable* aRunnable,
ErrorResult& aRv);
};

Просмотреть файл

@ -1,4 +1,4 @@
function fetchXHR(name, onload, onerror, headers) {
function fetchXHRWithMethod(name, method, onload, onerror, headers) {
expectAsyncResult();
onload = onload || function() {
@ -11,7 +11,7 @@ function fetchXHR(name, onload, onerror, headers) {
};
var x = new XMLHttpRequest();
x.open('GET', name, true);
x.open(method, name, true);
x.onload = function() { onload(x) };
x.onerror = function() { onerror(x) };
headers = headers || [];
@ -21,6 +21,10 @@ function fetchXHR(name, onload, onerror, headers) {
x.send();
}
function fetchXHR(name, onload, onerror, headers) {
return fetchXHRWithMethod(name, 'GET', onload, onerror, headers);
}
fetchXHR('bare-synthesized.txt', function(xhr) {
my_ok(xhr.status == 200, "load should be successful");
my_ok(xhr.responseText == "synthesized response body", "load should have synthesized response");
@ -297,3 +301,11 @@ fetch(new Request('body-blob', {method: 'POST', body: new Blob(new String('my bo
my_ok(body == 'my bodymy body', "the Blob body of the intercepted fetch should be visible in the SW");
finish();
});
['DELETE', 'GET', 'HEAD', 'OPTIONS', 'POST', 'PUT'].forEach(function(method) {
fetchXHRWithMethod('xhr-method-test.txt', method, function(xhr) {
my_ok(xhr.status == 200, method + " load should be successful");
my_ok(xhr.responseText == ("intercepted " + method), method + " load should have synthesized response");
finish();
});
});

Просмотреть файл

@ -268,4 +268,8 @@ onfetch = function(ev) {
var url = 'http://example.com/tests/dom/security/test/cors/file_CrossSiteXHR_server.sjs?status=200';
ev.respondWith(fetch(url, { mode: 'no-cors' }));
}
else if (ev.request.url.includes('xhr-method-test.txt')) {
ev.respondWith(new Response('intercepted ' + ev.request.method));
}
};

Просмотреть файл

@ -509,7 +509,7 @@ ClientLayerManager::MakeSnapshotIfRequired()
gfx::Matrix rotate = ComputeTransformForUnRotation(outerBounds, mTargetRotation);
gfx::Matrix oldMatrix = dt->GetTransform();
dt->SetTransform(oldMatrix * rotate);
dt->SetTransform(rotate * oldMatrix);
dt->DrawSurface(surf, dstRect, srcRect,
DrawSurfaceOptions(),
DrawOptions(1.0f, CompositionOp::OP_OVER));

Просмотреть файл

@ -20,16 +20,9 @@ ImageContainerParent::~ImageContainerParent()
}
}
static void SendDeleteAndIgnoreResult(ImageContainerParent* self)
{
unused << PImageContainerParent::Send__delete__(self);
}
bool ImageContainerParent::RecvAsyncDelete()
{
MessageLoop::current()->PostTask(
FROM_HERE, NewRunnableFunction(&SendDeleteAndIgnoreResult, this));
unused << PImageContainerParent::Send__delete__(this);
return true;
}

Просмотреть файл

@ -201,7 +201,7 @@ class BaseStackFrame {
// Get a unique identifier for this StackFrame. The identifier is not valid
// across garbage collections.
virtual uintptr_t identifier() const { return reinterpret_cast<uintptr_t>(ptr); }
virtual uint64_t identifier() const { return reinterpret_cast<uint64_t>(ptr); }
// Get this frame's parent frame.
virtual StackFrame parent() const = 0;
@ -376,7 +376,7 @@ class StackFrame : public JS::Traceable {
// Methods that forward to virtual calls through BaseStackFrame.
void trace(JSTracer* trc) { base()->trace(trc); }
uintptr_t identifier() const { return base()->identifier(); }
uint64_t identifier() const { return base()->identifier(); }
uint32_t line() const { return base()->line(); }
uint32_t column() const { return base()->column(); }
AtomOrTwoByteChars source() const { return base()->source(); }
@ -415,7 +415,7 @@ class ConcreteStackFrame<void> : public BaseStackFrame {
public:
static void construct(void* storage, void*) { new (storage) ConcreteStackFrame(nullptr); }
uintptr_t identifier() const override { return 0; }
uint64_t identifier() const override { return 0; }
void trace(JSTracer* trc) override { }
bool constructSavedFrameStack(JSContext* cx, MutableHandleObject out) const override {
out.set(nullptr);
@ -470,14 +470,14 @@ class Base {
//
// This is probably suitable for use in serializations, as it is an integral
// type. It may also help save memory when constructing HashSets of
// ubi::Nodes: since a uintptr_t will always be smaller than a ubi::Node, a
// HashSet<ubi::Node::Id> will use less space per element than a
// HashSet<ubi::Node>.
// ubi::Nodes: since a uint64_t will always be smaller-or-equal-to the size
// of a ubi::Node, a HashSet<ubi::Node::Id> may use less space per element
// than a HashSet<ubi::Node>.
//
// (Note that 'unique' only means 'up to equality on ubi::Node'; see the
// caveats about multiple objects allocated at the same address for
// 'ubi::Node::operator=='.)
typedef uintptr_t Id;
using Id = uint64_t;
virtual Id identifier() const { return reinterpret_cast<Id>(ptr); }
// Returns true if this node is pointing to something on the live heap, as
@ -495,8 +495,9 @@ class Base {
// Return the size of this node, in bytes. Include any structures that this
// node owns exclusively that are not exposed as their own ubi::Nodes.
// |mallocSizeOf| should be a malloc block sizing function; see
// |mfbt/MemoryReporting.h.
virtual size_t size(mozilla::MallocSizeOf mallocSizeof) const { return 0; }
// |mfbt/MemoryReporting.h|.
using Size = uint64_t;
virtual Size size(mozilla::MallocSizeOf mallocSizeof) const { return 1; }
// Return an EdgeRange that initially contains all the referent's outgoing
// edges. The caller takes ownership of the EdgeRange.
@ -688,7 +689,8 @@ class Node {
return base()->jsObjectConstructorName(cx, outName);
}
size_t size(mozilla::MallocSizeOf mallocSizeof) const {
using Size = Base::Size;
Size size(mozilla::MallocSizeOf mallocSizeof) const {
return base()->size(mallocSizeof);
}
@ -701,7 +703,7 @@ class Node {
return base()->allocationStack();
}
typedef Base::Id Id;
using Id = Base::Id;
Id identifier() const { return base()->identifier(); }
// A hash policy for ubi::Nodes.
@ -969,7 +971,7 @@ class Concrete<JSObject> : public TracerConcreteWithCompartment<JSObject> {
const char* jsObjectClassName() const override;
bool jsObjectConstructorName(JSContext* cx,
UniquePtr<char16_t[], JS::FreePolicy>& outName) const override;
size_t size(mozilla::MallocSizeOf mallocSizeOf) const override;
Size size(mozilla::MallocSizeOf mallocSizeOf) const override;
bool hasAllocationStack() const override;
StackFrame allocationStack() const override;
@ -985,7 +987,7 @@ class Concrete<JSObject> : public TracerConcreteWithCompartment<JSObject> {
// For JSString, we extend the generic template with a 'size' implementation.
template<> struct Concrete<JSString> : TracerConcrete<JSString> {
size_t size(mozilla::MallocSizeOf mallocSizeOf) const override;
Size size(mozilla::MallocSizeOf mallocSizeOf) const override;
protected:
explicit Concrete(JSString *ptr) : TracerConcrete<JSString>(ptr) { }
@ -998,7 +1000,7 @@ template<> struct Concrete<JSString> : TracerConcrete<JSString> {
template<>
class Concrete<void> : public Base {
const char16_t* typeName() const override;
size_t size(mozilla::MallocSizeOf mallocSizeOf) const override;
Size size(mozilla::MallocSizeOf mallocSizeOf) const override;
UniquePtr<EdgeRange> edges(JSContext* cx, bool wantNames) const override;
JS::Zone* zone() const override;
JSCompartment* compartment() const override;

Просмотреть файл

@ -0,0 +1,14 @@
setJitCompilerOption("ion.warmup.trigger", 30);
var spaces = [
"\u0009", "\u000b", "\u000c", "\u0020", "\u00a0", "\u1680",
"\u180e", "\u2000", "\u2001", "\u2002", "\u2003", "\u2004",
"\u2005", "\u2006", "\u2007", "\u2008", "\u2009", "\u200a",
];
var line_terminators = [ "\u2028", "\u2029", "\u000a", "\u000d" ];
var space_chars = [].concat(spaces, line_terminators);
var non_space_chars = [ "\u200b", "\u200c", "\u200d" ];
var chars = [].concat(space_chars, non_space_chars);
var is_space = [].concat(space_chars.map(function(ch) { return true; }),
non_space_chars.map(function() { return false; }));
chars.map(function(ch) {}).join(',');

Просмотреть файл

@ -0,0 +1,27 @@
const numRows = 600;
const numCols = 600;
function computeEscapeSpeed(c) {
const scaler = 5;
const threshold = (colors.length - 1) * scaler + 1;
for (var i = 1; i < threshold; ++i) {}
}
const colorStrings = [ "deeppink", ];
var colors = [];
function createMandelSet(realRange, imagRange) {
for each (var color in colorStrings) {
var [r, g, b] = [0, 0, 0];
colors.push([r, g, b, 0xff]);
}
var realStep = (realRange.max - realRange.min)/numCols;
var imagStep = (imagRange.min - imagRange.max)/(function (colors) {} ) ;
for (var i = 0, curReal = realRange.min; i < numCols; ++i, curReal += realStep) {
for (var j = 0, curImag = imagRange.max; j < numRows; ++j, curImag += imagStep) {
var c = { r: curReal, i: curImag }
var n = computeEscapeSpeed(c);
}
}
}
var realRange = { min: -2.1, max: 2 };
var imagRange = { min: -2, max: 2 };
createMandelSet(realRange, imagRange);

Просмотреть файл

@ -0,0 +1,9 @@
function printStatus (msg) {
var lines = msg.split ("\n");
for (var i=0; i<lines.length; i++)
lines[i];
}
Object.prototype.length = function(){};
var summary = 'Do not assert: !OBJ_GET_PROTO(cx, ctor)';
printStatus (summary);

Просмотреть файл

@ -0,0 +1,183 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* 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/. */
#include "jit/InstructionReordering.h"
using namespace js;
using namespace js::jit;
static void
MoveBefore(MBasicBlock* block, MInstruction* at, MInstruction* ins)
{
if (at == ins)
return;
// Update instruction numbers.
for (MInstructionIterator iter(block->begin(at)); *iter != ins; iter++) {
MOZ_ASSERT(iter->id() < ins->id());
iter->setId(iter->id() + 1);
}
ins->setId(at->id() - 1);
block->moveBefore(at, ins);
}
static bool
IsLastUse(MDefinition* ins, MDefinition* input, MBasicBlock* loopHeader)
{
// If we are in a loop, this cannot be the last use of any definitions from
// outside the loop, as those definitions can be used in future iterations.
if (loopHeader && input->block()->id() < loopHeader->id())
return false;
for (MUseDefIterator iter(input); iter; iter++) {
// Watch for uses defined in blocks which ReorderInstructions hasn't
// processed yet. These nodes have not had their ids set yet.
if (iter.def()->block()->id() > ins->block()->id())
return false;
if (iter.def()->id() > ins->id())
return false;
}
return true;
}
bool
jit::ReorderInstructions(MIRGenerator* mir, MIRGraph& graph)
{
// Renumber all instructions in the graph as we go.
size_t nextId = 0;
// List of the headers of any loops we are in.
Vector<MBasicBlock*, 4, SystemAllocPolicy> loopHeaders;
for (ReversePostorderIterator block(graph.rpoBegin()); block != graph.rpoEnd(); block++) {
// Don't reorder instructions within entry blocks, which have special requirements.
if (*block == graph.entryBlock() || *block == graph.osrBlock())
continue;
if (block->isLoopHeader()) {
if (!loopHeaders.append(*block))
return false;
}
MBasicBlock* innerLoop = loopHeaders.empty() ? nullptr : loopHeaders.back();
for (MPhiIterator iter(block->phisBegin()); iter != block->phisEnd(); iter++)
iter->setId(nextId++);
for (MInstructionIterator iter(block->begin()); iter != block->end(); iter++)
iter->setId(nextId++);
for (MInstructionIterator iter(block->begin()); iter != block->end(); ) {
MInstruction* ins = *iter;
// Filter out some instructions which are never reordered.
if (ins->isEffectful() ||
!ins->isMovable() ||
ins->resumePoint() ||
ins == block->lastIns())
{
iter++;
continue;
}
// Move constants with a single use in the current block to the
// start of the block. Constants won't be reordered by the logic
// below, as they have no inputs. Moving them up as high as
// possible can allow their use to be moved up further, though,
// and has no cost if the constant is emitted at its use.
if (ins->isConstant() &&
ins->hasOneUse() &&
ins->usesBegin()->consumer()->block() == *block &&
!IsFloatingPointType(ins->type()))
{
iter++;
MInstructionIterator targetIter = block->begin();
if (targetIter->isInterruptCheck())
targetIter++;
MoveBefore(*block, *targetIter, ins);
continue;
}
// Look for inputs where this instruction is the last use of that
// input. If we move this instruction up, the input's lifetime will
// be shortened, modulo resume point uses (which don't need to be
// stored in a register, and can be handled by the register
// allocator by just spilling at some point with no reload).
Vector<MDefinition*, 4, SystemAllocPolicy> lastUsedInputs;
for (size_t i = 0; i < ins->numOperands(); i++) {
MDefinition* input = ins->getOperand(i);
if (!input->isConstant() && IsLastUse(ins, input, innerLoop)) {
if (!lastUsedInputs.append(input))
return false;
}
}
// Don't try to move instructions which aren't the last use of any
// of their inputs (we really ought to move these down instead).
if (lastUsedInputs.length() < 2) {
iter++;
continue;
}
MInstruction* target = ins;
for (MInstructionReverseIterator riter = ++block->rbegin(ins); riter != block->rend(); riter++) {
MInstruction* prev = *riter;
if (prev->isInterruptCheck())
break;
// The instruction can't be moved before any of its uses.
bool isUse = false;
for (size_t i = 0; i < ins->numOperands(); i++) {
if (ins->getOperand(i) == prev) {
isUse = true;
break;
}
}
if (isUse)
break;
// The instruction can't be moved before an instruction that
// stores to a location read by the instruction.
if (prev->isEffectful() &&
(ins->getAliasSet().flags() & prev->getAliasSet().flags()) &&
ins->mightAlias(prev))
{
break;
}
// Make sure the instruction will still be the last use of one
// of its inputs when moved up this far.
for (size_t i = 0; i < lastUsedInputs.length(); ) {
bool found = false;
for (size_t j = 0; j < prev->numOperands(); j++) {
if (prev->getOperand(j) == lastUsedInputs[i]) {
found = true;
break;
}
}
if (found) {
lastUsedInputs[i] = lastUsedInputs.back();
lastUsedInputs.popBack();
} else {
i++;
}
}
if (lastUsedInputs.length() < 2)
break;
// We can move the instruction before this one.
target = prev;
}
iter++;
MoveBefore(*block, target, ins);
}
if (block->isLoopBackedge())
loopHeaders.popBack();
}
return true;
}

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше