зеркало из https://github.com/mozilla/gecko-dev.git
Merge autoland to mozilla-central. a=merge
This commit is contained in:
Коммит
65fc5da4af
|
@ -13,6 +13,7 @@ class BrowserTabParent extends JSWindowActorParent {
|
|||
}
|
||||
|
||||
let gBrowser = browser.ownerGlobal.gBrowser;
|
||||
|
||||
if (!gBrowser) {
|
||||
// Note: gBrowser might be null because this message might be received
|
||||
// from the extension process. There's still an embedderElement involved,
|
||||
|
@ -22,6 +23,15 @@ class BrowserTabParent extends JSWindowActorParent {
|
|||
return;
|
||||
}
|
||||
|
||||
if (!gBrowser.tabpanels || !gBrowser.tabpanels.contains(browser)) {
|
||||
// Note: This is ignoring browser elements related to extension pages that are not loaded
|
||||
// as a browser tab (like sidebars, devtools panels and options pages embedded into
|
||||
// about:addons, browserAction and pageAction popup panels.
|
||||
// (Ideally we could call gBrowser.getTabForBrowser, but it returns undefined early in
|
||||
// the tab browser creation and we would ignore browsers related to newly created tabs).
|
||||
return;
|
||||
}
|
||||
|
||||
switch (message.name) {
|
||||
case "Browser:WindowCreated": {
|
||||
gBrowser.announceWindowCreated(browser, message.data.userContextId);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<blocklist lastupdate="1562577903535" xmlns="http://www.mozilla.org/2006/addons-blocklist">
|
||||
<blocklist lastupdate="1562842544708" xmlns="http://www.mozilla.org/2006/addons-blocklist">
|
||||
<emItems>
|
||||
<emItem blockID="i334" id="{0F827075-B026-42F3-885D-98981EE7B1AE}">
|
||||
<prefs/>
|
||||
|
@ -2716,10 +2716,6 @@
|
|||
<prefs/>
|
||||
<versionRange minVersion="0" maxVersion="*" severity="3"/>
|
||||
</emItem>
|
||||
<emItem blockID="9fde5729-9be6-4955-9627-67742c5ed62a" id="sourcegraph-for-firefox@sourcegraph.com">
|
||||
<prefs/>
|
||||
<versionRange minVersion="0" maxVersion="19.4.2.1038" severity="1"/>
|
||||
</emItem>
|
||||
<emItem blockID="a1c376fe-20c5-4da3-9126-3fe95b874dce" id="/^((\{00b4b65b-79d9-4e92-bc1e-2b926918b91c\})|(\{0cb66591-e935-47e4-95c2-3063786f6555\})|(\{6cf25884-f86d-4a4e-a924-d95282ce5b71\})|(\{22cce9c6-a1de-457f-8938-c981b976b6f4\})|(\{89d99d4c-e7c4-4601-91a8-216e597a826b\})|(\{998d3ac7-b475-410e-ad3d-2eeb526c1853\})|(\{9423e8df-6200-45c0-877a-479c46e91b30\})|(\{64937e0b-6e00-4d5f-bf19-190d6614aae2\})|(\{91507dc4-c005-4534-80af-d8fbdeac29ed\})|(\{a2247e60-7b89-4857-a2fa-0eaee1cad460\})|(\{c9c28751-5865-449f-8e45-b3363edf9fb7\})|(\{cdfd004f-cddc-4ad7-8e2d-a58457e42b1f\})|(\{d3e7f35d-7d9f-4d38-9a2b-1581f6b3e870\})|(\{df574ffe-cce0-42db-857b-627cb164a4d4\})|(\{e06afe6e-ed52-40f8-82bf-d070a37387fb\})|(\{e7e7fb96-cfab-4a5b-85fe-20f621e1bc2e\})|(\{e12e5afd-bd1e-43c6-9288-321dc485cb1c\})|(\{e92d8545-0396-4808-96de-830c61c0d1b3\})|(\{e883b012-1987-4f37-8053-02e59e20c242\})|(\{ed3386c6-76c6-4786-a37b-9816d5f2a260\}))$/">
|
||||
<prefs/>
|
||||
<versionRange minVersion="0" maxVersion="*" severity="3"/>
|
||||
|
@ -3297,6 +3293,18 @@
|
|||
<prefs/>
|
||||
<versionRange minVersion="0" maxVersion="*" severity="3"/>
|
||||
</emItem>
|
||||
<emItem blockID="9fde5729-9be6-4955-9627-67742c5ed62a" id="sourcegraph-for-firefox@sourcegraph.com">
|
||||
<prefs/>
|
||||
<versionRange minVersion="0" maxVersion="*" severity="1"/>
|
||||
</emItem>
|
||||
<emItem blockID="d38035ff-7945-49cc-88fb-6de9f8a13658" id="/^((langpacasdjasdk-de@firefox\.mozilla\.org)|(langpack-de-7@niklasb)|(langpack-de-8@niklasb)|(langpack-de-9@niklasb)|(langpack-de-10@niklasb)|(langpack-de-nightly-1@firefox\.mozilla\.org))$/">
|
||||
<prefs/>
|
||||
<versionRange minVersion="0" maxVersion="*" severity="3"/>
|
||||
</emItem>
|
||||
<emItem blockID="9f945be6-12e7-4948-af77-668bc3996ff3" id="/^((\{9aa1f441-7c04-4b00-83b2-6a4362090b41\})|(\{3001d016-bc15-49af-a81b-2c8764139321\})|(\{0af1d242-b004-49ae-91fc-00fa0f642bf9\})|(\{95a5a094-ba8e-4fe1-80bb-6f6c0a01bc2c\})|(\{36b33158-36fc-4728-bf08-8e532100af58\})|(\{5bda1d03-6533-4d8c-adb4-7179402ddeec\})|(\{dc7d18c8-c832-42cd-b9b0-f6a46a737ad1\})|(\{56d85baf-c366-491b-b93c-733a4a36009d\})|(\{1b08c0c7-d2fd-4905-82ab-d4d759af4051\})|(\{1b8a9b33-b3d9-42ea-adce-cec910c44f29\})|(\{0be707e8-d7d6-45d5-8212-3fd3784d7de7\})|(\{fb2e3c38-be42-480f-b60c-d614d372e218\})|(\{c088d705-9f59-40ac-98eb-192f67c44f03\})|(\{9570bbbd-d761-4380-850c-d9cc15200916\})|(\{2652d5a4-26b1-4e6f-9134-304d7b57af7a\})|(\{1e0a2a5f-170c-43c1-b458-c8fc8bdd7dec\})|(\{47595710-e0b3-4a88-9bf7-54e1f3bb6772\})|(\{c25a320e-dc50-486a-9589-13ef22f75a21\})|(\{645237c8-7da2-4298-a789-e11fbaaa580e\})|(\{f2356af6-9b9d-4c69-876a-710d446a9124\})|(\{98a67ccd-599a-4675-9578-35af1824fdd2\})|(\{f3924f49-64a3-4fde-8598-76eec8e67f34\})|(\{2a46402d-b6c4-4a0b-87f0-dc90bb24fa93\})|(\{40d92297-295d-4a44-8a0f-dd69510c9c30\})|(\{a5462b0d-6528-47d5-ada5-4a23d1e0355e\})|(\{280f7325-eaf0-451a-ad2d-3b2c4e80e070\})|(\{ee5a7045-e216-4836-949a-07f5aa1dabc3\})|(\{34ee38f4-e2ba-4e9d-8b1f-dd06e8bd205f\})|(\{7c71c234-ba74-467c-b750-727ee7e38382\})|(\{a83b3b31-4bfc-4343-beab-761f21b97f57\})|(\{b85d35a4-3a03-430d-a1a0-437448a86c22\})|(\{8b6c1e29-5009-477e-a798-244b0efb1515\})|(\{64891348-7fc0-4299-bd6a-6bfaa6cf21a6\})|(\{baa828ff-1723-483b-8034-145ad2795efd\})|(\{81fd4851-7ea3-4ea5-8775-49372fe1c8c8\})|(\{ce7d8e95-c7d3-49dc-8abf-e860ee707b09\})|(\{d84109e8-9945-48bc-90e8-0dd0b1b63b73\})|(\{ec12fd66-7294-4167-8fbc-4774150c0fa4\})|(\{0c506de9-8467-4a92-8cd3-11c87e121db2\})|(\{b1671fe5-c90a-4f68-b8bf-e54a147b5d05\})|(\{8b25277a-4df8-4d2d-b3b4-f8219e2ce7d6\})|(\{5705cd04-46c2-459f-8a9a-97ce57eee1ae\})|(\{8340b371-ed61-4b07-b293-853aa5dbb866\})|(\{87bbb065-e195-48ac-989e-ba48ee63b404\})|(\{c455fc20-6e9d-418c-9b45-75fd85852b32\})|(\{a80c87a7-3366-4192-b9cc-d1e862e1c13d\})|(\{5f4ba05c-c1a5-4bc7-b8d3-c14e807b2c64\})|(\{0114315a-beda-4d55-89a3-e00f6346e7be\})|(\{0fb7b987-721e-4828-9a0e-a72860ded1b2\})|(\{c44cd2a5-bf28-4520-ab2d-187752e51a26\})|(\{3a34c1a6-3cbf-49a0-bfe9-beff60da5ec6\})|(\{677e89a4-ae10-42f3-8e9d-d51be40daf8f\})|(\{85d70eae-fde6-4ac0-ab82-0148f2eb1543\})|(\{fddac013-6d12-41a4-9924-f5ea7618f22d\})|(\{84b5ca75-a431-45c7-995d-6d7268decd0d\})|(\{7374dd37-a901-4b65-993c-3323f87e0f3c\})|(\{157a5c60-7899-4328-a90c-83d34d0844d4\})|(\{5b288e8d-f33c-4602-a945-07f96e43a041\})|(\{80f059bd-602a-42d5-9b17-9f2c6a074102\})|(\{8e5a8075-8e21-4ab2-b189-5d435208122c\})|(\{d5b94c09-0ff8-4b86-b52a-590d5e5ad9af\})|(\{a569eb31-9456-49a9-9aa9-e69a8db159d3\})|(\{0431a147-f9f5-4ee3-8dca-57303110c226\})|(\{88c77421-5ebd-46fb-92a8-e0459b6edd20\})|(\{a4a0697d-9a01-4b21-bb88-5ac949cdb7b3\})|(\{03e0da0a-da1d-46f2-85c7-08258189fc04\})|(\{351f5a4d-a0fd-4ce7-a85a-6cb74fb6c57d\})|(\{0e0b22ea-831e-4104-9c2e-612d7ebf82e2\})|(\{7b5c604f-ea41-4bfa-88d1-843f27645199\})|(\{863f023c-a2e5-4043-8e49-8e3029004b19\})|(\{20e4b367-f8ad-4c9a-b590-976be87206aa\})|(\{436ca3ce-f10a-4cdc-86c2-a46f086b5fdb\})|(\{a53983bc-545e-429a-8aaa-6332e1a6287f\})|(\{5fb1995e-ac7e-4c01-a592-8b262856e039\})|(\{56086da0-b20d-4118-9670-56e85624c875\})|(\{67ef5673-5769-4d5b-902f-ba22cb16a51b\})|(\{1d50e81b-0594-4c24-80c2-abc479be4d18\})|(\{b190f2cf-f3f0-40e7-a05b-8eed296a0c8d\})|(\{490d8bfc-fd42-4ded-9fee-1f009e777468\})|(\{1d647c69-8e4b-4fe8-b0f3-d914a1410ee8\})|(\{4958ae27-1251-49b4-a9d4-2af7c36c833b\})|(\{6e80fdc3-79c7-423a-8e95-0e123c0f2187\})|(\{d8d3230d-5642-4c3f-a64e-5ff690f7a466\})|(\{ddbe5d7a-e037-4749-89bc-3460d358aca1\})|(\{48cd023c-52ef-4fe7-a2ff-101c22c49a5e\})|(\{fef34931-b7ca-49a5-8827-bec353efaa08\})|(\{331a936b-a87e-4271-b9a6-30935dad77ed\})|(\{21084437-803c-49c3-8f84-9a615bfa5dfe\})|(\{93511e9d-badf-4b5c-9fbc-17ef6a9786ae\})|(\{470e388e-a039-43f8-a7a7-d8f54d273feb\})|(\{e4cd5604-caec-4139-9781-94add5f41ba3\})|(\{f00bc2b9-2b69-4f68-8bef-91d498686731\})|(\{7b3206c4-dc98-4ad9-88ba-5a7b3048fd92\})|(\{8e19f5f7-2445-48b1-8910-55d42d9dfe34\})|(\{770e30c6-f1b9-4df4-8551-c7f09ddbd8ed\})|(\{bb9a8679-1f82-4ab7-8ea2-bac864a38542\})|(\{13f5e078-b80a-45fb-a907-c4515a7bb0fa\})|(\{d8df47e3-5e86-4669-9a15-a37f8a8593db\})|(\{ab70d6ee-9d0a-4349-919f-2e3c9aa77927\})|(\{fe94f94a-75ff-48a9-9cab-03e626e30352\})|(\{085590fa-c340-423d-9b45-d8e963349513\})|(\{c06005f4-a53f-4503-b631-9c6fbea45e9e\})|(\{a1904bba-73b5-4fab-8556-95fdf0200c19\})|(\{4548ed4c-964e-4a53-acec-b24f5b9ea6a6\})|(\{99d68c16-4f64-463a-ad09-470a5ac07981\})|(\{14338345-a844-4c6e-9fca-d200a93f1d9b\})|(\{2bc78397-6bd3-4a2f-a737-dbc639ee9940\}))$/">
|
||||
<prefs/>
|
||||
<versionRange minVersion="0" maxVersion="*" severity="3"/>
|
||||
</emItem>
|
||||
</emItems>
|
||||
<pluginItems>
|
||||
<pluginItem blockID="p332">
|
||||
|
|
|
@ -1,9 +1,3 @@
|
|||
:host {
|
||||
/* these variable values come from about:preferences */
|
||||
--in-content-dialogtitle-background: #f1f1f1;
|
||||
--in-content-dialogtitle-border: #c1c1c1;
|
||||
}
|
||||
|
||||
.overlay {
|
||||
position: fixed;
|
||||
z-index: 1;
|
||||
|
@ -39,9 +33,9 @@
|
|||
position: relative;
|
||||
flex: 0 1 auto;
|
||||
text-align: center;
|
||||
background-color: var(--in-content-dialogtitle-background);
|
||||
background-color: var(--in-content-dialog-header-background);
|
||||
padding: 5px;
|
||||
border-bottom: 1px solid var(--in-content-dialogtitle-border);
|
||||
border-bottom: 1px solid var(--in-content-border-color);
|
||||
}
|
||||
|
||||
.title {
|
||||
|
|
|
@ -6,16 +6,12 @@
|
|||
@namespace html "http://www.w3.org/1999/xhtml";
|
||||
|
||||
:root {
|
||||
--in-content-dialogtitle-background: #f1f1f1;
|
||||
--in-content-dialogtitle-border: #c1c1c1;
|
||||
--in-content-warning-container: var(--grey-20);
|
||||
}
|
||||
|
||||
@supports -moz-bool-pref("browser.in-content.dark-mode") {
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--in-content-dialogtitle-background: rgba(249,249,250,0.05);
|
||||
--in-content-dialogtitle-border: rgba(0,0,0,0.5);
|
||||
--in-content-warning-container: var(--grey-90-a30);
|
||||
}
|
||||
}
|
||||
|
@ -526,8 +522,8 @@ button > hbox > label {
|
|||
.dialogTitleBar {
|
||||
margin-top: 0;
|
||||
padding: 3.5px 0;
|
||||
background-color: var(--in-content-dialogtitle-background);
|
||||
border-bottom: 1px solid var(--in-content-dialogtitle-border);
|
||||
background-color: var(--in-content-dialog-header-background);
|
||||
border-bottom: 1px solid var(--in-content-border-color);
|
||||
}
|
||||
|
||||
.dialogTitle {
|
||||
|
|
|
@ -14,11 +14,12 @@ import fnmatch
|
|||
import glob
|
||||
import errno
|
||||
import re
|
||||
from contextlib import contextmanager
|
||||
import sys
|
||||
import which
|
||||
from contextlib import contextmanager
|
||||
from distutils.dir_util import copy_tree
|
||||
|
||||
from mozfile import which
|
||||
|
||||
|
||||
def symlink(source, link_name):
|
||||
os_symlink = getattr(os, "symlink", None)
|
||||
|
@ -436,10 +437,10 @@ def get_tool(config, key):
|
|||
return f
|
||||
|
||||
# Assume that we have the name of some program that should be on PATH.
|
||||
try:
|
||||
return which.which(f) if f else which.which(key)
|
||||
except which.WhichError:
|
||||
raise ValueError("%s not found on PATH" % f)
|
||||
tool = which(f) if f else which(key)
|
||||
if not tool:
|
||||
raise ValueError("%s not found on PATH" % (f or key))
|
||||
return tool
|
||||
|
||||
|
||||
# This function is intended to be called on the final build directory when
|
||||
|
|
|
@ -8,6 +8,7 @@ mozilla.pth:python/mozversioncontrol
|
|||
mozilla.pth:python/l10n
|
||||
mozilla.pth:third_party/python/atomicwrites
|
||||
mozilla.pth:third_party/python/attrs/src
|
||||
python2:mozilla.pth:third_party/python/backports
|
||||
mozilla.pth:third_party/python/biplist
|
||||
mozilla.pth:third_party/python/blessings
|
||||
mozilla.pth:third_party/python/Click
|
||||
|
|
7
devtools/client/debugger/flow-typed/npm-custom/devtools-wasm-dwarf_vx.x.x.js
поставляемый
Normal file
7
devtools/client/debugger/flow-typed/npm-custom/devtools-wasm-dwarf_vx.x.x.js
поставляемый
Normal file
|
@ -0,0 +1,7 @@
|
|||
/* 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/>. */
|
||||
|
||||
declare module "devtools-wasm-dwarf" {
|
||||
declare module.exports: any;
|
||||
}
|
|
@ -6,8 +6,6 @@
|
|||
|
||||
import { uniq, remove } from "lodash";
|
||||
|
||||
import { asyncStore } from "../utils/prefs";
|
||||
|
||||
import {
|
||||
getActiveEventListeners,
|
||||
getEventListenerExpanded,
|
||||
|
@ -17,13 +15,6 @@ import type { ThunkArgs } from "./types";
|
|||
|
||||
async function updateBreakpoints(dispatch, client, newEvents: string[]) {
|
||||
dispatch({ type: "UPDATE_EVENT_LISTENERS", active: newEvents });
|
||||
|
||||
const current = await asyncStore.eventListenerBreakpoints;
|
||||
asyncStore.eventListenerBreakpoints = {
|
||||
...current,
|
||||
active: newEvents,
|
||||
};
|
||||
|
||||
await client.setEventListenerBreakpoints(newEvents);
|
||||
}
|
||||
|
||||
|
@ -32,12 +23,6 @@ async function updateExpanded(dispatch, newExpanded: string[]) {
|
|||
type: "UPDATE_EVENT_LISTENER_EXPANDED",
|
||||
expanded: newExpanded,
|
||||
});
|
||||
|
||||
const current = await asyncStore.eventListenerBreakpoints;
|
||||
asyncStore.eventListenerBreakpoints = {
|
||||
...current,
|
||||
expanded: newExpanded,
|
||||
};
|
||||
}
|
||||
|
||||
export function addEventListenerBreakpoints(eventsToAdd: string[]) {
|
||||
|
|
|
@ -12,11 +12,11 @@ import type {
|
|||
EventListenerExpandedList,
|
||||
} from "../actions/types";
|
||||
|
||||
export type EventListenersState = {
|
||||
active: EventListenerActiveList,
|
||||
categories: EventListenerCategoryList,
|
||||
expanded: EventListenerExpandedList,
|
||||
};
|
||||
export type EventListenersState = {|
|
||||
+active: EventListenerActiveList,
|
||||
+categories: EventListenerCategoryList,
|
||||
+expanded: EventListenerExpandedList,
|
||||
|};
|
||||
|
||||
export function initialEventListenerState(): EventListenersState {
|
||||
return {
|
||||
|
@ -46,19 +46,19 @@ function update(
|
|||
}
|
||||
|
||||
export function getActiveEventListeners(state: State): EventListenerActiveList {
|
||||
return state.eventListenerBreakpoints.active || [];
|
||||
return state.eventListenerBreakpoints.active;
|
||||
}
|
||||
|
||||
export function getEventListenerBreakpointTypes(
|
||||
state: State
|
||||
): EventListenerCategoryList {
|
||||
return state.eventListenerBreakpoints.categories || [];
|
||||
return state.eventListenerBreakpoints.categories;
|
||||
}
|
||||
|
||||
export function getEventListenerExpanded(
|
||||
state: State
|
||||
): EventListenerExpandedList {
|
||||
return state.eventListenerBreakpoints.expanded || [];
|
||||
return state.eventListenerBreakpoints.expanded;
|
||||
}
|
||||
|
||||
export default update;
|
||||
|
|
|
@ -117,11 +117,14 @@ export function bootstrapApp(store: any) {
|
|||
|
||||
let currentPendingBreakpoints;
|
||||
let currentXHRBreakpoints;
|
||||
let currentEventBreakpoints;
|
||||
function updatePrefs(state: any) {
|
||||
const previousPendingBreakpoints = currentPendingBreakpoints;
|
||||
const previousXHRBreakpoints = currentXHRBreakpoints;
|
||||
const previousEventBreakpoints = currentEventBreakpoints;
|
||||
currentPendingBreakpoints = selectors.getPendingBreakpoints(state);
|
||||
currentXHRBreakpoints = selectors.getXHRBreakpoints(state);
|
||||
currentEventBreakpoints = state.eventListenerBreakpoints;
|
||||
|
||||
if (
|
||||
previousPendingBreakpoints &&
|
||||
|
@ -130,6 +133,13 @@ function updatePrefs(state: any) {
|
|||
asyncStore.pendingBreakpoints = currentPendingBreakpoints;
|
||||
}
|
||||
|
||||
if (
|
||||
previousEventBreakpoints &&
|
||||
previousEventBreakpoints !== currentEventBreakpoints
|
||||
) {
|
||||
asyncStore.eventListenerBreakpoints = currentEventBreakpoints;
|
||||
}
|
||||
|
||||
if (currentXHRBreakpoints !== previousXHRBreakpoints) {
|
||||
asyncStore.xhrBreakpoints = currentXHRBreakpoints;
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ import { asyncStoreHelper } from "./asyncStoreHelper";
|
|||
// Schema version to bump when the async store format has changed incompatibly
|
||||
// and old stores should be cleared. This needs to match the prefs schema
|
||||
// version in devtools/client/preferences/debugger.js.
|
||||
const prefsSchemaVersion = "1.0.10";
|
||||
const prefsSchemaVersion = "1.0.11";
|
||||
const pref = Services.pref;
|
||||
|
||||
if (isDevelopment()) {
|
||||
|
|
|
@ -20,7 +20,7 @@ pref("devtools.debugger.workers", false);
|
|||
|
||||
// The default Debugger UI settings
|
||||
// This schema version needs to match that in devtools/client/debugger/src/utils/prefs.js.
|
||||
pref("devtools.debugger.prefs-schema-version", "1.0.10");
|
||||
pref("devtools.debugger.prefs-schema-version", "1.0.11");
|
||||
pref("devtools.debugger.ui.panes-workers-and-sources-width", 200);
|
||||
pref("devtools.debugger.ui.panes-instruments-width", 300);
|
||||
pref("devtools.debugger.ui.panes-visible-on-startup", false);
|
||||
|
|
|
@ -554,6 +554,8 @@ MediaCacheStream::MediaCacheStream(ChannelMediaResource* aClient,
|
|||
mIsPrivateBrowsing(aIsPrivateBrowsing) {}
|
||||
|
||||
size_t MediaCacheStream::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const {
|
||||
AutoLock lock(mMediaCache->Monitor());
|
||||
|
||||
// Looks like these are not owned:
|
||||
// - mClient
|
||||
size_t size = mBlocks.ShallowSizeOfExcludingThis(aMallocSizeOf);
|
||||
|
|
|
@ -1439,11 +1439,7 @@ bool RuntimeService::ScheduleWorker(WorkerPrivate* aWorkerPrivate) {
|
|||
}
|
||||
}
|
||||
|
||||
int32_t priority = aWorkerPrivate->IsChromeWorker()
|
||||
? nsISupportsPriority::PRIORITY_NORMAL
|
||||
: nsISupportsPriority::PRIORITY_LOW;
|
||||
|
||||
if (NS_FAILED(thread->SetPriority(priority))) {
|
||||
if (NS_FAILED(thread->SetPriority(nsISupportsPriority::PRIORITY_NORMAL))) {
|
||||
NS_WARNING("Could not set the thread's priority!");
|
||||
}
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#include "mozilla/ipc/BrowserProcessSubThread.h"
|
||||
#include "mozilla/ipc/EnvironmentMap.h"
|
||||
#include "mozilla/LinkedList.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/Omnijar.h"
|
||||
#include "mozilla/RecordReplay.h"
|
||||
#include "mozilla/RDDProcessHost.h"
|
||||
|
@ -84,11 +85,6 @@
|
|||
using mozilla::MonitorAutoLock;
|
||||
using mozilla::Preferences;
|
||||
using mozilla::StaticMutexAutoLock;
|
||||
using mozilla::ipc::GeckoChildProcessHost;
|
||||
using mozilla::ipc::LaunchError;
|
||||
using mozilla::ipc::LaunchResults;
|
||||
using mozilla::ipc::ProcessHandlePromise;
|
||||
using mozilla::ipc::ProcessLaunchPromise;
|
||||
|
||||
namespace mozilla {
|
||||
MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedPRFileDesc, PRFileDesc,
|
||||
|
@ -111,10 +107,12 @@ static bool ShouldHaveDirectoryService() {
|
|||
namespace mozilla {
|
||||
namespace ipc {
|
||||
|
||||
class ProcessLauncher {
|
||||
static Atomic<int32_t> gChildCounter;
|
||||
|
||||
class BaseProcessLauncher {
|
||||
public:
|
||||
ProcessLauncher(GeckoChildProcessHost* aHost,
|
||||
std::vector<std::string>&& aExtraOpts)
|
||||
BaseProcessLauncher(GeckoChildProcessHost* aHost,
|
||||
std::vector<std::string>&& aExtraOpts)
|
||||
: mProcessType(aHost->mProcessType),
|
||||
mLaunchOptions(std::move(aHost->mLaunchOptions)),
|
||||
mExtraOpts(std::move(aExtraOpts)),
|
||||
|
@ -127,26 +125,36 @@ class ProcessLauncher {
|
|||
mIsFileContent(aHost->mIsFileContent),
|
||||
mEnableSandboxLogging(aHost->mEnableSandboxLogging),
|
||||
#endif
|
||||
mTmpDirName(aHost->mTmpDirName) {
|
||||
mTmpDirName(aHost->mTmpDirName),
|
||||
mChildId(++gChildCounter) {
|
||||
SprintfLiteral(mPidString, "%d", base::GetCurrentProcId());
|
||||
}
|
||||
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ProcessLauncher);
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(BaseProcessLauncher);
|
||||
|
||||
RefPtr<ProcessLaunchPromise> Launch(GeckoChildProcessHost*);
|
||||
|
||||
private:
|
||||
~ProcessLauncher() {}
|
||||
protected:
|
||||
virtual ~BaseProcessLauncher() = default;
|
||||
|
||||
RefPtr<ProcessLaunchPromise> PerformAsyncLaunch();
|
||||
RefPtr<ProcessLaunchPromise> FinishLaunch();
|
||||
|
||||
// Overrideable hooks. If superclass behavior is invoked, it's always at the
|
||||
// top of the override.
|
||||
virtual bool DoSetup();
|
||||
virtual bool DoLaunch() = 0;
|
||||
virtual bool DoFinishLaunch() { return true; };
|
||||
|
||||
void MapChildLogging();
|
||||
|
||||
static BinPathType GetPathToBinary(FilePath&, GeckoProcessType);
|
||||
|
||||
#if defined(MOZ_WIDGET_ANDROID)
|
||||
void LaunchAndroidService(
|
||||
const char* type, const std::vector<std::string>& argv,
|
||||
const base::file_handle_mapping_vector& fds_to_remap,
|
||||
base::ProcessHandle* process_handle);
|
||||
#endif // defined(MOZ_WIDGET_ANDROID)
|
||||
void GetChildLogName(const char* origLogName, nsACString& buffer);
|
||||
|
||||
const char* ChildProcessType() {
|
||||
return XRE_ChildProcessTypeToString(mProcessType);
|
||||
}
|
||||
|
||||
GeckoProcessType mProcessType;
|
||||
UniquePtr<base::LaunchOptions> mLaunchOptions;
|
||||
|
@ -161,15 +169,112 @@ class ProcessLauncher {
|
|||
bool mEnableSandboxLogging;
|
||||
#endif
|
||||
nsCString mTmpDirName;
|
||||
LaunchResults mResults = LaunchResults();
|
||||
int32_t mChildId;
|
||||
TimeStamp mStartTimeStamp = TimeStamp::Now();
|
||||
char mPidString[32];
|
||||
|
||||
// Set during launch.
|
||||
IPC::Channel* mChannel;
|
||||
IPC::Channel* mChannel = nullptr;
|
||||
std::wstring mChannelId;
|
||||
ScopedPRFileDesc mCrashAnnotationReadPipe;
|
||||
ScopedPRFileDesc mCrashAnnotationWritePipe;
|
||||
};
|
||||
|
||||
} // namespace ipc
|
||||
} // namespace mozilla
|
||||
#ifdef XP_WIN
|
||||
class WindowsProcessLauncher : public BaseProcessLauncher {
|
||||
public:
|
||||
WindowsProcessLauncher(GeckoChildProcessHost* aHost,
|
||||
std::vector<std::string>&& aExtraOpts)
|
||||
: BaseProcessLauncher(aHost, std::move(aExtraOpts)) {}
|
||||
|
||||
protected:
|
||||
virtual bool DoSetup() override;
|
||||
virtual bool DoLaunch() override;
|
||||
virtual bool DoFinishLaunch() override;
|
||||
|
||||
mozilla::Maybe<CommandLine> mCmdLine;
|
||||
bool mUseSandbox = false;
|
||||
};
|
||||
typedef WindowsProcessLauncher ProcessLauncher;
|
||||
#endif // XP_WIN
|
||||
|
||||
#ifdef OS_POSIX
|
||||
class PosixProcessLauncher : public BaseProcessLauncher {
|
||||
public:
|
||||
PosixProcessLauncher(GeckoChildProcessHost* aHost,
|
||||
std::vector<std::string>&& aExtraOpts)
|
||||
: BaseProcessLauncher(aHost, std::move(aExtraOpts)) {}
|
||||
|
||||
protected:
|
||||
virtual bool DoSetup() override;
|
||||
virtual bool DoLaunch() override;
|
||||
virtual bool DoFinishLaunch() override;
|
||||
|
||||
std::vector<std::string> mChildArgv;
|
||||
};
|
||||
|
||||
# if defined(XP_MACOSX)
|
||||
class MacProcessLauncher : public PosixProcessLauncher {
|
||||
public:
|
||||
MacProcessLauncher(GeckoChildProcessHost* aHost,
|
||||
std::vector<std::string>&& aExtraOpts)
|
||||
: PosixProcessLauncher(aHost, std::move(aExtraOpts)),
|
||||
// Put a random number into the channel name, so that
|
||||
// a compromised renderer can't pretend being the child
|
||||
// that's forked off.
|
||||
mMachConnectionName(
|
||||
StringPrintf("org.mozilla.machname.%d",
|
||||
base::RandInt(0, std::numeric_limits<int>::max()))),
|
||||
mParentRecvPort(mMachConnectionName.c_str()) {}
|
||||
|
||||
protected:
|
||||
virtual bool DoFinishLaunch() override;
|
||||
|
||||
std::string mMachConnectionName;
|
||||
// We add a mach port to the command line so the child can communicate its
|
||||
// 'task_t' back to the parent.
|
||||
ReceivePort mParentRecvPort;
|
||||
|
||||
friend class PosixProcessLauncher;
|
||||
};
|
||||
typedef MacProcessLauncher ProcessLauncher;
|
||||
# elif defined(MOZ_WIDGET_ANDROID)
|
||||
class AndroidProcessLauncher : public PosixProcessLauncher {
|
||||
public:
|
||||
AndroidProcessLauncher(GeckoChildProcessHost* aHost,
|
||||
std::vector<std::string>&& aExtraOpts)
|
||||
: PosixProcessLauncher(aHost, std::move(aExtraOpts)) {}
|
||||
|
||||
protected:
|
||||
virtual bool DoLaunch() override;
|
||||
void LaunchAndroidService(
|
||||
const char* type, const std::vector<std::string>& argv,
|
||||
const base::file_handle_mapping_vector& fds_to_remap,
|
||||
base::ProcessHandle* process_handle);
|
||||
};
|
||||
typedef AndroidProcessLauncher ProcessLauncher;
|
||||
// NB: Technically Android is linux (i.e. XP_LINUX is defined), but we want
|
||||
// orthogonal IPC machinery there. Conversely, there are tier-3 non-Linux
|
||||
// platforms (BSD and Solaris) where we want the "linux" IPC machinery. So
|
||||
// we use MOZ_WIDGET_* to choose the platform backend.
|
||||
# elif defined(MOZ_WIDGET_GTK)
|
||||
class LinuxProcessLauncher : public PosixProcessLauncher {
|
||||
public:
|
||||
LinuxProcessLauncher(GeckoChildProcessHost* aHost,
|
||||
std::vector<std::string>&& aExtraOpts)
|
||||
: PosixProcessLauncher(aHost, std::move(aExtraOpts)) {}
|
||||
|
||||
protected:
|
||||
virtual bool DoSetup() override;
|
||||
};
|
||||
typedef LinuxProcessLauncher ProcessLauncher;
|
||||
# elif
|
||||
# error "Unknown platform"
|
||||
# endif
|
||||
#endif // OS_POSIX
|
||||
|
||||
using mozilla::ipc::BaseProcessLauncher;
|
||||
using mozilla::ipc::ProcessLauncher;
|
||||
|
||||
mozilla::StaticAutoPtr<mozilla::LinkedList<GeckoChildProcessHost>>
|
||||
|
@ -275,7 +380,7 @@ void GeckoChildProcessHost::Destroy() {
|
|||
}
|
||||
|
||||
// static
|
||||
mozilla::BinPathType ProcessLauncher::GetPathToBinary(
|
||||
mozilla::BinPathType BaseProcessLauncher::GetPathToBinary(
|
||||
FilePath& exePath, GeckoProcessType processType) {
|
||||
BinPathType pathType = XRE_GetChildProcBinPathType(processType);
|
||||
|
||||
|
@ -471,7 +576,7 @@ bool GeckoChildProcessHost::AsyncLaunch(std::vector<std::string> aExtraOpts) {
|
|||
}
|
||||
#endif
|
||||
|
||||
RefPtr<ProcessLauncher> launcher =
|
||||
RefPtr<BaseProcessLauncher> launcher =
|
||||
new ProcessLauncher(this, std::move(aExtraOpts));
|
||||
|
||||
// Note: Destroy() waits on mHandlePromise to delete |this|. As such, we want
|
||||
|
@ -483,7 +588,7 @@ bool GeckoChildProcessHost::AsyncLaunch(std::vector<std::string> aExtraOpts) {
|
|||
mHandlePromise = p;
|
||||
|
||||
mozilla::InvokeAsync<GeckoChildProcessHost*>(
|
||||
IOThread(), launcher.get(), __func__, &ProcessLauncher::Launch, this)
|
||||
IOThread(), launcher.get(), __func__, &BaseProcessLauncher::Launch, this)
|
||||
->Then(
|
||||
IOThread(), __func__,
|
||||
[this, p](const LaunchResults aResults) {
|
||||
|
@ -619,9 +724,8 @@ void GeckoChildProcessHost::SetAlreadyDead() {
|
|||
mChildProcessHandle = 0;
|
||||
}
|
||||
|
||||
static int32_t gChildCounter = 0;
|
||||
|
||||
static void GetChildLogName(const char* origLogName, nsACString& buffer) {
|
||||
void BaseProcessLauncher::GetChildLogName(const char* origLogName,
|
||||
nsACString& buffer) {
|
||||
#ifdef XP_WIN
|
||||
// On Windows we must expand relative paths because sandboxing rules
|
||||
// bound only to full paths. fopen fowards to NtCreateFile which checks
|
||||
|
@ -793,21 +897,33 @@ static bool Contains(const std::vector<std::string>& aExtraOpts,
|
|||
}
|
||||
#endif // defined(XP_WIN) && (defined(MOZ_SANDBOX) || defined(_ARM64_))
|
||||
|
||||
RefPtr<ProcessLaunchPromise> ProcessLauncher::PerformAsyncLaunch() {
|
||||
RefPtr<ProcessLaunchPromise> BaseProcessLauncher::PerformAsyncLaunch() {
|
||||
if (!DoSetup()) {
|
||||
return ProcessLaunchPromise::CreateAndReject(LaunchError{}, __func__);
|
||||
}
|
||||
if (!DoLaunch()) {
|
||||
return ProcessLaunchPromise::CreateAndReject(LaunchError{}, __func__);
|
||||
}
|
||||
|
||||
return FinishLaunch();
|
||||
}
|
||||
|
||||
bool BaseProcessLauncher::DoSetup() {
|
||||
#ifdef MOZ_GECKO_PROFILER
|
||||
RefPtr<ProcessLauncher> self = this;
|
||||
RefPtr<BaseProcessLauncher> self = this;
|
||||
GetProfilerEnvVarsForChildProcess([self](const char* key, const char* value) {
|
||||
self->mLaunchOptions->env_map[ENVIRONMENT_STRING(key)] =
|
||||
ENVIRONMENT_STRING(value);
|
||||
});
|
||||
#endif
|
||||
|
||||
const auto startTS = TimeStamp::Now();
|
||||
MapChildLogging();
|
||||
|
||||
// - Note: this code is not called re-entrantly, nor are restoreOrig*LogName
|
||||
// or gChildCounter touched by any other thread, so this is safe.
|
||||
++gChildCounter;
|
||||
return PR_CreatePipe(&mCrashAnnotationReadPipe.rwget(),
|
||||
&mCrashAnnotationWritePipe.rwget()) == PR_SUCCESS;
|
||||
}
|
||||
|
||||
void BaseProcessLauncher::MapChildLogging() {
|
||||
const char* origNSPRLogName = PR_GetEnv("NSPR_LOG_FILE");
|
||||
const char* origMozLogName = PR_GetEnv("MOZ_LOG_FILE");
|
||||
|
||||
|
@ -830,47 +946,14 @@ RefPtr<ProcessLaunchPromise> ProcessLauncher::PerformAsyncLaunch() {
|
|||
mLaunchOptions->env_map[ENVIRONMENT_LITERAL("RUST_LOG")] =
|
||||
ENVIRONMENT_STRING(childRustLog.get());
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(XP_LINUX) && defined(MOZ_SANDBOX)
|
||||
if (!mTmpDirName.IsEmpty()) {
|
||||
// Point a bunch of things that might want to write from content to our
|
||||
// shiny new content-process specific tmpdir
|
||||
mLaunchOptions->env_map[ENVIRONMENT_LITERAL("TMPDIR")] =
|
||||
ENVIRONMENT_STRING(mTmpDirName.get());
|
||||
// Partial fix for bug 1380051 (not persistent - should be)
|
||||
mLaunchOptions->env_map[ENVIRONMENT_LITERAL("MESA_GLSL_CACHE_DIR")] =
|
||||
ENVIRONMENT_STRING(mTmpDirName.get());
|
||||
}
|
||||
#endif
|
||||
|
||||
LaunchResults results = LaunchResults();
|
||||
results.mHandle = 0;
|
||||
|
||||
// send the child the PID so that it can open a ProcessHandle back to us.
|
||||
// probably don't want to do this in the long run
|
||||
char pidstring[32];
|
||||
SprintfLiteral(pidstring, "%d", base::GetCurrentProcId());
|
||||
|
||||
const char* const childProcessType =
|
||||
XRE_ChildProcessTypeToString(mProcessType);
|
||||
|
||||
ScopedPRFileDesc crashAnnotationReadPipe;
|
||||
ScopedPRFileDesc crashAnnotationWritePipe;
|
||||
if (PR_CreatePipe(&crashAnnotationReadPipe.rwget(),
|
||||
&crashAnnotationWritePipe.rwget()) != PR_SUCCESS) {
|
||||
return ProcessLaunchPromise::CreateAndReject(LaunchError{}, __func__);
|
||||
#if defined(MOZ_WIDGET_GTK)
|
||||
bool LinuxProcessLauncher::DoSetup() {
|
||||
if (!PosixProcessLauncher::DoSetup()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
#if defined(OS_POSIX)
|
||||
// For POSIX, we have to be extremely anal about *not* using
|
||||
// std::wstring in code compiled with Mozilla's -fshort-wchar
|
||||
// configuration, because chromium is compiled with -fno-short-wchar
|
||||
// and passing wstrings from one config to the other is unsafe. So
|
||||
// we split the logic here.
|
||||
|
||||
# if defined(OS_POSIX)
|
||||
# if defined(MOZ_WIDGET_GTK)
|
||||
if (mProcessType == GeckoProcessType_Content) {
|
||||
// disable IM module to avoid sandbox violation
|
||||
mLaunchOptions->env_map["GTK_IM_MODULE"] = "gtk-im-context-simple";
|
||||
|
@ -880,7 +963,28 @@ RefPtr<ProcessLaunchPromise> ProcessLauncher::PerformAsyncLaunch() {
|
|||
// anyway.
|
||||
mLaunchOptions->env_map["NO_AT_BRIDGE"] = "1";
|
||||
}
|
||||
# endif // defined(MOZ_WIDGET_GTK)
|
||||
|
||||
# ifdef MOZ_SANDBOX
|
||||
if (!mTmpDirName.IsEmpty()) {
|
||||
// Point a bunch of things that might want to write from content to our
|
||||
// shiny new content-process specific tmpdir
|
||||
mLaunchOptions->env_map[ENVIRONMENT_LITERAL("TMPDIR")] =
|
||||
ENVIRONMENT_STRING(mTmpDirName.get());
|
||||
// Partial fix for bug 1380051 (not persistent - should be)
|
||||
mLaunchOptions->env_map[ENVIRONMENT_LITERAL("MESA_GLSL_CACHE_DIR")] =
|
||||
ENVIRONMENT_STRING(mTmpDirName.get());
|
||||
}
|
||||
# endif // MOZ_SANDBOX
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif // MOZ_WIDGET_GTK
|
||||
|
||||
#ifdef OS_POSIX
|
||||
bool PosixProcessLauncher::DoSetup() {
|
||||
if (!BaseProcessLauncher::DoSetup()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// XPCOM may not be initialized in some subprocesses. We don't want
|
||||
// to initialize XPCOM just for the directory service, especially
|
||||
|
@ -890,23 +994,23 @@ RefPtr<ProcessLaunchPromise> ProcessLauncher::PerformAsyncLaunch() {
|
|||
MOZ_ASSERT(gGREBinPath);
|
||||
nsCString path;
|
||||
NS_CopyUnicodeToNative(nsDependentString(gGREBinPath), path);
|
||||
# if defined(OS_LINUX) || defined(OS_BSD)
|
||||
# if defined(OS_LINUX) || defined(OS_BSD)
|
||||
const char* ld_library_path = PR_GetEnv("LD_LIBRARY_PATH");
|
||||
nsCString new_ld_lib_path(path.get());
|
||||
|
||||
# ifdef MOZ_WIDGET_GTK
|
||||
# ifdef MOZ_WIDGET_GTK
|
||||
if (mProcessType == GeckoProcessType_Plugin) {
|
||||
new_ld_lib_path.AppendLiteral("/gtk2:");
|
||||
new_ld_lib_path.Append(path.get());
|
||||
}
|
||||
# endif // MOZ_WIDGET_GTK
|
||||
# endif // MOZ_WIDGET_GTK
|
||||
if (ld_library_path && *ld_library_path) {
|
||||
new_ld_lib_path.Append(':');
|
||||
new_ld_lib_path.Append(ld_library_path);
|
||||
}
|
||||
mLaunchOptions->env_map["LD_LIBRARY_PATH"] = new_ld_lib_path.get();
|
||||
|
||||
# elif OS_MACOSX // defined(OS_LINUX) || defined(OS_BSD)
|
||||
# elif OS_MACOSX // defined(OS_LINUX) || defined(OS_BSD)
|
||||
mLaunchOptions->env_map["DYLD_LIBRARY_PATH"] = path.get();
|
||||
// XXX DYLD_INSERT_LIBRARIES should only be set when launching a plugin
|
||||
// process, and has no effect on other subprocesses (the hooks in
|
||||
|
@ -927,9 +1031,8 @@ RefPtr<ProcessLaunchPromise> ProcessLauncher::PerformAsyncLaunch() {
|
|||
interpose.Append(path.get());
|
||||
interpose.AppendLiteral("/libplugin_child_interpose.dylib");
|
||||
mLaunchOptions->env_map["DYLD_INSERT_LIBRARIES"] = interpose.get();
|
||||
# endif // defined(OS_LINUX) || defined(OS_BSD)
|
||||
# endif // defined(OS_LINUX) || defined(OS_BSD)
|
||||
}
|
||||
# endif // defined(OS_POSIX)
|
||||
|
||||
FilePath exePath;
|
||||
BinPathType pathType = GetPathToBinary(exePath, mProcessType);
|
||||
|
@ -944,15 +1047,13 @@ RefPtr<ProcessLaunchPromise> ProcessLauncher::PerformAsyncLaunch() {
|
|||
// no need for kProcessChannelID, the child process inherits the
|
||||
// other end of the socketpair() from us
|
||||
|
||||
std::vector<std::string> childArgv;
|
||||
|
||||
childArgv.push_back(exePath.value());
|
||||
mChildArgv.push_back(exePath.value());
|
||||
|
||||
if (pathType == BinPathType::Self) {
|
||||
childArgv.push_back("-contentproc");
|
||||
mChildArgv.push_back("-contentproc");
|
||||
}
|
||||
|
||||
childArgv.insert(childArgv.end(), mExtraOpts.begin(), mExtraOpts.end());
|
||||
mChildArgv.insert(mChildArgv.end(), mExtraOpts.begin(), mExtraOpts.end());
|
||||
|
||||
if (mProcessType != GeckoProcessType_GMPlugin) {
|
||||
if (Omnijar::IsInitialized()) {
|
||||
|
@ -961,108 +1062,110 @@ RefPtr<ProcessLaunchPromise> ProcessLauncher::PerformAsyncLaunch() {
|
|||
nsAutoCString path;
|
||||
nsCOMPtr<nsIFile> file = Omnijar::GetPath(Omnijar::GRE);
|
||||
if (file && NS_SUCCEEDED(file->GetNativePath(path))) {
|
||||
childArgv.push_back("-greomni");
|
||||
childArgv.push_back(path.get());
|
||||
mChildArgv.push_back("-greomni");
|
||||
mChildArgv.push_back(path.get());
|
||||
}
|
||||
file = Omnijar::GetPath(Omnijar::APP);
|
||||
if (file && NS_SUCCEEDED(file->GetNativePath(path))) {
|
||||
childArgv.push_back("-appomni");
|
||||
childArgv.push_back(path.get());
|
||||
mChildArgv.push_back("-appomni");
|
||||
mChildArgv.push_back(path.get());
|
||||
}
|
||||
}
|
||||
// Add the application directory path (-appdir path)
|
||||
AddAppDirToCommandLine(childArgv);
|
||||
AddAppDirToCommandLine(mChildArgv);
|
||||
}
|
||||
|
||||
childArgv.push_back(pidstring);
|
||||
mChildArgv.push_back(mPidString);
|
||||
|
||||
if (!CrashReporter::IsDummy()) {
|
||||
# if defined(OS_LINUX) || defined(OS_BSD) || defined(OS_SOLARIS)
|
||||
int childCrashFd, childCrashRemapFd;
|
||||
if (!CrashReporter::CreateNotificationPipeForChild(&childCrashFd,
|
||||
&childCrashRemapFd)) {
|
||||
return ProcessLaunchPromise::CreateAndReject(LaunchError{}, __func__);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (0 <= childCrashFd) {
|
||||
mLaunchOptions->fds_to_remap.push_back(
|
||||
std::pair<int, int>(childCrashFd, childCrashRemapFd));
|
||||
// "true" == crash reporting enabled
|
||||
childArgv.push_back("true");
|
||||
mChildArgv.push_back("true");
|
||||
} else {
|
||||
// "false" == crash reporting disabled
|
||||
childArgv.push_back("false");
|
||||
mChildArgv.push_back("false");
|
||||
}
|
||||
# elif defined(MOZ_WIDGET_COCOA) /* defined(OS_LINUX) || defined(OS_BSD) || \
|
||||
defined(OS_SOLARIS) */
|
||||
childArgv.push_back(CrashReporter::GetChildNotificationPipe());
|
||||
mChildArgv.push_back(CrashReporter::GetChildNotificationPipe());
|
||||
# endif // defined(OS_LINUX) || defined(OS_BSD) || defined(OS_SOLARIS)
|
||||
}
|
||||
|
||||
int fd = PR_FileDesc2NativeHandle(crashAnnotationWritePipe);
|
||||
int fd = PR_FileDesc2NativeHandle(mCrashAnnotationWritePipe);
|
||||
mLaunchOptions->fds_to_remap.push_back(
|
||||
std::make_pair(fd, CrashReporter::GetAnnotationTimeCrashFd()));
|
||||
|
||||
# ifdef MOZ_WIDGET_COCOA
|
||||
// Add a mach port to the command line so the child can communicate its
|
||||
// 'task_t' back to the parent.
|
||||
//
|
||||
// Put a random number into the channel name, so that a compromised renderer
|
||||
// can't pretend being the child that's forked off.
|
||||
std::string mach_connection_name =
|
||||
StringPrintf("org.mozilla.machname.%d",
|
||||
base::RandInt(0, std::numeric_limits<int>::max()));
|
||||
childArgv.push_back(mach_connection_name.c_str());
|
||||
mChildArgv.push_back(
|
||||
static_cast<MacProcessLauncher*>(this)->mMachConnectionName.c_str());
|
||||
# endif // MOZ_WIDGET_COCOA
|
||||
|
||||
childArgv.push_back(childProcessType);
|
||||
mChildArgv.push_back(ChildProcessType());
|
||||
|
||||
# ifdef MOZ_WIDGET_COCOA
|
||||
// Register the listening port before launching the child, to ensure
|
||||
// that it's there when the child tries to look it up.
|
||||
ReceivePort parent_recv_port(mach_connection_name.c_str());
|
||||
# endif // MOZ_WIDGET_COCOA
|
||||
return true;
|
||||
}
|
||||
#endif // OS_POSIX
|
||||
|
||||
# if defined(MOZ_WIDGET_ANDROID)
|
||||
LaunchAndroidService(childProcessType, childArgv,
|
||||
mLaunchOptions->fds_to_remap, &results.mHandle);
|
||||
if (results.mHandle == 0) {
|
||||
return ProcessLaunchPromise::CreateAndReject(LaunchError{}, __func__);
|
||||
#if defined(MOZ_WIDGET_ANDROID)
|
||||
bool AndroidProcessLauncher::DoLaunch() {
|
||||
LaunchAndroidService(ChildProcessType(), mChildArgv,
|
||||
mLaunchOptions->fds_to_remap, &mResults.mHandle);
|
||||
return mResults.mHandle != 0;
|
||||
}
|
||||
#endif // MOZ_WIDGET_ANDROID
|
||||
|
||||
#ifdef OS_POSIX
|
||||
bool PosixProcessLauncher::DoLaunch() {
|
||||
return base::LaunchApp(mChildArgv, *mLaunchOptions, &mResults.mHandle);
|
||||
}
|
||||
|
||||
bool PosixProcessLauncher::DoFinishLaunch() {
|
||||
if (!BaseProcessLauncher::DoFinishLaunch()) {
|
||||
return false;
|
||||
}
|
||||
# else // goes with defined(MOZ_WIDGET_ANDROID)
|
||||
if (!base::LaunchApp(childArgv, *mLaunchOptions, &results.mHandle)) {
|
||||
return ProcessLaunchPromise::CreateAndReject(LaunchError{}, __func__);
|
||||
}
|
||||
# endif // defined(MOZ_WIDGET_ANDROID)
|
||||
|
||||
// We're in the parent and the child was launched. Close the child FD in the
|
||||
// parent as soon as possible, which will allow the parent to detect when the
|
||||
// child closes its FD (either due to normal exit or due to crash).
|
||||
mChannel->CloseClientFileDescriptor();
|
||||
|
||||
# ifdef MOZ_WIDGET_COCOA
|
||||
return true;
|
||||
}
|
||||
#endif // OS_POSIX
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
bool MacProcessLauncher::DoFinishLaunch() {
|
||||
// Wait for the child process to send us its 'task_t' data.
|
||||
const int kTimeoutMs = 10000;
|
||||
|
||||
MachReceiveMessage child_message;
|
||||
kern_return_t err =
|
||||
parent_recv_port.WaitForMessage(&child_message, kTimeoutMs);
|
||||
mParentRecvPort.WaitForMessage(&child_message, kTimeoutMs);
|
||||
if (err != KERN_SUCCESS) {
|
||||
std::string errString =
|
||||
StringPrintf("0x%x %s", err, mach_error_string(err));
|
||||
CHROMIUM_LOG(ERROR) << "parent WaitForMessage() failed: " << errString;
|
||||
return ProcessLaunchPromise::CreateAndReject(LaunchError{}, __func__);
|
||||
return false;
|
||||
}
|
||||
|
||||
task_t child_task = child_message.GetTranslatedPort(0);
|
||||
if (child_task == MACH_PORT_NULL) {
|
||||
CHROMIUM_LOG(ERROR) << "parent GetTranslatedPort(0) failed.";
|
||||
return ProcessLaunchPromise::CreateAndReject(LaunchError{}, __func__);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (child_message.GetTranslatedPort(1) == MACH_PORT_NULL) {
|
||||
CHROMIUM_LOG(ERROR) << "parent GetTranslatedPort(1) failed.";
|
||||
return ProcessLaunchPromise::CreateAndReject(LaunchError{}, __func__);
|
||||
return false;
|
||||
}
|
||||
MachPortSender parent_sender(child_message.GetTranslatedPort(1));
|
||||
|
||||
|
@ -1082,7 +1185,7 @@ RefPtr<ProcessLaunchPromise> ProcessLauncher::PerformAsyncLaunch() {
|
|||
if (!parent_message.AddDescriptor(MachMsgPortDescriptor(bootstrap_port))) {
|
||||
CHROMIUM_LOG(ERROR) << "parent AddDescriptor(" << bootstrap_port
|
||||
<< ") failed.";
|
||||
return ProcessLaunchPromise::CreateAndReject(LaunchError{}, __func__);
|
||||
return false;
|
||||
}
|
||||
|
||||
auto* parent_recv_port_memory = new ReceivePort();
|
||||
|
@ -1090,7 +1193,7 @@ RefPtr<ProcessLaunchPromise> ProcessLauncher::PerformAsyncLaunch() {
|
|||
MachMsgPortDescriptor(parent_recv_port_memory->GetPort()))) {
|
||||
CHROMIUM_LOG(ERROR) << "parent AddDescriptor("
|
||||
<< parent_recv_port_memory->GetPort() << ") failed.";
|
||||
return ProcessLaunchPromise::CreateAndReject(LaunchError{}, __func__);
|
||||
return false;
|
||||
}
|
||||
|
||||
auto* parent_send_port_memory_ack = new ReceivePort();
|
||||
|
@ -1099,7 +1202,7 @@ RefPtr<ProcessLaunchPromise> ProcessLauncher::PerformAsyncLaunch() {
|
|||
CHROMIUM_LOG(ERROR) << "parent AddDescriptor("
|
||||
<< parent_send_port_memory_ack->GetPort()
|
||||
<< ") failed.";
|
||||
return ProcessLaunchPromise::CreateAndReject(LaunchError{}, __func__);
|
||||
return false;
|
||||
}
|
||||
|
||||
err = parent_sender.SendMessage(parent_message, kTimeoutMs);
|
||||
|
@ -1107,17 +1210,27 @@ RefPtr<ProcessLaunchPromise> ProcessLauncher::PerformAsyncLaunch() {
|
|||
std::string errString =
|
||||
StringPrintf("0x%x %s", err, mach_error_string(err));
|
||||
CHROMIUM_LOG(ERROR) << "parent SendMessage() failed: " << errString;
|
||||
return ProcessLaunchPromise::CreateAndReject(LaunchError{}, __func__);
|
||||
return false;
|
||||
}
|
||||
|
||||
SharedMemoryBasic::SetupMachMemory(
|
||||
results.mHandle, parent_recv_port_memory, parent_recv_port_memory_ack,
|
||||
mResults.mHandle, parent_recv_port_memory, parent_recv_port_memory_ack,
|
||||
parent_send_port_memory, parent_send_port_memory_ack, false);
|
||||
|
||||
# endif // MOZ_WIDGET_COCOA
|
||||
// NB: on OS X, we block much longer than we need to in order to
|
||||
// reach this call, waiting for the child process's task_t. The
|
||||
// best way to fix that is to refactor this file, hard.
|
||||
mResults.mChildTask = child_task;
|
||||
|
||||
//--------------------------------------------------
|
||||
#elif defined(OS_WIN) // defined(OS_POSIX)
|
||||
return true;
|
||||
}
|
||||
#endif // XP_MACOSX
|
||||
|
||||
#ifdef XP_WIN
|
||||
bool WindowsProcessLauncher::DoSetup() {
|
||||
if (!BaseProcessLauncher::DoSetup()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
FilePath exePath;
|
||||
BinPathType pathType = GetPathToBinary(exePath, mProcessType);
|
||||
|
@ -1139,17 +1252,17 @@ RefPtr<ProcessLaunchPromise> ProcessLauncher::PerformAsyncLaunch() {
|
|||
# endif // if defined(_ARM64_)
|
||||
# endif // defined(MOZ_SANDBOX) || defined(_ARM64_)
|
||||
|
||||
CommandLine cmdLine(exePath.ToWStringHack());
|
||||
mCmdLine.emplace(exePath.ToWStringHack());
|
||||
|
||||
if (pathType == BinPathType::Self) {
|
||||
cmdLine.AppendLooseValue(UTF8ToWide("-contentproc"));
|
||||
mCmdLine->AppendLooseValue(UTF8ToWide("-contentproc"));
|
||||
}
|
||||
|
||||
cmdLine.AppendSwitchWithValue(switches::kProcessChannelID, mChannelId);
|
||||
mCmdLine->AppendSwitchWithValue(switches::kProcessChannelID, mChannelId);
|
||||
|
||||
for (std::vector<std::string>::iterator it = mExtraOpts.begin();
|
||||
it != mExtraOpts.end(); ++it) {
|
||||
cmdLine.AppendLooseValue(UTF8ToWide(*it));
|
||||
mCmdLine->AppendLooseValue(UTF8ToWide(*it));
|
||||
}
|
||||
|
||||
if (Omnijar::IsInitialized()) {
|
||||
|
@ -1158,25 +1271,23 @@ RefPtr<ProcessLaunchPromise> ProcessLauncher::PerformAsyncLaunch() {
|
|||
nsAutoString path;
|
||||
nsCOMPtr<nsIFile> file = Omnijar::GetPath(Omnijar::GRE);
|
||||
if (file && NS_SUCCEEDED(file->GetPath(path))) {
|
||||
cmdLine.AppendLooseValue(UTF8ToWide("-greomni"));
|
||||
cmdLine.AppendLooseValue(path.get());
|
||||
mCmdLine->AppendLooseValue(UTF8ToWide("-greomni"));
|
||||
mCmdLine->AppendLooseValue(path.get());
|
||||
}
|
||||
file = Omnijar::GetPath(Omnijar::APP);
|
||||
if (file && NS_SUCCEEDED(file->GetPath(path))) {
|
||||
cmdLine.AppendLooseValue(UTF8ToWide("-appomni"));
|
||||
cmdLine.AppendLooseValue(path.get());
|
||||
mCmdLine->AppendLooseValue(UTF8ToWide("-appomni"));
|
||||
mCmdLine->AppendLooseValue(path.get());
|
||||
}
|
||||
}
|
||||
|
||||
# if defined(MOZ_SANDBOX)
|
||||
# if defined(_ARM64_)
|
||||
if (isClearKey || isWidevine)
|
||||
results.mSandboxBroker = new RemoteSandboxBroker();
|
||||
mResults.mSandboxBroker = new RemoteSandboxBroker();
|
||||
else
|
||||
# endif // if defined(_ARM64_)
|
||||
results.mSandboxBroker = new SandboxBroker();
|
||||
|
||||
bool shouldSandboxCurrentProcess = false;
|
||||
mResults.mSandboxBroker = new SandboxBroker();
|
||||
|
||||
// XXX: Bug 1124167: We should get rid of the process specific logic for
|
||||
// sandboxing in this class at some point. Unfortunately it will take a bit
|
||||
|
@ -1188,19 +1299,18 @@ RefPtr<ProcessLaunchPromise> ProcessLauncher::PerformAsyncLaunch() {
|
|||
// SetSecurityLevelForContentProcess and just crash there right away.
|
||||
// Should this change in the future then we should also handle the error
|
||||
// here.
|
||||
results.mSandboxBroker->SetSecurityLevelForContentProcess(
|
||||
mResults.mSandboxBroker->SetSecurityLevelForContentProcess(
|
||||
mSandboxLevel, mIsFileContent);
|
||||
shouldSandboxCurrentProcess = true;
|
||||
mUseSandbox = true;
|
||||
}
|
||||
break;
|
||||
case GeckoProcessType_Plugin:
|
||||
if (mSandboxLevel > 0 && !PR_GetEnv("MOZ_DISABLE_NPAPI_SANDBOX")) {
|
||||
bool ok = results.mSandboxBroker->SetSecurityLevelForPluginProcess(
|
||||
mSandboxLevel);
|
||||
if (!ok) {
|
||||
return ProcessLaunchPromise::CreateAndReject(LaunchError{}, __func__);
|
||||
if (!mResults.mSandboxBroker->SetSecurityLevelForPluginProcess(
|
||||
mSandboxLevel)) {
|
||||
return false;
|
||||
}
|
||||
shouldSandboxCurrentProcess = true;
|
||||
mUseSandbox = true;
|
||||
}
|
||||
break;
|
||||
case GeckoProcessType_IPDLUnitTest:
|
||||
|
@ -1214,11 +1324,10 @@ RefPtr<ProcessLaunchPromise> ProcessLauncher::PerformAsyncLaunch() {
|
|||
// so use sandbox level USER_RESTRICTED instead of USER_LOCKDOWN.
|
||||
auto level =
|
||||
isWidevine ? SandboxBroker::Restricted : SandboxBroker::LockDown;
|
||||
bool ok = results.mSandboxBroker->SetSecurityLevelForGMPlugin(level);
|
||||
if (!ok) {
|
||||
return ProcessLaunchPromise::CreateAndReject(LaunchError{}, __func__);
|
||||
if (!mResults.mSandboxBroker->SetSecurityLevelForGMPlugin(level)) {
|
||||
return false;
|
||||
}
|
||||
shouldSandboxCurrentProcess = true;
|
||||
mUseSandbox = true;
|
||||
}
|
||||
break;
|
||||
case GeckoProcessType_GPU:
|
||||
|
@ -1226,8 +1335,8 @@ RefPtr<ProcessLaunchPromise> ProcessLauncher::PerformAsyncLaunch() {
|
|||
// For now we treat every failure as fatal in
|
||||
// SetSecurityLevelForGPUProcess and just crash there right away. Should
|
||||
// this change in the future then we should also handle the error here.
|
||||
results.mSandboxBroker->SetSecurityLevelForGPUProcess(mSandboxLevel);
|
||||
shouldSandboxCurrentProcess = true;
|
||||
mResults.mSandboxBroker->SetSecurityLevelForGPUProcess(mSandboxLevel);
|
||||
mUseSandbox = true;
|
||||
}
|
||||
break;
|
||||
case GeckoProcessType_VR:
|
||||
|
@ -1237,10 +1346,10 @@ RefPtr<ProcessLaunchPromise> ProcessLauncher::PerformAsyncLaunch() {
|
|||
break;
|
||||
case GeckoProcessType_RDD:
|
||||
if (!PR_GetEnv("MOZ_DISABLE_RDD_SANDBOX")) {
|
||||
if (!results.mSandboxBroker->SetSecurityLevelForRDDProcess()) {
|
||||
return ProcessLaunchPromise::CreateAndReject(LaunchError{}, __func__);
|
||||
if (!mResults.mSandboxBroker->SetSecurityLevelForRDDProcess()) {
|
||||
return false;
|
||||
}
|
||||
shouldSandboxCurrentProcess = true;
|
||||
mUseSandbox = true;
|
||||
}
|
||||
break;
|
||||
case GeckoProcessType_Socket:
|
||||
|
@ -1255,102 +1364,113 @@ RefPtr<ProcessLaunchPromise> ProcessLauncher::PerformAsyncLaunch() {
|
|||
break;
|
||||
};
|
||||
|
||||
if (shouldSandboxCurrentProcess) {
|
||||
if (mUseSandbox) {
|
||||
for (auto it = mAllowedFilesRead.begin(); it != mAllowedFilesRead.end();
|
||||
++it) {
|
||||
results.mSandboxBroker->AllowReadFile(it->c_str());
|
||||
mResults.mSandboxBroker->AllowReadFile(it->c_str());
|
||||
}
|
||||
}
|
||||
# endif // defined(MOZ_SANDBOX)
|
||||
# endif // defined(MOZ_SANDBOX)
|
||||
|
||||
// Add the application directory path (-appdir path)
|
||||
AddAppDirToCommandLine(cmdLine);
|
||||
AddAppDirToCommandLine(mCmdLine.ref());
|
||||
|
||||
// XXX Command line params past this point are expected to be at
|
||||
// the end of the command line string, and in a specific order.
|
||||
// See XRE_InitChildProcess in nsEmbedFunction.
|
||||
|
||||
// Win app model id
|
||||
cmdLine.AppendLooseValue(mGroupId.get());
|
||||
mCmdLine->AppendLooseValue(mGroupId.get());
|
||||
|
||||
// Process id
|
||||
cmdLine.AppendLooseValue(UTF8ToWide(pidstring));
|
||||
mCmdLine->AppendLooseValue(UTF8ToWide(mPidString));
|
||||
|
||||
cmdLine.AppendLooseValue(
|
||||
mCmdLine->AppendLooseValue(
|
||||
UTF8ToWide(CrashReporter::GetChildNotificationPipe()));
|
||||
|
||||
if (!CrashReporter::IsDummy()) {
|
||||
PROsfd h = PR_FileDesc2NativeHandle(crashAnnotationWritePipe);
|
||||
PROsfd h = PR_FileDesc2NativeHandle(mCrashAnnotationWritePipe);
|
||||
mLaunchOptions->handles_to_inherit.push_back(reinterpret_cast<HANDLE>(h));
|
||||
std::string hStr = std::to_string(h);
|
||||
cmdLine.AppendLooseValue(UTF8ToWide(hStr));
|
||||
mCmdLine->AppendLooseValue(UTF8ToWide(hStr));
|
||||
}
|
||||
|
||||
// Process type
|
||||
cmdLine.AppendLooseValue(UTF8ToWide(childProcessType));
|
||||
|
||||
# if defined(MOZ_SANDBOX)
|
||||
if (shouldSandboxCurrentProcess) {
|
||||
// Mark the handles to inherit as inheritable.
|
||||
for (HANDLE h : mLaunchOptions->handles_to_inherit) {
|
||||
results.mSandboxBroker->AddHandleToShare(h);
|
||||
}
|
||||
|
||||
if (results.mSandboxBroker->LaunchApp(
|
||||
cmdLine.program().c_str(), cmdLine.command_line_string().c_str(),
|
||||
mLaunchOptions->env_map, mProcessType, mEnableSandboxLogging,
|
||||
&results.mHandle)) {
|
||||
EnvironmentLog("MOZ_PROCESS_LOG")
|
||||
.print("==> process %d launched child process %d (%S)\n",
|
||||
base::GetCurrentProcId(), base::GetProcId(results.mHandle),
|
||||
cmdLine.command_line_string().c_str());
|
||||
} else {
|
||||
return ProcessLaunchPromise::CreateAndReject(LaunchError{}, __func__);
|
||||
}
|
||||
} else
|
||||
# endif // defined(MOZ_SANDBOX)
|
||||
{
|
||||
if (!base::LaunchApp(cmdLine, *mLaunchOptions, &results.mHandle)) {
|
||||
return ProcessLaunchPromise::CreateAndReject(LaunchError{}, __func__);
|
||||
}
|
||||
mCmdLine->AppendLooseValue(UTF8ToWide(ChildProcessType()));
|
||||
|
||||
# ifdef MOZ_SANDBOX
|
||||
// We need to be able to duplicate handles to some types of non-sandboxed
|
||||
// child processes.
|
||||
switch (mProcessType) {
|
||||
case GeckoProcessType_Default:
|
||||
MOZ_CRASH("shouldn't be launching a parent process");
|
||||
case GeckoProcessType_Plugin:
|
||||
case GeckoProcessType_IPDLUnitTest:
|
||||
// No handle duplication necessary.
|
||||
break;
|
||||
default:
|
||||
if (!SandboxBroker::AddTargetPeer(results.mHandle)) {
|
||||
NS_WARNING("Failed to add child process as target peer.");
|
||||
}
|
||||
break;
|
||||
if (mUseSandbox) {
|
||||
// Mark the handles to inherit as inheritable.
|
||||
for (HANDLE h : mLaunchOptions->handles_to_inherit) {
|
||||
mResults.mSandboxBroker->AddHandleToShare(h);
|
||||
}
|
||||
}
|
||||
# endif // MOZ_SANDBOX
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WindowsProcessLauncher::DoLaunch() {
|
||||
# ifdef MOZ_SANDBOX
|
||||
if (mUseSandbox) {
|
||||
if (mResults.mSandboxBroker->LaunchApp(
|
||||
mCmdLine->program().c_str(),
|
||||
mCmdLine->command_line_string().c_str(), mLaunchOptions->env_map,
|
||||
mProcessType, mEnableSandboxLogging, &mResults.mHandle)) {
|
||||
EnvironmentLog("MOZ_PROCESS_LOG")
|
||||
.print("==> process %d launched child process %d (%S)\n",
|
||||
base::GetCurrentProcId(), base::GetProcId(mResults.mHandle),
|
||||
mCmdLine->command_line_string().c_str());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
# endif // defined(MOZ_SANDBOX)
|
||||
|
||||
return base::LaunchApp(mCmdLine.ref(), *mLaunchOptions, &mResults.mHandle);
|
||||
}
|
||||
|
||||
bool WindowsProcessLauncher::DoFinishLaunch() {
|
||||
if (!BaseProcessLauncher::DoFinishLaunch()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
#else // goes with defined(OS_POSIX)
|
||||
# error Sorry
|
||||
#endif // defined(OS_POSIX)
|
||||
# ifdef MOZ_SANDBOX
|
||||
// We need to be able to duplicate handles to some types of non-sandboxed
|
||||
// child processes.
|
||||
switch (mProcessType) {
|
||||
case GeckoProcessType_Default:
|
||||
MOZ_CRASH("shouldn't be launching a parent process");
|
||||
case GeckoProcessType_Plugin:
|
||||
case GeckoProcessType_IPDLUnitTest:
|
||||
// No handle duplication necessary.
|
||||
break;
|
||||
default:
|
||||
if (!SandboxBroker::AddTargetPeer(mResults.mHandle)) {
|
||||
NS_WARNING("Failed to add child process as target peer.");
|
||||
}
|
||||
break;
|
||||
}
|
||||
# endif // MOZ_SANDBOX
|
||||
|
||||
MOZ_DIAGNOSTIC_ASSERT(results.mHandle);
|
||||
// NB: on OS X, we block much longer than we need to in order to
|
||||
// reach this call, waiting for the child process's task_t. The
|
||||
// best way to fix that is to refactor this file, hard.
|
||||
#ifdef XP_MACOSX
|
||||
results.mChildTask = child_task;
|
||||
#endif // XP_MACOSX
|
||||
return true;
|
||||
}
|
||||
#endif // XP_WIN
|
||||
|
||||
RefPtr<ProcessLaunchPromise> BaseProcessLauncher::FinishLaunch() {
|
||||
if (!DoFinishLaunch()) {
|
||||
return ProcessLaunchPromise::CreateAndReject(LaunchError{}, __func__);
|
||||
}
|
||||
|
||||
MOZ_DIAGNOSTIC_ASSERT(mResults.mHandle);
|
||||
|
||||
CrashReporter::RegisterChildCrashAnnotationFileDescriptor(
|
||||
base::GetProcId(results.mHandle), crashAnnotationReadPipe.forget());
|
||||
base::GetProcId(mResults.mHandle), mCrashAnnotationReadPipe.forget());
|
||||
|
||||
Telemetry::AccumulateTimeDelta(Telemetry::CHILD_PROCESS_LAUNCH_MS, startTS);
|
||||
Telemetry::AccumulateTimeDelta(Telemetry::CHILD_PROCESS_LAUNCH_MS,
|
||||
mStartTimeStamp);
|
||||
|
||||
return ProcessLaunchPromise::CreateAndResolve(results, __func__);
|
||||
return ProcessLaunchPromise::CreateAndResolve(mResults, __func__);
|
||||
}
|
||||
|
||||
bool GeckoChildProcessHost::OpenPrivilegedHandle(base::ProcessId aPid) {
|
||||
|
@ -1403,7 +1523,7 @@ void GeckoChildProcessHost::GetQueuedMessages(std::queue<IPC::Message>& queue) {
|
|||
}
|
||||
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
void ProcessLauncher::LaunchAndroidService(
|
||||
void AndroidProcessLauncher::LaunchAndroidService(
|
||||
const char* type, const std::vector<std::string>& argv,
|
||||
const base::file_handle_mapping_vector& fds_to_remap,
|
||||
base::ProcessHandle* process_handle) {
|
||||
|
@ -1518,7 +1638,7 @@ void GeckoChildProcessHost::GetAll(const GeckoProcessCallback& aCallback) {
|
|||
}
|
||||
}
|
||||
|
||||
RefPtr<ProcessLaunchPromise> ProcessLauncher::Launch(
|
||||
RefPtr<ProcessLaunchPromise> BaseProcessLauncher::Launch(
|
||||
GeckoChildProcessHost* aHost) {
|
||||
AssertIOThread();
|
||||
|
||||
|
@ -1553,5 +1673,8 @@ RefPtr<ProcessLaunchPromise> ProcessLauncher::Launch(
|
|||
}
|
||||
|
||||
return InvokeAsync(launchThread, this, __func__,
|
||||
&ProcessLauncher::PerformAsyncLaunch);
|
||||
&BaseProcessLauncher::PerformAsyncLaunch);
|
||||
}
|
||||
|
||||
} // namespace ipc
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -174,7 +174,7 @@ class GeckoChildProcessHost : public ChildProcessHost,
|
|||
// so you need to make sure the callback is as fast as possible.
|
||||
static void GetAll(const GeckoProcessCallback& aCallback);
|
||||
|
||||
friend class ProcessLauncher;
|
||||
friend class BaseProcessLauncher;
|
||||
|
||||
protected:
|
||||
~GeckoChildProcessHost();
|
||||
|
|
|
@ -37,14 +37,17 @@
|
|||
# It uses the C preprocessor to process its inputs.
|
||||
|
||||
from __future__ import with_statement
|
||||
|
||||
import errno
|
||||
import re
|
||||
import sys
|
||||
import os
|
||||
import mozpack.path as mozpath
|
||||
import subprocess
|
||||
import shlex
|
||||
import which
|
||||
|
||||
import buildconfig
|
||||
import mozpack.path as mozpath
|
||||
from mozfile import which
|
||||
|
||||
|
||||
def ToCAsciiArray(lines):
|
||||
|
@ -113,7 +116,11 @@ def embed(cxx, preprocessorOption, cppflags, msgs, sources, c_out, js_out, names
|
|||
|
||||
def preprocess(cxx, preprocessorOption, source, args=[]):
|
||||
if (not os.path.exists(cxx[0])):
|
||||
cxx[0] = which.which(cxx[0])
|
||||
binary = cxx[0]
|
||||
cxx[0] = which(binary)
|
||||
if not cxx[0]:
|
||||
raise OSError(errno.ENOENT, "%s not found on PATH" % binary)
|
||||
|
||||
# Clang seems to complain and not output anything if the extension of the
|
||||
# input is not something it recognizes, so just fake a .cpp here.
|
||||
tmpIn = 'self-hosting-cpp-input.cpp'
|
||||
|
|
|
@ -10815,6 +10815,12 @@ apigee.io
|
|||
// Submitted by Thomas Orozco <thomas@aptible.com>
|
||||
on-aptible.com
|
||||
|
||||
// ASEINet : https://www.aseinet.com/
|
||||
// Submitted by Asei SEKIGUCHI <mail@aseinet.com>
|
||||
user.aseinet.ne.jp
|
||||
gv.vc
|
||||
d.gv.vc
|
||||
|
||||
// Asociación Amigos de la Informática "Euskalamiga" : http://encounter.eus/
|
||||
// Submitted by Hector Martin <marcan@euskalencounter.org>
|
||||
user.party.eus
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
from __future__ import absolute_import, print_function, unicode_literals
|
||||
|
||||
import errno
|
||||
import sys
|
||||
|
||||
from mach.decorators import (
|
||||
|
@ -67,23 +68,24 @@ class VersionControlCommands(object):
|
|||
and this command only ensures that remote repositories providing
|
||||
VCS extensions are up to date.
|
||||
"""
|
||||
import which
|
||||
import mozboot.bootstrap as bootstrap
|
||||
import mozversioncontrol
|
||||
from mozfile import which
|
||||
|
||||
repo = mozversioncontrol.get_repository_object(self._context.topdir)
|
||||
vcs = 'hg'
|
||||
tool = 'hg'
|
||||
if repo.name == 'git':
|
||||
vcs = 'git'
|
||||
tool = 'git'
|
||||
|
||||
# "hg" is an executable script with a shebang, which will be found
|
||||
# by which.which. We need to pass a win32 executable to the function
|
||||
# because we spawn a process
|
||||
# from it.
|
||||
# "hg" is an executable script with a shebang, which will be found by
|
||||
# which. We need to pass a win32 executable to the function because we
|
||||
# spawn a process from it.
|
||||
if sys.platform in ('win32', 'msys'):
|
||||
vcs = which.which(vcs + '.exe')
|
||||
else:
|
||||
vcs = which.which(vcs)
|
||||
tool += '.exe'
|
||||
|
||||
vcs = which(tool)
|
||||
if not vcs:
|
||||
raise OSError(errno.ENOENT, "Could not find {} on $PATH".format(tool))
|
||||
|
||||
if update_only:
|
||||
if repo.name == 'git':
|
||||
|
|
|
@ -7,12 +7,9 @@ from __future__ import absolute_import, print_function, unicode_literals
|
|||
import argparse
|
||||
import os
|
||||
import subprocess
|
||||
import which
|
||||
|
||||
from mozbuild.base import (
|
||||
MachCommandBase,
|
||||
)
|
||||
|
||||
from mozbuild.base import MachCommandBase
|
||||
from mozfile import which
|
||||
from mach.decorators import (
|
||||
CommandArgument,
|
||||
CommandProvider,
|
||||
|
@ -32,13 +29,10 @@ class MachCommands(MachCommandBase):
|
|||
elif ide == 'visualstudio':
|
||||
backend = 'VisualStudio'
|
||||
|
||||
if ide == 'eclipse':
|
||||
try:
|
||||
which.which('eclipse')
|
||||
except which.WhichError:
|
||||
print('Eclipse CDT 8.4 or later must be installed in your PATH.')
|
||||
print('Download: http://www.eclipse.org/cdt/downloads.php')
|
||||
return 1
|
||||
if ide == 'eclipse' and not which('eclipse'):
|
||||
print('Eclipse CDT 8.4 or later must be installed in your PATH.')
|
||||
print('Download: http://www.eclipse.org/cdt/downloads.php')
|
||||
return 1
|
||||
|
||||
# Here we refresh the whole build. 'build export' is sufficient here and is probably more
|
||||
# correct but it's also nice having a single target to get a fully built and indexed
|
||||
|
|
|
@ -13,13 +13,9 @@ import six
|
|||
import subprocess
|
||||
import sys
|
||||
import errno
|
||||
try:
|
||||
from shutil import which
|
||||
except ImportError:
|
||||
# shutil.which is not available in Python 2.7
|
||||
import which
|
||||
|
||||
from mach.mixin.process import ProcessExecutionMixin
|
||||
from mozfile import which
|
||||
from mozversioncontrol import (
|
||||
get_repository_from_build_config,
|
||||
get_repository_object,
|
||||
|
@ -581,9 +577,8 @@ class MozbuildObject(ProcessExecutionMixin):
|
|||
|
||||
try:
|
||||
if sys.platform.startswith('darwin'):
|
||||
try:
|
||||
notifier = which.which('terminal-notifier')
|
||||
except which.WhichError:
|
||||
notifier = which('terminal-notifier')
|
||||
if not notifier:
|
||||
raise Exception('Install terminal-notifier to get '
|
||||
'a notification when the build finishes.')
|
||||
self.run_process([notifier, '-title',
|
||||
|
@ -616,9 +611,8 @@ class MozbuildObject(ProcessExecutionMixin):
|
|||
FLASHW_CAPTION | FLASHW_TRAY | FLASHW_TIMERNOFG, 3, 0)
|
||||
FlashWindowEx(params)
|
||||
else:
|
||||
try:
|
||||
notifier = which.which('notify-send')
|
||||
except which.WhichError:
|
||||
notifier = which('notify-send')
|
||||
if not notifier:
|
||||
raise Exception('Install notify-send (usually part of '
|
||||
'the libnotify package) to get a notification when '
|
||||
'the build finishes.')
|
||||
|
@ -785,9 +779,8 @@ class MozbuildObject(ProcessExecutionMixin):
|
|||
if os.path.isabs(test):
|
||||
make = test
|
||||
else:
|
||||
try:
|
||||
make = which.which(test)
|
||||
except which.WhichError:
|
||||
make = which(test)
|
||||
if not make:
|
||||
continue
|
||||
result, xcode_lisense_error_tmp = validate_make(make)
|
||||
if result:
|
||||
|
|
|
@ -13,7 +13,6 @@ import os
|
|||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
import which
|
||||
|
||||
from collections import (
|
||||
Counter,
|
||||
|
@ -528,15 +527,13 @@ class BuildMonitor(MozbuildObject):
|
|||
def ccache_stats(self):
|
||||
ccache_stats = None
|
||||
|
||||
try:
|
||||
ccache = which.which('ccache')
|
||||
output = subprocess.check_output([ccache, '-s'])
|
||||
ccache_stats = CCacheStats(output)
|
||||
except which.WhichError:
|
||||
pass
|
||||
except ValueError as e:
|
||||
self.log(logging.WARNING, 'ccache', {'msg': str(e)}, '{msg}')
|
||||
|
||||
ccache = mozfile.which('ccache')
|
||||
if ccache:
|
||||
try:
|
||||
output = subprocess.check_output([ccache, '-s'])
|
||||
ccache_stats = CCacheStats(output)
|
||||
except ValueError as e:
|
||||
self.log(logging.WARNING, 'ccache', {'msg': str(e)}, '{msg}')
|
||||
return ccache_stats
|
||||
|
||||
|
||||
|
|
|
@ -7,13 +7,13 @@ from __future__ import absolute_import, print_function
|
|||
import os
|
||||
import subprocess
|
||||
import platform
|
||||
from mozboot.util import get_state_dir
|
||||
import which
|
||||
|
||||
from distutils.version import (
|
||||
StrictVersion,
|
||||
)
|
||||
|
||||
from mozboot.util import get_state_dir
|
||||
from mozfile import which
|
||||
|
||||
NODE_MIN_VERSION = StrictVersion("8.11.0")
|
||||
NPM_MIN_VERSION = StrictVersion("5.6.0")
|
||||
|
||||
|
@ -66,21 +66,6 @@ def check_executable_version(exe, wrap_call_with_node=False):
|
|||
return StrictVersion(out)
|
||||
|
||||
|
||||
def simple_which(filename, path=None):
|
||||
# Note: On windows, npm uses ".cmd"
|
||||
exts = [".cmd", ".exe", ""] if platform.system() == "Windows" else [""]
|
||||
|
||||
for ext in exts:
|
||||
try:
|
||||
return which.which(filename + ext, path)
|
||||
except which.WhichError:
|
||||
pass
|
||||
|
||||
# If we got this far, we didn't find it with any of the extensions, so
|
||||
# just return.
|
||||
return None
|
||||
|
||||
|
||||
def find_node_executable(nodejs_exe=os.environ.get('NODEJS'), min_version=NODE_MIN_VERSION):
|
||||
"""Find a Node executable from the mozbuild directory.
|
||||
|
||||
|
@ -120,10 +105,7 @@ def find_executable(names, min_version, use_node_for_version_check=False):
|
|||
|
||||
found_exe = None
|
||||
for name in names:
|
||||
try:
|
||||
exe = simple_which(name, paths)
|
||||
except which.WhichError:
|
||||
continue
|
||||
exe = which(name, path=paths)
|
||||
|
||||
if not exe:
|
||||
continue
|
||||
|
|
|
@ -47,7 +47,7 @@ def find_python3_executable(min_version='3.5.0'):
|
|||
version tuple. Both tuple entries will be None if a Python executable
|
||||
could not be resolved.
|
||||
"""
|
||||
import which
|
||||
from mozfile import which
|
||||
|
||||
if not min_version.startswith('3.'):
|
||||
raise ValueError('min_version expected a 3.x string, got %s' %
|
||||
|
@ -80,9 +80,8 @@ def find_python3_executable(min_version='3.5.0'):
|
|||
names.append('python3.%d' % minor)
|
||||
|
||||
for name in names:
|
||||
try:
|
||||
exe = which.which(name)
|
||||
except which.WhichError:
|
||||
exe = which(name)
|
||||
if not exe:
|
||||
continue
|
||||
|
||||
# We always verify we can invoke the executable and its version is
|
||||
|
|
|
@ -4,18 +4,20 @@
|
|||
|
||||
from __future__ import absolute_import, print_function, unicode_literals
|
||||
|
||||
from distutils.version import LooseVersion
|
||||
import errno
|
||||
import hashlib
|
||||
import logging
|
||||
from mozbuild.base import (
|
||||
BuildEnvironmentNotFoundException,
|
||||
MozbuildObject,
|
||||
)
|
||||
import mozpack.path as mozpath
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
from distutils.version import LooseVersion
|
||||
|
||||
import mozpack.path as mozpath
|
||||
from mozbuild.base import (
|
||||
BuildEnvironmentNotFoundException,
|
||||
MozbuildObject,
|
||||
)
|
||||
|
||||
|
||||
class VendorRust(MozbuildObject):
|
||||
|
@ -24,8 +26,11 @@ class VendorRust(MozbuildObject):
|
|||
return self.substs['CARGO']
|
||||
except (BuildEnvironmentNotFoundException, KeyError):
|
||||
# Default if this tree isn't configured.
|
||||
import which
|
||||
return which.which('cargo')
|
||||
from mozfile import which
|
||||
cargo = which('cargo')
|
||||
if not cargo:
|
||||
raise OSError(errno.ENOENT, "Could not find 'cargo' on your $PATH.")
|
||||
return cargo
|
||||
|
||||
def check_cargo_version(self, cargo):
|
||||
'''
|
||||
|
|
|
@ -1155,4 +1155,4 @@ static const TransportSecurityPreload kPublicKeyPinningPreloadList[] = {
|
|||
|
||||
static const int32_t kUnknownId = -1;
|
||||
|
||||
static const PRTime kPreloadPKPinsExpirationTime = INT64_C(1571056897017000);
|
||||
static const PRTime kPreloadPKPinsExpirationTime = INT64_C(1571316284300000);
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -46,6 +46,7 @@ add_task(async function test_missing_crypto_collection() {
|
|||
];
|
||||
// Disable addon sync because AddonManager won't be initialized here.
|
||||
await Service.engineManager.unregister("addons");
|
||||
await Service.engineManager.unregister("extension-storage");
|
||||
|
||||
for (let coll of collections) {
|
||||
handlers["/1.1/johndoe/storage/" + coll] = johnU(
|
||||
|
|
|
@ -40,7 +40,9 @@ add_task(async function test_locally_changed_keys() {
|
|||
Service.clusterURL = Service.identity._token.endpoint;
|
||||
|
||||
await Service.engineManager.register(HistoryEngine);
|
||||
// Disable addon sync because AddonManager won't be initialized here.
|
||||
await Service.engineManager.unregister("addons");
|
||||
await Service.engineManager.unregister("extension-storage");
|
||||
|
||||
async function corrupt_local_keys() {
|
||||
Service.collectionKeys._default.keyPair = [
|
||||
|
|
|
@ -26,7 +26,9 @@ async function cleanup(engine, server) {
|
|||
}
|
||||
|
||||
add_task(async function setup() {
|
||||
await Service.engineManager.unregister("addons"); // To silence errors.
|
||||
// Disable addon sync because AddonManager won't be initialized here.
|
||||
await Service.engineManager.unregister("addons");
|
||||
await Service.engineManager.unregister("extension-storage");
|
||||
});
|
||||
|
||||
add_task(async function test_ignored_fields() {
|
||||
|
|
|
@ -91,6 +91,7 @@ async function cleanAndGo(engine, server) {
|
|||
add_task(async function setup() {
|
||||
// Avoid addon manager complaining about not being initialized
|
||||
await Service.engineManager.unregister("addons");
|
||||
await Service.engineManager.unregister("extension-storage");
|
||||
});
|
||||
|
||||
add_task(async function test_basic() {
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
from __future__ import absolute_import, print_function, unicode_literals
|
||||
|
||||
import argparse
|
||||
import errno
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
|
@ -667,9 +668,8 @@ class TestInfoCommand(MachCommandBase):
|
|||
@CommandArgument('--verbose', action='store_true',
|
||||
help='Enable debug logging.')
|
||||
def test_info(self, **params):
|
||||
|
||||
import which
|
||||
from mozbuild.base import MozbuildObject
|
||||
from mozfile import which
|
||||
|
||||
self.branches = params['branches']
|
||||
self.start = params['start']
|
||||
|
@ -698,17 +698,15 @@ class TestInfoCommand(MachCommandBase):
|
|||
|
||||
self._hg = None
|
||||
if conditions.is_hg(build_obj):
|
||||
if self._is_windows():
|
||||
self._hg = which.which('hg.exe')
|
||||
else:
|
||||
self._hg = which.which('hg')
|
||||
self._hg = which('hg')
|
||||
if not self._hg:
|
||||
raise OSError(errno.ENOENT, "Could not find 'hg' on PATH.")
|
||||
|
||||
self._git = None
|
||||
if conditions.is_git(build_obj):
|
||||
if self._is_windows():
|
||||
self._git = which.which('git.exe')
|
||||
else:
|
||||
self._git = which.which('git')
|
||||
self._git = which('git')
|
||||
if not self._git:
|
||||
raise OSError(errno.ENOENT, "Could not find 'git' on PATH.")
|
||||
|
||||
for test_name in params['test_names']:
|
||||
print("===== %s =====" % test_name)
|
||||
|
|
|
@ -8,13 +8,16 @@
|
|||
|
||||
from __future__ import absolute_import, print_function
|
||||
|
||||
from six.moves import urllib
|
||||
from contextlib import contextmanager
|
||||
import errno
|
||||
import os
|
||||
import stat
|
||||
import sys
|
||||
import time
|
||||
import warnings
|
||||
from contextlib import contextmanager
|
||||
|
||||
from six.moves import urllib
|
||||
|
||||
|
||||
__all__ = ['extract_tarball',
|
||||
'extract_zip',
|
||||
|
@ -25,6 +28,7 @@ __all__ = ['extract_tarball',
|
|||
'remove',
|
||||
'rmtree',
|
||||
'tree',
|
||||
'which',
|
||||
'NamedTemporaryFile',
|
||||
'TemporaryDirectory']
|
||||
|
||||
|
@ -310,6 +314,55 @@ def tree(directory, sort_key=lambda x: x.lower()):
|
|||
return '\n'.join(retval)
|
||||
|
||||
|
||||
def which(cmd, mode=os.F_OK | os.X_OK, path=None, exts=None):
|
||||
"""A wrapper around `shutil.which` to make the behavior on Windows
|
||||
consistent with other platforms.
|
||||
|
||||
On non-Windows platforms, this is a direct call to `shutil.which`. On
|
||||
Windows, this:
|
||||
|
||||
* Ensures that `cmd` without an extension will be found. Previously it was
|
||||
only found if it had an extension in `PATHEXT`.
|
||||
* Ensures the absolute path to the binary is returned. Previously if the
|
||||
binary was found in `cwd`, a relative path was returned.
|
||||
|
||||
The arguments are the same as the ones in `shutil.which`. In addition there
|
||||
is an `exts` argument that only has an effect on Windows. This is used to
|
||||
set a custom value for PATHEXT and is formatted as a list of file
|
||||
extensions.
|
||||
"""
|
||||
try:
|
||||
from shutil import which as shutil_which
|
||||
except ImportError:
|
||||
from shutil_which import which as shutil_which
|
||||
|
||||
if isinstance(path, (list, tuple)):
|
||||
path = os.pathsep.join(path)
|
||||
|
||||
if sys.platform != "win32":
|
||||
return shutil_which(cmd, mode=mode, path=path)
|
||||
|
||||
oldexts = os.environ.get("PATHEXT", "")
|
||||
if not exts:
|
||||
exts = oldexts.split(os.pathsep)
|
||||
|
||||
# This ensures that `cmd` without any extensions will be found.
|
||||
# See: https://bugs.python.org/issue31405
|
||||
if "." not in exts:
|
||||
exts.append(".")
|
||||
|
||||
os.environ["PATHEXT"] = os.pathsep.join(exts)
|
||||
try:
|
||||
path = shutil_which(cmd, mode=mode, path=path)
|
||||
return os.path.abspath(path.rstrip('.')) if path else None
|
||||
|
||||
finally:
|
||||
if oldexts:
|
||||
os.environ["PATHEXT"] = oldexts
|
||||
else:
|
||||
del os.environ["PATHEXT"]
|
||||
|
||||
|
||||
# utilities for temporary resources
|
||||
|
||||
class NamedTemporaryFile(object):
|
||||
|
|
|
@ -7,3 +7,4 @@ subsuite = mozbase
|
|||
[test_tempfile.py]
|
||||
[test_tree.py]
|
||||
[test_url.py]
|
||||
[test_which.py]
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
# Any copyright is dedicated to the Public Domain.
|
||||
# https://creativecommons.org/publicdomain/zero/1.0/
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
import mozunit
|
||||
|
||||
from mozfile import which
|
||||
|
||||
here = os.path.abspath(os.path.dirname(__file__))
|
||||
|
||||
|
||||
def test_which(monkeypatch):
|
||||
cwd = os.path.join(here, 'files', 'which')
|
||||
monkeypatch.chdir(cwd)
|
||||
|
||||
if sys.platform == "win32":
|
||||
bindir = os.path.join(cwd, "win")
|
||||
monkeypatch.setenv("PATH", bindir)
|
||||
|
||||
assert which("foo.exe").lower() == os.path.join(bindir, "foo.exe")
|
||||
assert which("foo").lower() == os.path.join(bindir, "foo.exe")
|
||||
assert which("foo", exts=[".FOO", ".BAR"]).lower() == os.path.join(bindir, "foo")
|
||||
assert os.environ.get("PATHEXT") != [".FOO", ".BAR"]
|
||||
assert which("foo.txt") is None
|
||||
|
||||
assert which("bar").lower() == os.path.join(bindir, "bar")
|
||||
assert which("baz").lower() == os.path.join(cwd, "baz.exe")
|
||||
|
||||
else:
|
||||
bindir = os.path.join(cwd, "unix")
|
||||
monkeypatch.setenv("PATH", bindir)
|
||||
assert which("foo") == os.path.join(bindir, "foo")
|
||||
assert which("baz") is None
|
||||
assert which("baz", exts=[".EXE"]) is None
|
||||
assert "PATHEXT" not in os.environ
|
||||
assert which("file") is None
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
mozunit.main()
|
|
@ -1,6 +1,7 @@
|
|||
[iframe_sandbox_navigation_download_block_downloads_without_user_activation.sub.tentative.html]
|
||||
[Navigation resulted download in sandbox is blocked.]
|
||||
disabled:
|
||||
if (os == "mac") and (version == "OS X 10.14") and not debug: new os version
|
||||
if (os == "mac") and (version == "OS X 10.14.5") and not debug: new os version
|
||||
if (os == "mac") and (version == "OS X 10.14") and not debug: new os version
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
"""Backport of shutil.which from Python 3.5
|
||||
|
||||
The function is included unmodified from Python stdlib 3.5.1,
|
||||
and is (C) Python
|
||||
"""
|
||||
from __future__ import absolute_import # Import system's os, not backports.os.
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
__version__ = '3.5.1'
|
||||
|
||||
def backport_which(cmd, mode=os.F_OK | os.X_OK, path=None):
|
||||
"""Given a command, mode, and a PATH string, return the path which
|
||||
conforms to the given mode on the PATH, or None if there is no such
|
||||
file.
|
||||
|
||||
`mode` defaults to os.F_OK | os.X_OK. `path` defaults to the result
|
||||
of os.environ.get("PATH"), or can be overridden with a custom search
|
||||
path.
|
||||
|
||||
"""
|
||||
# Check that a given file can be accessed with the correct mode.
|
||||
# Additionally check that `file` is not a directory, as on Windows
|
||||
# directories pass the os.access check.
|
||||
def _access_check(fn, mode):
|
||||
return (os.path.exists(fn) and os.access(fn, mode)
|
||||
and not os.path.isdir(fn))
|
||||
|
||||
# If we're given a path with a directory part, look it up directly rather
|
||||
# than referring to PATH directories. This includes checking relative to the
|
||||
# current directory, e.g. ./script
|
||||
if os.path.dirname(cmd):
|
||||
if _access_check(cmd, mode):
|
||||
return cmd
|
||||
return None
|
||||
|
||||
if path is None:
|
||||
path = os.environ.get("PATH", os.defpath)
|
||||
if not path:
|
||||
return None
|
||||
path = path.split(os.pathsep)
|
||||
|
||||
if sys.platform == "win32":
|
||||
# The current directory takes precedence on Windows.
|
||||
if not os.curdir in path:
|
||||
path.insert(0, os.curdir)
|
||||
|
||||
# PATHEXT is necessary to check on Windows.
|
||||
pathext = os.environ.get("PATHEXT", "").split(os.pathsep)
|
||||
# See if the given file matches any of the expected path extensions.
|
||||
# This will allow us to short circuit when given "python.exe".
|
||||
# If it does match, only test that one, otherwise we have to try
|
||||
# others.
|
||||
if any(cmd.lower().endswith(ext.lower()) for ext in pathext):
|
||||
files = [cmd]
|
||||
else:
|
||||
files = [cmd + ext for ext in pathext]
|
||||
else:
|
||||
# On other platforms you don't have things like PATHEXT to tell you
|
||||
# what file suffixes are executable, so just pass on cmd as-is.
|
||||
files = [cmd]
|
||||
|
||||
seen = set()
|
||||
for dir in path:
|
||||
normdir = os.path.normcase(dir)
|
||||
if not normdir in seen:
|
||||
seen.add(normdir)
|
||||
for thefile in files:
|
||||
name = os.path.join(dir, thefile)
|
||||
if _access_check(name, mode):
|
||||
return name
|
||||
return None
|
||||
|
||||
try:
|
||||
from shutil import which
|
||||
except ImportError:
|
||||
which = backport_which
|
|
@ -16,6 +16,9 @@ onmessage = async function(e) {
|
|||
let i = win.document.createElement("iframe");
|
||||
i.src = "about:blank";
|
||||
win.document.body.appendChild(i);
|
||||
await new Promise(resolve => {
|
||||
i.onload = resolve;
|
||||
});
|
||||
// override win to make it point to the initial about:blank window
|
||||
win = i.contentWindow;
|
||||
}
|
||||
|
|
|
@ -51,6 +51,7 @@ const { ExtensionUtils } = ChromeUtils.import(
|
|||
);
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
AddonManager: "resource://gre/modules/AddonManager.jsm",
|
||||
BulkKeyBundle: "resource://services-sync/keys.js",
|
||||
CollectionKeyManager: "resource://services-sync/record.js",
|
||||
CommonUtils: "resource://services-common/utils.js",
|
||||
|
@ -781,8 +782,41 @@ class ExtensionStorageSync {
|
|||
this.listeners = new WeakMap();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a set of extensions to sync (including the ones with an
|
||||
* active extension context that used the storage.sync API and
|
||||
* the extensions that are enabled and have been synced before).
|
||||
*
|
||||
* @returns {Promise<Set<Extension>>}
|
||||
* A promise which resolves to the set of the extensions to sync.
|
||||
*/
|
||||
async getExtensions() {
|
||||
// Start from the set of the extensions with an active
|
||||
// context that used the storage.sync APIs.
|
||||
const extensions = new Set(extensionContexts.keys());
|
||||
|
||||
const allEnabledExtensions = await AddonManager.getAddonsByTypes([
|
||||
"extension",
|
||||
]);
|
||||
|
||||
// Get the existing extension collections salts.
|
||||
const keysRecord = await this.cryptoCollection.getKeyRingRecord();
|
||||
|
||||
// Add any enabled extensions that have been synced before.
|
||||
for (const addon of allEnabledExtensions) {
|
||||
if (this.hasSaltsFor(keysRecord, [addon.id])) {
|
||||
const policy = WebExtensionPolicy.getByID(addon.id);
|
||||
if (policy && policy.extension) {
|
||||
extensions.add(policy.extension);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return extensions;
|
||||
}
|
||||
|
||||
async syncAll() {
|
||||
const extensions = extensionContexts.keys();
|
||||
const extensions = await this.getExtensions();
|
||||
const extIds = Array.from(extensions, extension => extension.id);
|
||||
log.debug(`Syncing extension settings for ${JSON.stringify(extIds)}`);
|
||||
if (extIds.length == 0) {
|
||||
|
@ -791,7 +825,7 @@ class ExtensionStorageSync {
|
|||
}
|
||||
await this.ensureCanSync(extIds);
|
||||
await this.checkSyncKeyRing();
|
||||
const promises = Array.from(extensionContexts.keys(), extension => {
|
||||
const promises = Array.from(extensions, extension => {
|
||||
return openCollection(this.cryptoCollection, extension).then(coll => {
|
||||
return this.sync(extension, coll);
|
||||
});
|
||||
|
@ -1296,11 +1330,11 @@ class ExtensionStorageSync {
|
|||
|
||||
/* Wipe local data for all collections without causing the changes to be synced */
|
||||
async clearAll() {
|
||||
const extensions = extensionContexts.keys();
|
||||
const extensions = await this.getExtensions();
|
||||
const extIds = Array.from(extensions, extension => extension.id);
|
||||
log.debug(`Clearing extension data for ${JSON.stringify(extIds)}`);
|
||||
if (extIds.length) {
|
||||
const promises = Array.from(extensionContexts.keys(), extension => {
|
||||
const promises = Array.from(extensions, extension => {
|
||||
return openCollection(this.cryptoCollection, extension).then(coll => {
|
||||
return coll.clear();
|
||||
});
|
||||
|
|
|
@ -10,6 +10,7 @@ const { CommonUtils } = ChromeUtils.import(
|
|||
"resource://services-common/utils.js"
|
||||
);
|
||||
const {
|
||||
cleanUpForContext,
|
||||
CollectionKeyEncryptionRemoteTransformer,
|
||||
CryptoCollection,
|
||||
ExtensionStorageSync,
|
||||
|
@ -22,6 +23,12 @@ const { BulkKeyBundle } = ChromeUtils.import(
|
|||
);
|
||||
const { Utils } = ChromeUtils.import("resource://services-sync/util.js");
|
||||
|
||||
const { createAppInfo, promiseStartupManager } = AddonTestUtils;
|
||||
|
||||
AddonTestUtils.init(this);
|
||||
|
||||
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "69");
|
||||
|
||||
/* globals BulkKeyBundle, CommonUtils, EncryptionRemoteTransformer */
|
||||
/* globals Utils */
|
||||
|
||||
|
@ -637,6 +644,10 @@ function uuid() {
|
|||
return uuidgen.generateUUID().toString();
|
||||
}
|
||||
|
||||
add_task(async function test_setup() {
|
||||
await promiseStartupManager();
|
||||
});
|
||||
|
||||
add_task(async function test_key_to_id() {
|
||||
equal(keyToId("foo"), "key-foo");
|
||||
equal(keyToId("my-new-key"), "key-my_2D_new_2D_key");
|
||||
|
@ -684,46 +695,92 @@ add_task(async function test_extension_id_to_collection_id() {
|
|||
});
|
||||
|
||||
add_task(async function ensureCanSync_clearAll() {
|
||||
const extensionId = uuid();
|
||||
const extension = { id: extensionId };
|
||||
// A test extension that will not have any active context around
|
||||
// but it is returned from a call to AddonManager.getExtensionsByType.
|
||||
const extensionId = "test-wipe-on-enabled-and-synced@mochi.test";
|
||||
const testExtension = ExtensionTestUtils.loadExtension({
|
||||
useAddonManager: "temporary",
|
||||
manifest: {
|
||||
permissions: ["storage"],
|
||||
applications: { gecko: { id: extensionId } },
|
||||
},
|
||||
});
|
||||
|
||||
await testExtension.startup();
|
||||
|
||||
// Retrieve the Extension class instance from the test extension.
|
||||
const { extension } = testExtension;
|
||||
|
||||
// Another test extension that will have an active extension context.
|
||||
const extensionId2 = "test-wipe-on-active-context@mochi.test";
|
||||
const extension2 = { id: extensionId2 };
|
||||
|
||||
await withContextAndServer(async function(context, server) {
|
||||
await withSignedInUser(loggedInUser, async function(
|
||||
extensionStorageSync,
|
||||
fxaService
|
||||
) {
|
||||
async function assertSetAndGetData(extension, data) {
|
||||
await extensionStorageSync.set(extension, data, context);
|
||||
let storedData = await extensionStorageSync.get(
|
||||
extension,
|
||||
Object.keys(data),
|
||||
context
|
||||
);
|
||||
const extId = extensionId;
|
||||
deepEqual(storedData, data, `${extId} should get back the data we set`);
|
||||
}
|
||||
|
||||
async function assertDataCleared(extension, keys) {
|
||||
const storedData = await extensionStorageSync.get(
|
||||
extension,
|
||||
keys,
|
||||
context
|
||||
);
|
||||
deepEqual(storedData, {}, `${extension.id} should have lost the data`);
|
||||
}
|
||||
|
||||
server.installCollection("storage-sync-crypto");
|
||||
server.etag = 1000;
|
||||
|
||||
let newKeys = await extensionStorageSync.ensureCanSync([extensionId]);
|
||||
let newKeys = await extensionStorageSync.ensureCanSync([
|
||||
extensionId,
|
||||
extensionId2,
|
||||
]);
|
||||
ok(
|
||||
newKeys.hasKeysFor([extensionId]),
|
||||
`key isn't present for ${extensionId}`
|
||||
);
|
||||
ok(
|
||||
newKeys.hasKeysFor([extensionId2]),
|
||||
`key isn't present for ${extensionId2}`
|
||||
);
|
||||
|
||||
let posts = server.getPosts();
|
||||
equal(posts.length, 1);
|
||||
const post = posts[0];
|
||||
assertPostedNewRecord(post);
|
||||
assertPostedNewRecord(posts[0]);
|
||||
|
||||
// Set data for an extension and sync.
|
||||
await extensionStorageSync.set(extension, { "my-key": 5 }, context);
|
||||
let keyValue = await extensionStorageSync.get(
|
||||
extension,
|
||||
["my-key"],
|
||||
context
|
||||
);
|
||||
equal(keyValue["my-key"], 5, "should get back the data we set");
|
||||
await assertSetAndGetData(extension, { "my-key": 1 });
|
||||
await assertSetAndGetData(extension2, { "my-key": 2 });
|
||||
|
||||
// Call cleanup for the first extension, to double check it has
|
||||
// been wiped out even without an active extension context.
|
||||
cleanUpForContext(extension, context);
|
||||
|
||||
// clear everything.
|
||||
await extensionStorageSync.clearAll();
|
||||
|
||||
keyValue = await extensionStorageSync.get(extension, ["my-key"], context);
|
||||
deepEqual(keyValue, {}, "should have lost the data");
|
||||
// Assert that the data is gone for both the extensions.
|
||||
await assertDataCleared(extension, ["my-key"]);
|
||||
await assertDataCleared(extension2, ["my-key"]);
|
||||
|
||||
// should have been no posts caused by the clear.
|
||||
posts = server.getPosts();
|
||||
equal(posts.length, 1);
|
||||
});
|
||||
});
|
||||
|
||||
await testExtension.unload();
|
||||
});
|
||||
|
||||
add_task(async function ensureCanSync_posts_new_keys() {
|
||||
|
@ -1615,6 +1672,86 @@ add_task(async function test_storage_sync_pulls_changes() {
|
|||
});
|
||||
});
|
||||
|
||||
// Tests that an enabled extension which have been synced before it is going
|
||||
// to be synced on ExtensionStorageSync.syncAll even if there is no active
|
||||
// context that is currently using the API.
|
||||
add_task(async function test_storage_sync_on_no_active_context() {
|
||||
const extensionId = "sync@mochi.test";
|
||||
const extension = ExtensionTestUtils.loadExtension({
|
||||
useAddonManager: "temporary",
|
||||
manifest: {
|
||||
permissions: ["storage"],
|
||||
applications: { gecko: { id: extensionId } },
|
||||
},
|
||||
files: {
|
||||
"ext-page.html": `<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<script src="ext-page.js"></script>
|
||||
</head>
|
||||
</html>
|
||||
`,
|
||||
"ext-page.js": function() {
|
||||
const { browser } = this;
|
||||
browser.test.onMessage.addListener(async msg => {
|
||||
if (msg === "get-sync-data") {
|
||||
browser.test.sendMessage(
|
||||
"get-sync-data:done",
|
||||
await browser.storage.sync.get(["remote-key"])
|
||||
);
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await extension.startup();
|
||||
|
||||
await withServer(async server => {
|
||||
await withSignedInUser(loggedInUser, async function(
|
||||
extensionStorageSync,
|
||||
fxaService
|
||||
) {
|
||||
const cryptoCollection = new CryptoCollection(fxaService);
|
||||
let transformer = new CollectionKeyEncryptionRemoteTransformer(
|
||||
cryptoCollection,
|
||||
extensionId
|
||||
);
|
||||
server.installCollection("storage-sync-crypto");
|
||||
|
||||
await extensionStorageSync.ensureCanSync([extensionId]);
|
||||
const collectionId = await cryptoCollection.extensionIdToCollectionId(
|
||||
extensionId
|
||||
);
|
||||
await server.encryptAndAddRecord(transformer, {
|
||||
collectionId,
|
||||
data: {
|
||||
id: "key-remote_2D_key",
|
||||
key: "remote-key",
|
||||
data: 6,
|
||||
},
|
||||
predicate: appearsAt(850),
|
||||
});
|
||||
|
||||
server.etag = 1000;
|
||||
await extensionStorageSync.syncAll();
|
||||
});
|
||||
});
|
||||
|
||||
const extPage = await ExtensionTestUtils.loadContentPage(
|
||||
`moz-extension://${extension.uuid}/ext-page.html`,
|
||||
{ extension }
|
||||
);
|
||||
|
||||
await extension.sendMessage("get-sync-data");
|
||||
const res = await extension.awaitMessage("get-sync-data:done");
|
||||
Assert.deepEqual(res, { "remote-key": 6 }, "Got the expected sync data");
|
||||
|
||||
await extPage.close();
|
||||
|
||||
await extension.unload();
|
||||
});
|
||||
|
||||
add_task(async function test_storage_sync_pushes_changes() {
|
||||
// FIXME: This test relies on the fact that previous tests pushed
|
||||
// keys and salts for the default extension ID
|
||||
|
|
|
@ -564,6 +564,13 @@ this.LoginManagerParent = {
|
|||
if (!usernameField && oldPasswordField && logins.length > 0) {
|
||||
let prompter = this._getPrompter(browser, openerTopWindowID);
|
||||
|
||||
let { browsingContext } = browser;
|
||||
let framePrincipalOrigin =
|
||||
browsingContext.currentWindowGlobal.documentPrincipal.origin;
|
||||
let generatedPW = this._generatedPasswordsByPrincipalOrigin.get(
|
||||
framePrincipalOrigin
|
||||
);
|
||||
|
||||
if (logins.length == 1) {
|
||||
let oldLogin = logins[0];
|
||||
|
||||
|
@ -580,15 +587,14 @@ this.LoginManagerParent = {
|
|||
formLogin.usernameField = oldLogin.usernameField;
|
||||
|
||||
prompter.promptToChangePassword(oldLogin, formLogin, dismissedPrompt);
|
||||
} else {
|
||||
return;
|
||||
} else if (!generatedPW || generatedPW.value != newPasswordField.value) {
|
||||
// Note: It's possible that that we already have the correct u+p saved
|
||||
// but since we don't have the username, we don't know if the user is
|
||||
// changing a second account to the new password so we ask anyways.
|
||||
|
||||
prompter.promptToChangePasswordWithUsernames(logins, formLogin);
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
let existingLogin = null;
|
||||
|
|
|
@ -62,6 +62,8 @@ support-files =
|
|||
file_focus_before_DOMContentLoaded.sjs
|
||||
[browser_formless_submit_chrome.js]
|
||||
[browser_generated_password_doorhangers.js]
|
||||
support-files =
|
||||
form_password_change.html
|
||||
[browser_hasInsecureLoginForms.js]
|
||||
skip-if = verify
|
||||
[browser_hasInsecureLoginForms_streamConverter.js]
|
||||
|
@ -92,4 +94,4 @@ tags = clipboard
|
|||
[browser_private_window.js]
|
||||
support-files =
|
||||
subtst_privbrowsing_1.html
|
||||
subtst_privbrowsing_2.html
|
||||
form_password_change.html
|
||||
|
|
|
@ -13,20 +13,25 @@ const FORM_PAGE_PATH =
|
|||
const passwordInputSelector = "#form-basic-password";
|
||||
const usernameInputSelector = "#form-basic-username";
|
||||
|
||||
let login1;
|
||||
async function addOneLogin() {
|
||||
login1 = LoginTestUtils.testData.formLogin({
|
||||
async function addLogin({ username, password }) {
|
||||
const login = LoginTestUtils.testData.formLogin({
|
||||
origin: "https://example.com",
|
||||
formActionOrigin: "https://example.com",
|
||||
username: "username",
|
||||
password: "pass1",
|
||||
username,
|
||||
password,
|
||||
});
|
||||
let storageChangedPromised = TestUtils.topicObserved(
|
||||
"passwordmgr-storage-changed",
|
||||
(_, data) => data == "addLogin"
|
||||
);
|
||||
Services.logins.addLogin(login1);
|
||||
Services.logins.addLogin(login);
|
||||
await storageChangedPromised;
|
||||
return login;
|
||||
}
|
||||
|
||||
let login1;
|
||||
function addOneLogin() {
|
||||
login1 = addLogin({ username: "username", password: "pass1" });
|
||||
}
|
||||
|
||||
function openACPopup(popup, browser, inputSelector) {
|
||||
|
@ -266,3 +271,45 @@ add_task(async function autocomplete_generated_password() {
|
|||
}
|
||||
);
|
||||
});
|
||||
|
||||
add_task(async function password_change_without_username() {
|
||||
const CHANGE_FORM_PATH =
|
||||
"/browser/toolkit/components/passwordmgr/test/browser/form_password_change.html";
|
||||
await BrowserTestUtils.withNewTab(
|
||||
{
|
||||
gBrowser,
|
||||
url: TEST_ORIGIN + CHANGE_FORM_PATH,
|
||||
},
|
||||
async function(browser) {
|
||||
await SimpleTest.promiseFocus(browser.ownerGlobal);
|
||||
// Save 2nd login different from the 1st one
|
||||
addLogin({
|
||||
username: "username2",
|
||||
password: "pass2",
|
||||
});
|
||||
|
||||
// Make the 2nd field use a generated password
|
||||
await doFillGeneratedPasswordContextMenuItem(browser, "#newpass");
|
||||
|
||||
// Submit the form
|
||||
await ContentTask.spawn(browser, null, function() {
|
||||
content.document.querySelector("#form").submit();
|
||||
});
|
||||
|
||||
// Check a non-dismissed prompt was shown
|
||||
let notif = getCaptureDoorhanger("password-save");
|
||||
ok(notif && !notif.dismissed, "Non-dismissed notification was created");
|
||||
|
||||
let { passwordValue, usernameValue } = await checkPromptContents(
|
||||
notif.anchorElement
|
||||
);
|
||||
is(
|
||||
passwordValue.length,
|
||||
15,
|
||||
"Doorhanger password field has generated 15-char value"
|
||||
);
|
||||
is(usernameValue, "", "Doorhanger username field has no value");
|
||||
notif.remove();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
|
|
@ -146,7 +146,7 @@ let login = new nsLoginInfo(
|
|||
"pass"
|
||||
);
|
||||
const form1Url = `https://example.com/${DIRECTORY_PATH}subtst_privbrowsing_1.html`;
|
||||
const form2Url = `https://example.com/${DIRECTORY_PATH}subtst_privbrowsing_2.html`;
|
||||
const form2Url = `https://example.com/${DIRECTORY_PATH}form_password_change.html`;
|
||||
const authUrl = `https://example.com/${DIRECTORY_PATH}authenticate.sjs`;
|
||||
|
||||
let normalWin;
|
||||
|
|
|
@ -246,6 +246,12 @@ var SessionHistoryInternal = {
|
|||
);
|
||||
}
|
||||
|
||||
if (shEntry.storagePrincipalToInherit) {
|
||||
entry.storagePrincipalToInherit_base64 = E10SUtils.serializePrincipal(
|
||||
shEntry.storagePrincipalToInherit
|
||||
);
|
||||
}
|
||||
|
||||
if (shEntry.triggeringPrincipal) {
|
||||
entry.triggeringPrincipal_base64 = E10SUtils.serializePrincipal(
|
||||
shEntry.triggeringPrincipal
|
||||
|
@ -521,6 +527,11 @@ var SessionHistoryInternal = {
|
|||
}
|
||||
);
|
||||
}
|
||||
if (entry.storagePrincipalToInherit_base64) {
|
||||
shEntry.storagePrincipalToInherit = E10SUtils.deserializePrincipal(
|
||||
entry.storagePrincipalToInherit_base64
|
||||
);
|
||||
}
|
||||
if (entry.principalToInherit_base64) {
|
||||
shEntry.principalToInherit = E10SUtils.deserializePrincipal(
|
||||
entry.principalToInherit_base64
|
||||
|
|
|
@ -236,6 +236,7 @@ recommended-addon-card .addon-description:not(:empty) {
|
|||
|
||||
.discopane-notice-content > span {
|
||||
flex-grow: 1;
|
||||
margin-inline-end: 4px;
|
||||
}
|
||||
|
||||
.discopane-notice-content > button {
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
--error-icon-url: url("chrome://global/skin/icons/error.svg");
|
||||
--close-icon-url: url("chrome://global/skin/icons/close.svg");
|
||||
--icon-size: 16px;
|
||||
--close-icon-size: 32px;
|
||||
}
|
||||
|
||||
/* MessageBar colors by message type */
|
||||
|
@ -58,24 +59,21 @@
|
|||
display: block;
|
||||
}
|
||||
|
||||
.container {
|
||||
background: inherit;
|
||||
color: inherit;
|
||||
::slotted(button) {
|
||||
/* Enforce micro-button width. */
|
||||
min-width: -moz-fit-content !important;
|
||||
}
|
||||
|
||||
/* MessageBar Grid Layout */
|
||||
|
||||
.container {
|
||||
padding-top: 2px;
|
||||
padding-bottom: 2px;
|
||||
background: inherit;
|
||||
color: inherit;
|
||||
|
||||
padding-inline-start: 4px;
|
||||
padding: 8px;
|
||||
|
||||
min-height: 32px;
|
||||
border-radius: 4px;
|
||||
font-size: 13px;
|
||||
font-weight: 400;
|
||||
line-height: 1.4;
|
||||
|
||||
display: flex;
|
||||
/* Ensure that the message bar shadow dom elements are vertically aligned. */
|
||||
|
@ -86,17 +84,8 @@
|
|||
justify-content: center;
|
||||
}
|
||||
|
||||
:host([dismissable]) .container {
|
||||
/* Add padding on the end of the container when the bar is dismissable. */
|
||||
padding-inline-end: 4px;
|
||||
}
|
||||
|
||||
.icon {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.content {
|
||||
margin-inline-end: 4px;
|
||||
margin: 0 4px;
|
||||
display: flex;
|
||||
/* Ensure that the message bar content is vertically aligned. */
|
||||
align-items: center;
|
||||
|
@ -104,63 +93,48 @@
|
|||
word-break: break-word;
|
||||
}
|
||||
|
||||
button.close {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
::slotted(button) {
|
||||
/* Enforce micro-button width. */
|
||||
min-width: -moz-fit-content !important;
|
||||
}
|
||||
|
||||
/* MessageBar icon style */
|
||||
|
||||
.icon {
|
||||
padding: 4px;
|
||||
width: var(--icon-size);
|
||||
height: var(--icon-size);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.icon::after {
|
||||
-moz-appearance: none;
|
||||
-moz-context-properties: fill, stroke;
|
||||
color: inherit !important;
|
||||
fill: currentColor;
|
||||
stroke: currentColor;
|
||||
content: var(--message-bar-icon-url);
|
||||
}
|
||||
|
||||
/* Use a spacer to position the close button at the end, but also support
|
||||
* centering if required. */
|
||||
.spacer {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
/* Close icon styles */
|
||||
|
||||
:host(:not([dismissable])) button.close {
|
||||
:host(:not([dismissable])) .close {
|
||||
display: none;
|
||||
}
|
||||
|
||||
button.close {
|
||||
padding: 4px;
|
||||
width: var(--icon-size);
|
||||
height: var(--icon-size);
|
||||
min-width: -moz-fit-content;
|
||||
}
|
||||
|
||||
button.close {
|
||||
background: var(--close-icon-url) no-repeat center center;
|
||||
.close {
|
||||
background-image: var(--close-icon-url);
|
||||
background-repeat: no-repeat;
|
||||
background-position: center center;
|
||||
-moz-context-properties: fill, fill-opacity;
|
||||
color: inherit !important;
|
||||
fill: currentColor;
|
||||
fill-opacity: 0;
|
||||
min-width: auto;
|
||||
min-height: auto;
|
||||
width: var(--icon-size);
|
||||
height: var(--icon-size);
|
||||
width: var(--close-icon-size);
|
||||
height: var(--close-icon-size);
|
||||
margin: 0;
|
||||
margin-inline-end: 4px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
button.close:hover {
|
||||
fill-opacity: 0.1;
|
||||
}
|
||||
|
||||
button.close:hover:active {
|
||||
fill-opacity: 0.2;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
|
|
@ -121,6 +121,10 @@ class MessageBarElement extends HTMLElement {
|
|||
barcontent.append(document.createElement("slot"));
|
||||
container.append(barcontent);
|
||||
|
||||
const spacer = document.createElement("span");
|
||||
spacer.classList.add("spacer");
|
||||
container.append(spacer);
|
||||
|
||||
const closeIcon = document.createElement("button");
|
||||
closeIcon.setAttribute("class", "close");
|
||||
container.append(closeIcon);
|
||||
|
|
|
@ -49,6 +49,7 @@
|
|||
--in-content-table-background: #ebebeb;
|
||||
--in-content-table-border-dark-color: #d1d1d1;
|
||||
--in-content-table-header-background: #0a84ff;
|
||||
--in-content-dialog-header-background: #f1f1f1;
|
||||
|
||||
--panel-border-radius: 2px; /* This is overridden on Windows */
|
||||
|
||||
|
@ -131,6 +132,7 @@
|
|||
--in-content-table-background: #202023;
|
||||
--in-content-table-border-dark-color: rgba(249,249,250,0.2);
|
||||
--in-content-table-header-background: #002b57;
|
||||
--in-content-dialog-header-background: rgba(249,249,250,0.05);
|
||||
|
||||
--in-content-category-text-selected: var(--blue-40);
|
||||
--in-content-category-text-selected-active: var(--blue-50);
|
||||
|
@ -295,6 +297,11 @@ html|select:not([size]):not([multiple]):dir(rtl) {
|
|||
background-position: left 3px center;
|
||||
}
|
||||
|
||||
html|select:not([size]):not([multiple]) > html|option {
|
||||
background-color: var(--in-content-box-background);
|
||||
color: var(--in-content-text-color);
|
||||
}
|
||||
|
||||
html|button:enabled:hover,
|
||||
html|select:not([size]):not([multiple]):enabled:hover,
|
||||
html|input[type="color"]:hover,
|
||||
|
|
|
@ -134,19 +134,21 @@ class MachBrowsertime(MachCommandBase):
|
|||
if host_platform().startswith('linux'):
|
||||
# On Linux ImageMagick needs to be installed manually, and `mach bootstrap` doesn't
|
||||
# do that (yet). Provide some guidance.
|
||||
import which
|
||||
im_programs = ('compare', 'convert', 'mogrify')
|
||||
try:
|
||||
for im_program in im_programs:
|
||||
which.which(im_program)
|
||||
except which.WhichError as e:
|
||||
print('Error: {} On Linux, ImageMagick must be on the PATH. '
|
||||
'Install ImageMagick manually and try again (or update PATH). '
|
||||
'On Ubuntu and Debian, try `sudo apt-get install imagemagick`. '
|
||||
'On Fedora, try `sudo dnf install imagemagick`. '
|
||||
'On CentOS, try `sudo yum install imagemagick`.'
|
||||
.format(e))
|
||||
return 1
|
||||
from shutil import which
|
||||
except ImportError:
|
||||
from shutil_which import which
|
||||
|
||||
im_programs = ('compare', 'convert', 'mogrify')
|
||||
for im_program in im_programs:
|
||||
prog = which(im_program)
|
||||
if not prog:
|
||||
print('Error: On Linux, ImageMagick must be on the PATH. '
|
||||
'Install ImageMagick manually and try again (or update PATH). '
|
||||
'On Ubuntu and Debian, try `sudo apt-get install imagemagick`. '
|
||||
'On Fedora, try `sudo dnf install imagemagick`. '
|
||||
'On CentOS, try `sudo yum install imagemagick`.')
|
||||
return 1
|
||||
|
||||
# Download the visualmetrics.py requirements.
|
||||
artifact_cache = ArtifactCache(self.artifact_cache_path,
|
||||
|
|
|
@ -8,15 +8,13 @@ import os
|
|||
import sys
|
||||
from functools import partial
|
||||
|
||||
from mozbuild.base import MachCommandBase
|
||||
from mach.decorators import (
|
||||
Command,
|
||||
CommandArgument,
|
||||
CommandProvider,
|
||||
)
|
||||
|
||||
import which
|
||||
from mozbuild.base import MachCommandBase
|
||||
|
||||
here = os.path.abspath(os.path.dirname(__file__))
|
||||
|
||||
|
||||
|
@ -53,9 +51,10 @@ class Documentation(MachCommandBase):
|
|||
help='Upload generated files to S3.')
|
||||
def build_docs(self, path=None, fmt='html', outdir=None, auto_open=True,
|
||||
serve=True, http=None, archive=False, upload=False):
|
||||
try:
|
||||
which.which('jsdoc')
|
||||
except which.WhichError:
|
||||
|
||||
from mozfile import which
|
||||
|
||||
if not which('jsdoc'):
|
||||
return die('jsdoc not found - please install from npm.')
|
||||
|
||||
self.activate_pipenv(os.path.join(here, 'Pipfile'))
|
||||
|
|
|
@ -109,6 +109,11 @@ let's call the file ``flake8_lint.py``:
|
|||
|
||||
from mozlint import result
|
||||
|
||||
try:
|
||||
from shutil import which
|
||||
except ImportError:
|
||||
from shutil_which import which
|
||||
|
||||
|
||||
FLAKE8_NOT_FOUND = """
|
||||
Could not find flake8! Install flake8 and try again.
|
||||
|
@ -116,13 +121,10 @@ let's call the file ``flake8_lint.py``:
|
|||
|
||||
|
||||
def lint(files, config, **lintargs):
|
||||
import which
|
||||
|
||||
binary = os.environ.get('FLAKE8')
|
||||
if not binary:
|
||||
try:
|
||||
binary = which.which('flake8')
|
||||
except which.WhichError:
|
||||
binary = which('flake8')
|
||||
if not binary:
|
||||
print(FLAKE8_NOT_FOUND)
|
||||
return 1
|
||||
|
||||
|
|
|
@ -7,10 +7,10 @@ from collections import namedtuple
|
|||
|
||||
import os
|
||||
import signal
|
||||
import which
|
||||
import re
|
||||
import subprocess
|
||||
|
||||
from mozfile import which
|
||||
from mozlint import result
|
||||
from mozlint.pathutils import expand_exclusions
|
||||
from mozprocess import ProcessHandler
|
||||
|
@ -105,10 +105,7 @@ def get_rustfmt_binary():
|
|||
if binary:
|
||||
return binary
|
||||
|
||||
try:
|
||||
return which.which("rustfmt")
|
||||
except which.WhichError:
|
||||
return None
|
||||
return which("rustfmt")
|
||||
|
||||
|
||||
def is_old_rustfmt(binary):
|
||||
|
|
|
@ -7,17 +7,17 @@ from __future__ import absolute_import, print_function
|
|||
import os
|
||||
import json
|
||||
import signal
|
||||
import which
|
||||
|
||||
# Py3/Py2 compatibility.
|
||||
# py2-compat
|
||||
try:
|
||||
from json.decoder import JSONDecodeError
|
||||
except ImportError:
|
||||
JSONDecodeError = ValueError
|
||||
|
||||
import mozpack.path as mozpath
|
||||
from mozpack.files import FileFinder
|
||||
from mozfile import which
|
||||
from mozlint import result
|
||||
from mozpack.files import FileFinder
|
||||
from mozprocess import ProcessHandlerMixin
|
||||
|
||||
|
||||
|
@ -135,10 +135,7 @@ def get_shellcheck_binary():
|
|||
if binary:
|
||||
return binary
|
||||
|
||||
try:
|
||||
return which.which('shellcheck')
|
||||
except which.WhichError:
|
||||
return None
|
||||
return which('shellcheck')
|
||||
|
||||
|
||||
def lint(paths, config, **lintargs):
|
||||
|
|
|
@ -6,15 +6,15 @@ from __future__ import absolute_import, print_function
|
|||
|
||||
import os
|
||||
import signal
|
||||
import which
|
||||
import re
|
||||
|
||||
# Py3/Py2 compatibility.
|
||||
# py2-compat
|
||||
try:
|
||||
from json.decoder import JSONDecodeError
|
||||
except ImportError:
|
||||
JSONDecodeError = ValueError
|
||||
|
||||
from mozfile import which
|
||||
from mozlint import result
|
||||
from mozlint.util import pip
|
||||
from mozprocess import ProcessHandlerMixin
|
||||
|
@ -90,10 +90,7 @@ def get_codespell_binary():
|
|||
if binary:
|
||||
return binary
|
||||
|
||||
try:
|
||||
return which.which('codespell')
|
||||
except which.WhichError:
|
||||
return None
|
||||
return which('codespell')
|
||||
|
||||
|
||||
def lint(paths, config, fix=None, **lintargs):
|
||||
|
|
|
@ -8,11 +8,10 @@ import signal
|
|||
import subprocess
|
||||
from collections import defaultdict
|
||||
|
||||
import which
|
||||
from mozprocess import ProcessHandlerMixin
|
||||
|
||||
from mozfile import which
|
||||
from mozlint import result
|
||||
from mozlint.pathutils import get_ancestors_by_name
|
||||
from mozprocess import ProcessHandlerMixin
|
||||
|
||||
|
||||
here = os.path.abspath(os.path.dirname(__file__))
|
||||
|
@ -71,10 +70,7 @@ def get_yamllint_binary():
|
|||
if binary:
|
||||
return binary
|
||||
|
||||
try:
|
||||
return which.which('yamllint')
|
||||
except which.WhichError:
|
||||
return None
|
||||
return which('yamllint')
|
||||
|
||||
|
||||
def _run_pip(*args):
|
||||
|
|
|
@ -4,19 +4,25 @@
|
|||
# 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/.
|
||||
|
||||
import errno
|
||||
import sys
|
||||
import os
|
||||
import shlex
|
||||
import subprocess
|
||||
import tempfile
|
||||
import which
|
||||
|
||||
import buildconfig
|
||||
from mozfile import which
|
||||
|
||||
|
||||
def preprocess(out, asm_file):
|
||||
cxx = shlex.split(buildconfig.substs['CXX'])
|
||||
if not os.path.exists(cxx[0]):
|
||||
cxx[0] = which.which(cxx[0])
|
||||
tool = cxx[0]
|
||||
cxx[0] = which(tool)
|
||||
if not cxx[0]:
|
||||
raise OSError(errno.ENOENT, "Could not find {} on PATH.".format(tool))
|
||||
|
||||
cppflags = buildconfig.substs['OS_CPPFLAGS']
|
||||
|
||||
# subprocess.Popen(stdout=) only accepts actual file objects, which `out`,
|
||||
|
|
Загрузка…
Ссылка в новой задаче