mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-20 08:45:46 +00:00
Merge mozilla-inbound to mozilla-central. a=merge
This commit is contained in:
commit
597a69c70a
@ -20,9 +20,6 @@ const kDumpAllStacks = false;
|
||||
const whitelist = {
|
||||
modules: new Set([
|
||||
"chrome://mochikit/content/ShutdownLeaksCollector.jsm",
|
||||
"resource://specialpowers/SpecialPowersChild.jsm",
|
||||
"resource://specialpowers/SpecialPowersAPI.jsm",
|
||||
"resource://specialpowers/WrapPrivileged.jsm",
|
||||
|
||||
"resource://gre/modules/ContentProcessSingleton.jsm",
|
||||
|
||||
@ -95,6 +92,9 @@ const intermittently_loaded_whitelist = {
|
||||
"resource://gre/modules/nsAsyncShutdown.jsm",
|
||||
"resource://gre/modules/sessionstore/Utils.jsm",
|
||||
|
||||
"resource://specialpowers/SpecialPowersChild.jsm",
|
||||
"resource://specialpowers/WrapPrivileged.jsm",
|
||||
|
||||
// Webcompat about:config front-end. This is presently nightly-only and
|
||||
// part of a system add-on which may not load early enough for the test.
|
||||
"resource://webcompat/AboutCompat.jsm",
|
||||
|
@ -33,7 +33,7 @@ add_task(async function setup() {
|
||||
|
||||
async function testPopup(hasPopup, buttonToClick) {
|
||||
let numPageLoaded = gProtectionsHandler._socialTrackingSessionPageLoad;
|
||||
let numPopupShown = SpecialPowers.getIntPref(
|
||||
let numPopupShown = Services.prefs.getIntPref(
|
||||
"privacy.socialtracking.notification.counter",
|
||||
0
|
||||
);
|
||||
@ -89,7 +89,7 @@ async function testPopup(hasPopup, buttonToClick) {
|
||||
// click on the button of the popup notification
|
||||
if (typeof buttonToClick === "string") {
|
||||
is(
|
||||
SpecialPowers.getBoolPref(
|
||||
Services.prefs.getBoolPref(
|
||||
"privacy.socialtracking.notification.enabled",
|
||||
false
|
||||
),
|
||||
@ -101,7 +101,7 @@ async function testPopup(hasPopup, buttonToClick) {
|
||||
EventUtils.synthesizeMouseAtCenter(notification[buttonToClick], {});
|
||||
|
||||
is(
|
||||
SpecialPowers.getBoolPref(
|
||||
Services.prefs.getBoolPref(
|
||||
"privacy.socialtracking.notification.enabled",
|
||||
true
|
||||
),
|
||||
@ -110,13 +110,13 @@ async function testPopup(hasPopup, buttonToClick) {
|
||||
);
|
||||
}
|
||||
|
||||
let lastShown = SpecialPowers.getCharPref(
|
||||
let lastShown = Services.prefs.getCharPref(
|
||||
"privacy.socialtracking.notification.lastShown",
|
||||
"0"
|
||||
);
|
||||
ok(lastShown !== "0", "last shown timestamp updated");
|
||||
is(
|
||||
SpecialPowers.getIntPref(
|
||||
Services.prefs.getIntPref(
|
||||
"privacy.socialtracking.notification.counter",
|
||||
0
|
||||
),
|
||||
@ -221,12 +221,12 @@ add_task(async function testSocialTrackingPopups() {
|
||||
|
||||
for (let config of configs) {
|
||||
ok(config.description, config.description);
|
||||
SpecialPowers.pushPrefEnv({
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: config.prefs,
|
||||
});
|
||||
for (let result of config.results) {
|
||||
await testPopup(result, config.button);
|
||||
}
|
||||
SpecialPowers.popPrefEnv();
|
||||
await SpecialPowers.popPrefEnv();
|
||||
}
|
||||
});
|
||||
|
@ -141,7 +141,7 @@ async function setDownloadDir() {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
["browser.download.folderList", 2],
|
||||
["browser.download.dir", tmpDir, Ci.nsIFile],
|
||||
["browser.download.dir", tmpDir.path],
|
||||
],
|
||||
});
|
||||
}
|
||||
|
@ -6,6 +6,12 @@
|
||||
# in this manifest to the sub-directory "test-oop-extensions", and then check
|
||||
# whether we're running from that directory from head.js
|
||||
install-to-subdir = test-oop-extensions
|
||||
prefs =
|
||||
extensions.webextensions.remote=true
|
||||
# We don't want to reset this at the end of the test, so that we don't have
|
||||
# to spawn a new extension child process for each test unit.
|
||||
dom.ipc.keepProcessesAlive.extension=1
|
||||
|
||||
tags = webextensions remote-webextensions
|
||||
skip-if = !e10s
|
||||
support-files =
|
||||
|
@ -2,6 +2,8 @@
|
||||
tags = webextensions in-process-webextensions
|
||||
support-files =
|
||||
head.js
|
||||
prefs =
|
||||
extensions.webextensions.remote=false
|
||||
|
||||
[browser_ext_autocompletepopup.js]
|
||||
[browser_ext_windows_allowScriptsToClose.js]
|
||||
|
@ -546,6 +546,7 @@ add_task(async function testBadgeColorPersistence() {
|
||||
add_task(async function testPropertyRemoval() {
|
||||
await runTests({
|
||||
manifest: {
|
||||
name: "Generated extension",
|
||||
browser_action: {
|
||||
default_icon: "default.png",
|
||||
default_popup: "default.html",
|
||||
|
@ -2,6 +2,8 @@
|
||||
/* vim: set sts=2 sw=2 et tw=80: */
|
||||
"use strict";
|
||||
|
||||
PromiseTestUtils.whitelistRejectionsGlobally(/packaging errors/);
|
||||
|
||||
// Test that an error is thrown when providing invalid icon sizes
|
||||
add_task(async function testInvalidIconSizes() {
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
|
@ -2,6 +2,8 @@
|
||||
/* vim: set sts=2 sw=2 et tw=80: */
|
||||
"use strict";
|
||||
|
||||
PromiseTestUtils.whitelistRejectionsGlobally(/packaging errors/);
|
||||
|
||||
const { GlobalManager } = ChromeUtils.import(
|
||||
"resource://gre/modules/Extension.jsm",
|
||||
null
|
||||
|
@ -2,6 +2,8 @@
|
||||
/* vim: set sts=2 sw=2 et tw=80: */
|
||||
"use strict";
|
||||
|
||||
PromiseTestUtils.whitelistRejectionsGlobally(/packaging errors/);
|
||||
|
||||
function getExtension(page_action) {
|
||||
return ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
|
@ -316,13 +316,13 @@ add_task(async function() {
|
||||
|
||||
const RESOLUTION_PREF = "layout.css.devPixelsPerPx";
|
||||
registerCleanupFunction(() => {
|
||||
SpecialPowers.clearUserPref(RESOLUTION_PREF);
|
||||
Services.prefs.clearUserPref(RESOLUTION_PREF);
|
||||
});
|
||||
|
||||
await Promise.all([extension.startup(), extension.awaitMessage("ready")]);
|
||||
|
||||
for (let resolution of [2, 1]) {
|
||||
SpecialPowers.setCharPref(RESOLUTION_PREF, String(resolution));
|
||||
Services.prefs.setCharPref(RESOLUTION_PREF, String(resolution));
|
||||
is(
|
||||
window.devicePixelRatio,
|
||||
resolution,
|
||||
@ -342,7 +342,7 @@ add_task(async function() {
|
||||
BrowserTestUtils.removeTab(tab1);
|
||||
BrowserTestUtils.removeTab(tab2);
|
||||
BrowserTestUtils.removeTab(tab3);
|
||||
SpecialPowers.clearUserPref(RESOLUTION_PREF);
|
||||
Services.prefs.clearUserPref(RESOLUTION_PREF);
|
||||
});
|
||||
|
||||
add_task(async function testQueryPermissions() {
|
||||
|
@ -1,5 +1,7 @@
|
||||
"use strict";
|
||||
|
||||
PromiseTestUtils.whitelistRejectionsGlobally(/packaging errors/);
|
||||
|
||||
/**
|
||||
* Helper function for testing a theme with invalid properties.
|
||||
* @param {object} invalidProps The invalid properties to load the theme with.
|
||||
|
@ -68,20 +68,6 @@ function loadTestSubscript(filePath) {
|
||||
Services.scriptloader.loadSubScript(new URL(filePath, gTestPath).href, this);
|
||||
}
|
||||
|
||||
// We run tests under two different configurations, from browser.ini and
|
||||
// browser-remote.ini. When running from browser-remote.ini, the tests are
|
||||
// copied to the sub-directory "test-oop-extensions", which we detect here, and
|
||||
// use to select our configuration.
|
||||
let remote = gTestPath.includes("test-oop-extensions");
|
||||
SpecialPowers.pushPrefEnv({
|
||||
set: [["extensions.webextensions.remote", remote]],
|
||||
});
|
||||
if (remote) {
|
||||
// We don't want to reset this at the end of the test, so that we don't have
|
||||
// to spawn a new extension child process for each test unit.
|
||||
SpecialPowers.setIntPref("dom.ipc.keepProcessesAlive.extension", 1);
|
||||
}
|
||||
|
||||
// Don't try to create screenshots of sites we load during tests.
|
||||
Services.prefs
|
||||
.getDefaultBranch("browser.newtabpage.activity-stream.")
|
||||
|
@ -43,7 +43,7 @@ add_task(async function copy_toolbar_shortcut() {
|
||||
});
|
||||
|
||||
add_task(async function copy_mobile_shortcut() {
|
||||
SpecialPowers.pushPrefEnv({
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [["browser.bookmarks.showMobileBookmarks", true]],
|
||||
});
|
||||
await promisePlacesInitComplete();
|
||||
|
@ -11,7 +11,6 @@
|
||||
"workaround-issue38586.patch",
|
||||
"unpoison-thread-stacks.patch",
|
||||
"downgrade-mangling-error.patch",
|
||||
"r355141-arm64-cfg.patch",
|
||||
"r357725-asan-vs2019.patch",
|
||||
"loosen-msvc-detection.patch",
|
||||
"revert-r355311.patch"
|
||||
|
@ -1,112 +0,0 @@
|
||||
[COFF] Add address-taken import thunks to the fid table
|
||||
|
||||
https://bugs.llvm.org/show_bug.cgi?id=39799
|
||||
https://reviews.llvm.org/D58739
|
||||
|
||||
--- a/lld/COFF/Writer.cpp
|
||||
+++ b/lld/COFF/Writer.cpp
|
||||
@@ -1390,19 +1390,47 @@
|
||||
// symbol in an executable section.
|
||||
static void maybeAddAddressTakenFunction(SymbolRVASet &AddressTakenSyms,
|
||||
Symbol *S) {
|
||||
- auto *D = dyn_cast_or_null<DefinedCOFF>(S);
|
||||
-
|
||||
- // Ignore undefined symbols and references to non-functions (e.g. globals and
|
||||
- // labels).
|
||||
- if (!D ||
|
||||
- D->getCOFFSymbol().getComplexType() != COFF::IMAGE_SYM_DTYPE_FUNCTION)
|
||||
+ if (!S)
|
||||
return;
|
||||
|
||||
- // Mark the symbol as address taken if it's in an executable section.
|
||||
- Chunk *RefChunk = D->getChunk();
|
||||
- OutputSection *OS = RefChunk ? RefChunk->getOutputSection() : nullptr;
|
||||
- if (OS && OS->Header.Characteristics & IMAGE_SCN_MEM_EXECUTE)
|
||||
- addSymbolToRVASet(AddressTakenSyms, D);
|
||||
+ switch (S->kind()) {
|
||||
+ case Symbol::DefinedLocalImportKind:
|
||||
+ case Symbol::DefinedImportDataKind:
|
||||
+ // Defines an __imp_ pointer, so it is data, so it is ignored.
|
||||
+ break;
|
||||
+ case Symbol::DefinedCommonKind:
|
||||
+ // Common is always data, so it is ignored.
|
||||
+ break;
|
||||
+ case Symbol::DefinedAbsoluteKind:
|
||||
+ case Symbol::DefinedSyntheticKind:
|
||||
+ // Absolute is never code, synthetic generally isn't and usually isn't
|
||||
+ // determinable.
|
||||
+ break;
|
||||
+ case Symbol::LazyKind:
|
||||
+ case Symbol::UndefinedKind:
|
||||
+ // Undefined symbols resolve to zero, so they don't have an RVA. Lazy
|
||||
+ // symbols shouldn't have relocations.
|
||||
+ break;
|
||||
+
|
||||
+ case Symbol::DefinedImportThunkKind:
|
||||
+ // Thunks are always code, include them.
|
||||
+ addSymbolToRVASet(AddressTakenSyms, cast<Defined>(S));
|
||||
+ break;
|
||||
+
|
||||
+ case Symbol::DefinedRegularKind: {
|
||||
+ // This is a regular, defined, symbol from a COFF file. Mark the symbol as
|
||||
+ // address taken if the symbol type is function and it's in an executable
|
||||
+ // section.
|
||||
+ auto *D = cast<DefinedRegular>(S);
|
||||
+ if (D->getCOFFSymbol().getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION) {
|
||||
+ Chunk *RefChunk = D->getChunk();
|
||||
+ OutputSection *OS = RefChunk ? RefChunk->getOutputSection() : nullptr;
|
||||
+ if (OS && OS->Header.Characteristics & IMAGE_SCN_MEM_EXECUTE)
|
||||
+ addSymbolToRVASet(AddressTakenSyms, D);
|
||||
+ }
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
}
|
||||
|
||||
// Visit all relocations from all section contributions of this object file and
|
||||
--- a/lld/test/COFF/guardcf-thunk.s
|
||||
+++ b/lld/test/COFF/guardcf-thunk.s
|
||||
@@ -0,0 +1,43 @@
|
||||
+# REQUIRES: x86
|
||||
+
|
||||
+# Make a DLL that exports exportfn1.
|
||||
+# RUN: yaml2obj < %p/Inputs/export.yaml > %t.obj
|
||||
+# RUN: lld-link /out:%t.dll /dll %t.obj /export:exportfn1 /implib:%t.lib
|
||||
+
|
||||
+# Make an obj that takes the address of that exported function.
|
||||
+# RUN: llvm-mc -filetype=obj -triple=x86_64-windows-msvc %s -o %t2.obj
|
||||
+# RUN: lld-link -entry:main -guard:cf %t2.obj %t.lib -nodefaultlib -out:%t.exe
|
||||
+# RUN: llvm-readobj -coff-load-config %t.exe | FileCheck %s
|
||||
+
|
||||
+# Check that the gfids table contains *exactly* two entries, one for exportfn1
|
||||
+# and one for main.
|
||||
+# CHECK: GuardFidTable [
|
||||
+# CHECK-NEXT: 0x{{[0-9A-Fa-f]+0$}}
|
||||
+# CHECK-NEXT: 0x{{[0-9A-Fa-f]+0$}}
|
||||
+# CHECK-NEXT: ]
|
||||
+
|
||||
+
|
||||
+ .def @feat.00;
|
||||
+ .scl 3;
|
||||
+ .type 0;
|
||||
+ .endef
|
||||
+ .globl @feat.00
|
||||
+@feat.00 = 0x001
|
||||
+
|
||||
+ .section .text,"rx"
|
||||
+ .def main; .scl 2; .type 32; .endef
|
||||
+ .global main
|
||||
+main:
|
||||
+ leaq exportfn1(%rip), %rax
|
||||
+ retq
|
||||
+
|
||||
+ .section .rdata,"dr"
|
||||
+.globl _load_config_used
|
||||
+_load_config_used:
|
||||
+ .long 256
|
||||
+ .fill 124, 1, 0
|
||||
+ .quad __guard_fids_table
|
||||
+ .quad __guard_fids_count
|
||||
+ .long __guard_flags
|
||||
+ .fill 128, 1, 0
|
||||
+
|
@ -31,6 +31,7 @@ skip-if = true # original stepping is currently disabled
|
||||
skip-if = os == "win" # Bug 1448523, Bug 1448450
|
||||
[browser_dbg-breaking.js]
|
||||
[browser_dbg-breaking-from-console.js]
|
||||
skip-if = debug # Window leaks: bug 1575332
|
||||
[browser_dbg-breakpoints.js]
|
||||
[browser_dbg-breakpoints-actions.js]
|
||||
[browser_dbg-breakpoints-columns.js]
|
||||
@ -62,6 +63,7 @@ skip-if = (os == "win" && ccov) # Bug 1424154
|
||||
[browser_dbg-editor-select.js]
|
||||
[browser_dbg-editor-highlight.js]
|
||||
[browser_dbg-ember-quickstart.js]
|
||||
skip-if = debug # Window leaks: bug 1575332
|
||||
[browser_dbg-expressions.js]
|
||||
[browser_dbg-expressions-error.js]
|
||||
[browser_dbg-expressions-focus.js]
|
||||
|
@ -53,6 +53,10 @@ support-files =
|
||||
!/devtools/client/shared/test/shared-head.js
|
||||
!/devtools/client/shared/test/shared-redux-head.js
|
||||
!/devtools/client/shared/test/telemetry-test-helpers.js
|
||||
# This is far from ideal. https://bugzilla.mozilla.org/show_bug.cgi?id=1565279
|
||||
# covers removing this pref flip.
|
||||
prefs =
|
||||
security.allow_unsafe_parent_loads=true
|
||||
|
||||
[browser_about-devtools-toolbox_load.js]
|
||||
[browser_about-devtools-toolbox_reload.js]
|
||||
|
@ -12,12 +12,6 @@ Services.scriptloader.loadSubScript(
|
||||
|
||||
const EventEmitter = require("devtools/shared/event-emitter");
|
||||
|
||||
// This is far from ideal. https://bugzilla.mozilla.org/show_bug.cgi?id=1565279
|
||||
// covers removing this pref flip.
|
||||
SpecialPowers.pushPrefEnv({
|
||||
set: [["security.allow_unsafe_parent_loads", true]],
|
||||
});
|
||||
|
||||
function toggleAllTools(state) {
|
||||
for (const [, tool] of gDevTools._tools) {
|
||||
if (!tool.visibilityswitch) {
|
||||
|
@ -8,20 +8,20 @@ const TEST_JSON_URL = URL_ROOT + "valid_json.json";
|
||||
add_task(async function() {
|
||||
info("Test JSON theme started.");
|
||||
|
||||
const oldPref = SpecialPowers.getCharPref("devtools.theme");
|
||||
SpecialPowers.setCharPref("devtools.theme", "light");
|
||||
const oldPref = Services.prefs.getCharPref("devtools.theme");
|
||||
Services.prefs.setCharPref("devtools.theme", "light");
|
||||
|
||||
await addJsonViewTab(TEST_JSON_URL);
|
||||
|
||||
is(await getTheme(), "theme-light", "The initial theme is light");
|
||||
|
||||
SpecialPowers.setCharPref("devtools.theme", "dark");
|
||||
Services.prefs.setCharPref("devtools.theme", "dark");
|
||||
is(await getTheme(), "theme-dark", "Theme changed to dark");
|
||||
|
||||
SpecialPowers.setCharPref("devtools.theme", "light");
|
||||
Services.prefs.setCharPref("devtools.theme", "light");
|
||||
is(await getTheme(), "theme-light", "Theme changed to light");
|
||||
|
||||
SpecialPowers.setCharPref("devtools.theme", oldPref);
|
||||
Services.prefs.setCharPref("devtools.theme", oldPref);
|
||||
});
|
||||
|
||||
function getTheme() {
|
||||
|
@ -8,7 +8,6 @@
|
||||
onload="setTimeout(runTests, 0);"
|
||||
title="bug 293235 test">
|
||||
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/ChromePowers.js"/>
|
||||
<script type="application/javascript" src= "chrome://mochikit/content/chrome-harness.js" />
|
||||
<script type="application/javascript" src="docshell_helpers.js" />
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/WindowSnapshot.js"></script>
|
||||
|
@ -8,7 +8,6 @@
|
||||
onload="setTimeout(nextTest, 0);"
|
||||
title="bug 396649 test">
|
||||
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/ChromePowers.js"/>
|
||||
<script type="application/javascript" src= "chrome://mochikit/content/chrome-harness.js" />
|
||||
<script type="application/javascript" src="docshell_helpers.js" />
|
||||
<script type="application/javascript"><![CDATA[
|
||||
|
@ -9,7 +9,6 @@
|
||||
title="bug 89419 test">
|
||||
|
||||
<script type="application/javascript" src= "chrome://mochikit/content/chrome-harness.js" />
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/ChromePowers.js"/>
|
||||
<script type="application/javascript" src="docshell_helpers.js" />
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/WindowSnapshot.js"></script>
|
||||
|
||||
|
@ -73,11 +73,11 @@ callback interface MozObserverCallback {
|
||||
};
|
||||
|
||||
/**
|
||||
* WebIDL callback interface calling the `willDestroy` and `didDestroy`
|
||||
* method on JSWindowActors.
|
||||
* WebIDL callback interface calling the `willDestroy`, `didDestroy`, and
|
||||
* `actorCreated` methods on JSWindowActors.
|
||||
*/
|
||||
[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
|
||||
callback MozActorDestroyCallback = void();
|
||||
callback MozJSWindowActorCallback = void();
|
||||
|
||||
/**
|
||||
* The willDestroy method, if present, will be called at the last opportunity
|
||||
@ -85,13 +85,16 @@ callback MozActorDestroyCallback = void();
|
||||
* up and send final messages.
|
||||
* The didDestroy method, if present, will be called after the actor is no
|
||||
* longer able to receive any more messages.
|
||||
* The actorCreated method, if present, will be called immediately after the
|
||||
* actor has been created and initialized.
|
||||
*
|
||||
* NOTE: Messages may be received between willDestroy and didDestroy, but they
|
||||
* may not be sent.
|
||||
*/
|
||||
dictionary MozActorDestroyCallbacks {
|
||||
[ChromeOnly] MozActorDestroyCallback willDestroy;
|
||||
[ChromeOnly] MozActorDestroyCallback didDestroy;
|
||||
dictionary MozJSWindowActorCallbacks {
|
||||
[ChromeOnly] MozJSWindowActorCallback willDestroy;
|
||||
[ChromeOnly] MozJSWindowActorCallback didDestroy;
|
||||
[ChromeOnly] MozJSWindowActorCallback actorCreated;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -144,6 +144,11 @@ If you register your Actor to listen for ``nsIObserver`` notifications, implemen
|
||||
|
||||
If you register your Actor to listen for content events, implement a ``handleEvent`` method with the above signature to handle the event.
|
||||
|
||||
``actorCreated``
|
||||
````````````````
|
||||
|
||||
This method is called immediately after a child actor is created and initialized. Unlike the actor's constructor, it is possible to do things like access the actor's content window and send messages from this callback.
|
||||
|
||||
``willDestroy``
|
||||
```````````````
|
||||
|
||||
|
@ -38,17 +38,17 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(JSWindowActor)
|
||||
JSWindowActor::JSWindowActor() : mNextQueryId(0) {}
|
||||
|
||||
void JSWindowActor::StartDestroy() {
|
||||
DestroyCallback(DestroyCallbackFunction::WillDestroy);
|
||||
InvokeCallback(CallbackFunction::WillDestroy);
|
||||
}
|
||||
|
||||
void JSWindowActor::AfterDestroy() {
|
||||
DestroyCallback(DestroyCallbackFunction::DidDestroy);
|
||||
InvokeCallback(CallbackFunction::DidDestroy);
|
||||
}
|
||||
|
||||
void JSWindowActor::DestroyCallback(DestroyCallbackFunction callback) {
|
||||
void JSWindowActor::InvokeCallback(CallbackFunction callback) {
|
||||
AutoEntryScript aes(GetParentObject(), "JSWindowActor destroy callback");
|
||||
JSContext* cx = aes.cx();
|
||||
MozActorDestroyCallbacks callbacksHolder;
|
||||
MozJSWindowActorCallbacks callbacksHolder;
|
||||
NS_ENSURE_TRUE_VOID(GetWrapper());
|
||||
JS::Rooted<JS::Value> val(cx, JS::ObjectValue(*GetWrapper()));
|
||||
if (NS_WARN_IF(!callbacksHolder.Init(cx, val))) {
|
||||
@ -56,14 +56,18 @@ void JSWindowActor::DestroyCallback(DestroyCallbackFunction callback) {
|
||||
}
|
||||
|
||||
// Destroy callback is optional.
|
||||
if (callback == DestroyCallbackFunction::WillDestroy) {
|
||||
if (callback == CallbackFunction::WillDestroy) {
|
||||
if (callbacksHolder.mWillDestroy.WasPassed()) {
|
||||
callbacksHolder.mWillDestroy.Value()->Call(this);
|
||||
}
|
||||
} else {
|
||||
} else if (callback == CallbackFunction::DidDestroy) {
|
||||
if (callbacksHolder.mDidDestroy.WasPassed()) {
|
||||
callbacksHolder.mDidDestroy.Value()->Call(this);
|
||||
}
|
||||
} else {
|
||||
if (callbacksHolder.mActorCreated.WasPassed()) {
|
||||
callbacksHolder.mActorCreated.Value()->Call(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -39,7 +39,7 @@ class JSWindowActor : public nsISupports, public nsWrapperCache {
|
||||
JSWindowActor();
|
||||
|
||||
enum class Type { Parent, Child };
|
||||
enum class DestroyCallbackFunction { WillDestroy, DidDestroy };
|
||||
enum class CallbackFunction { WillDestroy, DidDestroy, ActorCreated };
|
||||
|
||||
const nsString& Name() const { return mName; }
|
||||
|
||||
@ -76,7 +76,7 @@ class JSWindowActor : public nsISupports, public nsWrapperCache {
|
||||
|
||||
void AfterDestroy();
|
||||
|
||||
void DestroyCallback(DestroyCallbackFunction willDestroy);
|
||||
void InvokeCallback(CallbackFunction willDestroy);
|
||||
|
||||
private:
|
||||
void ReceiveMessageOrQuery(JSContext* aCx,
|
||||
|
@ -35,6 +35,8 @@ void JSWindowActorChild::Init(const nsAString& aName,
|
||||
MOZ_ASSERT(!mManager, "Cannot Init() a JSWindowActorChild twice!");
|
||||
SetName(aName);
|
||||
mManager = aManager;
|
||||
|
||||
InvokeCallback(CallbackFunction::ActorCreated);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
@ -81,9 +81,9 @@ function startTests() {
|
||||
|
||||
async function mozBrowserTests(browser) {
|
||||
info("Granting special powers for mozbrowser");
|
||||
SpecialPowers.addPermission("browser", true, TEST_URI);
|
||||
SpecialPowers.setBoolPref("dom.mozBrowserFramesEnabled", true);
|
||||
SpecialPowers.setBoolPref("network.disable.ipc.security", true);
|
||||
await SpecialPowers.addPermission("browser", true, TEST_URI);
|
||||
Services.prefs.setBoolPref("dom.mozBrowserFramesEnabled", true);
|
||||
Services.prefs.setBoolPref("network.disable.ipc.security", true);
|
||||
|
||||
await ContentTask.spawn(browser, null, function() {
|
||||
info("Checking mozbrowser iframe");
|
||||
@ -103,7 +103,7 @@ async function mozBrowserTests(browser) {
|
||||
});
|
||||
|
||||
info("Revoking special powers for mozbrowser");
|
||||
SpecialPowers.clearUserPref("dom.mozBrowserFramesEnabled");
|
||||
SpecialPowers.clearUserPref("network.disable.ipc.security");
|
||||
SpecialPowers.removePermission("browser", TEST_URI);
|
||||
Services.prefs.clearUserPref("dom.mozBrowserFramesEnabled");
|
||||
Services.prefs.clearUserPref("network.disable.ipc.security");
|
||||
await SpecialPowers.removePermission("browser", TEST_URI);
|
||||
}
|
||||
|
@ -394,11 +394,11 @@ clang-7:
|
||||
revision: d0d8eb2e5415b8be29343e3c17a18e49e67b5551
|
||||
|
||||
clang-8:
|
||||
description: clang 8 source code
|
||||
description: clang 8.0.1 source code
|
||||
fetch:
|
||||
type: git
|
||||
repo: https://github.com/llvm/llvm-project
|
||||
revision: d2298e74235598f15594fe2c99bbac870a507c59
|
||||
revision: 19a71f6bdf2dddb10764939e7f0ec2b98dba76c9
|
||||
|
||||
ninja:
|
||||
description: ninja 1.9.0
|
||||
|
@ -457,11 +457,12 @@ function Tester(aTests, structuredLogger, aCallback) {
|
||||
this.cpowEventUtils
|
||||
);
|
||||
|
||||
// Make sure our SpecialPowers actor is instantiated, in case it was
|
||||
// registered after our DOMWindowCreated event was fired (which it
|
||||
// most likely was).
|
||||
window.getWindowGlobalChild().getActor("SpecialPowers");
|
||||
|
||||
var simpleTestScope = {};
|
||||
this._scriptLoader.loadSubScript(
|
||||
"chrome://mochikit/content/tests/SimpleTest/ChromePowers.js",
|
||||
simpleTestScope
|
||||
);
|
||||
this._scriptLoader.loadSubScript(
|
||||
"chrome://mochikit/content/tests/SimpleTest/SimpleTest.js",
|
||||
simpleTestScope
|
||||
@ -476,6 +477,9 @@ function Tester(aTests, structuredLogger, aCallback) {
|
||||
);
|
||||
this.SimpleTest = simpleTestScope.SimpleTest;
|
||||
|
||||
window.SpecialPowers.SimpleTest = this.SimpleTest;
|
||||
window.SpecialPowers.setAsDefaultAssertHandler();
|
||||
|
||||
var extensionUtilsScope = {
|
||||
registerCleanupFunction: fn => {
|
||||
this.currentTest.scope.registerCleanupFunction(fn);
|
||||
|
@ -47,7 +47,6 @@ FINAL_TARGET_FILES.content.tests.SimpleTest += [
|
||||
'../../docshell/test/chrome/docshell_helpers.js',
|
||||
'../modules/StructuredLog.jsm',
|
||||
'tests/SimpleTest/AsyncUtilsContent.js',
|
||||
'tests/SimpleTest/ChromePowers.js',
|
||||
'tests/SimpleTest/EventUtils.js',
|
||||
'tests/SimpleTest/ExtensionTestUtils.js',
|
||||
'tests/SimpleTest/iframe-between-tests.html',
|
||||
|
@ -37,8 +37,11 @@ async function interceptDiagnostics(func) {
|
||||
}
|
||||
|
||||
add_task(async function() {
|
||||
const frameSrc = "https://example.com/tests/testing/mochitest/tests/Harness_sanity/file_spawn.html";
|
||||
const subframeSrc = "https://example.org/tests/testing/mochitest/tests/Harness_sanity/file_spawn.html";
|
||||
|
||||
let frame = document.getElementById("iframe");
|
||||
frame.src = "https://example.com/tests/testing/mochitest/tests/Harness_sanity/file_spawn.html";
|
||||
frame.src = frameSrc;
|
||||
|
||||
await new Promise(resolve => {
|
||||
frame.addEventListener("load", resolve, {once: true});
|
||||
@ -59,13 +62,31 @@ add_task(async function() {
|
||||
// just need to make sure that the general functionality works as expected.
|
||||
let tests = {
|
||||
"SpecialPowers.spawn": () => {
|
||||
return SpecialPowers.spawn(frame, [], () => {
|
||||
return SpecialPowers.spawn(frame, [], async () => {
|
||||
Assert.equal(1, 2, "Thing");
|
||||
Assert.equal(1, 1, "Hmm");
|
||||
Assert.ok(true, "Yay.");
|
||||
Assert.ok(false, "Boo!.");
|
||||
});
|
||||
},
|
||||
"SpecialPowers.spawn-subframe": () => {
|
||||
return SpecialPowers.spawn(frame, [subframeSrc], async src => {
|
||||
let frame = this.content.document.createElement("iframe");
|
||||
frame.src = src;
|
||||
this.content.document.body.appendChild(frame);
|
||||
|
||||
await new Promise(resolve => {
|
||||
frame.addEventListener("load", resolve, { once: true });
|
||||
});
|
||||
|
||||
await SpecialPowers.spawn(frame, [], () => {
|
||||
Assert.equal(1, 2, "Thing");
|
||||
Assert.equal(1, 1, "Hmm");
|
||||
Assert.ok(true, "Yay.");
|
||||
Assert.ok(false, "Boo!.");
|
||||
});
|
||||
});
|
||||
},
|
||||
"SpecialPowers.loadChromeScript": async () => {
|
||||
let script = SpecialPowers.loadChromeScript(() => {
|
||||
this.addMessageListener("ping", () => "pong");
|
||||
|
@ -1,120 +0,0 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
const {SpecialPowersAPI, bindDOMWindowUtils} = ChromeUtils.import("resource://specialpowers/SpecialPowersAPI.jsm");
|
||||
const {SpecialPowersAPIParent} = ChromeUtils.import("resource://specialpowers/SpecialPowersAPIParent.jsm");
|
||||
|
||||
class ChromePowers extends SpecialPowersAPI {
|
||||
constructor(window) {
|
||||
super();
|
||||
|
||||
this.window = Cu.getWeakReference(window);
|
||||
|
||||
this.chromeWindow = window;
|
||||
|
||||
this.DOMWindowUtils = bindDOMWindowUtils(window);
|
||||
|
||||
this.parentActor = new SpecialPowersAPIParent();
|
||||
this.parentActor.sendAsyncMessage = this.sendReply.bind(this);
|
||||
|
||||
this.listeners = new Map();
|
||||
}
|
||||
|
||||
toString() { return "[ChromePowers]"; }
|
||||
sanityCheck() { return "foo"; }
|
||||
|
||||
get contentWindow() {
|
||||
return window;
|
||||
}
|
||||
|
||||
get document() {
|
||||
return window.document;
|
||||
}
|
||||
|
||||
get docShell() {
|
||||
return window.docShell;
|
||||
}
|
||||
|
||||
sendReply(aType, aMsg) {
|
||||
var msg = {name: aType, json: aMsg, data: aMsg};
|
||||
if (!this.listeners.has(aType)) {
|
||||
throw new Error(`No listener for ${aType}`);
|
||||
}
|
||||
this.listeners.get(aType)(msg);
|
||||
}
|
||||
|
||||
sendAsyncMessage(aType, aMsg) {
|
||||
var msg = {name: aType, json: aMsg, data: aMsg};
|
||||
this.receiveMessage(msg);
|
||||
}
|
||||
|
||||
async sendQuery(aType, aMsg) {
|
||||
var msg = {name: aType, json: aMsg, data: aMsg};
|
||||
return this.receiveMessage(msg);
|
||||
}
|
||||
|
||||
_addMessageListener(aType, aCallback) {
|
||||
if (this.listeners.has(aType)) {
|
||||
throw new Error(`unable to handle multiple listeners for ${aType}`);
|
||||
}
|
||||
this.listeners.set(aType, aCallback);
|
||||
}
|
||||
_removeMessageListener(aType, aCallback) {
|
||||
this.listeners.delete(aType);
|
||||
}
|
||||
|
||||
registerProcessCrashObservers() {
|
||||
this._sendSyncMessage("SPProcessCrashService", { op: "register-observer" });
|
||||
}
|
||||
|
||||
unregisterProcessCrashObservers() {
|
||||
this._sendSyncMessage("SPProcessCrashService", { op: "unregister-observer" });
|
||||
}
|
||||
|
||||
receiveMessage(aMessage) {
|
||||
switch (aMessage.name) {
|
||||
case "SpecialPowers.Quit":
|
||||
let appStartup = Cc["@mozilla.org/toolkit/app-startup;1"].getService(Ci.nsIAppStartup);
|
||||
appStartup.quit(Ci.nsIAppStartup.eForceQuit);
|
||||
break;
|
||||
case "SPProcessCrashService":
|
||||
if (aMessage.json.op == "register-observer" || aMessage.json.op == "unregister-observer") {
|
||||
// Hack out register/unregister specifically for browser-chrome leaks
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// All calls go here, because we need to handle SPProcessCrashService calls as well
|
||||
return this.parentActor.receiveMessage(aMessage);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
quit() {
|
||||
// We come in here as SpecialPowers.quit, but SpecialPowers is really ChromePowers.
|
||||
// For some reason this.<func> resolves to TestRunner, so using SpecialPowers
|
||||
// allows us to use the ChromePowers object which we defined below.
|
||||
SpecialPowers._sendSyncMessage("SpecialPowers.Quit", {});
|
||||
}
|
||||
|
||||
focus(aWindow) {
|
||||
// We come in here as SpecialPowers.focus, but SpecialPowers is really ChromePowers.
|
||||
// For some reason this.<func> resolves to TestRunner, so using SpecialPowers
|
||||
// allows us to use the ChromePowers object which we defined below.
|
||||
if (aWindow)
|
||||
aWindow.focus();
|
||||
}
|
||||
|
||||
executeAfterFlushingMessageQueue(aCallback) {
|
||||
aCallback();
|
||||
}
|
||||
}
|
||||
|
||||
if (window.parent.SpecialPowers && !window.SpecialPowers) {
|
||||
window.SpecialPowers = window.parent.SpecialPowers;
|
||||
} else {
|
||||
ChromeUtils.import("resource://specialpowers/SpecialPowersAPIParent.jsm", this);
|
||||
|
||||
window.SpecialPowers = new ChromePowers(window);
|
||||
}
|
||||
|
@ -228,6 +228,8 @@ SimpleTest._inChaosMode = false;
|
||||
SimpleTest.expected = 'pass';
|
||||
SimpleTest.num_failed = 0;
|
||||
|
||||
SpecialPowers.setAsDefaultAssertHandler();
|
||||
|
||||
function usesFailurePatterns() {
|
||||
return Array.isArray(SimpleTest.expected);
|
||||
}
|
||||
|
@ -35,6 +35,7 @@ this.specialpowers = class extends ExtensionAPI {
|
||||
|
||||
ChromeUtils.registerWindowActor("SpecialPowers", {
|
||||
allFrames: true,
|
||||
includeChrome: true,
|
||||
child: {
|
||||
moduleURI: "resource://specialpowers/SpecialPowersChild.jsm",
|
||||
events: {
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,926 +0,0 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
var EXPORTED_SYMBOLS = ["SpecialPowersAPIParent", "SpecialPowersError"];
|
||||
|
||||
var { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
ExtensionData: "resource://gre/modules/Extension.jsm",
|
||||
ExtensionTestCommon: "resource://testing-common/ExtensionTestCommon.jsm",
|
||||
PerTestCoverageUtils: "resource://testing-common/PerTestCoverageUtils.jsm",
|
||||
ServiceWorkerCleanUp: "resource://gre/modules/ServiceWorkerCleanUp.jsm",
|
||||
SpecialPowersSandbox: "resource://specialpowers/SpecialPowersSandbox.jsm",
|
||||
HiddenFrame: "resource://gre/modules/HiddenFrame.jsm",
|
||||
});
|
||||
|
||||
class SpecialPowersError extends Error {
|
||||
get name() {
|
||||
return "SpecialPowersError";
|
||||
}
|
||||
}
|
||||
|
||||
function parseKeyValuePairs(text) {
|
||||
var lines = text.split("\n");
|
||||
var data = {};
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
if (lines[i] == "") {
|
||||
continue;
|
||||
}
|
||||
|
||||
// can't just .split() because the value might contain = characters
|
||||
let eq = lines[i].indexOf("=");
|
||||
if (eq != -1) {
|
||||
let [key, value] = [
|
||||
lines[i].substring(0, eq),
|
||||
lines[i].substring(eq + 1),
|
||||
];
|
||||
if (key && value) {
|
||||
data[key] = value.replace(/\\n/g, "\n").replace(/\\\\/g, "\\");
|
||||
}
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
function parseKeyValuePairsFromFile(file) {
|
||||
var fstream = Cc["@mozilla.org/network/file-input-stream;1"].createInstance(
|
||||
Ci.nsIFileInputStream
|
||||
);
|
||||
fstream.init(file, -1, 0, 0);
|
||||
var is = Cc["@mozilla.org/intl/converter-input-stream;1"].createInstance(
|
||||
Ci.nsIConverterInputStream
|
||||
);
|
||||
is.init(
|
||||
fstream,
|
||||
"UTF-8",
|
||||
1024,
|
||||
Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER
|
||||
);
|
||||
var str = {};
|
||||
var contents = "";
|
||||
while (is.readString(4096, str) != 0) {
|
||||
contents += str.value;
|
||||
}
|
||||
is.close();
|
||||
fstream.close();
|
||||
return parseKeyValuePairs(contents);
|
||||
}
|
||||
|
||||
function getTestPlugin(pluginName) {
|
||||
var ph = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
|
||||
var tags = ph.getPluginTags();
|
||||
var name = pluginName || "Test Plug-in";
|
||||
for (var tag of tags) {
|
||||
if (tag.name == name) {
|
||||
return tag;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
const PREF_TYPES = {
|
||||
[Ci.nsIPrefBranch.PREF_INVALID]: "INVALID",
|
||||
[Ci.nsIPrefBranch.PREF_INT]: "INT",
|
||||
[Ci.nsIPrefBranch.PREF_BOOL]: "BOOL",
|
||||
[Ci.nsIPrefBranch.PREF_STRING]: "CHAR",
|
||||
number: "INT",
|
||||
boolean: "BOOL",
|
||||
string: "CHAR",
|
||||
};
|
||||
|
||||
// We share a single preference environment stack between all
|
||||
// SpecialPowers instances, across all processes.
|
||||
let prefUndoStack = [];
|
||||
let inPrefEnvOp = false;
|
||||
|
||||
function doPrefEnvOp(fn) {
|
||||
if (inPrefEnvOp) {
|
||||
throw new Error(
|
||||
"Reentrant preference environment operations not supported"
|
||||
);
|
||||
}
|
||||
inPrefEnvOp = true;
|
||||
try {
|
||||
return fn();
|
||||
} finally {
|
||||
inPrefEnvOp = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Supplies the unique IDs for tasks created by SpecialPowers.spawn(),
|
||||
// used to bounce assertion messages back down to the correct child.
|
||||
let nextTaskID = 1;
|
||||
|
||||
class SpecialPowersAPIParent extends JSWindowActorParent {
|
||||
constructor() {
|
||||
super();
|
||||
this._crashDumpDir = null;
|
||||
this._processCrashObserversRegistered = false;
|
||||
this._chromeScriptListeners = [];
|
||||
this._extensions = new Map();
|
||||
this._taskActors = new Map();
|
||||
}
|
||||
|
||||
_observe(aSubject, aTopic, aData) {
|
||||
function addDumpIDToMessage(propertyName) {
|
||||
try {
|
||||
var id = aSubject.getPropertyAsAString(propertyName);
|
||||
} catch (ex) {
|
||||
id = null;
|
||||
}
|
||||
if (id) {
|
||||
message.dumpIDs.push({ id, extension: "dmp" });
|
||||
message.dumpIDs.push({ id, extension: "extra" });
|
||||
}
|
||||
}
|
||||
|
||||
switch (aTopic) {
|
||||
case "plugin-crashed":
|
||||
case "ipc:content-shutdown":
|
||||
var message = { type: "crash-observed", dumpIDs: [] };
|
||||
aSubject = aSubject.QueryInterface(Ci.nsIPropertyBag2);
|
||||
if (aTopic == "plugin-crashed") {
|
||||
addDumpIDToMessage("pluginDumpID");
|
||||
addDumpIDToMessage("browserDumpID");
|
||||
|
||||
let pluginID = aSubject.getPropertyAsAString("pluginDumpID");
|
||||
let extra = this._getExtraData(pluginID);
|
||||
if (extra && "additional_minidumps" in extra) {
|
||||
let dumpNames = extra.additional_minidumps.split(",");
|
||||
for (let name of dumpNames) {
|
||||
message.dumpIDs.push({
|
||||
id: pluginID + "-" + name,
|
||||
extension: "dmp",
|
||||
});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// ipc:content-shutdown
|
||||
if (!aSubject.hasKey("abnormal")) {
|
||||
return; // This is a normal shutdown, ignore it
|
||||
}
|
||||
|
||||
addDumpIDToMessage("dumpID");
|
||||
}
|
||||
this.sendAsyncMessage("SPProcessCrashService", message);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_getCrashDumpDir() {
|
||||
if (!this._crashDumpDir) {
|
||||
this._crashDumpDir = Services.dirsvc.get("ProfD", Ci.nsIFile);
|
||||
this._crashDumpDir.append("minidumps");
|
||||
}
|
||||
return this._crashDumpDir;
|
||||
}
|
||||
|
||||
_getPendingCrashDumpDir() {
|
||||
if (!this._pendingCrashDumpDir) {
|
||||
this._pendingCrashDumpDir = Services.dirsvc.get("UAppData", Ci.nsIFile);
|
||||
this._pendingCrashDumpDir.append("Crash Reports");
|
||||
this._pendingCrashDumpDir.append("pending");
|
||||
}
|
||||
return this._pendingCrashDumpDir;
|
||||
}
|
||||
|
||||
_getExtraData(dumpId) {
|
||||
let extraFile = this._getCrashDumpDir().clone();
|
||||
extraFile.append(dumpId + ".extra");
|
||||
if (!extraFile.exists()) {
|
||||
return null;
|
||||
}
|
||||
return parseKeyValuePairsFromFile(extraFile);
|
||||
}
|
||||
|
||||
_deleteCrashDumpFiles(aFilenames) {
|
||||
var crashDumpDir = this._getCrashDumpDir();
|
||||
if (!crashDumpDir.exists()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var success = aFilenames.length != 0;
|
||||
aFilenames.forEach(function(crashFilename) {
|
||||
var file = crashDumpDir.clone();
|
||||
file.append(crashFilename);
|
||||
if (file.exists()) {
|
||||
file.remove(false);
|
||||
} else {
|
||||
success = false;
|
||||
}
|
||||
});
|
||||
return success;
|
||||
}
|
||||
|
||||
_findCrashDumpFiles(aToIgnore) {
|
||||
var crashDumpDir = this._getCrashDumpDir();
|
||||
var entries = crashDumpDir.exists() && crashDumpDir.directoryEntries;
|
||||
if (!entries) {
|
||||
return [];
|
||||
}
|
||||
|
||||
var crashDumpFiles = [];
|
||||
while (entries.hasMoreElements()) {
|
||||
var file = entries.nextFile;
|
||||
var path = String(file.path);
|
||||
if (path.match(/\.(dmp|extra)$/) && !aToIgnore[path]) {
|
||||
crashDumpFiles.push(path);
|
||||
}
|
||||
}
|
||||
return crashDumpFiles.concat();
|
||||
}
|
||||
|
||||
_deletePendingCrashDumpFiles() {
|
||||
var crashDumpDir = this._getPendingCrashDumpDir();
|
||||
var removed = false;
|
||||
if (crashDumpDir.exists()) {
|
||||
let entries = crashDumpDir.directoryEntries;
|
||||
while (entries.hasMoreElements()) {
|
||||
let file = entries.nextFile;
|
||||
if (file.isFile()) {
|
||||
file.remove(false);
|
||||
removed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return removed;
|
||||
}
|
||||
|
||||
_getURI(url) {
|
||||
return Services.io.newURI(url);
|
||||
}
|
||||
_notifyCategoryAndObservers(subject, topic, data) {
|
||||
const serviceMarker = "service,";
|
||||
|
||||
// First create observers from the category manager.
|
||||
|
||||
let observers = [];
|
||||
|
||||
for (let { value: contractID } of Services.catMan.enumerateCategory(
|
||||
topic
|
||||
)) {
|
||||
let factoryFunction;
|
||||
if (contractID.substring(0, serviceMarker.length) == serviceMarker) {
|
||||
contractID = contractID.substring(serviceMarker.length);
|
||||
factoryFunction = "getService";
|
||||
} else {
|
||||
factoryFunction = "createInstance";
|
||||
}
|
||||
|
||||
try {
|
||||
let handler = Cc[contractID][factoryFunction]();
|
||||
if (handler) {
|
||||
let observer = handler.QueryInterface(Ci.nsIObserver);
|
||||
observers.push(observer);
|
||||
}
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
// Next enumerate the registered observers.
|
||||
for (let observer of Services.obs.enumerateObservers(topic)) {
|
||||
if (observer instanceof Ci.nsIObserver && !observers.includes(observer)) {
|
||||
observers.push(observer);
|
||||
}
|
||||
}
|
||||
|
||||
observers.forEach(function(observer) {
|
||||
try {
|
||||
observer.observe(subject, topic, data);
|
||||
} catch (e) {}
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
Iterate through one atomic set of pref actions and perform sets/clears as appropriate.
|
||||
All actions performed must modify the relevant pref.
|
||||
*/
|
||||
_applyPrefs(actions) {
|
||||
for (let pref of actions) {
|
||||
if (pref.action == "set") {
|
||||
this._setPref(pref.name, pref.type, pref.value, pref.iid);
|
||||
} else if (pref.action == "clear") {
|
||||
Services.prefs.clearUserPref(pref.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Take in a list of pref changes to make, pushes their current values
|
||||
* onto the restore stack, and makes the changes. When the test
|
||||
* finishes, these changes are reverted.
|
||||
*
|
||||
* |inPrefs| must be an object with up to two properties: "set" and "clear".
|
||||
* pushPrefEnv will set prefs as indicated in |inPrefs.set| and will unset
|
||||
* the prefs indicated in |inPrefs.clear|.
|
||||
*
|
||||
* For example, you might pass |inPrefs| as:
|
||||
*
|
||||
* inPrefs = {'set': [['foo.bar', 2], ['magic.pref', 'baz']],
|
||||
* 'clear': [['clear.this'], ['also.this']] };
|
||||
*
|
||||
* Notice that |set| and |clear| are both an array of arrays. In |set|, each
|
||||
* of the inner arrays must have the form [pref_name, value] or [pref_name,
|
||||
* value, iid]. (The latter form is used for prefs with "complex" values.)
|
||||
*
|
||||
* In |clear|, each inner array should have the form [pref_name].
|
||||
*
|
||||
* If you set the same pref more than once (or both set and clear a pref),
|
||||
* the behavior of this method is undefined.
|
||||
*/
|
||||
pushPrefEnv(inPrefs) {
|
||||
return doPrefEnvOp(() => {
|
||||
let pendingActions = [];
|
||||
let cleanupActions = [];
|
||||
|
||||
for (let [action, prefs] of Object.entries(inPrefs)) {
|
||||
for (let pref of prefs) {
|
||||
let name = pref[0];
|
||||
let value = null;
|
||||
let iid = null;
|
||||
let type = PREF_TYPES[Services.prefs.getPrefType(name)];
|
||||
let originalValue = null;
|
||||
|
||||
if (pref.length == 3) {
|
||||
value = pref[1];
|
||||
iid = pref[2];
|
||||
} else if (pref.length == 2) {
|
||||
value = pref[1];
|
||||
}
|
||||
|
||||
/* If pref is not found or invalid it doesn't exist. */
|
||||
if (type !== "INVALID") {
|
||||
if (
|
||||
(Services.prefs.prefHasUserValue(name) && action == "clear") ||
|
||||
action == "set"
|
||||
) {
|
||||
originalValue = this._getPref(name, type);
|
||||
}
|
||||
} else if (action == "set") {
|
||||
/* name doesn't exist, so 'clear' is pointless */
|
||||
if (iid) {
|
||||
type = "COMPLEX";
|
||||
}
|
||||
}
|
||||
|
||||
if (type === "INVALID") {
|
||||
type = PREF_TYPES[typeof value];
|
||||
}
|
||||
if (type === "INVALID") {
|
||||
throw new Error("Unexpected preference type");
|
||||
}
|
||||
|
||||
pendingActions.push({ action, type, name, value, iid });
|
||||
|
||||
/* Push original preference value or clear into cleanup array */
|
||||
var cleanupTodo = { type, name, value: originalValue, iid };
|
||||
if (originalValue == null) {
|
||||
cleanupTodo.action = "clear";
|
||||
} else {
|
||||
cleanupTodo.action = "set";
|
||||
}
|
||||
cleanupActions.push(cleanupTodo);
|
||||
}
|
||||
}
|
||||
|
||||
prefUndoStack.push(cleanupActions);
|
||||
this._applyPrefs(pendingActions);
|
||||
});
|
||||
}
|
||||
|
||||
async popPrefEnv() {
|
||||
return doPrefEnvOp(() => {
|
||||
let env = prefUndoStack.pop();
|
||||
if (env) {
|
||||
this._applyPrefs(env);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
flushPrefEnv() {
|
||||
while (prefUndoStack.length) {
|
||||
this.popPrefEnv();
|
||||
}
|
||||
}
|
||||
|
||||
_setPref(name, type, value, iid) {
|
||||
switch (type) {
|
||||
case "BOOL":
|
||||
return Services.prefs.setBoolPref(name, value);
|
||||
case "INT":
|
||||
return Services.prefs.setIntPref(name, value);
|
||||
case "CHAR":
|
||||
return Services.prefs.setCharPref(name, value);
|
||||
case "COMPLEX":
|
||||
return Services.prefs.setComplexValue(name, iid, value);
|
||||
}
|
||||
throw new Error(`Unexpected preference type: ${type}`);
|
||||
}
|
||||
|
||||
_getPref(name, type, defaultValue, iid) {
|
||||
switch (type) {
|
||||
case "BOOL":
|
||||
if (defaultValue !== undefined) {
|
||||
return Services.prefs.getBoolPref(name, defaultValue);
|
||||
}
|
||||
return Services.prefs.getBoolPref(name);
|
||||
case "INT":
|
||||
if (defaultValue !== undefined) {
|
||||
return Services.prefs.getIntPref(name, defaultValue);
|
||||
}
|
||||
return Services.prefs.getIntPref(name);
|
||||
case "CHAR":
|
||||
if (defaultValue !== undefined) {
|
||||
return Services.prefs.getCharPref(name, defaultValue);
|
||||
}
|
||||
return Services.prefs.getCharPref(name);
|
||||
case "COMPLEX":
|
||||
return Services.prefs.getComplexValue(name, iid);
|
||||
}
|
||||
throw new Error(`Unexpected preference type: ${type}`);
|
||||
}
|
||||
|
||||
_toggleMuteAudio(aMuted) {
|
||||
let browser = this.browsingContext.top.embedderElement;
|
||||
if (aMuted) {
|
||||
browser.mute();
|
||||
} else {
|
||||
browser.unmute();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* messageManager callback function
|
||||
* This will get requests from our API in the window and process them in chrome for it
|
||||
**/
|
||||
// eslint-disable-next-line complexity
|
||||
receiveMessage(aMessage) {
|
||||
// We explicitly return values in the below code so that this function
|
||||
// doesn't trigger a flurry of warnings about "does not always return
|
||||
// a value".
|
||||
switch (aMessage.name) {
|
||||
case "SPToggleMuteAudio":
|
||||
return this._toggleMuteAudio(aMessage.data.mute);
|
||||
case "PushPrefEnv":
|
||||
return this.pushPrefEnv(aMessage.data);
|
||||
|
||||
case "PopPrefEnv":
|
||||
return this.popPrefEnv();
|
||||
|
||||
case "FlushPrefEnv":
|
||||
return this.flushPrefEnv();
|
||||
|
||||
case "SPPrefService": {
|
||||
let prefs = Services.prefs;
|
||||
let prefType = aMessage.json.prefType.toUpperCase();
|
||||
let { prefName, prefValue, iid, defaultValue } = aMessage.json;
|
||||
|
||||
if (aMessage.json.op == "get") {
|
||||
if (!prefName || !prefType) {
|
||||
throw new SpecialPowersError(
|
||||
"Invalid parameters for get in SPPrefService"
|
||||
);
|
||||
}
|
||||
|
||||
// return null if the pref doesn't exist
|
||||
if (
|
||||
defaultValue === undefined &&
|
||||
prefs.getPrefType(prefName) == prefs.PREF_INVALID
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
return this._getPref(prefName, prefType, defaultValue, iid);
|
||||
} else if (aMessage.json.op == "set") {
|
||||
if (!prefName || !prefType || prefValue === undefined) {
|
||||
throw new SpecialPowersError(
|
||||
"Invalid parameters for set in SPPrefService"
|
||||
);
|
||||
}
|
||||
|
||||
return this._setPref(prefName, prefType, prefValue, iid);
|
||||
} else if (aMessage.json.op == "clear") {
|
||||
if (!prefName) {
|
||||
throw new SpecialPowersError(
|
||||
"Invalid parameters for clear in SPPrefService"
|
||||
);
|
||||
}
|
||||
|
||||
prefs.clearUserPref(prefName);
|
||||
} else {
|
||||
throw new SpecialPowersError("Invalid operation for SPPrefService");
|
||||
}
|
||||
|
||||
return undefined; // See comment at the beginning of this function.
|
||||
}
|
||||
|
||||
case "SPProcessCrashService": {
|
||||
switch (aMessage.json.op) {
|
||||
case "register-observer":
|
||||
this._addProcessCrashObservers();
|
||||
break;
|
||||
case "unregister-observer":
|
||||
this._removeProcessCrashObservers();
|
||||
break;
|
||||
case "delete-crash-dump-files":
|
||||
return this._deleteCrashDumpFiles(aMessage.json.filenames);
|
||||
case "find-crash-dump-files":
|
||||
return this._findCrashDumpFiles(
|
||||
aMessage.json.crashDumpFilesToIgnore
|
||||
);
|
||||
case "delete-pending-crash-dump-files":
|
||||
return this._deletePendingCrashDumpFiles();
|
||||
default:
|
||||
throw new SpecialPowersError(
|
||||
"Invalid operation for SPProcessCrashService"
|
||||
);
|
||||
}
|
||||
return undefined; // See comment at the beginning of this function.
|
||||
}
|
||||
|
||||
case "SPProcessCrashManagerWait": {
|
||||
let promises = aMessage.json.crashIds.map(crashId => {
|
||||
return Services.crashmanager.ensureCrashIsPresent(crashId);
|
||||
});
|
||||
return Promise.all(promises);
|
||||
}
|
||||
|
||||
case "SPPermissionManager": {
|
||||
let msg = aMessage.json;
|
||||
let principal = msg.principal;
|
||||
|
||||
switch (msg.op) {
|
||||
case "add":
|
||||
Services.perms.addFromPrincipal(
|
||||
principal,
|
||||
msg.type,
|
||||
msg.permission,
|
||||
msg.expireType,
|
||||
msg.expireTime
|
||||
);
|
||||
break;
|
||||
case "remove":
|
||||
Services.perms.removeFromPrincipal(principal, msg.type);
|
||||
break;
|
||||
case "has":
|
||||
let hasPerm = Services.perms.testPermissionFromPrincipal(
|
||||
principal,
|
||||
msg.type
|
||||
);
|
||||
return hasPerm == Ci.nsIPermissionManager.ALLOW_ACTION;
|
||||
case "test":
|
||||
let testPerm = Services.perms.testPermissionFromPrincipal(
|
||||
principal,
|
||||
msg.type
|
||||
);
|
||||
return testPerm == msg.value;
|
||||
default:
|
||||
throw new SpecialPowersError(
|
||||
"Invalid operation for SPPermissionManager"
|
||||
);
|
||||
}
|
||||
return undefined; // See comment at the beginning of this function.
|
||||
}
|
||||
|
||||
case "SPSetTestPluginEnabledState": {
|
||||
var plugin = getTestPlugin(aMessage.data.pluginName);
|
||||
if (!plugin) {
|
||||
return undefined;
|
||||
}
|
||||
var oldEnabledState = plugin.enabledState;
|
||||
plugin.enabledState = aMessage.data.newEnabledState;
|
||||
return oldEnabledState;
|
||||
}
|
||||
|
||||
case "SPObserverService": {
|
||||
let topic = aMessage.json.observerTopic;
|
||||
switch (aMessage.json.op) {
|
||||
case "notify":
|
||||
let data = aMessage.json.observerData;
|
||||
Services.obs.notifyObservers(null, topic, data);
|
||||
break;
|
||||
case "add":
|
||||
this._registerObservers._add(topic);
|
||||
break;
|
||||
default:
|
||||
throw new SpecialPowersError(
|
||||
"Invalid operation for SPObserverervice"
|
||||
);
|
||||
}
|
||||
return undefined; // See comment at the beginning of this function.
|
||||
}
|
||||
|
||||
case "SPLoadChromeScript": {
|
||||
let id = aMessage.json.id;
|
||||
let scriptName;
|
||||
|
||||
let jsScript = aMessage.json.function.body;
|
||||
if (aMessage.json.url) {
|
||||
scriptName = aMessage.json.url;
|
||||
} else if (aMessage.json.function) {
|
||||
scriptName =
|
||||
aMessage.json.function.name ||
|
||||
"<loadChromeScript anonymous function>";
|
||||
} else {
|
||||
throw new SpecialPowersError("SPLoadChromeScript: Invalid script");
|
||||
}
|
||||
|
||||
// Setup a chrome sandbox that has access to sendAsyncMessage
|
||||
// and {add,remove}MessageListener in order to communicate with
|
||||
// the mochitest.
|
||||
let sb = new SpecialPowersSandbox(
|
||||
scriptName,
|
||||
data => {
|
||||
this.sendAsyncMessage("Assert", data);
|
||||
},
|
||||
aMessage.data
|
||||
);
|
||||
|
||||
Object.assign(sb.sandbox, {
|
||||
sendAsyncMessage: (name, message) => {
|
||||
this.sendAsyncMessage("SPChromeScriptMessage", {
|
||||
id,
|
||||
name,
|
||||
message,
|
||||
});
|
||||
},
|
||||
addMessageListener: (name, listener) => {
|
||||
this._chromeScriptListeners.push({ id, name, listener });
|
||||
},
|
||||
removeMessageListener: (name, listener) => {
|
||||
let index = this._chromeScriptListeners.findIndex(function(obj) {
|
||||
return (
|
||||
obj.id == id && obj.name == name && obj.listener == listener
|
||||
);
|
||||
});
|
||||
if (index >= 0) {
|
||||
this._chromeScriptListeners.splice(index, 1);
|
||||
}
|
||||
},
|
||||
actorParent: this.manager,
|
||||
});
|
||||
|
||||
// Evaluate the chrome script
|
||||
try {
|
||||
Cu.evalInSandbox(jsScript, sb.sandbox, "1.8", scriptName, 1);
|
||||
} catch (e) {
|
||||
throw new SpecialPowersError(
|
||||
"Error while executing chrome script '" +
|
||||
scriptName +
|
||||
"':\n" +
|
||||
e +
|
||||
"\n" +
|
||||
e.fileName +
|
||||
":" +
|
||||
e.lineNumber
|
||||
);
|
||||
}
|
||||
return undefined; // See comment at the beginning of this function.
|
||||
}
|
||||
|
||||
case "SPChromeScriptMessage": {
|
||||
let id = aMessage.json.id;
|
||||
let name = aMessage.json.name;
|
||||
let message = aMessage.json.message;
|
||||
let result;
|
||||
for (let listener of this._chromeScriptListeners) {
|
||||
if (listener.name == name && listener.id == id) {
|
||||
result = listener.listener(message);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
case "SPImportInMainProcess": {
|
||||
var message = { hadError: false, errorMessage: null };
|
||||
try {
|
||||
ChromeUtils.import(aMessage.data);
|
||||
} catch (e) {
|
||||
message.hadError = true;
|
||||
message.errorMessage = e.toString();
|
||||
}
|
||||
return message;
|
||||
}
|
||||
|
||||
case "SPCleanUpSTSData": {
|
||||
let origin = aMessage.data.origin;
|
||||
let flags = aMessage.data.flags;
|
||||
let uri = Services.io.newURI(origin);
|
||||
let sss = Cc["@mozilla.org/ssservice;1"].getService(
|
||||
Ci.nsISiteSecurityService
|
||||
);
|
||||
sss.resetState(Ci.nsISiteSecurityService.HEADER_HSTS, uri, flags);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
case "SPRequestDumpCoverageCounters": {
|
||||
return PerTestCoverageUtils.afterTest();
|
||||
}
|
||||
|
||||
case "SPRequestResetCoverageCounters": {
|
||||
return PerTestCoverageUtils.beforeTest();
|
||||
}
|
||||
|
||||
case "SPCheckServiceWorkers": {
|
||||
let swm = Cc["@mozilla.org/serviceworkers/manager;1"].getService(
|
||||
Ci.nsIServiceWorkerManager
|
||||
);
|
||||
let regs = swm.getAllRegistrations();
|
||||
|
||||
// XXX This code is shared with specialpowers.js.
|
||||
let workers = new Array(regs.length);
|
||||
for (let i = 0; i < regs.length; ++i) {
|
||||
let { scope, scriptSpec } = regs.queryElementAt(
|
||||
i,
|
||||
Ci.nsIServiceWorkerRegistrationInfo
|
||||
);
|
||||
workers[i] = { scope, scriptSpec };
|
||||
}
|
||||
return { workers };
|
||||
}
|
||||
|
||||
case "SPLoadExtension": {
|
||||
let id = aMessage.data.id;
|
||||
let ext = aMessage.data.ext;
|
||||
let extension = ExtensionTestCommon.generate(ext);
|
||||
|
||||
let resultListener = (...args) => {
|
||||
this.sendAsyncMessage("SPExtensionMessage", {
|
||||
id,
|
||||
type: "testResult",
|
||||
args,
|
||||
});
|
||||
};
|
||||
|
||||
let messageListener = (...args) => {
|
||||
args.shift();
|
||||
this.sendAsyncMessage("SPExtensionMessage", {
|
||||
id,
|
||||
type: "testMessage",
|
||||
args,
|
||||
});
|
||||
};
|
||||
|
||||
// Register pass/fail handlers.
|
||||
extension.on("test-result", resultListener);
|
||||
extension.on("test-eq", resultListener);
|
||||
extension.on("test-log", resultListener);
|
||||
extension.on("test-done", resultListener);
|
||||
|
||||
extension.on("test-message", messageListener);
|
||||
|
||||
this._extensions.set(id, extension);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
case "SPStartupExtension": {
|
||||
let id = aMessage.data.id;
|
||||
// This is either an Extension, or (if useAddonManager is set) a MockExtension.
|
||||
let extension = this._extensions.get(id);
|
||||
extension.on("startup", (eventName, ext) => {
|
||||
if (!ext) {
|
||||
// ext is only set by the "startup" event from Extension.jsm.
|
||||
// Unfortunately ext-backgroundPage.js emits an event with the same
|
||||
// name, but without the extension object as parameter.
|
||||
return;
|
||||
}
|
||||
// ext is always the "real" Extension object, even when "extension"
|
||||
// is a MockExtension.
|
||||
this.sendAsyncMessage("SPExtensionMessage", {
|
||||
id,
|
||||
type: "extensionSetId",
|
||||
args: [ext.id, ext.uuid],
|
||||
});
|
||||
});
|
||||
|
||||
// Make sure the extension passes the packaging checks when
|
||||
// they're run on a bare archive rather than a running instance,
|
||||
// as the add-on manager runs them.
|
||||
let extensionData = new ExtensionData(extension.rootURI);
|
||||
return extensionData
|
||||
.loadManifest()
|
||||
.then(
|
||||
() => {
|
||||
return extensionData.initAllLocales().then(() => {
|
||||
if (extensionData.errors.length) {
|
||||
return Promise.reject("Extension contains packaging errors");
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
},
|
||||
() => {
|
||||
// loadManifest() will throw if we're loading an embedded
|
||||
// extension, so don't worry about locale errors in that
|
||||
// case.
|
||||
}
|
||||
)
|
||||
.then(async () => {
|
||||
// browser tests do not call startup in ExtensionXPCShellUtils or MockExtension,
|
||||
// in that case we have an ID here and we need to set the override.
|
||||
if (extension.id) {
|
||||
await ExtensionTestCommon.setIncognitoOverride(extension);
|
||||
}
|
||||
return extension.startup().then(
|
||||
() => {},
|
||||
e => {
|
||||
dump(`Extension startup failed: ${e}\n${e.stack}`);
|
||||
throw e;
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
case "SPExtensionMessage": {
|
||||
let id = aMessage.data.id;
|
||||
let extension = this._extensions.get(id);
|
||||
extension.testMessage(...aMessage.data.args);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
case "SPUnloadExtension": {
|
||||
let id = aMessage.data.id;
|
||||
let extension = this._extensions.get(id);
|
||||
this._extensions.delete(id);
|
||||
return extension.shutdown().then(() => {
|
||||
return extension._uninstallPromise;
|
||||
});
|
||||
}
|
||||
|
||||
case "Spawn": {
|
||||
let { browsingContext, task, args, caller } = aMessage.data;
|
||||
|
||||
let spParent = browsingContext.currentWindowGlobal.getActor(
|
||||
"SpecialPowers"
|
||||
);
|
||||
|
||||
let taskId = nextTaskID++;
|
||||
spParent._taskActors.set(taskId, this);
|
||||
|
||||
return spParent
|
||||
.sendQuery("Spawn", { task, args, caller, taskId })
|
||||
.finally(() => {
|
||||
spParent._taskActors.delete(taskId);
|
||||
});
|
||||
}
|
||||
|
||||
case "Snapshot": {
|
||||
let { browsingContext, rect, background } = aMessage.data;
|
||||
|
||||
return browsingContext.currentWindowGlobal
|
||||
.drawSnapshot(rect, 1.0, background)
|
||||
.then(async image => {
|
||||
let hiddenFrame = new HiddenFrame();
|
||||
let win = await hiddenFrame.get();
|
||||
|
||||
let canvas = win.document.createElement("canvas");
|
||||
canvas.width = image.width;
|
||||
canvas.height = image.height;
|
||||
|
||||
const ctx = canvas.getContext("2d");
|
||||
ctx.drawImage(image, 0, 0);
|
||||
|
||||
let data = ctx.getImageData(0, 0, image.width, image.height);
|
||||
hiddenFrame.destroy();
|
||||
return data;
|
||||
});
|
||||
}
|
||||
|
||||
case "ProxiedAssert": {
|
||||
let { taskId, data } = aMessage.data;
|
||||
let actor = this._taskActors.get(taskId);
|
||||
|
||||
actor.sendAsyncMessage("Assert", data);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
case "SPRemoveAllServiceWorkers": {
|
||||
return ServiceWorkerCleanUp.removeAll();
|
||||
}
|
||||
|
||||
case "SPRemoveServiceWorkerDataForExampleDomain": {
|
||||
return ServiceWorkerCleanUp.removeFromHost("example.com");
|
||||
}
|
||||
|
||||
case "Wakeup":
|
||||
return undefined;
|
||||
|
||||
default:
|
||||
throw new SpecialPowersError(
|
||||
`Unrecognized Special Powers API: ${aMessage.name}`
|
||||
);
|
||||
}
|
||||
|
||||
// We throw an exception before reaching this explicit return because
|
||||
// we should never be arriving here anyway.
|
||||
throw new SpecialPowersError("Unreached code"); // eslint-disable-line no-unreachable
|
||||
return undefined;
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -19,8 +19,6 @@ FINAL_TARGET_FILES.content += [
|
||||
'content/MockColorPicker.jsm',
|
||||
'content/MockFilePicker.jsm',
|
||||
'content/MockPermissionPrompt.jsm',
|
||||
'content/SpecialPowersAPI.jsm',
|
||||
'content/SpecialPowersAPIParent.jsm',
|
||||
'content/SpecialPowersChild.jsm',
|
||||
'content/SpecialPowersParent.jsm',
|
||||
'content/SpecialPowersSandbox.jsm',
|
||||
|
Loading…
Reference in New Issue
Block a user