Merge mozilla-central to mozilla-inbound

--HG--
extra : rebase_source : 3825f1263f779efcb8dca836b3de0571b536d98e
This commit is contained in:
Daniel Varga 2018-09-08 01:13:18 +03:00
Родитель c4219b4843 bdd611d2ef
Коммит f62c999a8d
52 изменённых файлов: 585 добавлений и 347 удалений

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

@ -119,7 +119,7 @@ tasks:
TASKCLUSTER_CACHES: /builds/worker/checkouts
- $if: 'tasks_for == "action"'
then:
ACTION_TASK_GROUP_ID: '${taskGroupId}' # taskGroupId of the target task
ACTION_TASK_GROUP_ID: '${action.taskGroupId}' # taskGroupId of the target task
ACTION_TASK_ID: {$json: {$eval: 'taskId'}} # taskId of the target task (JSON-encoded)
ACTION_INPUT: {$json: {$eval: 'input'}}
ACTION_CALLBACK: '${action.cb_name}'

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

@ -11,7 +11,7 @@ function hideSelectPopup(selectPopup, mode = "enter", win = window) {
} else if (mode == "enter") {
EventUtils.synthesizeKey("KEY_Enter", {}, win);
} else if (mode == "click") {
EventUtils.synthesizeMouseAtCenter(selectPopup.lastChild, { }, win);
EventUtils.synthesizeMouseAtCenter(selectPopup.lastElementChild, { }, win);
}
return selectClosedPromise;

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

@ -47,6 +47,17 @@ if (Services.appinfo.OS == "WINNT" || Services.appinfo.OS == "Darwin") {
);
}
// We'll assume the changes we are seeing are due to this focus change if
// there are at least 5 areas that changed near the top of the screen, or if
// the toolbar background is involved on OSX, but will only ignore this once.
function isLikelyFocusChange(rects) {
if (rects.length > 5 && rects.every(r => r.y2 < 100))
return true;
if (Services.appinfo.OS == "Darwin" && rects.length == 2 && rects.every(r => r.y1 == 0 && r.h == 33))
return true;
return false;
}
/*
* This test ensures that there are no unexpected
* uninterruptible reflows or flickering areas when opening new windows.
@ -71,11 +82,7 @@ add_task(async function() {
filter(rects, frame, previousFrame) {
// The first screenshot we get in OSX / Windows shows an unfocused browser
// window for some reason. See bug 1445161.
//
// We'll assume the changes we are seeing are due to this focus change if
// there are at least 5 areas that changed near the top of the screen, but
// will only ignore this once (hence the alreadyFocused variable).
if (!alreadyFocused && rects.length > 5 && rects.every(r => r.y2 < 100)) {
if (!alreadyFocused && isLikelyFocusChange(rects)) {
alreadyFocused = true;
todo(false,
"bug 1445161 - the window should be focused at first paint, " +

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

@ -27,7 +27,7 @@ add_task(async function testMainViewVisible() {
await BrowserTestUtils.withNewTab(AUTOPLAY_PAGE, async function() {
let permissionsList = document.getElementById("identity-popup-permission-list");
let emptyLabel = permissionsList.nextSibling.nextSibling;
let emptyLabel = permissionsList.nextElementSibling.nextElementSibling;
ok(BrowserTestUtils.is_hidden(autoplayBlockedIcon()), "Blocked icon not shown");
@ -40,7 +40,7 @@ add_task(async function testMainViewVisible() {
await BrowserTestUtils.withNewTab(AUTOPLAY_PAGE, async function() {
let permissionsList = document.getElementById("identity-popup-permission-list");
let emptyLabel = permissionsList.nextSibling.nextSibling;
let emptyLabel = permissionsList.nextElementSibling.nextElementSibling;
ok(!BrowserTestUtils.is_hidden(autoplayBlockedIcon()), "Blocked icon is shown");

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

@ -289,7 +289,7 @@ function triggerSecondaryCommand(popup, index) {
}
// Extra secondary actions appear in a menu.
notification.secondaryButton.nextSibling.nextSibling.focus();
notification.secondaryButton.nextElementSibling.nextElementSibling.focus();
popup.addEventListener("popupshown", function() {
info("Command popup open for notification " + notification.id);

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

@ -278,7 +278,7 @@ function promisePageActionViewShown() {
}
function promisePageActionViewChildrenVisible(panelViewNode) {
return promiseNodeVisible(panelViewNode.firstChild.firstChild);
return promiseNodeVisible(panelViewNode.firstElementChild.firstElementChild);
}
function promiseNodeVisible(node) {

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

@ -31,7 +31,7 @@ function promisePopupNotificationShown(name) {
ok(PopupNotifications.isPanelOpen, "notification panel open");
PopupNotifications.panel.removeEventListener("popupshown", popupshown);
resolve(PopupNotifications.panel.firstChild);
resolve(PopupNotifications.panel.firstElementChild);
}
PopupNotifications.panel.addEventListener("popupshown", popupshown);

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

@ -298,7 +298,7 @@ function promisePopupNotificationShown(aName, aAction) {
PopupNotifications.panel.addEventListener("popupshown", function() {
ok(!!PopupNotifications.getNotification(aName), aName + " notification shown");
ok(PopupNotifications.isPanelOpen, "notification panel open");
ok(!!PopupNotifications.panel.firstChild, "notification panel populated");
ok(!!PopupNotifications.panel.firstElementChild, "notification panel populated");
executeSoon(resolve);
}, {once: true});
@ -341,7 +341,7 @@ const kActionDeny = 2;
const kActionNever = 3;
function activateSecondaryAction(aAction) {
let notification = PopupNotifications.panel.firstChild;
let notification = PopupNotifications.panel.firstElementChild;
switch (aAction) {
case kActionNever:
notification.checkbox.setAttribute("checked", true); // fallthrough

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

@ -283,7 +283,7 @@ AreaPositionManager.prototype = {
_getVisibleSiblingForDirection(aNode, aDirection) {
let rv = aNode;
do {
rv = rv[aDirection + "Sibling"];
rv = rv[aDirection + "ElementSibling"];
} while (rv && rv.getAttribute("hidden") == "true");
return rv;
},

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

@ -6,6 +6,8 @@ ChromeUtils.defineModuleGetter(this, "CustomizableUI",
"resource:///modules/CustomizableUI.jsm");
ChromeUtils.defineModuleGetter(this, "clearTimeout",
"resource://gre/modules/Timer.jsm");
ChromeUtils.defineModuleGetter(this, "ExtensionTelemetry",
"resource://gre/modules/ExtensionTelemetry.jsm");
ChromeUtils.defineModuleGetter(this, "setTimeout",
"resource://gre/modules/Timer.jsm");
ChromeUtils.defineModuleGetter(this, "ViewPopup",
@ -14,7 +16,6 @@ ChromeUtils.defineModuleGetter(this, "ViewPopup",
var {
DefaultWeakMap,
ExtensionError,
ExtensionTelemetry,
} = ExtensionUtils;
ChromeUtils.import("resource://gre/modules/ExtensionParent.jsm");

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

@ -2,6 +2,8 @@
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
ChromeUtils.defineModuleGetter(this, "ExtensionTelemetry",
"resource://gre/modules/ExtensionTelemetry.jsm");
ChromeUtils.defineModuleGetter(this, "PageActions",
"resource:///modules/PageActions.jsm");
ChromeUtils.defineModuleGetter(this, "PanelPopup",
@ -16,7 +18,6 @@ var {
var {
DefaultWeakMap,
ExtensionTelemetry,
} = ExtensionUtils;
// WeakMap[Extension -> PageAction]

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

@ -79,6 +79,7 @@ skip-if = (verify && (os == 'linux' || os == 'mac'))
[browser_ext_commands_update.js]
[browser_ext_connect_and_move_tabs.js]
[browser_ext_contentscript_connect.js]
[browser_ext_contentscript_nontab_connect.js]
[browser_ext_contextMenus.js]
[browser_ext_contextMenus_checkboxes.js]
[browser_ext_contextMenus_commands.js]

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

@ -0,0 +1,107 @@
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
// This script is loaded in a non-tab extension context, and starts the test by
// loading an iframe that runs contentScript as a content script.
function extensionScript() {
let FRAME_URL = browser.runtime.getManifest().content_scripts[0].matches[0];
// Cannot use :8888 in the manifest because of bug 1468162.
FRAME_URL = FRAME_URL.replace("mochi.test", "mochi.test:8888");
browser.runtime.onConnect.addListener((port) => {
browser.test.assertEq(port.sender.tab, undefined, "Sender is not a tab");
browser.test.assertEq(port.sender.url, FRAME_URL, "Expected sender URL");
port.onMessage.addListener(msg => {
browser.test.assertEq("pong", msg, "Reply from content script");
port.disconnect();
});
port.postMessage("ping");
});
browser.test.log(`Going to open ${FRAME_URL} at ${location.pathname}`);
let f = document.createElement("iframe");
f.src = FRAME_URL;
document.body.appendChild(f);
}
function contentScript() {
browser.test.log(`Running content script at ${document.URL}`);
let port = browser.runtime.connect();
port.onMessage.addListener(msg => {
browser.test.assertEq("ping", msg, "Expected message to content script");
port.postMessage("pong");
});
port.onDisconnect.addListener(() => {
browser.test.sendMessage("disconnected_in_content_script");
});
}
add_task(async function connect_from_background_frame() {
let extension = ExtensionTestUtils.loadExtension({
manifest: {
content_scripts: [{
matches: ["http://mochi.test/?background"],
js: ["contentscript.js"],
all_frames: true,
}],
},
files: {
"contentscript.js": contentScript,
},
background: extensionScript,
});
await extension.startup();
await extension.awaitMessage("disconnected_in_content_script");
await extension.unload();
});
add_task(async function connect_from_sidebar_panel() {
let extension = ExtensionTestUtils.loadExtension({
useAddonManager: "temporary", // To automatically show sidebar on load.
manifest: {
content_scripts: [{
matches: ["http://mochi.test/?sidebar"],
js: ["contentscript.js"],
all_frames: true,
}],
sidebar_action: {
default_panel: "sidebar.html",
},
},
files: {
"contentscript.js": contentScript,
"sidebar.html": `<!DOCTYPE html><meta charset="utf-8"><body><script src="sidebar.js"></script></body>`,
"sidebar.js": extensionScript,
},
});
await extension.startup();
await extension.awaitMessage("disconnected_in_content_script");
await extension.unload();
});
add_task(async function connect_from_browser_action_popup() {
let extension = ExtensionTestUtils.loadExtension({
manifest: {
content_scripts: [{
matches: ["http://mochi.test/?browser_action_popup"],
js: ["contentscript.js"],
all_frames: true,
}],
browser_action: {
default_popup: "popup.html",
},
},
files: {
"contentscript.js": contentScript,
"popup.html": `<!DOCTYPE html><meta charset="utf-8"><body><script src="popup.js"></script></body>`,
"popup.js": extensionScript,
},
});
await extension.startup();
await clickBrowserAction(extension);
await extension.awaitMessage("disconnected_in_content_script");
await closeBrowserAction(extension);
await extension.unload();
});

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

@ -398,7 +398,7 @@ async function openChromeContextMenu(menuId, target, win = window) {
}
async function openSubmenu(submenuItem, win = window) {
const submenu = submenuItem.firstChild;
const submenu = submenuItem.firstElementChild;
const shown = BrowserTestUtils.waitForEvent(submenu, "popupshown");
EventUtils.synthesizeMouseAtCenter(submenuItem, {}, win);
await shown;

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

@ -26,28 +26,32 @@ add_task(async function test() {
// Step 1
let non_private_browser = gBrowser.selectedBrowser;
non_private_browser.loadURI(prefix + "?action=set&name=test&value=value&initial=true");
await BrowserTestUtils.browserLoaded(non_private_browser);
let url = prefix + "?action=set&name=test&value=value&initial=true";
non_private_browser.loadURI(url);
await BrowserTestUtils.browserLoaded(non_private_browser, false, url);
// Step 2
let private_window = await BrowserTestUtils.openNewBrowserWindow({ private: true });
let private_browser = private_window.getBrowser().selectedBrowser;
private_browser.loadURI(prefix + "?action=set&name=test2&value=value2");
await BrowserTestUtils.browserLoaded(private_browser);
url = prefix + "?action=set&name=test2&value=value2";
private_browser.loadURI(url);
await BrowserTestUtils.browserLoaded(private_browser, false, url);
// Step 3
non_private_browser.loadURI(prefix + "?action=get&name=test2");
await BrowserTestUtils.browserLoaded(non_private_browser);
url = prefix + "?action=get&name=test2";
non_private_browser.loadURI(url);
await BrowserTestUtils.browserLoaded(non_private_browser, false, url);
let elts = await getElts(non_private_browser);
isnot(elts[0], "value2", "public window shouldn't see private storage");
is(elts[1], "1", "public window should only see public items");
// Step 4
private_browser.loadURI(prefix + "?action=get&name=test");
await BrowserTestUtils.browserLoaded(private_browser);
url = prefix + "?action=get&name=test";
private_browser.loadURI(url);
await BrowserTestUtils.browserLoaded(private_browser, false, url);
elts = await getElts(private_browser);
isnot(elts[0], "value", "private window shouldn't see public storage");
is(elts[1], "1", "private window should only see private items");
@ -61,8 +65,9 @@ add_task(async function test() {
await new Promise(resolve => Cu.schedulePreciseGC(resolve));
private_browser = private_window.getBrowser().selectedBrowser;
private_browser.loadURI(prefix + "?action=get&name=test2");
await BrowserTestUtils.browserLoaded(private_browser, false, prefix + "?action=get&name=test2");
url = prefix + "?action=get&name=test2";
private_browser.loadURI(url);
await BrowserTestUtils.browserLoaded(private_browser, false, url);
elts = await getElts(private_browser);
isnot(elts[0], "value2", "public window shouldn't see cleared private storage");
is(elts[1], "1", "public window should only see public items");
@ -76,13 +81,15 @@ add_task(async function test() {
await new Promise(resolve => Cu.schedulePreciseGC(resolve));
private_browser = private_window.getBrowser().selectedBrowser;
private_browser.loadURI(prefix + "?action=set&name=test3&value=value3");
await BrowserTestUtils.browserLoaded(private_browser);
url = prefix + "?action=set&name=test3&value=value3";
private_browser.loadURI(url);
await BrowserTestUtils.browserLoaded(private_browser, false, url);
elts = await getElts(private_browser);
is(elts[1], "1", "private window should only see new private items");
// Cleanup.
non_private_browser.loadURI(prefix + "?final=true");
await BrowserTestUtils.browserLoaded(non_private_browser);
url = prefix + "?final=true";
non_private_browser.loadURI(url);
await BrowserTestUtils.browserLoaded(non_private_browser, false, url);
private_window.close();
});

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

@ -56,8 +56,8 @@ function promisePageActionViewChildrenVisible(panelViewNode) {
info("promisePageActionViewChildrenVisible waiting for a child node to be visible");
let dwu = window.windowUtils;
return BrowserTestUtils.waitForCondition(() => {
let bodyNode = panelViewNode.firstChild;
for (let childNode of bodyNode.childNodes) {
let bodyNode = panelViewNode.firstElementChild;
for (let childNode of bodyNode.children) {
let bounds = dwu.getBoundsWithoutFlushing(childNode);
if (bounds.width > 0 && bounds.height > 0) {
return true;

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

@ -18,12 +18,12 @@ body:not([lwt-sidebar]) .content-container {
font-size: 12px;
}
.item.selected > .item-title-container {
body:not([lwt-sidebar]) .item.selected > .item-title-container {
-moz-appearance: -moz-mac-source-list-selection;
-moz-font-smoothing-background-color: -moz-mac-source-list-selection;
}
.item.selected:focus > .item-title-container {
body:not([lwt-sidebar-highlight]) .item.selected:focus > .item-title-container {
-moz-appearance: -moz-mac-active-source-list-selection;
-moz-font-smoothing-background-color: -moz-mac-active-source-list-selection;
}

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

@ -196,7 +196,6 @@ body {
.sync-state > p {
padding-inline-end: 10px;
padding-inline-start: 10px;
color: #888;
}
.text-link {
@ -255,6 +254,11 @@ body {
margin: 0 auto;
}
body[lwt-sidebar] .deck .instructions {
color: inherit;
opacity: .6;
}
.deck .button {
display: block;
background-color: #0060df;
@ -309,12 +313,10 @@ body[lwt-sidebar] .item.selected > .item-title-container {
}
body[lwt-sidebar-brighttext] .item.selected > .item-title-container {
-moz-appearance: none;
background-color: rgba(249,249,250,.1);
}
body[lwt-sidebar-highlight] .item.selected:focus > .item-title-container {
-moz-appearance: none;
background-color: var(--lwt-sidebar-highlight-background-color);
color: var(--lwt-sidebar-highlight-text-color);
}

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

@ -24,11 +24,11 @@ add_task(async function() {
ok(pageMenuSep && !pageMenuSep.hidden,
"Page menu separator should be shown");
let testMenuSep = pageMenuSep.previousSibling;
let testMenuSep = pageMenuSep.previousElementSibling;
ok(testMenuSep && !testMenuSep.hidden,
"User-added menu separator should be shown");
let testMenuItem = testMenuSep.previousSibling;
let testMenuItem = testMenuSep.previousElementSibling;
is(testMenuItem.label, "Test Context Menu Click", "Got context menu item");
let promiseCtxMenuClick = ContentTask.spawn(aBrowser, null, async function() {

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

@ -834,7 +834,8 @@ ParticularProcessPriorityManager::CurrentPriority()
ProcessPriority
ParticularProcessPriorityManager::ComputePriority()
{
if (!mActiveTabParents.IsEmpty()) {
if (!mActiveTabParents.IsEmpty() ||
mContentParent->GetRemoteType().EqualsLiteral(EXTENSION_REMOTE_TYPE)) {
return PROCESS_PRIORITY_FOREGROUND;
}

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

@ -118,7 +118,7 @@ add_task(async function test_register() {
// Cancel the request.
ok(active, "request should still be active");
PopupNotifications.panel.firstChild.button.click();
PopupNotifications.panel.firstElementChild.button.click();
await request;
// Close tab.
@ -139,7 +139,7 @@ add_task(async function test_sign() {
// Cancel the request.
ok(active, "request should still be active");
PopupNotifications.panel.firstChild.button.click();
PopupNotifications.panel.firstElementChild.button.click();
await request;
// Close tab.
@ -159,7 +159,7 @@ add_task(async function test_register_direct_cancel() {
// Cancel the request.
ok(active, "request should still be active");
PopupNotifications.panel.firstChild.secondaryButton.click();
PopupNotifications.panel.firstElementChild.secondaryButton.click();
await promise;
// Close tab.
@ -186,7 +186,7 @@ add_task(async function test_register_direct_proceed() {
await promiseNotification("webauthn-prompt-register-direct");
// Proceed.
PopupNotifications.panel.firstChild.button.click();
PopupNotifications.panel.firstElementChild.button.click();
// Ensure we got "direct" attestation.
await request.then(verifyDirectCertificate);
@ -204,8 +204,8 @@ add_task(async function test_register_direct_proceed_anon() {
await promiseNotification("webauthn-prompt-register-direct");
// Check "anonymize anyway" and proceed.
PopupNotifications.panel.firstChild.checkbox.checked = true;
PopupNotifications.panel.firstChild.button.click();
PopupNotifications.panel.firstElementChild.checkbox.checked = true;
PopupNotifications.panel.firstElementChild.button.click();
// Ensure we got "none" attestation.
await request.then(verifyAnonymizedCertificate);

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

@ -531,13 +531,13 @@ typedef int64_t (*Prototype_General7)(int64_t arg0, int64_t arg1, int64_t arg2,
int64_t arg4, int64_t arg5, int64_t arg6);
typedef int64_t (*Prototype_General8)(int64_t arg0, int64_t arg1, int64_t arg2, int64_t arg3,
int64_t arg4, int64_t arg5, int64_t arg6, int64_t arg7);
typedef int64_t (*Prototype_GeneralGeneralGeneralInt64)(int64_t arg0, int32_t arg1, int32_t arg2,
typedef int64_t (*Prototype_GeneralGeneralGeneralInt64)(int64_t arg0, int64_t arg1, int64_t arg2,
int64_t arg3);
typedef int64_t (*Prototype_GeneralGeneralInt64Int64)(int64_t arg0, int32_t arg1, int64_t arg2,
typedef int64_t (*Prototype_GeneralGeneralInt64Int64)(int64_t arg0, int64_t arg1, int64_t arg2,
int64_t arg3);
typedef int64_t (*Prototype_Int_Double)(double arg0);
typedef int64_t (*Prototype_Int_IntDouble)(int32_t arg0, double arg1);
typedef int64_t (*Prototype_Int_IntDouble)(int64_t arg0, double arg1);
typedef int64_t (*Prototype_Int_DoubleIntInt)(double arg0, uint64_t arg1, uint64_t arg2);
typedef int64_t (*Prototype_Int_IntDoubleIntInt)(uint64_t arg0, double arg1,
uint64_t arg2, uint64_t arg3);
@ -547,7 +547,7 @@ typedef float (*Prototype_Float32_Float32Float32)(float arg0, float arg1);
typedef double (*Prototype_Double_None)();
typedef double (*Prototype_Double_Double)(double arg0);
typedef double (*Prototype_Double_Int)(int32_t arg0);
typedef double (*Prototype_Double_Int)(int64_t arg0);
typedef double (*Prototype_Double_DoubleInt)(double arg0, int64_t arg1);
typedef double (*Prototype_Double_IntDouble)(int64_t arg0, double arg1);
typedef double (*Prototype_Double_DoubleDouble)(double arg0, double arg1);

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

@ -4526,6 +4526,12 @@ ScrollFrameHelper::FireScrollPortEvent()
nsSize scrollportSize = mScrollPort.Size();
nsSize childSize = GetScrolledRect().Size();
// TODO(emilio): why do we need the whole WillPaintObserver infrastructure and
// can't use AddScriptRunner & co? I guess it made sense when we used
// WillPaintObserver for scroll events too, or when this used to flush.
//
// Should we remove this?
bool newVerticalOverflow = childSize.height > scrollportSize.height;
bool vertChanged = mVerticalOverflow != newVerticalOverflow;
@ -5087,10 +5093,6 @@ ScrollFrameHelper::PostScrollEvent()
NS_IMETHODIMP
ScrollFrameHelper::AsyncScrollPortEvent::Run()
{
if (mHelper) {
mHelper->mOuter->PresContext()->Document()->
FlushPendingNotifications(FlushType::InterruptibleLayout);
}
return mHelper ? mHelper->FireScrollPortEvent() : NS_OK;
}

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

@ -27,6 +27,7 @@ import org.mozilla.gecko.GeckoActivityMonitor;
import org.mozilla.gecko.GeckoAppShell;
import org.mozilla.gecko.R;
import org.mozilla.gecko.mozglue.SafeIntent;
import org.mozilla.gecko.updater.UpdateServiceHelper;
import org.mozilla.gecko.util.BitmapUtils;
import org.mozilla.gecko.util.BundleEventListener;
import org.mozilla.gecko.util.EventCallback;
@ -38,6 +39,7 @@ import java.io.File;
import java.io.UnsupportedEncodingException;
import java.net.URLConnection;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
@ -118,7 +120,10 @@ public final class NotificationHelper implements BundleEventListener {
// Holds the mapping between the Channel enum used by the rest of our codebase and the
// channel ID used for communication with the system NotificationManager.
private final Map<Channel, String> mDefinedNotificationChannels = new HashMap<Channel, String>(7) {{
// How to determine the initialCapacity: Count all channels (including the Updater, which is
// only added further down in initNotificationChannels), multiply by 4/3 for a maximum load
// factor of 75 % and round up to the next multiple of two.
private final Map<Channel, String> mDefinedNotificationChannels = new HashMap<Channel, String>(16) {{
final String DEFAULT_CHANNEL_TAG = "default2-notification-channel";
put(Channel.DEFAULT, DEFAULT_CHANNEL_TAG);
@ -136,20 +141,15 @@ public final class NotificationHelper implements BundleEventListener {
put(Channel.LP_DEFAULT, LP_DEFAULT_CHANNEL_TAG);
}
if (AppConstants.MOZ_UPDATER) {
final String UPDATER_CHANNEL_TAG = "updater-notification-channel";
put(Channel.UPDATER, UPDATER_CHANNEL_TAG);
}
final String SYNCED_TABS_CHANNEL_TAG = "synced-tabs-notification-channel";
put(Channel.SYNCED_TABS, SYNCED_TABS_CHANNEL_TAG);
}};
// These are channels we no longer require and want to retire from Android's settings UI.
private final List<String> mDeprecatedNotificationChannels = Arrays.asList(
private final List<String> mDeprecatedNotificationChannels = new ArrayList<>(Arrays.asList(
"default-notification-channel",
null
);
));
// Holds a list of notifications that should be cleared if the Fennec Activity is shut down.
// Will not include ongoing or persistent notifications that are tied to Gecko's lifecycle.
@ -192,6 +192,13 @@ public final class NotificationHelper implements BundleEventListener {
}
private void initNotificationChannels() {
final String UPDATER_CHANNEL_TAG = "updater-notification-channel";
if (UpdateServiceHelper.isUpdaterEnabled(mContext)) {
mDefinedNotificationChannels.put(Channel.UPDATER, UPDATER_CHANNEL_TAG);
} else {
mDeprecatedNotificationChannels.add(UPDATER_CHANNEL_TAG);
}
final NotificationManager notificationManager =
(NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);

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

@ -2797,7 +2797,12 @@ ServerHandler.prototype =
// getting the line number where we evaluate the SJS file. Don't
// separate these two lines!
var line = new Error().lineNumber;
Cu.evalInSandbox(sis.read(file.fileSize), s, "latest");
let uri = Cc["@mozilla.org/network/io-service;1"]
.getService(Ci.nsIIOService)
.newFileURI(file);
let scriptLoader = Cc["@mozilla.org/moz/jssubscript-loader;1"]
.getService(Ci.mozIJSSubScriptLoader);
scriptLoader.loadSubScript(uri.spec, s);
}
catch (e)
{

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

@ -25,6 +25,7 @@ job-defaults:
default: scriptworker-prov-v1/treescript-dev
worker:
implementation: treescript
dontbuild: true
tags: ['release']
bump: true
bump-files:

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

@ -17,35 +17,32 @@ from subprocess import CalledProcessError
from mozbuild.util import memoize
logger = logging.getLogger(__name__)
_cache = {}
@memoize
def get_changed_files(repository, revision):
"""
Get the set of files changed in the push headed by the given revision.
Responses are cached, so multiple calls with the same arguments are OK.
"""
key = repository, revision
if key not in _cache:
url = '%s/json-automationrelevance/%s' % (repository.rstrip('/'), revision)
logger.debug("Querying version control for metadata: %s", url)
url = '%s/json-automationrelevance/%s' % (repository.rstrip('/'), revision)
logger.debug("Querying version control for metadata: %s", url)
def get_automationrelevance():
response = requests.get(url, timeout=5)
return response.json()
contents = retry(get_automationrelevance, attempts=10, sleeptime=10)
def get_automationrelevance():
response = requests.get(url, timeout=5)
return response.json()
contents = retry(get_automationrelevance, attempts=10, sleeptime=10)
logger.debug('{} commits influencing task scheduling:'
.format(len(contents['changesets'])))
changed_files = set()
for c in contents['changesets']:
logger.debug(" {cset} {desc}".format(
cset=c['node'][0:12],
desc=c['desc'].splitlines()[0].encode('ascii', 'ignore')))
changed_files |= set(c['files'])
logger.debug('{} commits influencing task scheduling:'
.format(len(contents['changesets'])))
changed_files = set()
for c in contents['changesets']:
logger.debug(" {cset} {desc}".format(
cset=c['node'][0:12],
desc=c['desc'].splitlines()[0].encode('ascii', 'ignore')))
changed_files |= set(c['files'])
_cache[key] = changed_files
return _cache[key]
return changed_files
def check(params, file_patterns):

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

@ -558,7 +558,7 @@ Tester.prototype = {
// Remove stale tabs
if (this.currentTest && window.gBrowser && gBrowser.tabs.length > 1) {
while (gBrowser.tabs.length > 1) {
let lastTab = gBrowser.tabContainer.lastChild;
let lastTab = gBrowser.tabContainer.lastElementChild;
if (!lastTab.closing) {
// Report the stale tab as an error only when they're not closing.
// Tests can finish without waiting for the closing tabs.

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

@ -35,6 +35,9 @@ from mozharness.base.python import Python3Virtualenv
from mozharness.mozilla.testing.testbase import TestingMixin
from mozharness.base.vcs.vcsbase import MercurialScript
# import mozharness write_autoconfig_files
from mozharness.mozilla.firefox.autoconfig import write_autoconfig_files
raptor_dir = os.path.join(here, '..')
sys.path.insert(0, raptor_dir)
@ -58,7 +61,7 @@ except Exception:
DEFAULT_CERT_PATH = os.path.join(os.getenv('HOMEDRIVE'), os.getenv('HOMEPATH'),
'.mitmproxy', 'mitmproxy-ca-cert.cer')
MITMPROXY_SETTINGS = '''// Start with a comment
MITMPROXY_ON_SETTINGS = '''// Start with a comment
// Load up mitmproxy cert
var certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(Ci.nsIX509CertDB);
var certdb2 = certdb;
@ -79,6 +82,11 @@ pref("network.proxy.ssl", "127.0.0.1");
pref("network.proxy.ssl_port", 8080);
'''
MITMPROXY_OFF_SETTINGS = '''// Start with a comment
// Turn off proxy
pref("network.proxy.type", 0);
'''
class Mitmproxy(Playback, Python3Virtualenv, TestingMixin, MercurialScript):
@ -191,13 +199,8 @@ class Mitmproxy(Playback, Python3Virtualenv, TestingMixin, MercurialScript):
def setup(self):
# install the generated CA certificate into Firefox
# mitmproxy cert setup needs path to mozharness install; mozharness has set this
# value in the SCRIPTSPATH env var for us in mozharness/mozilla/testing/talos.py
scripts_path = os.environ.get('SCRIPTSPATH')
LOG.info('scripts_path: %s' % str(scripts_path))
self.install_mitmproxy_cert(self.mitmproxy_proc,
self.browser_path,
str(scripts_path))
self.browser_path)
return
def start(self):
@ -214,20 +217,15 @@ class Mitmproxy(Playback, Python3Virtualenv, TestingMixin, MercurialScript):
def stop(self):
self.stop_mitmproxy_playback()
self.turn_off_browser_proxy()
return
def configure_mitmproxy(self,
fx_install_dir,
scripts_path,
certificate_path=DEFAULT_CERT_PATH):
# scripts_path is path to mozharness on test machine; needed so can import
if scripts_path is not False:
sys.path.insert(1, scripts_path)
sys.path.insert(1, os.path.join(scripts_path, 'mozharness'))
from mozharness.mozilla.firefox.autoconfig import write_autoconfig_files
certificate = self._read_certificate(certificate_path)
write_autoconfig_files(fx_install_dir=fx_install_dir,
cfg_contents=MITMPROXY_SETTINGS % {
cfg_contents=MITMPROXY_ON_SETTINGS % {
'cert': certificate})
def _read_certificate(self, certificate_path):
@ -245,7 +243,7 @@ class Mitmproxy(Playback, Python3Virtualenv, TestingMixin, MercurialScript):
# read autoconfig file, confirm mitmproxy cert is in there
certificate = self._read_certificate(DEFAULT_CERT_PATH)
contents = read_autoconfig_file(browser_install)
if (MITMPROXY_SETTINGS % {'cert': certificate}) in contents:
if (MITMPROXY_ON_SETTINGS % {'cert': certificate}) in contents:
LOG.info("Verified mitmproxy CA certificate is installed in Firefox")
else:
LOG.info("Firefox autoconfig file contents:")
@ -256,19 +254,19 @@ class Mitmproxy(Playback, Python3Virtualenv, TestingMixin, MercurialScript):
return False
return True
def install_mitmproxy_cert(self, mitmproxy_proc, browser_path, scripts_path):
def install_mitmproxy_cert(self, mitmproxy_proc, browser_path):
"""Install the CA certificate generated by mitmproxy, into Firefox"""
LOG.info("Installing mitmxproxy CA certficate into Firefox")
# browser_path is exe, we want install dir
browser_install = os.path.dirname(browser_path)
self.browser_install = os.path.dirname(browser_path)
# on macosx we need to remove the last folders 'Content/MacOS'
if mozinfo.os == 'mac':
browser_install = browser_install[:-14]
self.browser_install = self.browser_install[:-14]
LOG.info('Calling configure_mitmproxy with browser folder: %s' % browser_install)
self.configure_mitmproxy(browser_install, scripts_path)
LOG.info('Calling configure_mitmproxy with browser folder: %s' % self.browser_install)
self.configure_mitmproxy(self.browser_install)
# cannot continue if failed to add CA cert to Firefox, need to check
if not self.is_mitmproxy_cert_installed(browser_install):
if not self.is_mitmproxy_cert_installed(self.browser_install):
LOG.error('Aborting: failed to install mitmproxy CA cert into Firefox')
self.stop_mitmproxy_playback(mitmproxy_proc)
sys.exit()
@ -342,3 +340,10 @@ class Mitmproxy(Playback, Python3Virtualenv, TestingMixin, MercurialScript):
LOG.info(str(status))
else:
LOG.info("Successfully killed the mitmproxy playback process")
def turn_off_browser_proxy(self):
"""Turn off the browser proxy that was used for mitmproxy playback"""
LOG.info("Turning off the browser proxy")
write_autoconfig_files(fx_install_dir=self.browser_install,
cfg_contents=MITMPROXY_OFF_SETTINGS)

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

@ -45,6 +45,7 @@ XPCOMUtils.defineLazyModuleGetters(this, {
ExtensionPermissions: "resource://gre/modules/ExtensionPermissions.jsm",
ExtensionStorage: "resource://gre/modules/ExtensionStorage.jsm",
ExtensionStorageIDB: "resource://gre/modules/ExtensionStorageIDB.jsm",
ExtensionTelemetry: "resource://gre/modules/ExtensionTelemetry.jsm",
ExtensionTestCommon: "resource://testing-common/ExtensionTestCommon.jsm",
FileSource: "resource://gre/modules/L10nRegistry.jsm",
L10nRegistry: "resource://gre/modules/L10nRegistry.jsm",
@ -98,7 +99,6 @@ var {
const {
getUniqueId,
promiseTimeout,
ExtensionTelemetry,
} = ExtensionUtils;
const {

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

@ -13,6 +13,7 @@ ChromeUtils.import("resource://gre/modules/Services.jsm");
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetters(this, {
ExtensionTelemetry: "resource://gre/modules/ExtensionTelemetry.jsm",
LanguageDetector: "resource:///modules/translation/LanguageDetector.jsm",
MessageChannel: "resource://gre/modules/MessageChannel.jsm",
Schemas: "resource://gre/modules/Schemas.jsm",
@ -41,7 +42,6 @@ XPCOMUtils.defineLazyGlobalGetters(this, ["crypto", "TextEncoder"]);
const {
DefaultMap,
DefaultWeakMap,
ExtensionTelemetry,
getInnerWindowID,
getWinUtils,
promiseDocumentIdle,

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

@ -481,6 +481,15 @@ ProxyMessenger = {
return {messageManager: browser.messageManager, xulBrowser: browser};
}
// port.postMessage / port.disconnect to non-tab contexts.
if (recipient.envType === "content_child") {
let childId = `${recipient.extensionId}.${recipient.contextId}`;
let context = ParentAPIManager.proxyContexts.get(childId);
if (context) {
return {messageManager: context.parentMessageManager, xulBrowser: context.xulBrowser};
}
}
// runtime.sendMessage / runtime.connect
let extension = GlobalManager.extensionMap.get(recipient.extensionId);
if (extension) {

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

@ -8,11 +8,11 @@ this.EXPORTED_SYMBOLS = ["ExtensionStorageIDB"];
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
ChromeUtils.import("resource://gre/modules/IndexedDB.jsm");
ChromeUtils.import("resource://gre/modules/ExtensionUtils.jsm");
XPCOMUtils.defineLazyModuleGetters(this, {
ContextualIdentityService: "resource://gre/modules/ContextualIdentityService.jsm",
ExtensionStorage: "resource://gre/modules/ExtensionStorage.jsm",
getTrimmedString: "resource://gre/modules/ExtensionTelemetry.jsm",
Services: "resource://gre/modules/Services.jsm",
OS: "resource://gre/modules/osfile.jsm",
});
@ -24,10 +24,6 @@ XPCOMUtils.defineLazyGetter(this, "WEBEXT_STORAGE_USER_CONTEXT_ID", () => {
"userContextIdInternal.webextStorageLocal").userContextId;
});
var {
getTrimmedString,
} = ExtensionUtils;
const IDB_NAME = "webExtensions-storage-local";
const IDB_DATA_STORENAME = "storage-local-data";
const IDB_VERSION = 1;

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

@ -0,0 +1,180 @@
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
/* 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 = ["ExtensionTelemetry", "getTrimmedString"];
ChromeUtils.defineModuleGetter(this, "Services",
"resource://gre/modules/Services.jsm");
ChromeUtils.defineModuleGetter(this, "TelemetryStopwatch",
"resource://gre/modules/TelemetryStopwatch.jsm");
// Map of the base histogram ids for the metrics recorded for the extensions.
const histograms = {
"extensionStartup": "WEBEXT_EXTENSION_STARTUP_MS",
"backgroundPageLoad": "WEBEXT_BACKGROUND_PAGE_LOAD_MS",
"browserActionPopupOpen": "WEBEXT_BROWSERACTION_POPUP_OPEN_MS",
"browserActionPreloadResult": "WEBEXT_BROWSERACTION_POPUP_PRELOAD_RESULT_COUNT",
"contentScriptInjection": "WEBEXT_CONTENT_SCRIPT_INJECTION_MS",
"pageActionPopupOpen": "WEBEXT_PAGEACTION_POPUP_OPEN_MS",
"storageLocalGetJSON": "WEBEXT_STORAGE_LOCAL_GET_MS",
"storageLocalSetJSON": "WEBEXT_STORAGE_LOCAL_SET_MS",
"storageLocalGetIDB": "WEBEXT_STORAGE_LOCAL_IDB_GET_MS",
"storageLocalSetIDB": "WEBEXT_STORAGE_LOCAL_IDB_SET_MS",
};
/**
* Get a trimmed version of the given string if it is longer than 80 chars (used in telemetry
* when a string may be longer than allowed).
*
* @param {string} str
* The original string content.
*
* @returns {string}
* The trimmed version of the string when longer than 80 chars, or the given string
* unmodified otherwise.
*/
function getTrimmedString(str) {
if (str.length <= 80) {
return str;
}
const length = str.length;
// Trim the string to prevent a flood of warnings messages logged internally by recordEvent,
// the trimmed version is going to be composed by the first 40 chars and the last 37 and 3 dots
// that joins the two parts, to visually indicate that the string has been trimmed.
return `${str.slice(0, 40)}...${str.slice(length - 37, length)}`;
}
/**
* This is a internal helper object which contains a collection of helpers used to make it easier
* to collect extension telemetry (in both the general histogram and in the one keyed by addon id).
*
* This helper object is not exported from ExtensionUtils, it is used by the ExtensionTelemetry
* Proxy which is exported and used by the callers to record telemetry data for one of the
* supported metrics.
*/
class ExtensionTelemetryMetric {
constructor(metric) {
this.metric = metric;
}
// Stopwatch methods.
stopwatchStart(extension, obj = extension) {
this._wrappedStopwatchMethod("start", this.metric, extension, obj);
}
stopwatchFinish(extension, obj = extension) {
this._wrappedStopwatchMethod("finish", this.metric, extension, obj);
}
stopwatchCancel(extension, obj = extension) {
this._wrappedStopwatchMethod("cancel", this.metric, extension, obj);
}
// Histogram counters methods.
histogramAdd(opts) {
this._histogramAdd(this.metric, opts);
}
/**
* Wraps a call to a TelemetryStopwatch method for a given metric and extension.
*
* @param {string} method
* The stopwatch method to call ("start", "finish" or "cancel").
* @param {string} metric
* The stopwatch metric to record (used to retrieve the base histogram id from the _histogram object).
* @param {Extension | BrowserExtensionContent} extension
* The extension to record the telemetry for.
* @param {any | undefined} [obj = extension]
* An optional telemetry stopwatch object (which defaults to the extension parameter when missing).
*/
_wrappedStopwatchMethod(method, metric, extension, obj = extension) {
if (!extension) {
throw new Error(`Mandatory extension parameter is undefined`);
}
const baseId = histograms[metric];
if (!baseId) {
throw new Error(`Unknown metric ${metric}`);
}
// Record metric in the general histogram.
TelemetryStopwatch[method](baseId, obj);
// Record metric in the histogram keyed by addon id.
let extensionId = getTrimmedString(extension.id);
TelemetryStopwatch[`${method}Keyed`](`${baseId}_BY_ADDONID`, extensionId, obj);
}
/**
* Record a telemetry category and/or value for a given metric.
*
* @param {string} metric
* The metric to record (used to retrieve the base histogram id from the _histogram object).
* @param {Object} options
* @param {Extension | BrowserExtensionContent} options.extension
* The extension to record the telemetry for.
* @param {string | undefined} [options.category]
* An optional histogram category.
* @param {number | undefined} [options.value]
* An optional value to record.
*/
_histogramAdd(metric, {category, extension, value}) {
if (!extension) {
throw new Error(`Mandatory extension parameter is undefined`);
}
const baseId = histograms[metric];
if (!baseId) {
throw new Error(`Unknown metric ${metric}`);
}
const histogram = Services.telemetry.getHistogramById(baseId);
if (typeof category === "string") {
histogram.add(category, value);
} else {
histogram.add(value);
}
const keyedHistogram = Services.telemetry.getKeyedHistogramById(`${baseId}_BY_ADDONID`);
const extensionId = getTrimmedString(extension.id);
if (typeof category === "string") {
keyedHistogram.add(extensionId, category, value);
} else {
keyedHistogram.add(extensionId, value);
}
}
}
// Cache of the ExtensionTelemetryMetric instances that has been lazily created by the
// Extension Telemetry Proxy.
const metricsCache = new Map();
/**
* This proxy object provides the telemetry helpers for the currently supported metrics (the ones listed in
* ExtensionTelemetryHelpers._histograms), the telemetry helpers for a particular metric are lazily created
* when the related property is being accessed on this object for the first time, e.g.:
*
* ExtensionTelemetry.extensionStartup.stopwatchStart(extension);
* ExtensionTelemetry.browserActionPreloadResult.histogramAdd({category: "Shown", extension});
*/
var ExtensionTelemetry = new Proxy(metricsCache, {
get(target, prop, receiver) {
if (!(prop in histograms)) {
throw new Error(`Unknown metric ${prop}`);
}
// Lazily create and cache the metric result object.
if (!target.has(prop)) {
target.set(prop, new ExtensionTelemetryMetric(prop));
}
return target.get(prop);
},
});

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

@ -12,8 +12,6 @@ ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
ChromeUtils.defineModuleGetter(this, "setTimeout",
"resource://gre/modules/Timer.jsm");
ChromeUtils.defineModuleGetter(this, "TelemetryStopwatch",
"resource://gre/modules/TelemetryStopwatch.jsm");
// xpcshell doesn't handle idle callbacks well.
XPCOMUtils.defineLazyGetter(this, "idleTimeout",
@ -269,165 +267,12 @@ const chromeModifierKeyMap = {
"Shift": "shift",
};
/**
* Get a trimmed version of the given string if it is longer than 80 chars (used in telemetry
* when a string may be longer than allowed).
*
* @param {string} str
* The original string content.
*
* @returns {string}
* The trimmed version of the string when longer than 80 chars, or the given string
* unmodified otherwise.
*/
function getTrimmedString(str) {
if (str.length <= 80) {
return str;
}
const length = str.length;
// Trim the string to prevent a flood of warnings messages logged internally by recordEvent,
// the trimmed version is going to be composed by the first 40 chars and the last 37 and 3 dots
// that joins the two parts, to visually indicate that the string has been trimmed.
return `${str.slice(0, 40)}...${str.slice(length - 37, length)}`;
}
/**
* This is a internal helper object which contains a collection of helpers used to make it easier
* to collect extension telemetry (in both the general histogram and in the one keyed by addon id).
*
* This helper object is not exported from ExtensionUtils, it is used by the ExtensionTelemetry
* Proxy which is exported and used by the callers to record telemetry data for one of the
* supported metrics.
*/
const ExtensionTelemetryHelpers = {
// Allow callers to refer to the existing metrics by accessing it as properties of the
// ExtensionTelemetry.metrics (e.g. ExtensionTelemetry.metrics.extensionStartup).
// Cache of the metrics helper lazily created by the ExtensionTelemetry Proxy.
_metricsMap: new Map(),
// Map of the base histogram ids for the metrics recorded for the extensions.
_histograms: {
"extensionStartup": "WEBEXT_EXTENSION_STARTUP_MS",
"backgroundPageLoad": "WEBEXT_BACKGROUND_PAGE_LOAD_MS",
"browserActionPopupOpen": "WEBEXT_BROWSERACTION_POPUP_OPEN_MS",
"browserActionPreloadResult": "WEBEXT_BROWSERACTION_POPUP_PRELOAD_RESULT_COUNT",
"contentScriptInjection": "WEBEXT_CONTENT_SCRIPT_INJECTION_MS",
"pageActionPopupOpen": "WEBEXT_PAGEACTION_POPUP_OPEN_MS",
"storageLocalGetJSON": "WEBEXT_STORAGE_LOCAL_GET_MS",
"storageLocalSetJSON": "WEBEXT_STORAGE_LOCAL_SET_MS",
"storageLocalGetIDB": "WEBEXT_STORAGE_LOCAL_IDB_GET_MS",
"storageLocalSetIDB": "WEBEXT_STORAGE_LOCAL_IDB_SET_MS",
},
// Wraps a call to a TelemetryStopwatch method.
/**
* Wraps a call to a TelemetryStopwatch method for a given metric and extension.
*
* @param {string} method
* The stopwatch method to call ("start", "finish" or "cancel").
* @param {string} metric
* The stopwatch metric to record (used to retrieve the base histogram id from the _histogram object).
* @param {Extension | BrowserExtensionContent} extension
* The extension to record the telemetry for.
* @param {any | undefined} [obj = extension]
* An optional telemetry stopwatch object (which defaults to the extension parameter when missing).
*/
_wrappedStopwatchMethod(method, metric, extension, obj = extension) {
if (!extension) {
throw new Error(`Mandatory extension parameter is undefined`);
}
const baseId = this._histograms[metric];
if (!baseId) {
throw new Error(`Unknown metric ${metric}`);
}
// Record metric in the general histogram.
TelemetryStopwatch[method](baseId, obj);
// Record metric in the histogram keyed by addon id.
let extensionId = getTrimmedString(extension.id);
TelemetryStopwatch[`${method}Keyed`](`${baseId}_BY_ADDONID`, extensionId, obj);
},
/**
* Record a telemetry category and/or value for a given metric.
*
* @param {string} metric
* The metric to record (used to retrieve the base histogram id from the _histogram object).
* @param {Object} options
* @param {Extension | BrowserExtensionContent} options.extension
* The extension to record the telemetry for.
* @param {string | undefined} [options.category]
* An optional histogram category.
* @param {number | undefined} [options.value]
* An optional value to record.
*/
_histogramAdd(metric, {category, extension, value}) {
if (!extension) {
throw new Error(`Mandatory extension parameter is undefined`);
}
const baseId = this._histograms[metric];
if (!baseId) {
throw new Error(`Unknown metric ${metric}`);
}
const histogram = Services.telemetry.getHistogramById(baseId);
if (typeof category === "string") {
histogram.add(category, value);
} else {
histogram.add(value);
}
const keyedHistogram = Services.telemetry.getKeyedHistogramById(`${baseId}_BY_ADDONID`);
const extensionId = getTrimmedString(extension.id);
if (typeof category === "string") {
keyedHistogram.add(extensionId, category, value);
} else {
keyedHistogram.add(extensionId, value);
}
},
};
/**
* This proxy object provides the telemetry helpers for the currently supported metrics (the ones listed in
* ExtensionTelemetryHelpers._histograms), the telemetry helpers for a particular metric are lazily created
* when the related property is being accessed on this object for the first time, e.g.:
*
* ExtensionTelemetry.extensionStartup.stopwatchStart(extension);
* ExtensionTelemetry.browserActionPreloadResult.histogramAdd({category: "Shown", extension});
*/
const ExtensionTelemetry = new Proxy(ExtensionTelemetryHelpers, {
get(target, prop, receiver) {
if (!(prop in target._histograms)) {
throw new Error(`Unknown metric ${prop}`);
}
// Lazily create and cache the metric result object.
if (!target._metricsMap.has(prop)) {
target._metricsMap.set(prop, {
// Stopwatch histogram helpers.
stopwatchStart: target._wrappedStopwatchMethod.bind(target, "start", prop),
stopwatchFinish: target._wrappedStopwatchMethod.bind(target, "finish", prop),
stopwatchCancel: target._wrappedStopwatchMethod.bind(target, "cancel", prop),
// Result histogram helpers.
histogramAdd: target._histogramAdd.bind(target, prop),
});
}
return target._metricsMap.get(prop);
},
});
var ExtensionUtils = {
chromeModifierKeyMap,
flushJarCache,
getInnerWindowID,
getMessageManager,
getTrimmedString,
getUniqueId,
filterStack,
getWinUtils,
@ -440,6 +285,5 @@ var ExtensionUtils = {
DefaultMap,
DefaultWeakMap,
ExtensionError,
ExtensionTelemetry,
LimitedSet,
};

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

@ -4,13 +4,11 @@ ChromeUtils.defineModuleGetter(this, "ExtensionStorage",
"resource://gre/modules/ExtensionStorage.jsm");
ChromeUtils.defineModuleGetter(this, "ExtensionStorageIDB",
"resource://gre/modules/ExtensionStorageIDB.jsm");
ChromeUtils.defineModuleGetter(this, "ExtensionTelemetry",
"resource://gre/modules/ExtensionTelemetry.jsm");
ChromeUtils.defineModuleGetter(this, "Services",
"resource://gre/modules/Services.jsm");
var {
ExtensionTelemetry,
} = ExtensionUtils;
// Wrap a storage operation in a TelemetryStopWatch.
async function measureOp(telemetryMetric, extension, fn) {
const stopwatchKey = {};

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

@ -22,6 +22,7 @@ EXTRA_JS_MODULES += [
'ExtensionStorage.jsm',
'ExtensionStorageIDB.jsm',
'ExtensionStorageSync.jsm',
'ExtensionTelemetry.jsm',
'ExtensionUtils.jsm',
'FindContent.jsm',
'LegacyExtensionsUtils.jsm',

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

@ -6,10 +6,9 @@ var {
promiseExtensionViewLoaded,
} = ExtensionParent;
ChromeUtils.import("resource://gre/modules/ExtensionUtils.jsm");
var {
ExtensionTelemetry,
} = ExtensionUtils;
ChromeUtils.defineModuleGetter(this, "ExtensionTelemetry",
"resource://gre/modules/ExtensionTelemetry.jsm");
XPCOMUtils.defineLazyPreferenceGetter(this, "DELAYED_STARTUP",
"extensions.webextensions.background-delayed-startup");

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

@ -0,0 +1,61 @@
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
const server = createHttpServer({hosts: ["example.com"]});
server.registerPathHandler("/dummyFrame", (request, response) => {
response.setStatusLine(request.httpVersion, 200, "OK");
response.setHeader("Content-Type", "text/html; charset=utf-8", false);
response.write("");
});
add_task(async function connect_from_background_frame() {
async function background() {
const FRAME_URL = "http://example.com:8888/dummyFrame";
browser.runtime.onConnect.addListener((port) => {
browser.test.assertEq(port.sender.tab, undefined, "Sender is not a tab");
browser.test.assertEq(port.sender.url, FRAME_URL, "Expected sender URL");
port.onMessage.addListener(msg => {
browser.test.assertEq("pong", msg, "Reply from content script");
port.disconnect();
});
port.postMessage("ping");
});
await browser.contentScripts.register({
matches: ["http://example.com/dummyFrame"],
js: [{file: "contentscript.js"}],
allFrames: true,
});
let f = document.createElement("iframe");
f.src = FRAME_URL;
document.body.appendChild(f);
}
function contentScript() {
browser.test.log(`Running content script at ${document.URL}`);
let port = browser.runtime.connect();
port.onMessage.addListener(msg => {
browser.test.assertEq("ping", msg, "Expected message to content script");
port.postMessage("pong");
});
port.onDisconnect.addListener(() => {
browser.test.sendMessage("disconnected_in_content_script");
});
}
let extension = ExtensionTestUtils.loadExtension({
manifest: {
permissions: ["http://example.com/*"],
},
files: {
"contentscript.js": contentScript,
},
background,
});
await extension.startup();
await extension.awaitMessage("disconnected_in_content_script");
await extension.unload();
});

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

@ -15,6 +15,7 @@ const STARTUP_MODULES = [
// this.
"resource://gre/modules/ExtensionPermissions.jsm",
"resource://gre/modules/ExtensionUtils.jsm",
"resource://gre/modules/ExtensionTelemetry.jsm",
];
if (!Services.prefs.getBoolPref("extensions.webextensions.remote")) {

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

@ -10,13 +10,16 @@ AddonTestUtils.createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "42"
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
ChromeUtils.import("resource://gre/modules/ExtensionStorage.jsm");
ChromeUtils.import("resource://gre/modules/ExtensionUtils.jsm");
ChromeUtils.import("resource://gre/modules/TelemetryController.jsm");
const {
ExtensionStorageIDB,
} = ChromeUtils.import("resource://gre/modules/ExtensionStorageIDB.jsm", {});
const {
getTrimmedString,
} = ChromeUtils.import("resource://gre/modules/ExtensionTelemetry.jsm", {});
XPCOMUtils.defineLazyModuleGetters(this, {
OS: "resource://gre/modules/osfile.jsm",
});
@ -252,7 +255,7 @@ add_task(async function test_extensionId_trimmed_in_telemetry_event() {
await extension.awaitMessage("storage-local-data-migrated");
const expectedTrimmedExtensionId = ExtensionUtils.getTrimmedString(EXTENSION_ID);
const expectedTrimmedExtensionId = getTrimmedString(EXTENSION_ID);
equal(expectedTrimmedExtensionId.length, 80, "The trimmed version of the extensionId should be 80 chars long");

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

@ -29,6 +29,7 @@ skip-if = os == 'android' && debug # The generated script takes too long to load
[test_ext_contentscript_create_iframe.js]
[test_ext_contentscript_css.js]
[test_ext_contentscript_exporthelpers.js]
[test_ext_contentscript_in_background.js]
[test_ext_contentscript_restrictSchemes.js]
[test_ext_contentscript_teardown.js]
[test_ext_contextual_identities.js]

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

@ -6,15 +6,10 @@
ChromeUtils.import("resource://gre/modules/Services.jsm");
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
ChromeUtils.defineModuleGetter(
this, "CleanupManager", "resource://normandy/lib/CleanupManager.jsm",
);
ChromeUtils.defineModuleGetter(
this, "AddonStudies", "resource://normandy/lib/AddonStudies.jsm",
);
ChromeUtils.defineModuleGetter(
this, "RecipeRunner", "resource://normandy/lib/RecipeRunner.jsm",
);
ChromeUtils.defineModuleGetter(this, "AddonStudyAction", "resource://normandy/actions/AddonStudyAction.jsm");
ChromeUtils.defineModuleGetter(this, "CleanupManager", "resource://normandy/lib/CleanupManager.jsm");
ChromeUtils.defineModuleGetter(this, "AddonStudies", "resource://normandy/lib/AddonStudies.jsm");
ChromeUtils.defineModuleGetter(this, "RecipeRunner", "resource://normandy/lib/RecipeRunner.jsm");
var EXPORTED_SYMBOLS = ["AboutPages"];
@ -183,7 +178,8 @@ XPCOMUtils.defineLazyGetter(this.AboutPages, "aboutStudies", () => {
* @param {String} studyName
*/
async removeStudy(recipeId, reason) {
await AddonStudies.stop(recipeId, reason);
const action = new AddonStudyAction();
await action.unenroll(recipeId, reason);
// Update any open tabs with the new study list now that it has changed.
Services.mm.broadcastAsyncMessage("Shield:ReceiveStudyList", {

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

@ -66,7 +66,7 @@ add_task(async function test_backButton_forwardButton() {
let forwardButton = document.getElementById("forward-button");
let forwardTransitionPromise;
if (forwardButton.nextSibling == gURLBar) {
if (forwardButton.nextElementSibling == gURLBar) {
// We need to wait for the forward button transition to complete before we
// can click it, so we hook up a listener to wait for it to be ready.
forwardTransitionPromise = BrowserTestUtils.waitForEvent(forwardButton, "transitionend");

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

@ -5766,10 +5766,10 @@
"description": "Firefox: Time taken to kick off image compression of the canvas that will be used during swiping through history (ms)."
},
"FX_TAB_CLOSE_TIME_ANIM_MS": {
"record_in_processes": ["main", "content"],
"alert_emails": ["mconley@mozilla.com", "hkirschner@mozilla.com", "sphilp@mozilla.com"],
"bug_numbers": [1340842],
"expires_in_version": "65",
"record_in_processes": ["main"],
"alert_emails": ["mconley@mozilla.com", "dolske@mozilla.com"],
"bug_numbers": [1340842, 1488952],
"expires_in_version": "never",
"releaseChannelCollection": "opt-out",
"kind": "exponential",
"high": 10000,
@ -5777,20 +5777,20 @@
"description": "Firefox: Time taken from the point of closing a tab (with animation), to the browser element being removed from the DOM. (ms)."
},
"FX_TAB_CLOSE_TIME_NO_ANIM_MS": {
"record_in_processes": ["main", "content"],
"record_in_processes": ["main"],
"alert_emails": ["mconley@mozilla.com", "hkirschner@mozilla.com"],
"bug_numbers": [1340842],
"expires_in_version": "65",
"expires_in_version": "68",
"kind": "exponential",
"high": 10000,
"n_buckets": 50,
"description": "Firefox: Time taken from the point of closing a tab (without animation) to the browser element being removed from the DOM. (ms)."
},
"FX_TAB_CLOSE_PERMIT_UNLOAD_TIME_MS": {
"record_in_processes": ["main", "content"],
"record_in_processes": ["main"],
"alert_emails": ["mconley@mozilla.com", "hkirschner@mozilla.com"],
"bug_numbers": [1340842],
"expires_in_version": "65",
"expires_in_version": "68",
"kind": "exponential",
"high": 10000,
"n_buckets": 50,

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

@ -159,7 +159,7 @@ async function testAutoplayUnknownPermission(args) {
PopupNotifications.panel.firstElementChild.button.click();
} else if (args.button == "block") {
info("Clicking block button");
PopupNotifications.panel.firstChild.secondaryButton.click();
PopupNotifications.panel.firstElementChild.secondaryButton.click();
} else {
ok(false, "Invalid button field");
}

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

@ -278,7 +278,7 @@
<body>
<![CDATA[
var startTab = this.selectedItem;
var next = startTab[aDir == -1 ? "previousSibling" : "nextSibling"];
var next = startTab[(aDir == -1 ? "previous" : "next") + "ElementSibling"];
if (!next && aWrap) {
next = aDir == -1 ? this.children[this.children.length - 1] :
this.children[0];

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

@ -33,7 +33,7 @@ function promisePopupNotificationShown(name) {
ok(PopupNotifications.isPanelOpen, "notification panel open");
PopupNotifications.panel.removeEventListener("popupshown", popupshown);
resolve(PopupNotifications.panel.firstChild);
resolve(PopupNotifications.panel.firstElementChild);
}
PopupNotifications.panel.addEventListener("popupshown", popupshown);

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

@ -1386,7 +1386,7 @@ function promiseNotification(id = "addon-webext-permissions") {
let notification = PopupNotifications.getNotification(id);
if (notification) {
PopupNotifications.panel.removeEventListener("popupshown", popupshown);
PopupNotifications.panel.firstChild.button.click();
PopupNotifications.panel.firstElementChild.button.click();
resolve();
}
}

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

@ -478,9 +478,9 @@ async function test_allUnverified() {
is(message, "Caution: This site would like to install an unverified add-on in " + gApp + ". Proceed at your own risk.");
let container = document.getElementById("addon-install-confirmation-content");
is(container.childNodes.length, 1, "Should be one item listed");
is(container.childNodes[0].firstChild.getAttribute("value"), "XPI Test", "Should have the right add-on");
is(container.childNodes[0].childNodes.length, 1, "Shouldn't have the unverified marker");
is(container.children.length, 1, "Should be one item listed");
is(container.children[0].firstElementChild.getAttribute("value"), "XPI Test", "Should have the right add-on");
is(container.children[0].children.length, 1, "Shouldn't have the unverified marker");
let notificationPromise = waitForNotification("addon-installed");
acceptInstallDialog(installDialog);

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

@ -265,12 +265,12 @@ var Harness = {
handleEvent(event) {
if (event.type === "popupshown") {
if (event.target.firstChild) {
if (event.target.firstElementChild) {
let popupId = event.target.getAttribute("popupid");
if (popupId === "addon-webext-permissions") {
this.popupReady(event.target.firstChild);
this.popupReady(event.target.firstElementChild);
} else if (popupId === "addon-installed" || popupId === "addon-install-failed") {
event.target.firstChild.button.click();
event.target.firstElementChild.button.click();
}
}
}

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

@ -17,35 +17,25 @@ namespace mozilla {
inline bool
EnsureLongPath(nsAString& aDosPath)
{
uint32_t aDosPathOriginalLen = aDosPath.Length();
auto inputPath = PromiseFlatString(aDosPath);
// Try to get the long path, or else get the required length of the long path
DWORD longPathLen = GetLongPathNameW(inputPath.get(),
reinterpret_cast<wchar_t*>(aDosPath.BeginWriting()),
aDosPathOriginalLen);
if (longPathLen == 0) {
return false;
nsAutoString inputPath(aDosPath);
while (true) {
DWORD requiredLength = GetLongPathNameW(inputPath.get(),
reinterpret_cast<wchar_t*>(aDosPath.BeginWriting()),
aDosPath.Length());
if (!requiredLength) {
return false;
}
if (requiredLength < aDosPath.Length()) {
// When GetLongPathNameW deems the last argument too small,
// it returns a value, but when you pass that value back, it's
// satisfied and returns a number that's one smaller. If the above
// check was == instead of <, the loop would go on forever with
// GetLongPathNameW returning oscillating values!
aDosPath.Truncate(requiredLength);
return true;
}
aDosPath.SetLength(requiredLength);
}
aDosPath.SetLength(longPathLen);
if (longPathLen <= aDosPathOriginalLen) {
// Our string happened to be long enough for the first call to succeed.
return true;
}
// Now we have a large enough buffer, get the actual string
longPathLen = GetLongPathNameW(inputPath.get(),
reinterpret_cast<wchar_t*>(aDosPath.BeginWriting()), aDosPath.Length());
if (longPathLen == 0) {
return false;
}
// This success check should always be less-than because longPathLen excludes
// the null terminator on success, but includes it in the first call that
// returned the required size.
if (longPathLen < aDosPath.Length()) {
aDosPath.SetLength(longPathLen);
return true;
}
// We shouldn't reach this, but if we do then it's a failure!
return false;
}
inline bool
@ -67,24 +57,32 @@ NtPathToDosPath(const nsAString& aNtPath, nsAString& aDosPath)
return true;
}
nsAutoString logicalDrives;
DWORD len = 0;
while (true) {
len = GetLogicalDriveStringsW(
len, reinterpret_cast<wchar_t*>(logicalDrives.BeginWriting()));
if (!len) {
DWORD requiredLength = GetLogicalDriveStringsW(
logicalDrives.Length(), reinterpret_cast<wchar_t*>(logicalDrives.BeginWriting()));
if (!requiredLength) {
return false;
} else if (len > logicalDrives.Length()) {
logicalDrives.SetLength(len);
} else {
}
if (requiredLength < logicalDrives.Length()) {
// When GetLogicalDriveStringsW deems the first argument too small,
// it returns a value, but when you pass that value back, it's
// satisfied and returns a number that's one smaller. If the above
// check was == instead of <, the loop would go on forever with
// GetLogicalDriveStringsW returning oscillating values!
logicalDrives.Truncate(requiredLength);
// logicalDrives now has the format "C:\\\0D:\\\0Z:\\\0". That is,
// the sequence drive letter, colon, backslash, U+0000 repeats.
break;
}
logicalDrives.SetLength(requiredLength);
}
const char16_t* cur = logicalDrives.BeginReading();
const char16_t* end = logicalDrives.EndReading();
nsString targetPath;
targetPath.SetLength(MAX_PATH);
wchar_t driveTemplate[] = L" :";
do {
while (cur < end) {
// Unfortunately QueryDosDevice doesn't support the idiom for querying the
// output buffer size, so it may require retries.
driveTemplate[0] = *cur;
@ -113,9 +111,16 @@ NtPathToDosPath(const nsAString& aNtPath, nsAString& aDosPath)
return EnsureLongPath(aDosPath);
}
}
// Advance to the next NUL character in logicalDrives
while (*cur++);
} while (cur != end);
// Find the next U+0000 within the logical string
while (*cur) {
// This loop skips the drive letter, the colon
// and the backslash.
cur++;
}
// Skip over the U+0000 that ends a drive entry
// within the logical string
cur++;
}
// Try to handle UNC paths. NB: This must happen after we've checked drive
// mappings in case a UNC path is mapped to a drive!
NS_NAMED_LITERAL_STRING(uncPrefix, "\\\\");