Merge m-c to b2ginbound, a=merge CLOSED TREE

This commit is contained in:
Wes Kocher 2015-09-08 17:08:19 -07:00
Родитель 1b13244b81 eea972e415
Коммит f58cdf511a
73 изменённых файлов: 1784 добавлений и 1111 удалений

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

@ -95,6 +95,11 @@ var FullScreen = {
// TabsInTitlebar._update() and bug 1173768.
TabsInTitlebar.updateAppearance(true);
}
if (enterFS) {
Services.telemetry.getHistogramById("FX_BROWSER_FULLSCREEN_USED")
.add(1);
}
},
exitDomFullScreen : function() {

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

@ -7533,8 +7533,6 @@ function switchToTabHavingURI(aURI, aOpenNew, aOpenParams={}) {
aWindow.focus();
if (ignoreFragment) {
let spec = aURI.spec;
if (!aURI.ref)
spec += "#";
browser.loadURI(spec);
}
aWindow.gBrowser.tabContainer.selectedIndex = i;

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

@ -25,6 +25,12 @@ add_task(function test_ignoreFragment() {
switchTab("about:home#1", false);
isnot(tabRefAboutHome, gBrowser.selectedTab, "Selected tab should not be initial about:blank tab");
is(gBrowser.tabs.length, numTabsAtStart + 1, "Should have one new tab opened");
switchTab("about:mozilla", true);
switchTab("about:home", true, {ignoreFragment: true});
yield promiseWaitForCondition(function() {
return tabRefAboutHome.linkedBrowser.currentURI.spec == "about:home";
});
is(tabRefAboutHome.linkedBrowser.currentURI.spec, "about:home", "about:home shouldn't have hash");
switchTab("about:about", false, { ignoreFragment: true });
cleanupTestTabs();
});

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

@ -5,8 +5,7 @@
const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/Task.jsm");
Cu.import("resource://gre/modules/AppConstants.jsm");
Cu.import("resource:///modules/MigrationUtils.jsm");
Cu.import("resource:///modules/MSMigrationUtils.jsm");
@ -23,6 +22,16 @@ EdgeProfileMigrator.prototype.getResources = function() {
return resources.filter(r => r.exists);
};
/* Somewhat counterintuitively, this returns:
* - |null| to indicate "There is only 1 (default) profile" (on win10+)
* - |[]| to indicate "There are no profiles" (on <=win8.1) which will avoid using this migrator.
* See MigrationUtils.jsm for slightly more info on how sourceProfiles is used.
*/
EdgeProfileMigrator.prototype.__defineGetter__("sourceProfiles", function() {
let isWin10OrHigher = AppConstants.isPlatformAndVersionAtLeast("win", "10.0");
return isWin10OrHigher ? null : [];
});
EdgeProfileMigrator.prototype.classDescription = "Edge Profile Migrator";
EdgeProfileMigrator.prototype.contractID = "@mozilla.org/profile/migrator;1?app=browser&type=edge";
EdgeProfileMigrator.prototype.classID = Components.ID("{62e8834b-2d17-49f5-96ff-56344903a2ae}");

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

@ -32,6 +32,10 @@ nsEdgeReadingListExtractor::Extract(const nsAString& aDBPath, nsIArray** aItems)
nsresult rv = NS_OK;
*aItems = nullptr;
if (!aDBPath.Length()) {
return NS_ERROR_FAILURE;
}
JET_ERR err;
JET_INSTANCE instance;
JET_SESID sesid;
@ -50,11 +54,9 @@ nsEdgeReadingListExtractor::Extract(const nsAString& aDBPath, nsIArray** aItems)
// the right things
bool instanceCreated, sessionCreated, dbOpened, tableOpened;
char16ptr_t dbPath = ToNewUnicode(aDBPath);
// Check for the right page size and initialize with that
unsigned long pageSize;
err = JetGetDatabaseFileInfoW(dbPath, &pageSize, sizeof(pageSize), JET_DbInfoPageSize);
err = JetGetDatabaseFileInfoW(aDBPath.BeginReading(), &pageSize, sizeof(pageSize), JET_DbInfoPageSize);
NS_HANDLE_JET_ERROR(err)
err = JetSetSystemParameter(&instance, NULL, JET_paramDatabasePageSize, pageSize, NULL);
NS_HANDLE_JET_ERROR(err)
@ -77,10 +79,10 @@ nsEdgeReadingListExtractor::Extract(const nsAString& aDBPath, nsIArray** aItems)
sessionCreated = true;
// Actually open the DB, and make sure to do so readonly:
err = JetAttachDatabaseW(sesid, dbPath, JET_bitDbReadOnly);
err = JetAttachDatabaseW(sesid, aDBPath.BeginReading(), JET_bitDbReadOnly);
NS_HANDLE_JET_ERROR(err)
dbOpened = true;
err = JetOpenDatabaseW(sesid, dbPath, NULL, &dbid, JET_bitDbReadOnly);
err = JetOpenDatabaseW(sesid, aDBPath.BeginReading(), NULL, &dbid, JET_bitDbReadOnly);
NS_HANDLE_JET_ERROR(err)
// Open the readinglist table and get information on the columns we are interested in:

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

@ -675,6 +675,7 @@ Messages.NavigationMarker.prototype = Heritage.extend(Messages.BaseMessage.proto
* handler.
* - location: object that tells the message source: url, line, column
* and lineText.
* - stack: array that tells the message source stack.
* - className: (string) additional element class names for styling
* purposes.
* - private: (boolean) mark this as a private message.
@ -688,6 +689,7 @@ Messages.Simple = function(message, options = {})
this.category = options.category;
this.severity = options.severity;
this.location = options.location;
this.stack = options.stack;
this.timestamp = options.timestamp || Date.now();
this.prefix = options.prefix;
this.private = !!options.private;
@ -697,6 +699,8 @@ Messages.Simple = function(message, options = {})
this._link = options.link;
this._linkCallback = options.linkCallback;
this._filterDuplicates = options.filterDuplicates;
this._onClickCollapsible = this._onClickCollapsible.bind(this);
};
Messages.Simple.prototype = Heritage.extend(Messages.BaseMessage.prototype,
@ -719,6 +723,14 @@ Messages.Simple.prototype = Heritage.extend(Messages.BaseMessage.prototype,
*/
location: null,
/**
* Holds the stackframes received from the server.
*
* @private
* @type array
*/
stack: null,
/**
* Message prefix
* @type string|null
@ -810,6 +822,20 @@ Messages.Simple.prototype = Heritage.extend(Messages.BaseMessage.prototype,
return this;
},
/**
* Tells if the message can be expanded/collapsed.
* @type boolean
*/
collapsible: false,
/**
* Getter that tells if this message is collapsed - no details are shown.
* @type boolean
*/
get collapsed() {
return this.collapsible && this.element && !this.element.hasAttribute("open");
},
_initRepeatID: function()
{
if (!this._filterDuplicates) {
@ -854,6 +880,9 @@ Messages.Simple.prototype = Heritage.extend(Messages.BaseMessage.prototype,
let icon = this.document.createElementNS(XHTML_NS, "span");
icon.className = "icon";
icon.title = l10n.getStr("severity." + this._severityNameCompat);
if (this.stack) {
icon.addEventListener("click", this._onClickCollapsible);
}
let prefixNode;
if (this.prefix) {
@ -886,6 +915,18 @@ Messages.Simple.prototype = Heritage.extend(Messages.BaseMessage.prototype,
if (prefixNode) {
this.element.appendChild(prefixNode);
}
if (this.stack) {
let twisty = this.document.createElementNS(XHTML_NS, "a");
twisty.className = "theme-twisty";
twisty.href = "#";
twisty.title = l10n.getStr("messageToggleDetails");
twisty.addEventListener("click", this._onClickCollapsible);
this.element.appendChild(twisty);
this.collapsible = true;
this.element.setAttribute("collapsible", true);
}
this.element.appendChild(body);
if (repeatNode) {
this.element.appendChild(repeatNode);
@ -893,6 +934,7 @@ Messages.Simple.prototype = Heritage.extend(Messages.BaseMessage.prototype,
if (location) {
this.element.appendChild(location);
}
this.element.appendChild(this.document.createTextNode("\n"));
this.element.clipboardText = this.element.textContent;
@ -944,6 +986,12 @@ Messages.Simple.prototype = Heritage.extend(Messages.BaseMessage.prototype,
container.textContent = this._message;
}
if (this.stack) {
let stack = new Widgets.Stacktrace(this, this.stack).render().element;
body.appendChild(this.document.createTextNode("\n"));
body.appendChild(stack);
}
return body;
},
@ -988,6 +1036,36 @@ Messages.Simple.prototype = Heritage.extend(Messages.BaseMessage.prototype,
line: line,
column: column});
},
/**
* The click event handler for the message expander arrow element. This method
* toggles the display of message details.
*
* @private
* @param nsIDOMEvent ev
* The DOM event object.
* @see this.toggleDetails()
*/
_onClickCollapsible: function(ev)
{
ev.preventDefault();
this.toggleDetails();
},
/**
* Expand/collapse message details.
*/
toggleDetails: function()
{
let twisty = this.element.querySelector(".theme-twisty");
if (this.element.hasAttribute("open")) {
this.element.removeAttribute("open");
twisty.removeAttribute("open");
} else {
this.element.setAttribute("open", true);
twisty.setAttribute("open", true);
}
},
}); // Messages.Simple.prototype
@ -1330,30 +1408,13 @@ Messages.ConsoleGeneric = function(packet)
this._repeatID.consoleApiLevel = packet.level;
this._repeatID.styles = packet.styles;
this._stacktrace = this._repeatID.stacktrace = packet.stacktrace;
this.stack = this._repeatID.stacktrace = packet.stacktrace;
this._styles = packet.styles || [];
this._onClickCollapsible = this._onClickCollapsible.bind(this);
};
Messages.ConsoleGeneric.prototype = Heritage.extend(Messages.Extended.prototype,
{
_styles: null,
_stacktrace: null,
/**
* Tells if the message can be expanded/collapsed.
* @type boolean
*/
collapsible: false,
/**
* Getter that tells if this message is collapsed - no details are shown.
* @type boolean
*/
get collapsed() {
return this.collapsible && this.element && !this.element.hasAttribute("open");
},
_renderBodyPieceSeparator: function()
{
@ -1373,25 +1434,9 @@ Messages.ConsoleGeneric.prototype = Heritage.extend(Messages.Extended.prototype,
location.target = "jsdebugger";
}
let stack = null;
let twisty = null;
if (this._stacktrace && this._stacktrace.length > 0) {
stack = new Widgets.Stacktrace(this, this._stacktrace).render().element;
twisty = this.document.createElementNS(XHTML_NS, "a");
twisty.className = "theme-twisty";
twisty.href = "#";
twisty.title = l10n.getStr("messageToggleDetails");
twisty.addEventListener("click", this._onClickCollapsible);
}
let flex = this.document.createElementNS(XHTML_NS, "span");
flex.className = "message-flex-body";
if (twisty) {
flex.appendChild(twisty);
}
flex.appendChild(msg);
if (repeatNode) {
@ -1404,24 +1449,11 @@ Messages.ConsoleGeneric.prototype = Heritage.extend(Messages.Extended.prototype,
let result = this.document.createDocumentFragment();
result.appendChild(flex);
if (stack) {
result.appendChild(this.document.createTextNode("\n"));
result.appendChild(stack);
}
this._message = result;
this._stacktrace = null;
Messages.Simple.prototype.render.call(this);
if (stack) {
this.collapsible = true;
this.element.setAttribute("collapsible", true);
let icon = this.element.querySelector(".icon");
icon.addEventListener("click", this._onClickCollapsible);
}
return this;
},
@ -1484,36 +1516,6 @@ Messages.ConsoleGeneric.prototype = Heritage.extend(Messages.Extended.prototype,
_renderLocation: function() { },
_renderRepeatNode: function() { },
/**
* Expand/collapse message details.
*/
toggleDetails: function()
{
let twisty = this.element.querySelector(".theme-twisty");
if (this.element.hasAttribute("open")) {
this.element.removeAttribute("open");
twisty.removeAttribute("open");
} else {
this.element.setAttribute("open", true);
twisty.setAttribute("open", true);
}
},
/**
* The click event handler for the message expander arrow element. This method
* toggles the display of message details.
*
* @private
* @param nsIDOMEvent ev
* The DOM event object.
* @see this.toggleDetails()
*/
_onClickCollapsible: function(ev)
{
ev.preventDefault();
this.toggleDetails();
},
/**
* Given a style attribute value, return a cleaned up version of the string
* such that:

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

@ -129,6 +129,7 @@ support-files =
test-bug_1050691_click_function_to_source.html
test-bug_1050691_click_function_to_source.js
test-console-api-stackframe.html
test-exception-stackframe.html
test_bug_1010953_cspro.html^headers^
test_bug_1010953_cspro.html
test_bug1045902_console_csp_ignore_reflected_xss_message.html^headers^
@ -383,6 +384,7 @@ skip-if = e10s # Bug 1042253 - webconsole e10s tests (Linux debug timeout)
[browser_webconsole_autocomplete_crossdomain_iframe.js]
[browser_webconsole_console_custom_styles.js]
[browser_webconsole_console_api_stackframe.js]
[browser_webconsole_exception_stackframe.js]
[browser_webconsole_column_numbers.js]
[browser_console_open_or_focus.js]
[browser_webconsole_bug_922212_console_dirxml.js]

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

@ -57,7 +57,7 @@ function test() {
let msg = [...result.matched][0];
ok(msg, "message element found");
let locationNode = msg.querySelector(".message-location");
let locationNode = msg.querySelector(".message > .message-location");
ok(locationNode, "message location element found");
let title = locationNode.getAttribute("title");
@ -78,7 +78,7 @@ function test() {
browserconsole.iframeWindow);
info("wait for click on locationNode");
yield clickPromise;
yield clickPromise.promise;
info("view-source url: " + URL);
ok(URL, "we have some source URL after the click");

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

@ -58,7 +58,7 @@ function test() {
let msg = [...results[0].matched][0];
ok(msg, "message element found for: " + result.text);
let locationNode = msg.querySelector(".message-location");
let locationNode = msg.querySelector(".message > .message-location");
ok(locationNode, "message location element found");
EventUtils.synthesizeMouse(locationNode, 2, 2, {}, hud.iframeWindow);

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

@ -0,0 +1,71 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test that the console receive exceptions include a stackframe.
// See bug 1184172.
// On e10s, the exception is triggered in child process
// and is ignored by test harness
if (!Services.appinfo.browserTabsRemoteAutostart) {
expectUncaughtException();
}
function test() {
let hud;
const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/" +
"test/test-exception-stackframe.html";
const TEST_FILE = TEST_URI.substr(TEST_URI.lastIndexOf("/"));
Task.spawn(runner).then(finishTest);
function* runner() {
const {tab} = yield loadTab(TEST_URI);
hud = yield openConsole(tab);
const stack = [{
file: TEST_FILE,
fn: "thirdCall",
line: 21,
}, {
file: TEST_FILE,
fn: "secondCall",
line: 17,
}, {
file: TEST_FILE,
fn: "firstCall",
line: 12,
}];
let results = yield waitForMessages({
webconsole: hud,
messages: [{
text: "nonExistingMethodCall is not defined",
category: CATEGORY_JS,
severity: SEVERITY_ERROR,
collapsible: true,
stacktrace: stack,
}],
});
let elem = [...results[0].matched][0];
ok(elem, "message element");
let msg = elem._messageObject;
ok(msg, "message object");
ok(msg.collapsed, "message is collapsed");
msg.toggleDetails();
ok(!msg.collapsed, "message is not collapsed");
msg.toggleDetails();
ok(msg.collapsed, "message is collapsed");
yield closeConsole(tab);
}
}

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

@ -1079,7 +1079,7 @@ function waitForMessages(options) {
let file = frame.querySelector(".message-location").title;
if (!checkText(expected.file, file)) {
ok(false, "frame #" + i + " does not match file name: " +
expected.file);
expected.file + " != " + file);
displayErrorContext(rule, element);
return false;
}
@ -1089,7 +1089,7 @@ function waitForMessages(options) {
let fn = frame.querySelector(".function").textContent;
if (!checkText(expected.fn, fn)) {
ok(false, "frame #" + i + " does not match the function name: " +
expected.fn);
expected.fn + " != " + fn);
displayErrorContext(rule, element);
return false;
}
@ -1099,7 +1099,7 @@ function waitForMessages(options) {
let line = frame.querySelector(".message-location").sourceLine;
if (!checkText(expected.line, line)) {
ok(false, "frame #" + i + " does not match the line number: " +
expected.line);
expected.line + " != " + line);
displayErrorContext(rule, element);
return false;
}

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

@ -0,0 +1,30 @@
<!DOCTYPE HTML>
<html dir="ltr" lang="en">
<head>
<meta charset="utf8">
<!--
- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/
-->
<title>Test for bug 1184172 - stacktraces for exceptions</title>
<script>
function firstCall() {
secondCall();
}
// Check anonymous functions
var secondCall = function () {
thirdCall();
}
function thirdCall() {
nonExistingMethodCall();
}
window.onload = firstCall;
</script>
</head>
<body>
<p>Hello world!</p>
</body>
</html>

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

@ -1528,6 +1528,7 @@ WebConsoleFrame.prototype = {
line: aScriptError.lineNumber,
column: aScriptError.columnNumber
},
stack: aScriptError.stacktrace,
category: category,
severity: severity,
timestamp: aScriptError.timeStamp,

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

@ -1900,6 +1900,7 @@ richlistitem[type~="action"][actiontype="switchtab"][selected="true"] > .ac-url-
list-style-image: url("chrome://browser/skin/reload-stop-go.png");
padding: 0 9px;
margin-inline-start: 2px;
border-inline-end-style: none;
border-inline-start: 1px solid var(--urlbar-separator-color);
border-image: linear-gradient(transparent 15%,
var(--urlbar-separator-color) 15%,

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

@ -29,29 +29,3 @@ postflight_all:
# actually does a universal staging with both OBJDIR_ARCH_1 and OBJDIR_ARCH_2.
$(MAKE) -C $(OBJDIR_ARCH_1)/$(MOZ_BUILD_APP)/installer \
PKG_SKIP_STRIP=1 stage-package
ifdef ENABLE_TESTS
# Now, repeat the process for the test package.
$(MAKE) -C $(OBJDIR_ARCH_1) UNIVERSAL_BINARY= CHROME_JAR= package-tests
$(MAKE) -C $(OBJDIR_ARCH_2) UNIVERSAL_BINARY= CHROME_JAR= package-tests
rm -rf $(DIST_UNI)/test-stage
# automation.py differs because it hardcodes a path to
# dist/bin. It doesn't matter which one we use.
if test -d $(DIST_ARCH_1)/test-stage -a \
-d $(DIST_ARCH_2)/test-stage; then \
cp $(DIST_ARCH_1)/test-stage/mochitest/automation.py \
$(DIST_ARCH_2)/test-stage/mochitest/; \
cp -RL $(DIST_ARCH_1)/test-stage/mochitest/extensions/specialpowers \
$(DIST_ARCH_2)/test-stage/mochitest/extensions/; \
cp $(DIST_ARCH_1)/test-stage/xpcshell/automation.py \
$(DIST_ARCH_2)/test-stage/xpcshell/; \
cp $(DIST_ARCH_1)/test-stage/reftest/automation.py \
$(DIST_ARCH_2)/test-stage/reftest/; \
cp -RL $(DIST_ARCH_1)/test-stage/reftest/specialpowers \
$(DIST_ARCH_2)/test-stage/reftest/; \
$(TOPSRCDIR)/build/macosx/universal/unify \
--unify-with-sort "\.manifest$$" \
--unify-with-sort "all-test-dirs\.list$$" \
$(DIST_ARCH_1)/test-stage \
$(DIST_ARCH_2)/test-stage \
$(DIST_UNI)/test-stage; fi
endif

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

@ -6,6 +6,6 @@
# As used here, arguments in $MOZ_BUILD_PROJECTS are suitable as arguments
# to gcc's -arch parameter.
mk_add_options MOZ_BUILD_PROJECTS="i386 x86_64"
mk_add_options MOZ_BUILD_PROJECTS="x86_64 i386"
. $topsrcdir/build/macosx/universal/mozconfig.common

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

@ -366,7 +366,7 @@ IntelWebMVideoDecoder::PopSample()
}
MOZ_ASSERT(!mSampleQueue.empty());
sample = mSampleQueue.front();
sample = mSampleQueue.front().forget();
mSampleQueue.pop_front();
return sample.forget();
}

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

@ -89,7 +89,7 @@ class WebMPacketQueue {
}
already_AddRefed<NesteggPacketHolder> PopFront() {
nsRefPtr<NesteggPacketHolder> result = mQueue.front();
nsRefPtr<NesteggPacketHolder> result = mQueue.front().forget();
mQueue.pop_front();
return result.forget();
}

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

@ -33,7 +33,7 @@ class MediaRawDataQueue {
}
already_AddRefed<MediaRawData> PopFront() {
nsRefPtr<MediaRawData> result = mQueue.front();
nsRefPtr<MediaRawData> result = mQueue.front().forget();
mQueue.pop_front();
return result.forget();
}

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

@ -36,3 +36,4 @@ qemu = true
[test_mobile_clir_radio_off.js]
[test_mobile_neighboring_cell_ids.js]
[test_mobile_cell_Info_list.js]
skip-if = android_version < '19'

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

@ -4,22 +4,8 @@
MARIONETTE_TIMEOUT = 60000;
MARIONETTE_HEAD_JS = "head_chrome.js";
function getAndroidVersion() {
return runEmulatorShellCmdSafe(["getprop", "ro.build.version.sdk"])
.then(aResults => aResults[0]);
}
// Start test.
startTestBase(function() {
return getAndroidVersion().
then((aVersion) => {
if (aVersion < "19") {
// Only emulator-kk supports REQUEST_GET_CELL_INFO_LIST, so we skip this
// test if in older android version.
log("Skip test: AndroidVersion: " + aVersion);
return;
}
return getCellInfoList()
.then((aResults) => {
// Cell Info are hard-coded in hardware/ril/reference-ril/reference-ril.c.
@ -36,5 +22,4 @@ startTestBase(function() {
// isn't correct (missing timeStampType), so we skip to check other
// attributes first until we fix it.
});
});
});

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

@ -983,6 +983,14 @@ GeckoChildProcessHost::PerformAsyncLaunchInternal(std::vector<std::string>& aExt
#endif
{
base::LaunchApp(cmdLine, false, false, &process);
// We need to be able to duplicate handles to non-sandboxed content
// processes, so add it as a target peer.
if (mProcessType == GeckoProcessType_Content) {
if (!mSandboxBroker.AddTargetPeer(process)) {
NS_WARNING("Failed to add content process as target peer.");
}
}
}
#else

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

@ -154,7 +154,7 @@ int NrIceResolver::resolve(nr_resolver_resource *resource,
if (resource->transport_protocol != IPPROTO_UDP &&
resource->transport_protocol != IPPROTO_TCP) {
MOZ_MTLOG(ML_ERROR, "Only UDP and TCP are is supported.");
MOZ_MTLOG(ML_ERROR, "Only UDP and TCP are supported.");
ABORT(R_NOT_FOUND);
}
pr = new PendingResolution(sts_thread_,

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

@ -71,6 +71,10 @@ class NrIceResolver
void DestroyResolver();
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(NrIceResolver)
int resolve(nr_resolver_resource *resource,
int (*cb)(void *cb_arg, nr_transport_addr *addr),
void *cb_arg, void **handle);
private:
// Implementations of vtbl functions
static int destroy(void **objp);
@ -80,10 +84,6 @@ class NrIceResolver
static void resolve_cb(NR_SOCKET s, int how, void *cb_arg);
static int cancel(void *obj, void *handle);
int resolve(nr_resolver_resource *resource,
int (*cb)(void *cb_arg, nr_transport_addr *addr),
void *cb_arg, void **handle);
class PendingResolution : public nsIDNSListener
{
public:

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

@ -50,6 +50,7 @@
extern "C" {
#include "r_data.h"
#include "util.h"
}
#define GTEST_HAS_RTTI 0
@ -65,7 +66,6 @@ static unsigned int kDefaultTimeout = 7000;
//TODO(nils@mozilla.com): This should get replaced with some non-external
//solution like discussed in bug 860775.
const std::string kDefaultStunServerAddress((char *)"52.27.56.60");
const std::string kDefaultStunServerHostname(
(char *)"global.stun.twilio.com");
const std::string kBogusStunServerHostname(
@ -77,7 +77,7 @@ const std::string kBogusIceCandidate(
const std::string kUnreachableHostIceCandidate(
(char *)"candidate:0 1 UDP 2113601790 192.168.178.20 50769 typ host");
std::string g_stun_server_address(kDefaultStunServerAddress);
std::string g_stun_server_address;
std::string g_stun_server_hostname(kDefaultStunServerHostname);
std::string g_turn_server;
std::string g_turn_user;
@ -3060,6 +3060,48 @@ static std::string get_environment(const char *name) {
return value;
}
// DNS resolution helper code
static std::string
Resolve(const std::string& fqdn, int address_family)
{
struct addrinfo hints;
memset(&hints, 0, sizeof(hints));
hints.ai_family = address_family;
hints.ai_protocol = IPPROTO_UDP;
struct addrinfo *res;
int err = getaddrinfo(fqdn.c_str(), nullptr, &hints, &res);
if (err) {
std::cerr << "Error in getaddrinfo: " << err << std::endl;
return "";
}
char str_addr[64] = {0};
switch (res->ai_family) {
case AF_INET:
inet_ntop(
AF_INET,
&reinterpret_cast<struct sockaddr_in*>(res->ai_addr)->sin_addr,
str_addr,
sizeof(str_addr));
case AF_INET6:
inet_ntop(
AF_INET6,
&reinterpret_cast<struct sockaddr_in6*>(res->ai_addr)->sin6_addr,
str_addr,
sizeof(str_addr));
default:
std::cerr << "Got unexpected address family in DNS lookup: "
<< res->ai_family << std::endl;
return "";
}
if (!strlen(str_addr)) {
std::cerr << "inet_ntop failed" << std::endl;
}
return str_addr;
}
int main(int argc, char **argv)
{
#ifdef ANDROID
@ -3071,6 +3113,7 @@ int main(int argc, char **argv)
g_turn_user = get_environment("TURN_SERVER_USER");
g_turn_password = get_environment("TURN_SERVER_PASSWORD");
if (g_turn_server.empty() ||
g_turn_user.empty(),
g_turn_password.empty()) {
@ -3104,6 +3147,12 @@ int main(int argc, char **argv)
NSS_NoDB_Init(nullptr);
NSS_SetDomesticPolicy();
// If only a STUN server FQDN was provided, look up its IP address for the
// address-only tests.
if (g_stun_server_address.empty() && !g_stun_server_hostname.empty()) {
g_stun_server_address = Resolve(g_stun_server_hostname, AF_INET);
}
// Start the tests
::testing::InitGoogleTest(&argc, argv);

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

@ -42,7 +42,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define NR_RESOLVE_PROTOCOL_TURN 2
typedef struct nr_resolver_resource_ {
char *domain_name;
const char *domain_name;
UINT2 port;
int stun_turn;
UCHAR transport_protocol;

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

@ -5,6 +5,7 @@
package org.mozilla.gecko.home;
import org.mozilla.gecko.AppConstants;
import org.mozilla.gecko.db.BrowserContract.SearchHistory;
import org.mozilla.gecko.R;
import org.mozilla.gecko.Telemetry;
@ -274,9 +275,11 @@ class SearchEngineRow extends AnimatedHeightLayout {
if (suggestionsEnabled) {
final int recycledSuggestionCount = mSuggestionView.getChildCount();
final int suggestionViewCount = updateFromSearchEngine(searchEngine, animate, recycledSuggestionCount);
if (AppConstants.NIGHTLY_BUILD) {
updateFromSavedSearches(searchTerm, animate, suggestionViewCount, recycledSuggestionCount);
}
}
}
@Override
public boolean onKeyDown(int keyCode, android.view.KeyEvent event) {

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

@ -18,8 +18,7 @@ import android.support.v4.graphics.drawable.DrawableCompat;
public class DrawableUtil {
/**
* Tints the given drawable with the given color and returns it. Note that this
* transformation does not occur in place on pre-Lollipop devices (bug 1193950).
* Tints the given drawable with the given color and returns it.
*/
@CheckResult
public static Drawable tintDrawable(@NonNull final Context context, @DrawableRes final int drawableID,
@ -31,8 +30,10 @@ public class DrawableUtil {
}
/**
* Tints the given drawable with the given tint list and returns it. Note that this
* transformation does not occur in place on pre-Lollipop devices (bug 1193950).
* Tints the given drawable with the given tint list and returns it. Note that you
* should no longer use the argument Drawable because the argument is not mutated
* on pre-Lollipop devices but is mutated on L+ due to differences in the Support
* Library implementation (bug 1193950).
*/
@CheckResult
public static Drawable tintDrawableWithStateList(@NonNull final Drawable drawable,

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

@ -325,10 +325,6 @@ const kStateActive = 0x00000001; // :active pseudoclass for elements
const kXLinkNamespace = "http://www.w3.org/1999/xlink";
const kDefaultCSSViewportWidth = 980;
const kViewportRemeasureThrottle = 500;
function fuzzyEquals(a, b) {
return (Math.abs(a - b) < 1e-6);
}
@ -1059,9 +1055,6 @@ var BrowserApp = {
return;
aTab.setActive(true);
if (!AppConstants.MOZ_ANDROID_APZ) {
aTab.setResolution(aTab._zoom, true);
}
this.contentDocumentChanged();
this.deck.selectedPanel = aTab.browser;
// Focus the browser so that things like selection will be styled correctly.
@ -3722,18 +3715,11 @@ Tab.prototype = {
bottom: aDisplayPort.bottom - (scrolly + gScreenHeight)
};
if (this._oldDisplayPortMargins == null ||
!fuzzyEquals(displayPortMargins.left, this._oldDisplayPortMargins.left) ||
!fuzzyEquals(displayPortMargins.top, this._oldDisplayPortMargins.top) ||
!fuzzyEquals(displayPortMargins.right, this._oldDisplayPortMargins.right) ||
!fuzzyEquals(displayPortMargins.bottom, this._oldDisplayPortMargins.bottom)) {
cwu.setDisplayPortMarginsForElement(displayPortMargins.left,
displayPortMargins.top,
displayPortMargins.right,
displayPortMargins.bottom,
element, 0);
}
this._oldDisplayPortMargins = displayPortMargins;
},
setScrollClampingSize: function(zoom) {

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

@ -1504,9 +1504,10 @@ z_streamp strm;
{
struct inflate_state FAR *state;
if (strm == Z_NULL || strm->state == Z_NULL) return -1L << 16;
if (strm == Z_NULL || strm->state == Z_NULL)
return (long)(((unsigned long)0 - 1) << 16);
state = (struct inflate_state FAR *)strm->state;
return ((long)(state->back) << 16) +
return (long)(((unsigned long)((long)state->back)) << 16) +
(state->mode == COPY ? state->length :
(state->mode == MATCH ? state->was - state->length : 0));
}

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

@ -439,6 +439,13 @@ SandboxBroker::AllowDirectory(wchar_t const *dir)
return (sandbox::SBOX_ALL_OK == result);
}
bool
SandboxBroker::AddTargetPeer(HANDLE aPeerProcess)
{
sandbox::ResultCode result = sBrokerService->AddTargetPeer(aPeerProcess);
return (sandbox::SBOX_ALL_OK == result);
}
SandboxBroker::~SandboxBroker()
{
if (mPolicy) {

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

@ -14,6 +14,7 @@
#endif
#include <stdint.h>
#include <windows.h>
namespace sandbox {
class BrokerServices;
@ -45,6 +46,9 @@ public:
bool AllowReadWriteFile(wchar_t const *file);
bool AllowDirectory(wchar_t const *dir);
// Exposes AddTargetPeer from broker services, so that none sandboxed
// processes can be added as handle duplication targets.
bool AddTargetPeer(HANDLE aPeerProcess);
private:
static sandbox::BrokerServices *sBrokerService;
sandbox::TargetPolicy *mPolicy;

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

@ -1 +1 @@
quay.io/djmitche
taskcluster

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

@ -1 +1 @@
0.1.1
0.1.2

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

@ -25,10 +25,6 @@ set -x -e
: TOOLS_HEAD_REF ${TOOLS_HEAD_REF:=${TOOLS_HEAD_REV}}
: TOOLS_DISABLE ${TOOLS_DISABLE:=false}
: MH_CUSTOM_BUILD_VARIANT_CFG ${MH_CUSTOM_BUILD_VARIANT_CFG}
: MH_BRANCH ${MH_BRANCH:=mozilla-central}
: MH_BUILD_POOL ${MH_BUILD_POOL:=staging}
: WORKSPACE ${WORKSPACE:=/home/worker/workspace}
set -v

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

@ -743,6 +743,17 @@ setReq.onerror = function() {
self.marionette.baseurl = self.server_root
self.logger.info("using remote content from %s" % self.marionette.baseurl)
device_info = None
if self.capabilities['device'] != 'desktop' and self.capabilities['browserName'] == 'B2G':
dm = get_dm(self.marionette)
device_info = dm.getInfo()
# Add Android version (SDK level) to mozinfo so that manifest entries
# can be conditional on android_version.
androidVersion = dm.shellCheckOutput(['getprop', 'ro.build.version.sdk'])
self.logger.info(
"Android sdk version '%s'; will use this to filter manifests" % androidVersion)
mozinfo.info['android_version'] = androidVersion
for test in tests:
self.add_test(test)
@ -762,11 +773,6 @@ setReq.onerror = function() {
adb_host=self.marionette.adb_host,
adb_port=self.marionette.adb_port)
device_info = None
if self.capabilities['device'] != 'desktop' and self.capabilities['browserName'] == 'B2G':
dm = get_dm(self.marionette)
device_info = dm.getInfo()
self.logger.suite_start(self.tests,
version_info=version_info,
device_info=device_info)
@ -985,6 +991,8 @@ setReq.onerror = function() {
self.todo += len(results.expectedFailures)
self.mixin_run_tests = []
for result in self.results:
result.result_modifiers = []
def run_test_set(self, tests):
if self.shuffle:

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

@ -32,7 +32,7 @@ config = {
'purge_basedirs': [],
'enable_ccache': True,
'vcs_share_base': '/builds/hg-shared',
'objdir': 'obj-firefox/i386',
'objdir': 'obj-firefox/x86_64',
'tooltool_script': ["/builds/tooltool.py"],
'tooltool_bootstrap': "setup.sh",
'enable_count_ctors': False,

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

@ -134,9 +134,9 @@ builds:
- Linux64
types:
opt:
task: tasks/builds/opt_linux64.yml
task: tasks/builds/opt_linux64_clobber.yml
debug:
task: tasks/builds/dbg_linux64.yml
task: tasks/builds/dbg_linux64_clobber.yml
sm-plain:
platforms:
- Linux64

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

@ -1,22 +1,10 @@
$inherits:
from: 'tasks/builds/opt_linux64.yml'
variables:
build_name: 'linux64'
build_type: 'dbg'
from: 'tasks/builds/dbg_linux64_clobber.yml'
task:
metadata:
name: '[TC] Linux64 Dbg'
description: 'Linux64 Dbg'
workerType: dbg-linux64
# same as clobber, but with a cached workspace
scopes:
- 'docker-worker:cache:build-linux64-c6-workspace'
payload:
env:
MH_CUSTOM_BUILD_VARIANT_CFG: 'debug'
extra:
treeherder:
groupSymbol: tc
groupName: Submitted by taskcluster
symbol: B
collection:
debug: true
cache:
build-linux64-c6-workspace: '/home/worker/workspace'

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

@ -0,0 +1,24 @@
$inherits:
from: 'tasks/builds/linux64_clobber.yml'
variables:
build_name: 'linux64'
build_type: 'dbg'
task:
metadata:
name: '[TC] Linux64 Dbg'
description: 'Linux64 Dbg'
workerType: dbg-linux64
payload:
env:
MH_CUSTOM_BUILD_VARIANT_CFG: 'debug'
extra:
treeherder:
groupSymbol: tc
groupName: Submitted by taskcluster
symbol: B
collection:
debug: true

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

@ -0,0 +1,53 @@
$inherits:
from: 'tasks/builds/firefox_base.yml'
variables:
build_name: 'linux64'
task:
#workerType: ..
routes:
- 'index.buildbot.branches.{{project}}.linux64'
- 'index.buildbot.revisions.{{head_rev}}.{{project}}.linux64'
scopes:
- 'docker-worker:cache:tooltool-cache'
- 'docker-worker:relengapi-proxy:tooltool.download.public'
payload:
image: '{{#docker_image}}desktop-build{{/docker_image}}'
cache:
# "clobber" means no workspace cache; non-clobber subclasses should add that
tooltool-cache: '/home/worker/tooltool-cache'
features:
relengAPIProxy: true
env:
MOZHARNESS_SCRIPT: 'mozharness/scripts/fx_desktop_build.py'
MOZHARNESS_CONFIG: 'builds/releng_base_linux_64_builds.py balrog/production.py'
MH_BRANCH: {{project}}
MH_BUILD_POOL: taskcluster
# image paths
TOOLTOOL_CACHE: '/home/worker/tooltool-cache'
NEED_XVFB: true
DIST_UPLOADS: 'jsshell-linux-x86_64.zip'
DIST_TARGET_UPLOADS: 'x-test.linux-x86_64.tar.bz2 linux-x86_64.tar.bz2 linux-x86_64.json tests.zip crashreporter-symbols.zip'
maxRunTime: 36000
command: ["/bin/bash", "bin/build.sh"]
extra:
treeherderEnv:
- production
- staging
treeherder:
machine:
# see https://github.com/mozilla/treeherder/blob/master/ui/js/values.js
platform: linux64
# Rather then enforcing particular conventions we require that all build
# tasks provide the "build" extra field to specify where the build and tests
# files are located.
locations:
build: 'public/build/target.linux-x86_64.tar.bz2'
tests: 'public/build/target.tests.zip'

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

@ -1,60 +1,10 @@
$inherits:
from: 'tasks/builds/firefox_base.yml'
variables:
build_name: 'linux64'
build_type: 'opt'
from: 'tasks/builds/opt_linux64_clobber.yml'
task:
metadata:
name: '[TC] Linux64 Opt'
description: 'Linux64 Opt'
workerType: opt-linux64
routes:
- 'index.buildbot.branches.{{project}}.linux64'
- 'index.buildbot.revisions.{{head_rev}}.{{project}}.linux64'
# same as clobber, but with a cached workspace
scopes:
- 'docker-worker:cache:build-linux64-c6-workspace'
- 'docker-worker:cache:tooltool-cache'
- 'docker-worker:relengapi-proxy:tooltool.download.public'
payload:
image: '{{#docker_image}}desktop-build{{/docker_image}}'
cache:
build-linux64-c6-workspace: '/home/worker/workspace'
tooltool-cache: '/home/worker/tooltool-cache'
features:
relengAPIProxy: true
env:
MOZHARNESS_SCRIPT: 'mozharness/scripts/fx_desktop_build.py'
MOZHARNESS_CONFIG: 'builds/releng_base_linux_64_builds.py balrog/production.py'
MH_BRANCH: {{project}}
MH_BUILD_POOL: taskcluster
# image paths
TOOLTOOL_CACHE: '/home/worker/tooltool-cache'
RELENGAPI_TOKEN: 'TODO' # 1164612: encrypt this secret
NEED_XVFB: true
DIST_UPLOADS: 'jsshell-linux-x86_64.zip'
DIST_TARGET_UPLOADS: 'x-test.linux-x86_64.tar.bz2 linux-x86_64.tar.bz2 linux-x86_64.json tests.zip crashreporter-symbols.zip'
maxRunTime: 36000
command: ["/bin/bash", "bin/build.sh"]
extra:
treeherderEnv:
- production
- staging
treeherder:
machine:
# see https://github.com/mozilla/treeherder/blob/master/ui/js/values.js
platform: linux64
# Rather then enforcing particular conventions we require that all build
# tasks provide the "build" extra field to specify where the build and tests
# files are located.
locations:
build: 'public/build/target.linux-x86_64.tar.bz2'
tests: 'public/build/target.tests.zip'

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

@ -0,0 +1,18 @@
$inherits:
from: 'tasks/builds/linux64_clobber.yml'
variables:
build_name: 'linux64'
build_type: 'opt'
task:
metadata:
name: '[TC] Linux64 Opt'
description: 'Linux64 Opt'
workerType: opt-linux64
extra:
treeherder:
groupSymbol: tc
groupName: Submitted by taskcluster
symbol: B

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

@ -369,8 +369,8 @@ pgo-profile-run:
# Package up the tests and test harnesses
include $(topsrcdir)/toolkit/mozapps/installer/package-name.mk
ifndef UNIVERSAL_BINARY
PKG_STAGE = $(DIST)/test-stage
package-tests: \
stage-config \
stage-mach \
@ -393,10 +393,6 @@ package-tests: \
ifdef MOZ_WEBRTC
package-tests: stage-steeplechase
endif
else
# This staging area has been built for us by universal/flight.mk
PKG_STAGE = $(DIST)/universal/test-stage
endif
TEST_PKGS := \
cppunittest \
@ -410,9 +406,7 @@ PKG_ARG = --$(1) '$(PKG_BASENAME).$(1).tests.zip'
test-packages-manifest-tc:
@rm -f $(MOZ_TEST_PACKAGES_FILE_TC)
ifndef UNIVERSAL_BINARY
$(NSINSTALL) -D $(dir $(MOZ_TEST_PACKAGES_FILE_TC))
endif
$(PYTHON) $(topsrcdir)/build/gen_test_packages_manifest.py \
--jsshell $(JSSHELL_NAME) \
--dest-file $(MOZ_TEST_PACKAGES_FILE_TC) \
@ -422,9 +416,7 @@ endif
test-packages-manifest:
@rm -f $(MOZ_TEST_PACKAGES_FILE)
ifndef UNIVERSAL_BINARY
$(NSINSTALL) -D $(dir $(MOZ_TEST_PACKAGES_FILE))
endif
$(PYTHON) $(topsrcdir)/build/gen_test_packages_manifest.py \
--jsshell $(JSSHELL_NAME) \
--dest-file $(MOZ_TEST_PACKAGES_FILE) \
@ -433,9 +425,7 @@ endif
package-tests:
@rm -f '$(DIST)/$(PKG_PATH)$(TEST_PACKAGE)'
ifndef UNIVERSAL_BINARY
$(NSINSTALL) -D $(DIST)/$(PKG_PATH)
endif
# Exclude harness specific directories when generating the common zip.
$(MKDIR) -p $(abspath $(DIST))/$(PKG_PATH) && \
cd $(PKG_STAGE) && \

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

@ -4062,6 +4062,11 @@
"extended_statistics_ok": true,
"description": "Firefox: Time to initialize the bookmarks toolbar view (ms)"
},
"FX_BROWSER_FULLSCREEN_USED": {
"expires_in_version": "46",
"kind": "count",
"description": "The number of times that a session enters browser fullscreen (f11-fullscreen)"
},
"FX_NEW_WINDOW_MS": {
"expires_in_version": "default",
"kind": "exponential",

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

@ -141,6 +141,7 @@ SrcdirProvider.prototype = {
let devtoolsURI = this.fileURI(devtoolsDir);
let toolkitURI = this.fileURI(toolkitDir);
let serverURI = this.fileURI(OS.Path.join(toolkitDir, "server"));
let webideURI = this.fileURI(OS.Path.join(devtoolsDir, "webide", "modules"));
let webconsoleURI = this.fileURI(OS.Path.join(toolkitDir, "webconsole"));
let appActorURI = this.fileURI(OS.Path.join(toolkitDir, "apps", "app-actor-front.js"));
let cssLogicURI = this.fileURI(OS.Path.join(toolkitDir, "styleinspector", "css-logic"));
@ -152,7 +153,7 @@ SrcdirProvider.prototype = {
let asyncUtilsURI = this.fileURI(OS.Path.join(toolkitDir, "async-utils.js"));
let contentObserverURI = this.fileURI(OS.Path.join(toolkitDir), "content-observer.js");
let gcliURI = this.fileURI(OS.Path.join(toolkitDir, "gcli", "source", "lib", "gcli"));
let projecteditorURI = this.fileURI(OS.Path.join(devtoolsDir, "projecteditor"));
let projecteditorURI = this.fileURI(OS.Path.join(devtoolsDir, "projecteditor", "lib"));
let promiseURI = this.fileURI(OS.Path.join(modulesDir, "Promise-backend.js"));
let acornURI = this.fileURI(OS.Path.join(toolkitDir, "acorn"));
let acornWalkURI = OS.Path.join(acornURI, "walk.js");
@ -168,6 +169,7 @@ SrcdirProvider.prototype = {
"devtools": devtoolsURI,
"devtools/toolkit": toolkitURI,
"devtools/server": serverURI,
"devtools/webide": webideURI,
"devtools/toolkit/webconsole": webconsoleURI,
"devtools/app-actor-front": appActorURI,
"devtools/styleinspector/css-logic": cssLogicURI,

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

@ -9,6 +9,8 @@ const {TargetFactory} = require("devtools/framework/target");
const l10n = require("gcli/l10n");
const gcli = require("gcli/index");
loader.lazyRequireGetter(this, "TargetFactory", "devtools/framework/target", true);
loader.lazyImporter(this, "gDevTools", "resource:///modules/devtools/gDevTools.jsm");
loader.lazyGetter(this, "Debugger", () => {

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

@ -5,8 +5,8 @@
"use strict";
const { Ci } = require("chrome");
const { getOuterId } = require("sdk/window/utils");
const { getBrowserForTab } = require("sdk/tabs/utils");
loader.lazyRequireGetter(this, "getOuterId", "sdk/window/utils", true);
loader.lazyRequireGetter(this, "getBrowserForTab", "sdk/tabs/utils", true);
let telemetry;
try {

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

@ -7,8 +7,8 @@
const EventEmitter = require("devtools/toolkit/event-emitter");
const eventEmitter = new EventEmitter();
const events = require("sdk/event/core");
const { getOuterId } = require("sdk/window/utils");
const { getBrowserForTab } = require("sdk/tabs/utils");
loader.lazyRequireGetter(this, "getOuterId", "sdk/window/utils", true);
loader.lazyRequireGetter(this, "getBrowserForTab", "sdk/tabs/utils", true);
const l10n = require("gcli/l10n");
require("devtools/server/actors/inspector");

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

@ -32,9 +32,14 @@ exports.join = OS.Path.join;
exports.sep = OS.Path.sep;
exports.dirname = OS.Path.dirname;
var dirService = Cc['@mozilla.org/file/directory_service;1']
// On B2G, there is no home folder
var home = null;
try {
var dirService = Cc['@mozilla.org/file/directory_service;1']
.getService(Ci.nsIProperties);
exports.home = dirService.get('Home', Ci.nsIFile).path;
home = dirService.get('Home', Ci.nsIFile).path;
} catch(e) {}
exports.home = home;
if ('winGetDrive' in OS.Path) {
exports.sep = '\\';

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

@ -1288,6 +1288,21 @@ WebConsoleActor.prototype =
*/
preparePageErrorForRemote: function WCA_preparePageErrorForRemote(aPageError)
{
let stack = null;
// Convert stack objects to the JSON attributes expected by client code
if (aPageError.stack) {
stack = [];
let s = aPageError.stack;
while (s !== null) {
stack.push({
filename: s.source,
lineNumber: s.line,
columnNumber: s.column,
functionName: s.functionDisplayName
});
s = s.parent;
}
}
let lineText = aPageError.sourceLine;
if (lineText && lineText.length > DebuggerServer.LONG_STRING_INITIAL_LENGTH) {
lineText = lineText.substr(0, DebuggerServer.LONG_STRING_INITIAL_LENGTH);
@ -1307,6 +1322,7 @@ WebConsoleActor.prototype =
strict: !!(aPageError.flags & aPageError.strictFlag),
info: !!(aPageError.flags & aPageError.infoFlag),
private: aPageError.isFromPrivateWindow,
stacktrace: stack
};
},

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

@ -31,6 +31,7 @@ function init(msg) {
if (!DebuggerServer.initialized) {
DebuggerServer.init();
DebuggerServer.isInChildProcess = true;
}
// In case of apps being loaded in parent process, DebuggerServer is already
@ -45,6 +46,7 @@ function init(msg) {
// Connect both parent/child processes debugger servers RDP via message managers
let conn = DebuggerServer.connectToParent(prefix, mm);
conn.parentMessageManager = mm;
let { ChildProcessActor } = devtools.require("devtools/server/actors/child-process");
let actor = new ChildProcessActor(conn);

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

@ -43,8 +43,8 @@
srcdir.load();
is(builtin.loader.mapping.length,
srcdir.loader.mapping.length + 1,
"The built-in loader should have only one more mapping for testing.");
srcdir.loader.mapping.length,
"The built-in loader should have the same number of mapping than testing.");
Services.prefs.clearUserPref(SRCDIR_PREF);
</script>

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

@ -1646,6 +1646,7 @@ var AddonManagerInternal = {
if (gStartupComplete)
return;
logger.debug("Registering startup change '" + aType + "' for " + aID);
// Ensure that an ID is only listed in one type of change
for (let type in this.startupChanges)

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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

@ -12,6 +12,7 @@ const Cu = Components.utils;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/AddonManager.jsm");
Cu.import("resource://gre/modules/Preferences.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "AddonRepository",
"resource://gre/modules/addons/AddonRepository.jsm");
@ -23,6 +24,9 @@ XPCOMUtils.defineLazyModuleGetter(this, "Promise",
"resource://gre/modules/Promise.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "OS",
"resource://gre/modules/osfile.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "Blocklist",
"@mozilla.org/extensions/blocklist;1",
Ci.nsIBlocklistService);
Cu.import("resource://gre/modules/Log.jsm");
const LOGGER_ID = "addons.xpi-utils";
@ -46,6 +50,12 @@ const PREF_DB_SCHEMA = "extensions.databaseSchema";
const PREF_PENDING_OPERATIONS = "extensions.pendingOperations";
const PREF_EM_ENABLED_ADDONS = "extensions.enabledAddons";
const PREF_EM_DSS_ENABLED = "extensions.dss.enabled";
const PREF_EM_AUTO_DISABLED_SCOPES = "extensions.autoDisableScopes";
const KEY_APP_PROFILE = "app-profile";
const KEY_APP_SYSTEM_ADDONS = "app-system-addons";
const KEY_APP_SYSTEM_DEFAULTS = "app-system-defaults";
const KEY_APP_GLOBAL = "app-global";
// Properties that only exist in the database
const DB_METADATA = ["syncGUID",
@ -72,6 +82,13 @@ const PROP_JSON_FIELDS = ["id", "syncGUID", "location", "version", "type",
"strictCompatibility", "locales", "targetApplications",
"targetPlatforms", "multiprocessCompatible", "signedState"];
// Properties that should be migrated where possible from an old database. These
// shouldn't include properties that can be read directly from install.rdf files
// or calculated
const DB_MIGRATE_METADATA= ["installDate", "userDisabled", "softDisabled",
"sourceURI", "applyBackgroundUpdates",
"releaseNotesURI", "foreignInstall", "syncGUID"];
// Time to wait before async save of XPI JSON database, in milliseconds
const ASYNC_SAVE_DELAY_MS = 20;
@ -314,13 +331,15 @@ function DBAddonInternal(aLoaded) {
this._key = this.location + ":" + this.id;
try {
this._sourceBundle = this._installLocation.getLocationForID(this.id);
if (aLoaded._sourceBundle) {
this._sourceBundle = aLoaded._sourceBundle;
}
catch (e) {
// An exception will be thrown if the add-on appears in the database but
// not on disk. In general this should only happen during startup as
// this change is being detected.
else if (aLoaded.descriptor) {
this._sourceBundle = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
this._sourceBundle.persistentDescriptor = aLoaded.descriptor;
}
else {
throw new Error("Expected passed argument to contain a descriptor");
}
XPCOMUtils.defineLazyGetter(this, "pendingUpgrade",
@ -785,7 +804,7 @@ this.XPIDatabase = {
if (aRebuildOnError) {
logger.warn("Rebuilding add-ons database from installed extensions.");
try {
XPIProvider.processFileChanges({}, false);
XPIDatabaseReconcile.processFileChanges({}, false);
}
catch (e) {
logger.error("Failed to rebuild XPI database from installed extensions", e);
@ -1084,7 +1103,7 @@ this.XPIDatabase = {
})
.then(null,
error => {
logger.error("getAddon failed", e);
logger.error("getAddon failed", error);
makeSafe(aCallback)(null);
});
},
@ -1301,6 +1320,7 @@ this.XPIDatabase = {
if ((otherAddon.id == aAddon.id) && (otherAddon._key != aAddon._key)) {
logger.debug("Hide addon " + otherAddon._key);
otherAddon.visible = false;
otherAddon.active = false;
}
}
aAddon.visible = true;
@ -1488,3 +1508,638 @@ this.XPIDatabase = {
return true;
}
};
this.XPIDatabaseReconcile = {
/**
* Returns a map of ID -> add-on. When the same add-on ID exists in multiple
* install locations the highest priority location is chosen.
*/
flattenByID(addonMap, hideLocation) {
let map = new Map();
for (let installLocation of XPIProvider.installLocations) {
if (installLocation.name == hideLocation)
continue;
let locationMap = addonMap.get(installLocation.name);
if (!locationMap)
continue;
for (let [id, addon] of locationMap) {
if (!map.has(id))
map.set(id, addon);
}
}
return map;
},
/**
* Finds the visible add-ons from the map.
*/
getVisibleAddons(addonMap) {
let map = new Map();
for (let [location, addons] of addonMap) {
for (let [id, addon] of addons) {
if (!addon.visible)
continue;
if (map.has(id)) {
logger.warn("Previous database listed more than one visible add-on with id " + id);
continue;
}
map.set(id, addon);
}
}
return map;
},
/**
* Called to add the metadata for an add-on in one of the install locations
* to the database. This can be called in three different cases. Either an
* add-on has been dropped into the location from outside of Firefox, or
* an add-on has been installed through the application, or the database
* has been upgraded or become corrupt and add-on data has to be reloaded
* into it.
*
* @param aInstallLocation
* The install location containing the add-on
* @param aId
* The ID of the add-on
* @param aAddonState
* The new state of the add-on
* @param aNewAddon
* The manifest for the new add-on if it has already been loaded
* @param aOldAppVersion
* The version of the application last run with this profile or null
* if it is a new profile or the version is unknown
* @param aOldPlatformVersion
* The version of the platform last run with this profile or null
* if it is a new profile or the version is unknown
* @param aMigrateData
* If during startup the database had to be upgraded this will
* contain data that used to be held about this add-on
* @return a boolean indicating if flushing caches is required to complete
* changing this add-on
*/
addMetadata(aInstallLocation, aId, aAddonState, aNewAddon, aOldAppVersion,
aOldPlatformVersion, aMigrateData) {
logger.debug("New add-on " + aId + " installed in " + aInstallLocation.name);
// If we had staged data for this add-on or we aren't recovering from a
// corrupt database and we don't have migration data for this add-on then
// this must be a new install.
let isNewInstall = (!!aNewAddon) || (!XPIDatabase.activeBundles && !aMigrateData);
// If it's a new install and we haven't yet loaded the manifest then it
// must be something dropped directly into the install location
let isDetectedInstall = isNewInstall && !aNewAddon;
// Load the manifest if necessary and sanity check the add-on ID
try {
if (!aNewAddon) {
// Load the manifest from the add-on.
let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
file.persistentDescriptor = aAddonState.descriptor;
aNewAddon = syncLoadManifestFromFile(file);
}
// The add-on in the manifest should match the add-on ID.
if (aNewAddon.id != aId) {
throw new Error("Invalid addon ID: expected addon ID " + aId +
", found " + aNewAddon.id + " in manifest");
}
}
catch (e) {
logger.warn("addMetadata: Add-on " + aId + " is invalid", e);
// Remove the invalid add-on from the install location if the install
// location isn't locked, no restart will be necessary
if (!aInstallLocation.locked)
aInstallLocation.uninstallAddon(aId);
else
logger.warn("Could not uninstall invalid item from locked install location");
return null;
}
// Update the AddonInternal properties.
aNewAddon._installLocation = aInstallLocation;
aNewAddon.installDate = aAddonState.mtime;
aNewAddon.updateDate = aAddonState.mtime;
// Assume that add-ons in the system add-ons install location aren't
// foreign and should default to enabled.
aNewAddon.foreignInstall = isDetectedInstall &&
aInstallLocation.name != KEY_APP_SYSTEM_ADDONS &&
aInstallLocation.name != KEY_APP_SYSTEM_DEFAULTS;
// appDisabled depends on whether the add-on is a foreignInstall so update
aNewAddon.appDisabled = !isUsableAddon(aNewAddon);
if (aMigrateData) {
// If there is migration data then apply it.
logger.debug("Migrating data from old database");
DB_MIGRATE_METADATA.forEach(function(aProp) {
// A theme's disabled state is determined by the selected theme
// preference which is read in loadManifestFromRDF
if (aProp == "userDisabled" && aNewAddon.type == "theme")
return;
if (aProp in aMigrateData)
aNewAddon[aProp] = aMigrateData[aProp];
});
// Force all non-profile add-ons to be foreignInstalls since they can't
// have been installed through the API
aNewAddon.foreignInstall |= aInstallLocation.name != KEY_APP_PROFILE;
// Some properties should only be migrated if the add-on hasn't changed.
// The version property isn't a perfect check for this but covers the
// vast majority of cases.
if (aMigrateData.version == aNewAddon.version) {
logger.debug("Migrating compatibility info");
if ("targetApplications" in aMigrateData)
aNewAddon.applyCompatibilityUpdate(aMigrateData, true);
}
// Since the DB schema has changed make sure softDisabled is correct
applyBlocklistChanges(aNewAddon, aNewAddon, aOldAppVersion,
aOldPlatformVersion);
}
// The default theme is never a foreign install
if (aNewAddon.type == "theme" && aNewAddon.internalName == XPIProvider.defaultSkin)
aNewAddon.foreignInstall = false;
if (isDetectedInstall && aNewAddon.foreignInstall) {
// If the add-on is a foreign install and is in a scope where add-ons
// that were dropped in should default to disabled then disable it
let disablingScopes = Preferences.get(PREF_EM_AUTO_DISABLED_SCOPES, 0);
if (aInstallLocation.scope & disablingScopes) {
logger.warn("Disabling foreign installed add-on " + aNewAddon.id + " in "
+ aInstallLocation.name);
aNewAddon.userDisabled = true;
}
}
return XPIDatabase.addAddonMetadata(aNewAddon, aAddonState.descriptor);
},
/**
* Called when an add-on has been removed.
*
* @param aOldAddon
* The AddonInternal as it appeared the last time the application
* ran
* @return a boolean indicating if flushing caches is required to complete
* changing this add-on
*/
removeMetadata(aOldAddon) {
// This add-on has disappeared
logger.debug("Add-on " + aOldAddon.id + " removed from " + aOldAddon.location);
XPIDatabase.removeAddonMetadata(aOldAddon);
},
/**
* Updates an add-on's metadata and determines if a restart of the
* application is necessary. This is called when either the add-on's
* install directory path or last modified time has changed.
*
* @param aInstallLocation
* The install location containing the add-on
* @param aOldAddon
* The AddonInternal as it appeared the last time the application
* ran
* @param aAddonState
* The new state of the add-on
* @param aNewAddon
* The manifest for the new add-on if it has already been loaded
* @return a boolean indicating if flushing caches is required to complete
* changing this add-on
*/
updateMetadata(aInstallLocation, aOldAddon, aAddonState, aNewAddon) {
logger.debug("Add-on " + aOldAddon.id + " modified in " + aInstallLocation.name);
try {
// If there isn't an updated install manifest for this add-on then load it.
if (!aNewAddon) {
let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
file.persistentDescriptor = aAddonState.descriptor;
aNewAddon = syncLoadManifestFromFile(file);
applyBlocklistChanges(aOldAddon, aNewAddon);
// Carry over any pendingUninstall state to add-ons modified directly
// in the profile. This is important when the attempt to remove the
// add-on in processPendingFileChanges failed and caused an mtime
// change to the add-ons files.
aNewAddon.pendingUninstall = aOldAddon.pendingUninstall;
}
// The ID in the manifest that was loaded must match the ID of the old
// add-on.
if (aNewAddon.id != aOldAddon.id)
throw new Error("Incorrect id in install manifest for existing add-on " + aOldAddon.id);
}
catch (e) {
logger.warn("updateMetadata: Add-on " + aOldAddon.id + " is invalid", e);
XPIDatabase.removeAddonMetadata(aOldAddon);
XPIStates.removeAddon(aOldAddon.location, aOldAddon.id);
if (!aInstallLocation.locked)
aInstallLocation.uninstallAddon(aOldAddon.id);
else
logger.warn("Could not uninstall invalid item from locked install location");
return null;
}
// Set the additional properties on the new AddonInternal
aNewAddon._installLocation = aInstallLocation;
aNewAddon.updateDate = aAddonState.mtime;
// Update the database
return XPIDatabase.updateAddonMetadata(aOldAddon, aNewAddon, aAddonState.descriptor);
},
/**
* Updates an add-on's descriptor for when the add-on has moved in the
* filesystem but hasn't changed in any other way.
*
* @param aInstallLocation
* The install location containing the add-on
* @param aOldAddon
* The AddonInternal as it appeared the last time the application
* ran
* @param aAddonState
* The new state of the add-on
* @return a boolean indicating if flushing caches is required to complete
* changing this add-on
*/
updateDescriptor(aInstallLocation, aOldAddon, aAddonState) {
logger.debug("Add-on " + aOldAddon.id + " moved to " + aAddonState.descriptor);
aOldAddon.descriptor = aAddonState.descriptor;
aOldAddon._sourceBundle.persistentDescriptor = aAddonState.descriptor;
return aOldAddon;
},
/**
* Called when no change has been detected for an add-on's metadata but the
* application has changed so compatibility may have changed.
*
* @param aInstallLocation
* The install location containing the add-on
* @param aOldAddon
* The AddonInternal as it appeared the last time the application
* ran
* @param aAddonState
* The new state of the add-on
* @param aOldAppVersion
* The version of the application last run with this profile or null
* if it is a new profile or the version is unknown
* @param aOldPlatformVersion
* The version of the platform last run with this profile or null
* if it is a new profile or the version is unknown
* @return a boolean indicating if flushing caches is required to complete
* changing this add-on
*/
updateCompatibility(aInstallLocation, aOldAddon, aAddonState, aOldAppVersion, aOldPlatformVersion) {
logger.debug("Updating compatibility for add-on " + aOldAddon.id + " in " + aInstallLocation.name);
// If updating from a version of the app that didn't support signedState
// then fetch that property now
if (aOldAddon.signedState === undefined && ADDON_SIGNING &&
SIGNED_TYPES.has(aOldAddon.type)) {
let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
file.persistentDescriptor = aAddonState.descriptor;
let manifest = syncLoadManifestFromFile(file);
aOldAddon.signedState = manifest.signedState;
}
// This updates the addon's JSON cached data in place
applyBlocklistChanges(aOldAddon, aOldAddon, aOldAppVersion,
aOldPlatformVersion);
aOldAddon.appDisabled = !isUsableAddon(aOldAddon);
return aOldAddon;
},
/**
* Compares the add-ons that are currently installed to those that were
* known to be installed when the application last ran and applies any
* changes found to the database. Also sends "startupcache-invalidate" signal to
* observerservice if it detects that data may have changed.
* Always called after XPIProviderUtils.js and extensions.json have been loaded.
*
* @param aManifests
* A dictionary of cached AddonInstalls for add-ons that have been
* installed
* @param aUpdateCompatibility
* true to update add-ons appDisabled property when the application
* version has changed
* @param aOldAppVersion
* The version of the application last run with this profile or null
* if it is a new profile or the version is unknown
* @param aOldPlatformVersion
* The version of the platform last run with this profile or null
* if it is a new profile or the version is unknown
* @return a boolean indicating if a change requiring flushing the caches was
* detected
*/
processFileChanges(aManifests, aUpdateCompatibility, aOldAppVersion, aOldPlatformVersion) {
let loadedManifest = (aInstallLocation, aId) => {
if (!(aInstallLocation.name in aManifests))
return null;
if (!(aId in aManifests[aInstallLocation.name]))
return null;
return aManifests[aInstallLocation.name][aId];
};
// Get the previous add-ons from the database and put them into maps by location
let previousAddons = new Map();
for (let a of XPIDatabase.getAddons()) {
let locationAddonMap = previousAddons.get(a.location);
if (!locationAddonMap) {
locationAddonMap = new Map();
previousAddons.set(a.location, locationAddonMap);
}
locationAddonMap.set(a.id, a);
}
// Build the list of current add-ons into similar maps. When add-ons are still
// present we re-use the add-on objects from the database and update their
// details directly
let currentAddons = new Map();
for (let installLocation of XPIProvider.installLocations) {
let locationAddonMap = new Map();
currentAddons.set(installLocation.name, locationAddonMap);
// Get all the on-disk XPI states for this location, and keep track of which
// ones we see in the database.
let states = XPIStates.getLocation(installLocation.name);
// Iterate through the add-ons installed the last time the application
// ran
let dbAddons = previousAddons.get(installLocation.name);
if (dbAddons) {
for (let [id, oldAddon] of dbAddons) {
// Check if the add-on is still installed
let xpiState = states && states.get(id);
if (xpiState) {
// Here the add-on was present in the database and on disk
recordAddonTelemetry(oldAddon);
// Check if the add-on has been changed outside the XPI provider
if (oldAddon.updateDate != xpiState.mtime) {
// Did time change in the wrong direction?
if (xpiState.mtime < oldAddon.updateDate) {
XPIProvider.setTelemetry(oldAddon.id, "olderFile", {
name: XPIProvider._mostRecentlyModifiedFile[id],
mtime: xpiState.mtime,
oldtime: oldAddon.updateDate
});
} else {
XPIProvider.setTelemetry(oldAddon.id, "modifiedFile",
XPIProvider._mostRecentlyModifiedFile[id]);
}
}
// The add-on has changed if the modification time has changed, or
// we have an updated manifest for it. Also reload the metadata for
// add-ons in the application directory when the application version
// has changed
let newAddon = loadedManifest(installLocation, id);
if (newAddon || oldAddon.updateDate != xpiState.mtime ||
(aUpdateCompatibility && (installLocation.name == KEY_APP_GLOBAL ||
installLocation.name == KEY_APP_SYSTEM_DEFAULTS))) {
newAddon = this.updateMetadata(installLocation, oldAddon, xpiState, newAddon);
}
else if (oldAddon.descriptor != xpiState.descriptor) {
newAddon = this.updateDescriptor(installLocation, oldAddon, xpiState);
}
else if (aUpdateCompatibility) {
newAddon = this.updateCompatibility(installLocation, oldAddon, xpiState,
aOldAppVersion, aOldPlatformVersion);
}
else {
// No change
newAddon = oldAddon;
}
if (newAddon)
locationAddonMap.set(newAddon.id, newAddon);
}
else {
// The add-on is in the DB, but not in xpiState (and thus not on disk).
this.removeMetadata(oldAddon);
}
}
}
// Any add-on in our current location that we haven't seen needs to
// be added to the database.
// Get the migration data for this install location so we can include that as
// we add, in case this is a database upgrade or rebuild.
let locMigrateData = {};
if (XPIDatabase.migrateData && installLocation.name in XPIDatabase.migrateData)
locMigrateData = XPIDatabase.migrateData[installLocation.name];
if (states) {
for (let [id, xpiState] of states) {
if (locationAddonMap.has(id))
continue;
let migrateData = id in locMigrateData ? locMigrateData[id] : null;
let newAddon = loadedManifest(installLocation, id);
let addon = this.addMetadata(installLocation, id, xpiState, newAddon,
aOldAppVersion, aOldPlatformVersion, migrateData);
if (addon)
locationAddonMap.set(addon.id, addon);
}
}
}
// previousAddons may contain locations where the database contains add-ons
// but the browser is no longer configured to use that location. The metadata
// for those add-ons must be removed from the database.
for (let [locationName, addons] of previousAddons) {
if (!currentAddons.has(locationName)) {
for (let [id, oldAddon] of addons)
this.removeMetadata(oldAddon);
}
}
// Validate the updated system add-ons
let systemAddonLocation = XPIProvider.installLocationsByName[KEY_APP_SYSTEM_ADDONS];
let addons = currentAddons.get(KEY_APP_SYSTEM_ADDONS) || new Map();
let hideLocation;
if (systemAddonLocation.isActive() && systemAddonLocation.isValid(addons)) {
// Hide the system add-on defaults
logger.info("Hiding the default system add-ons.");
hideLocation = KEY_APP_SYSTEM_DEFAULTS;
}
else {
// Hide the system add-on updates
logger.info("Hiding the updated system add-ons.");
hideLocation = KEY_APP_SYSTEM_ADDONS;
}
let previousVisible = this.getVisibleAddons(previousAddons);
let currentVisible = this.flattenByID(currentAddons, hideLocation);
let sawActiveTheme = false;
XPIProvider.bootstrappedAddons = {};
// Pass over the new set of visible add-ons, record any changes that occured
// during startup and call bootstrap install/uninstall scripts as necessary
for (let [id, currentAddon] of currentVisible) {
let previousAddon = previousVisible.get(id);
// Note if any visible add-on is not in the application install location
if (currentAddon._installLocation.name != KEY_APP_GLOBAL)
XPIProvider.allAppGlobal = false;
let isActive = !currentAddon.disabled;
let wasActive = previousAddon ? previousAddon.active : currentAddon.active
if (!previousAddon) {
// If we had a manifest for this add-on it was a staged install and
// so wasn't something recovered from a corrupt database
let wasStaged = !!loadedManifest(currentAddon._installLocation, id);
// We might be recovering from a corrupt database, if so use the
// list of known active add-ons to update the new add-on
if (!wasStaged && XPIDatabase.activeBundles) {
// For themes we know which is active by the current skin setting
if (currentAddon.type == "theme")
isActive = currentAddon.internalName == XPIProvider.currentSkin;
else
isActive = XPIDatabase.activeBundles.indexOf(currentAddon.descriptor) != -1;
// If the add-on wasn't active and it isn't already disabled in some way
// then it was probably either softDisabled or userDisabled
if (!isActive && !currentAddon.disabled) {
// If the add-on is softblocked then assume it is softDisabled
if (currentAddon.blocklistState == Blocklist.STATE_SOFTBLOCKED)
currentAddon.softDisabled = true;
else
currentAddon.userDisabled = true;
}
}
else {
// This is a new install
if (currentAddon.foreignInstall)
AddonManagerPrivate.addStartupChange(AddonManager.STARTUP_CHANGE_INSTALLED, id);
if (currentAddon.bootstrap) {
// Visible bootstrapped add-ons need to have their install method called
XPIProvider.callBootstrapMethod(currentAddon, currentAddon._sourceBundle,
"install", BOOTSTRAP_REASONS.ADDON_INSTALL);
if (!isActive)
XPIProvider.unloadBootstrapScope(currentAddon.id);
}
}
}
else {
if (previousAddon !== currentAddon) {
// This is an add-on that has changed, either the metadata was reloaded
// or the version in a different location has become visible
AddonManagerPrivate.addStartupChange(AddonManager.STARTUP_CHANGE_CHANGED, id);
let installReason = Services.vc.compare(previousAddon.version, currentAddon.version) < 0 ?
BOOTSTRAP_REASONS.ADDON_UPGRADE :
BOOTSTRAP_REASONS.ADDON_DOWNGRADE;
// If the previous add-on was in a different location, bootstrapped
// and still exists then call its uninstall method.
if (previousAddon.bootstrap && previousAddon._installLocation &&
currentAddon._installLocation != previousAddon._installLocation &&
previousAddon._sourceBundle.exists()) {
XPIProvider.callBootstrapMethod(previousAddon, previousAddon._sourceBundle,
"uninstall", installReason,
{ newVersion: currentAddon.version });
XPIProvider.unloadBootstrapScope(previousAddon.id);
}
// Make sure to flush the cache when an old add-on has gone away
flushStartupCache();
if (currentAddon.bootstrap) {
// Visible bootstrapped add-ons need to have their install method called
let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
file.persistentDescriptor = currentAddon._sourceBundle.persistentDescriptor;
XPIProvider.callBootstrapMethod(currentAddon, file,
"install", installReason,
{ oldVersion: previousAddon.version });
if (currentAddon.disabled)
XPIProvider.unloadBootstrapScope(currentAddon.id);
}
}
if (isActive != wasActive) {
let change = isActive ? AddonManager.STARTUP_CHANGE_ENABLED
: AddonManager.STARTUP_CHANGE_DISABLED;
AddonManagerPrivate.addStartupChange(change, id);
}
}
XPIDatabase.makeAddonVisible(currentAddon);
currentAddon.active = isActive;
// Make sure the bootstrap information is up to date for this ID
if (currentAddon.bootstrap && currentAddon.active) {
XPIProvider.bootstrappedAddons[id] = {
version: currentAddon.version,
type: currentAddon.type,
descriptor: currentAddon._sourceBundle.persistentDescriptor,
multiprocessCompatible: currentAddon.multiprocessCompatible
};
}
if (currentAddon.active && currentAddon.internalName == XPIProvider.selectedSkin)
sawActiveTheme = true;
}
// Pass over the set of previously visible add-ons that have now gone away
// and record the change.
for (let [id, previousAddon] of previousVisible) {
if (currentVisible.has(id))
continue;
// This add-on vanished
AddonManagerPrivate.addStartupChange(AddonManager.STARTUP_CHANGE_UNINSTALLED, id);
}
// Make sure add-ons from hidden locations are marked invisible and inactive
let locationAddonMap = currentAddons.get(hideLocation);
if (locationAddonMap) {
for (let addon of locationAddonMap.values()) {
addon.visible = false;
addon.active = false;
}
}
// None of the active add-ons match the selected theme, enable the default.
if (!sawActiveTheme) {
XPIProvider.enableDefaultTheme();
}
// Finally update XPIStates to match everything
for (let [locationName, locationAddonMap] of currentAddons) {
for (let [id, addon] of locationAddonMap) {
let xpiState = XPIStates.getAddon(locationName, id);
xpiState.syncWithDB(addon);
}
}
XPIStates.save();
XPIProvider.persistBootstrappedAddons();
// Clear out any cached migration data.
XPIDatabase.migrateData = null;
XPIDatabase.saveChanges();
return true;
},
}

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

Двоичный файл не отображается.

Двоичный файл не отображается.

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

@ -0,0 +1,18 @@
Components.utils.import("resource://gre/modules/Services.jsm");
const ID = "system1@tests.mozilla.org";
const VERSION = "1.0";
function install(data, reason) {
}
function startup(data, reason) {
Services.prefs.setCharPref("bootstraptest." + ID + ".active_version", VERSION);
}
function shutdown(data, reason) {
Services.prefs.clearUserPref("bootstraptest." + ID + ".active_version");
}
function uninstall(data, reason) {
}

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

@ -0,0 +1,23 @@
<?xml version="1.0"?>
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
<Description about="urn:mozilla:install-manifest">
<em:id>system1@tests.mozilla.org</em:id>
<em:version>1.0</em:version>
<em:bootstrap>true</em:bootstrap>
<!-- Front End MetaData -->
<em:name>System Add-on 1</em:name>
<em:targetApplication>
<Description>
<em:id>xpcshell@tests.mozilla.org</em:id>
<em:minVersion>1</em:minVersion>
<em:maxVersion>5</em:maxVersion>
</Description>
</em:targetApplication>
</Description>
</RDF>

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

@ -0,0 +1,18 @@
Components.utils.import("resource://gre/modules/Services.jsm");
const ID = "system2@tests.mozilla.org";
const VERSION = "1.0";
function install(data, reason) {
}
function startup(data, reason) {
Services.prefs.setCharPref("bootstraptest." + ID + ".active_version", VERSION);
}
function shutdown(data, reason) {
Services.prefs.clearUserPref("bootstraptest." + ID + ".active_version");
}
function uninstall(data, reason) {
}

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

@ -0,0 +1,23 @@
<?xml version="1.0"?>
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
<Description about="urn:mozilla:install-manifest">
<em:id>system2@tests.mozilla.org</em:id>
<em:version>1.0</em:version>
<em:bootstrap>true</em:bootstrap>
<!-- Front End MetaData -->
<em:name>System Add-on 2</em:name>
<em:targetApplication>
<Description>
<em:id>xpcshell@tests.mozilla.org</em:id>
<em:minVersion>1</em:minVersion>
<em:maxVersion>5</em:maxVersion>
</Description>
</em:targetApplication>
</Description>
</RDF>

Двоичный файл не отображается.

Двоичный файл не отображается.

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

@ -0,0 +1,18 @@
Components.utils.import("resource://gre/modules/Services.jsm");
const ID = "system1@tests.mozilla.org";
const VERSION = "2.0";
function install(data, reason) {
}
function startup(data, reason) {
Services.prefs.setCharPref("bootstraptest." + ID + ".active_version", VERSION);
}
function shutdown(data, reason) {
Services.prefs.clearUserPref("bootstraptest." + ID + ".active_version");
}
function uninstall(data, reason) {
}

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

@ -0,0 +1,23 @@
<?xml version="1.0"?>
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
<Description about="urn:mozilla:install-manifest">
<em:id>system1@tests.mozilla.org</em:id>
<em:version>2.0</em:version>
<em:bootstrap>true</em:bootstrap>
<!-- Front End MetaData -->
<em:name>System Add-on 1</em:name>
<em:targetApplication>
<Description>
<em:id>xpcshell@tests.mozilla.org</em:id>
<em:minVersion>1</em:minVersion>
<em:maxVersion>5</em:maxVersion>
</Description>
</em:targetApplication>
</Description>
</RDF>

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

@ -0,0 +1,18 @@
Components.utils.import("resource://gre/modules/Services.jsm");
const ID = "system3@tests.mozilla.org";
const VERSION = "1.0";
function install(data, reason) {
}
function startup(data, reason) {
Services.prefs.setCharPref("bootstraptest." + ID + ".active_version", VERSION);
}
function shutdown(data, reason) {
Services.prefs.clearUserPref("bootstraptest." + ID + ".active_version");
}
function uninstall(data, reason) {
}

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

@ -0,0 +1,23 @@
<?xml version="1.0"?>
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
<Description about="urn:mozilla:install-manifest">
<em:id>system3@tests.mozilla.org</em:id>
<em:version>1.0</em:version>
<em:bootstrap>true</em:bootstrap>
<!-- Front End MetaData -->
<em:name>System Add-on 3</em:name>
<em:targetApplication>
<Description>
<em:id>xpcshell@tests.mozilla.org</em:id>
<em:minVersion>1</em:minVersion>
<em:maxVersion>5</em:maxVersion>
</Description>
</em:targetApplication>
</Description>
</RDF>

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

@ -1026,7 +1026,7 @@ function getFileForAddon(aDir, aId) {
function registerDirectory(aKey, aDir) {
var dirProvider = {
getFile: function(aProp, aPersistent) {
aPersistent.value = true;
aPersistent.value = false;
if (aProp == aKey)
return aDir.clone();
return null;

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

@ -1067,9 +1067,8 @@ function run_test_21() {
do_check_eq(getUninstallReason(), -1);
do_check_eq(getUninstallNewVersion(), -1);
// TODO this reason should probably be ADDON_DOWNGRADE (bug 607818)
do_check_eq(getInstallReason(), ADDON_INSTALL);
do_check_eq(getInstallOldVersion(), 0);
do_check_eq(getInstallReason(), ADDON_DOWNGRADE);
do_check_eq(getInstallOldVersion(), 2);
do_check_eq(getStartupReason(), APP_STARTUP);
do_check_eq(getStartupOldVersion(), 0);

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

@ -0,0 +1,200 @@
// Tests that we reset to the default system add-ons correctly when switching
// application versions
const PREF_SYSTEM_ADDON_SET = "extensions.systemAddonSet";
const featureDir = gProfD.clone();
featureDir.append("features");
const distroDir = do_get_file("data/system_addons/app0");
registerDirectory("XREAppDist", distroDir);
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "0");
function makeUUID() {
let uuidGen = AM_Cc["@mozilla.org/uuid-generator;1"].
getService(AM_Ci.nsIUUIDGenerator);
return uuidGen.generateUUID().toString();
}
function* check_installed(inProfile, ...versions) {
let expectedDir;
if (inProfile) {
expectedDir = featureDir;
}
else {
expectedDir = distroDir.clone();
expectedDir.append("features");
}
for (let i = 0; i < versions.length; i++) {
let id = "system" + (i + 1) + "@tests.mozilla.org";
let addon = yield promiseAddonByID(id);
if (versions[i]) {
// Add-on should be installed
do_check_neq(addon, null);
do_check_eq(addon.version, versions[i]);
do_check_true(addon.isActive);
do_check_false(addon.foreignInstall);
// Verify the add-ons file is in the right place
let file = expectedDir.clone();
file.append(id + ".xpi");
do_check_true(file.exists());
do_check_true(file.isFile());
let uri = addon.getResourceURI(null);
do_check_true(uri instanceof AM_Ci.nsIFileURL);
do_check_eq(uri.file.path, file.path);
// Verify the add-on actually started
let installed = Services.prefs.getCharPref("bootstraptest." + id + ".active_version");
do_check_eq(installed, versions[i]);
}
else {
// Add-on should not be installed
do_check_eq(addon, null);
try {
Services.prefs.getCharPref("bootstraptest." + id + ".active_version");
do_throw("Expected pref to be missing");
}
catch (e) {
}
}
}
}
// Test with a missing features directory
add_task(function* test_missing_app_dir() {
startupManager();
yield check_installed(false, null, null, null);
do_check_false(featureDir.exists());
yield promiseShutdownManager();
});
// Add some features in a new version
add_task(function* test_new_version() {
gAppInfo.version = "1";
distroDir.leafName = "app1";
startupManager();
yield check_installed(false, "1.0", "1.0", null);
do_check_false(featureDir.exists());
yield promiseShutdownManager();
});
// Another new version swaps one feature and upgrades another
add_task(function* test_upgrade() {
gAppInfo.version = "2";
distroDir.leafName = "app2";
startupManager();
yield check_installed(false, "2.0", null, "1.0");
do_check_false(featureDir.exists());
yield promiseShutdownManager();
});
// Downgrade
add_task(function* test_downgrade() {
gAppInfo.version = "1";
distroDir.leafName = "app1";
startupManager();
yield check_installed(false, "1.0", "1.0", null);
do_check_false(featureDir.exists());
yield promiseShutdownManager();
});
// Fake a mid-cycle install
add_task(function* test_updated() {
// Create a random dir to install into
let dirname = makeUUID();
FileUtils.getDir("ProfD", ["features", dirname], true);
featureDir.append(dirname);
// Copy in the system add-ons
let file = do_get_file("data/system_addons/app1/features/system2@tests.mozilla.org.xpi");
file.copyTo(featureDir, file.leafName);
file = do_get_file("data/system_addons/app2/features/system3@tests.mozilla.org.xpi");
file.copyTo(featureDir, file.leafName);
// Inject it into the system set
let addonSet = {
schema: 1,
directory: dirname,
addons: {
"system2@tests.mozilla.org": {
version: "1.0"
},
"system3@tests.mozilla.org": {
version: "1.0"
},
}
};
Services.prefs.setCharPref(PREF_SYSTEM_ADDON_SET, JSON.stringify(addonSet));
startupManager(false);
yield check_installed(true, null, "1.0", "1.0");
yield promiseShutdownManager();
});
// An additional add-on in the directory should be ignored
add_task(function* test_skips_additional() {
// Copy in the system add-ons
let file = do_get_file("data/system_addons/app1/features/system1@tests.mozilla.org.xpi");
file.copyTo(featureDir, file.leafName);
startupManager(false);
yield check_installed(true, null, "1.0", "1.0");
yield promiseShutdownManager();
});
// Missing add-on should revert to the default set
add_task(function* test_revert() {
manuallyUninstall(featureDir, "system2@tests.mozilla.org");
startupManager(false);
// With system add-on 2 gone the updated set is now invalid so it reverts to
// the default set which is system add-ons 1 and 2.
yield check_installed(false, "1.0", "1.0", null);
yield promiseShutdownManager();
});
// Putting it back will make the set work again
add_task(function* test_reuse() {
let file = do_get_file("data/system_addons/app1/features/system2@tests.mozilla.org.xpi");
file.copyTo(featureDir, file.leafName);
startupManager(false);
yield check_installed(true, null, "1.0", "1.0");
yield promiseShutdownManager();
});
// Making the pref corrupt should revert to the default set
add_task(function* test_corrupt_pref() {
Services.prefs.setCharPref(PREF_SYSTEM_ADDON_SET, "foo");
startupManager(false);
yield check_installed(false, "1.0", "1.0", null);
yield promiseShutdownManager();
});

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

@ -24,6 +24,7 @@ skip-if = appname != "firefox"
[test_provider_unsafe_access_shutdown.js]
[test_provider_unsafe_access_startup.js]
[test_shutdown.js]
[test_system_reset.js]
[test_XPIcancel.js]
[test_XPIStates.js]