Merge mozilla-central to mozilla-inbound

This commit is contained in:
Carsten "Tomcat" Book 2015-09-24 12:06:06 +02:00
Родитель 4fe48de950 2376775adf
Коммит be2a184fb0
109 изменённых файлов: 2488 добавлений и 1575 удалений

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

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="8d83715f08b7849f16a0dfc88f78d5c3a89c0a54">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="8472f0c736660072799aaae60e4b6001a6aaceb4"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="4bb17b24620818cbda0ba0c0d69e0ce3f914e1b7"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="9465d16f95ab87636b2ae07538ee88e5aeff2d7d"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

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

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="8d83715f08b7849f16a0dfc88f78d5c3a89c0a54">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="8472f0c736660072799aaae60e4b6001a6aaceb4"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="4bb17b24620818cbda0ba0c0d69e0ce3f914e1b7"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="9465d16f95ab87636b2ae07538ee88e5aeff2d7d"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

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

@ -19,7 +19,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="8472f0c736660072799aaae60e4b6001a6aaceb4"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="4bb17b24620818cbda0ba0c0d69e0ce3f914e1b7"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="9465d16f95ab87636b2ae07538ee88e5aeff2d7d"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="27eb2f04e149fc2c9976d881b1b5984bbe7ee089"/>

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

@ -17,7 +17,7 @@
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="8472f0c736660072799aaae60e4b6001a6aaceb4"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="4bb17b24620818cbda0ba0c0d69e0ce3f914e1b7"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="9465d16f95ab87636b2ae07538ee88e5aeff2d7d"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="828317e64d28138f24d578ab340c2a0ff8552df0"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="f004530b30a63c08a16d82536858600446b2abf5"/>

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

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="8d83715f08b7849f16a0dfc88f78d5c3a89c0a54">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="8472f0c736660072799aaae60e4b6001a6aaceb4"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="4bb17b24620818cbda0ba0c0d69e0ce3f914e1b7"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="9465d16f95ab87636b2ae07538ee88e5aeff2d7d"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

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

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="c9d4fe680662ee44a4bdea42ae00366f5df399cf">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="8472f0c736660072799aaae60e4b6001a6aaceb4"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="4bb17b24620818cbda0ba0c0d69e0ce3f914e1b7"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="9465d16f95ab87636b2ae07538ee88e5aeff2d7d"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

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

@ -19,7 +19,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="8472f0c736660072799aaae60e4b6001a6aaceb4"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="4bb17b24620818cbda0ba0c0d69e0ce3f914e1b7"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="9465d16f95ab87636b2ae07538ee88e5aeff2d7d"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="27eb2f04e149fc2c9976d881b1b5984bbe7ee089"/>

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

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="8d83715f08b7849f16a0dfc88f78d5c3a89c0a54">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="8472f0c736660072799aaae60e4b6001a6aaceb4"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="4bb17b24620818cbda0ba0c0d69e0ce3f914e1b7"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="9465d16f95ab87636b2ae07538ee88e5aeff2d7d"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

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

@ -1,9 +1,9 @@
{
"git": {
"git_revision": "8472f0c736660072799aaae60e4b6001a6aaceb4",
"git_revision": "4bb17b24620818cbda0ba0c0d69e0ce3f914e1b7",
"remote": "https://git.mozilla.org/releases/gaia.git",
"branch": ""
},
"revision": "e4b5ba76d5a4de0cd220310e0fe2ba334f0e250a",
"revision": "0bdd0b54cb40d7e928e9e6de720c0506dc7e52db",
"repo_path": "integration/gaia-central"
}

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

@ -17,7 +17,7 @@
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="8472f0c736660072799aaae60e4b6001a6aaceb4"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="4bb17b24620818cbda0ba0c0d69e0ce3f914e1b7"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="9465d16f95ab87636b2ae07538ee88e5aeff2d7d"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="828317e64d28138f24d578ab340c2a0ff8552df0"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="f004530b30a63c08a16d82536858600446b2abf5"/>

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

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="c9d4fe680662ee44a4bdea42ae00366f5df399cf">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="8472f0c736660072799aaae60e4b6001a6aaceb4"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="4bb17b24620818cbda0ba0c0d69e0ce3f914e1b7"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="9465d16f95ab87636b2ae07538ee88e5aeff2d7d"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

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

@ -1367,8 +1367,6 @@ pref("devtools.command-button-rulers.enabled", false);
pref("devtools.inspector.enabled", true);
// What was the last active sidebar in the inspector
pref("devtools.inspector.activeSidebar", "ruleview");
// Enable the markup preview
pref("devtools.inspector.markupPreview", false);
pref("devtools.inspector.remote", false);
// Collapse pseudo-elements by default in the rule-view
pref("devtools.inspector.show_pseudo_elements", false);

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

@ -72,7 +72,7 @@ function init(aEvent)
let defaults = Services.prefs.getDefaultBranch("");
let channelLabel = document.getElementById("currentChannel");
let currentChannelText = document.getElementById("currentChannelText");
channelLabel.value = UpdateChannel.get();
channelLabel.value = UpdateUtils.UpdateChannel;
if (/^release($|\-)/.test(channelLabel.value))
currentChannelText.hidden = true;
#endif
@ -89,8 +89,8 @@ Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
Components.utils.import("resource://gre/modules/DownloadUtils.jsm");
Components.utils.import("resource://gre/modules/AddonManager.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "UpdateChannel",
"resource://gre/modules/UpdateChannel.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "UpdateUtils",
"resource://gre/modules/UpdateUtils.jsm");
var gAppUpdater;

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

@ -167,5 +167,17 @@ var FeedHandler = {
clearTimeout(this._updateFeedTimeout);
this._updateFeedTimeout = setTimeout(this.updateFeeds.bind(this), 100);
}
}
},
init() {
window.messageManager.addMessageListener("FeedWriter:ShownFirstRun", this);
},
receiveMessage(msg) {
switch (msg.name) {
case "FeedWriter:ShownFirstRun":
Services.prefs.setBoolPref("browser.feeds.showFirstRunUI", false);
break;
}
},
};

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

@ -42,8 +42,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "Log",
"resource://gre/modules/Log.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "AppConstants",
"resource://gre/modules/AppConstants.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "UpdateChannel",
"resource://gre/modules/UpdateChannel.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "UpdateUtils",
"resource://gre/modules/UpdateUtils.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "Favicons",
"@mozilla.org/browser/favicon-service;1",
"mozIAsyncFavicons");
@ -965,6 +965,7 @@ var gBrowserInit = {
gPageStyleMenu.init();
LanguageDetectionListener.init();
BrowserOnClick.init();
FeedHandler.init();
DevEdition.init();
AboutPrivateBrowsingListener.init();
TrackingProtection.init();
@ -2918,7 +2919,7 @@ var BrowserOnClick = {
version: 1,
build: gAppInfo.appBuildID,
product: gAppInfo.name,
channel: UpdateChannel.get()
channel: UpdateUtils.UpdateChannel
}
let reportURL = Services.prefs.getCharPref("security.ssl.errorReporting.url");

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

@ -18,8 +18,6 @@ XPCOMUtils.defineLazyModuleGetter(this, "Rect",
"resource://gre/modules/Geometry.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
"resource://gre/modules/PrivateBrowsingUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "UpdateChannel",
"resource://gre/modules/UpdateChannel.jsm");
var {
links: gLinks,

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

@ -60,7 +60,7 @@ add_task(function*() {
let updateChannel = null;
try {
updateChannel = Cu.import("resource://gre/modules/UpdateChannel.jsm", {}).UpdateChannel.get();
updateChannel = Cu.import("resource://gre/modules/UpdateUtils.jsm", {}).UpdateUtils.UpdateChannel;
} catch (ex) {}
if (!updateChannel) {
Assert.ok(!('updateChannel' in got.message.application),

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

@ -9,6 +9,7 @@ const Cr = Components.results;
const Cu = Components.utils;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
const FEEDWRITER_CID = Components.ID("{49bb6593-3aff-4eb3-a068-2712c28bd58e}");
const FEEDWRITER_CONTRACTID = "@mozilla.org/browser/feeds/result-writer;1";
@ -713,9 +714,7 @@ FeedWriter.prototype = {
if (checkbox) {
var alwaysUse = false;
try {
var prefs = Cc["@mozilla.org/preferences-service;1"].
getService(Ci.nsIPrefBranch);
if (prefs.getCharPref(getPrefActionForType(feedType)) != "ask")
if (Services.prefs.getCharPref(getPrefActionForType(feedType)) != "ask")
alwaysUse = true;
}
catch(ex) { }
@ -803,10 +802,7 @@ FeedWriter.prototype = {
},
_setSelectedHandler: function FW__setSelectedHandler(feedType) {
var prefs =
Cc["@mozilla.org/preferences-service;1"].
getService(Ci.nsIPrefBranch);
var prefs = Services.prefs;
var handler = "bookmarks";
try {
handler = prefs.getCharPref(getPrefReaderForType(feedType));
@ -899,10 +895,8 @@ FeedWriter.prototype = {
menuItem.className = "menuitem-iconic selectedAppMenuItem";
menuItem.setAttribute("handlerType", "client");
try {
var prefs = Cc["@mozilla.org/preferences-service;1"].
getService(Ci.nsIPrefBranch);
this._selectedApp = prefs.getComplexValue(getPrefAppForType(feedType),
Ci.nsILocalFile);
this._selectedApp = Services.prefs.getComplexValue(getPrefAppForType(feedType),
Ci.nsILocalFile);
if (this._selectedApp.exists())
this._initMenuItemWithFile(menuItem, this._selectedApp);
@ -958,25 +952,29 @@ FeedWriter.prototype = {
var chooseAppSep = liveBookmarksMenuItem.nextSibling.cloneNode(false);
handlersMenuPopup.appendChild(chooseAppSep);
// List of web handlers
var wccr = Cc["@mozilla.org/embeddor.implemented/web-content-handler-registrar;1"].
getService(Ci.nsIWebContentConverterService);
var handlers = wccr.getContentHandlers(this._getMimeTypeForFeedType(feedType));
if (handlers.length != 0) {
for (var i = 0; i < handlers.length; ++i) {
if (!handlers[i].uri) {
LOG("Handler with name " + handlers[i].name + " has no URI!? Skipping...");
continue;
}
menuItem = liveBookmarksMenuItem.cloneNode(false);
menuItem.removeAttribute("selected");
menuItem.className = "menuitem-iconic";
menuItem.setAttribute("label", handlers[i].name);
menuItem.setAttribute("handlerType", "web");
menuItem.setAttribute("webhandlerurl", handlers[i].uri);
handlersMenuPopup.appendChild(menuItem);
// FIXME: getting a list of webhandlers doesn't work in the content process
// right now, see bug 1109714.
if (Services.appinfo.processType != Services.appinfo.PROCESS_TYPE_CONTENT) {
// List of web handlers
var wccr = Cc["@mozilla.org/embeddor.implemented/web-content-handler-registrar;1"].
getService(Ci.nsIWebContentConverterService);
var handlers = wccr.getContentHandlers(this._getMimeTypeForFeedType(feedType));
if (handlers.length != 0) {
for (var i = 0; i < handlers.length; ++i) {
if (!handlers[i].uri) {
LOG("Handler with name " + handlers[i].name + " has no URI!? Skipping...");
continue;
}
menuItem = liveBookmarksMenuItem.cloneNode(false);
menuItem.removeAttribute("selected");
menuItem.className = "menuitem-iconic";
menuItem.setAttribute("label", handlers[i].name);
menuItem.setAttribute("handlerType", "web");
menuItem.setAttribute("webhandlerurl", handlers[i].uri);
handlersMenuPopup.appendChild(menuItem);
this._setFaviconForWebReader(handlers[i].uri, menuItem);
this._setFaviconForWebReader(handlers[i].uri, menuItem);
}
}
}
@ -1000,7 +998,7 @@ FeedWriter.prototype = {
// first-run ui
var showFirstRunUI = true;
try {
showFirstRunUI = prefs.getBoolPref(PREF_SHOW_FIRST_RUN_UI);
showFirstRunUI = Services.prefs.getBoolPref(PREF_SHOW_FIRST_RUN_UI);
}
catch (ex) { }
if (showFirstRunUI) {
@ -1029,7 +1027,7 @@ FeedWriter.prototype = {
header.setAttribute('firstrun', 'true');
prefs.setBoolPref(PREF_SHOW_FIRST_RUN_UI, false);
this._mm.sendAsyncMessage("FeedWriter:ShownFirstRun");
}
},
@ -1090,8 +1088,7 @@ FeedWriter.prototype = {
// Set up the subscription UI
this._initSubscriptionUI();
var prefs = Cc["@mozilla.org/preferences-service;1"].
getService(Ci.nsIPrefBranch);
let prefs = Services.prefs;
prefs.addObserver(PREF_SELECTED_ACTION, this, false);
prefs.addObserver(PREF_SELECTED_READER, this, false);
prefs.addObserver(PREF_SELECTED_WEB, this, false);
@ -1133,8 +1130,7 @@ FeedWriter.prototype = {
.removeEventListener("command", this, false);
this._document = null;
this._window = null;
var prefs = Cc["@mozilla.org/preferences-service;1"].
getService(Ci.nsIPrefBranch);
let prefs = Services.prefs;
prefs.removeObserver(PREF_SELECTED_ACTION, this);
prefs.removeObserver(PREF_SELECTED_READER, this);
prefs.removeObserver(PREF_SELECTED_WEB, this);
@ -1172,8 +1168,7 @@ FeedWriter.prototype = {
var feedType = this._getFeedType();
// Subscribe to the feed using the selected handler and save prefs
var prefs = Cc["@mozilla.org/preferences-service;1"].
getService(Ci.nsIPrefBranch);
var prefs = Services.prefs;
var defaultHandler = "reader";
var useAsDefault = this._getUIElement("alwaysUse").getAttribute("checked");
@ -1320,6 +1315,15 @@ FeedWriter.prototype = {
});
},
get _mm() {
let mm = this._window.QueryInterface(Ci.nsIInterfaceRequestor).
getInterface(Ci.nsIDocShell).
QueryInterface(Ci.nsIInterfaceRequestor).
getInterface(Ci.nsIContentFrameMessageManager);
delete this._mm;
return this._mm = mm;
},
classID: FEEDWRITER_CID,
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMEventListener, Ci.nsIObserver,
Ci.nsINavHistoryObserver,

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

@ -10,9 +10,6 @@ support-files =
valid-unsniffable-feed.xml
[test_bug436801.html]
skip-if = e10s
[test_bug494328.html]
skip-if = e10s
[test_bug589543.html]
skip-if = e10s
[test_registerHandler.html]

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

@ -25,8 +25,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "PageMetadata",
"resource://gre/modules/PageMetadata.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PluralForm",
"resource://gre/modules/PluralForm.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "UpdateChannel",
"resource://gre/modules/UpdateChannel.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "UpdateUtils",
"resource://gre/modules/UpdateUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "UITour",
"resource:///modules/UITour.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Social",
@ -810,7 +810,7 @@ function injectLoopAPI(targetWindow) {
// which doesn't have what we need, so log an error.
try {
appVersionInfo = Cu.cloneInto({
channel: UpdateChannel.get(),
channel: UpdateUtils.UpdateChannel,
version: appInfo.version,
OS: appInfo.OS
}, targetWindow);

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

@ -124,8 +124,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "ContentSearch",
"resource:///modules/ContentSearch.jsm");
#ifdef E10S_TESTING_ONLY
XPCOMUtils.defineLazyModuleGetter(this, "UpdateChannel",
"resource://gre/modules/UpdateChannel.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "UpdateUtils",
"resource://gre/modules/UpdateUtils.jsm");
#endif
#ifdef MOZ_CRASHREPORTER
@ -2977,7 +2977,7 @@ var E10SUINotification = {
checkStatus: function() {
let skipE10sChecks = false;
try {
let updateChannel = UpdateChannel.get();
let updateChannel = UpdateUtils.UpdateChannel;
let channelAuthorized = updateChannel == "nightly" || updateChannel == "aurora";
skipE10sChecks = !channelAuthorized ||

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

@ -165,8 +165,8 @@ var gMainPane = {
}
let tmp = {};
Components.utils.import("resource://gre/modules/UpdateChannel.jsm", tmp);
if (!e10sCheckbox.checked && tmp.UpdateChannel.get() != "default") {
Components.utils.import("resource://gre/modules/UpdateUtils.jsm", tmp);
if (!e10sCheckbox.checked && tmp.UpdateUtils.UpdateChannel != "default") {
Services.prefs.setBoolPref("browser.requestE10sFeedback", true);
Services.prompt.alert(window, brandName, bundle.getString("e10sFeedbackAfterRestart"));
}

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

@ -20,8 +20,8 @@ Cu.import("resource://gre/modules/Log.jsm");
Cu.import("resource://gre/modules/Preferences.jsm");
Cu.import("resource://gre/modules/AsyncShutdown.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "UpdateChannel",
"resource://gre/modules/UpdateChannel.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "UpdateUtils",
"resource://gre/modules/UpdateUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "AddonManager",
"resource://gre/modules/AddonManager.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "AddonManagerPrivate",
@ -275,7 +275,7 @@ Experiments.Policy.prototype = {
},
updatechannel: function () {
return UpdateChannel.get();
return UpdateUtils.UpdateChannel;
},
locale: function () {

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

@ -26,8 +26,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "OS",
"resource://gre/modules/osfile.jsm")
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
"resource://gre/modules/Promise.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "UpdateChannel",
"resource://gre/modules/UpdateChannel.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "UpdateUtils",
"resource://gre/modules/UpdateUtils.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "eTLD",
"@mozilla.org/network/effective-tld-service;1",
"nsIEffectiveTLDService");
@ -280,7 +280,7 @@ var DirectoryLinksProvider = {
_fetchAndCacheLinks: function DirectoryLinksProvider_fetchAndCacheLinks(uri) {
// Replace with the same display locale used for selecting links data
uri = uri.replace("%LOCALE%", this.locale);
uri = uri.replace("%CHANNEL%", UpdateChannel.get());
uri = uri.replace("%CHANNEL%", UpdateUtils.UpdateChannel);
return this._downloadJsonData(uri).then(json => {
return OS.File.writeAtomic(this._directoryFilePath, json, {tmpPath: this._directoryFilePath + ".tmp"});

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

@ -98,6 +98,12 @@
}
}
@media not all and (-moz-windows-default-theme) {
#main-window {
background-color: transparent;
}
}
#titlebar-buttonbox,
.titlebar-button {
-moz-appearance: none !important;

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

@ -349,18 +349,13 @@
background-image: linear-gradient(@toolbarHighlight@, transparent);
}
@media (-moz-os-version: windows-xp),
(-moz-os-version: windows-vista),
(-moz-os-version: windows-win7),
(-moz-os-version: windows-win8) {
#nav-bar {
border-top: 1px solid @toolbarShadowColor@ !important;
box-shadow: 0 1px 0 @toolbarHighlight@ inset;
}
@media not all and (-moz-windows-compositor) {
#TabsToolbar[collapsed="true"] + #nav-bar {
border-top-style: none !important;
}
#nav-bar {
border-top: 1px solid @toolbarShadowColor@ !important;
box-shadow: 0 1px 0 @toolbarHighlight@ inset;
}
@media not all and (-moz-windows-compositor) {
#TabsToolbar[collapsed="true"] + #nav-bar {
border-top-style: none !important;
}
}
@ -2005,17 +2000,24 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-
@media not all and (-moz-os-version: windows-vista) {
@media not all and (-moz-os-version: windows-win7) {
@media not all and (-moz-os-version: windows-win8) {
.tab-background-end[visuallyselected=true]::after,
.tab-background-start[visuallyselected=true]::after {
content: none;
}
@media (-moz-windows-default-theme) {
.tab-background-end[visuallyselected=true]::after,
.tab-background-start[visuallyselected=true]::after {
content: none;
}
#TabsToolbar {
--tab-stroke-background-size: 0 0;
}
#TabsToolbar {
--tab-stroke-background-size: 0 0;
}
:root {
--tab-toolbar-navbar-overlap: 0;
:root {
--tab-toolbar-navbar-overlap: 0;
}
#nav-bar {
border-top-style: none !important;
box-shadow: none;
}
}
}
}

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

@ -223,7 +223,9 @@ menu.subviewbutton > .menu-right:-moz-locale-dir(rtl) {
}
#BMB_bookmarksPopup menupopup[placespopup=true] > hbox {
box-shadow: none;
/* After fixing of bug 1194480 the box-shadow can be removed again */
/* box-shadow: none; */
box-shadow: 0 0 4px rgba(0,0,0,0.02);
background: -moz-field;
border: 1px solid ThreeDShadow;
}

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

@ -8,7 +8,6 @@ const {Cc, Cu, Ci} = require("chrome");
// Page size for pageup/pagedown
const PAGE_SIZE = 10;
const PREVIEW_AREA = 700;
const DEFAULT_MAX_CHILDREN = 100;
const COLLAPSE_ATTRIBUTE_LENGTH = 120;
const COLLAPSE_DATA_URL_REGEX = /^data.+base64/;
@ -122,7 +121,6 @@ function MarkupView(aInspector, aFrame, aControllerWindow) {
this._makeTooltipPersistent = this._makeTooltipPersistent.bind(this);
this._initPreview();
this._initTooltips();
this._initHighlighter();
@ -647,6 +645,11 @@ MarkupView.prototype = {
this.beginEditingOuterHTML(this._selectedContainer.node);
break;
}
case Ci.nsIDOMKeyEvent.DOM_VK_S: {
let selection = this._selectedContainer.node;
this._inspector.scrollNodeIntoView(selection);
break;
}
case Ci.nsIDOMKeyEvent.DOM_VK_ESCAPE: {
if (this.isDragging) {
this.cancelDragging();
@ -1571,92 +1574,6 @@ MarkupView.prototype = {
return this._destroyer;
},
/**
* Initialize the preview panel.
*/
_initPreview: function() {
this._previewEnabled = Services.prefs.getBoolPref("devtools.inspector.markupPreview");
if (!this._previewEnabled) {
return;
}
this._previewBar = this.doc.querySelector("#previewbar");
this._preview = this.doc.querySelector("#preview");
this._viewbox = this.doc.querySelector("#viewbox");
this._previewBar.classList.remove("disabled");
this._previewWidth = this._preview.getBoundingClientRect().width;
this._boundResizePreview = this._resizePreview.bind(this);
this._frame.contentWindow.addEventListener("resize",
this._boundResizePreview, true);
this._frame.contentWindow.addEventListener("overflow",
this._boundResizePreview, true);
this._frame.contentWindow.addEventListener("underflow",
this._boundResizePreview, true);
this._boundUpdatePreview = this._updatePreview.bind(this);
this._frame.contentWindow.addEventListener("scroll",
this._boundUpdatePreview, true);
this._updatePreview();
},
/**
* Move the preview viewbox.
*/
_updatePreview: function() {
if (!this._previewEnabled) {
return;
}
let win = this._frame.contentWindow;
if (win.scrollMaxY == 0) {
this._previewBar.classList.add("disabled");
return;
}
this._previewBar.classList.remove("disabled");
let ratio = this._previewWidth / PREVIEW_AREA;
let width = ratio * win.innerWidth;
let height = ratio * (win.scrollMaxY + win.innerHeight);
let scrollTo
if (height >= win.innerHeight) {
scrollTo = -(height - win.innerHeight) * (win.scrollY / win.scrollMaxY);
this._previewBar.setAttribute("style", "height:" + height +
"px;transform:translateY(" + scrollTo + "px)");
} else {
this._previewBar.setAttribute("style", "height:100%");
}
let bgSize = ~~width + "px " + ~~height + "px";
this._preview.setAttribute("style", "background-size:" + bgSize);
height = ~~(win.innerHeight * ratio) + "px";
let top = ~~(win.scrollY * ratio) + "px";
this._viewbox.setAttribute("style", "height:" + height +
";transform: translateY(" + top + ")");
},
/**
* Hide the preview while resizing, to avoid slowness.
*/
_resizePreview: function() {
if (!this._previewEnabled) {
return;
}
let win = this._frame.contentWindow;
this._previewBar.classList.add("hide");
clearTimeout(this._resizePreviewTimeout);
setTimeout(() => {
this._updatePreview();
this._previewBar.classList.remove("hide");
}, 1000);
},
/**
* Takes an element as it's only argument and marks the element
* as the drop target

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

@ -97,9 +97,5 @@
--></span>
</div>
<div id="previewbar" class="disabled">
<div id="preview"/>
<div id="viewbox"/>
</div>
</body>
</html>

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

@ -190,6 +190,15 @@ StyleSheetEditor.prototype = {
return this._friendlyName;
},
/**
* Check if transitions are enabled for style changes.
*
* @return Boolean
*/
get transitionsEnabled() {
return Services.prefs.getBoolPref(TRANSITION_PREF);
},
/**
* If this is an original source, get the path of the CSS file it generated.
*/
@ -495,9 +504,7 @@ StyleSheetEditor.prototype = {
this._state.text = this.sourceEditor.getText();
}
let transitionsEnabled = Services.prefs.getBoolPref(TRANSITION_PREF);
this.styleSheet.update(this._state.text, transitionsEnabled)
this.styleSheet.update(this._state.text, this.transitionsEnabled)
.then(null, Cu.reportError);
},
@ -683,7 +690,7 @@ StyleSheetEditor.prototype = {
let text = decoder.decode(array);
let relatedSheet = this.styleSheet.relatedStyleSheet;
relatedSheet.update(text, true);
relatedSheet.update(text, this.transitionsEnabled);
}, this.markLinkedFileBroken);
},

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

@ -52,49 +52,6 @@
padding-left: 2px;
}
/* Preview */
#previewbar {
position: fixed;
top: 0;
right: 0;
width: 90px;
background: black;
border-left: 1px solid;
border-bottom: 1px solid;
overflow: hidden;
}
#previewbar {
background: var(--theme-tab-toolbar-background);
border-color: var(--theme-splitter-color);
}
#preview {
position: absolute;
top: 0;
right: 5px;
width: 80px;
height: 100%;
background-image: -moz-element(#root);
background-repeat: no-repeat;
}
#previewbar.hide,
#previewbar.disabled {
display: none;
}
#viewbox {
position: absolute;
top: 0;
right: 5px;
width: 80px;
border: 1px dashed #888;
background: rgba(205,205,255,0.2);
outline: 1px solid transparent;
}
/* Events */
.markupview-events {
font-size: 8px;

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

@ -80,8 +80,8 @@ nsresult
AccessibleCaretManager::OnSelectionChanged(nsIDOMDocument* aDoc,
nsISelection* aSel, int16_t aReason)
{
AC_LOG("aSel: %p, GetSelection(): %p, aReason: %d", aSel, GetSelection(),
aReason);
AC_LOG("%s: aSel: %p, GetSelection(): %p, aReason: %d", __FUNCTION__,
aSel, GetSelection(), aReason);
if (aSel != GetSelection()) {
return NS_OK;
@ -99,6 +99,13 @@ AccessibleCaretManager::OnSelectionChanged(nsIDOMDocument* aDoc,
return NS_OK;
}
// OnBlur() might be called between mouse down and mouse up, so we hide carets
// upon mouse down anyway, and update carets upon mouse up.
if (aReason & nsISelectionListener::MOUSEDOWN_REASON) {
HideCarets();
return NS_OK;
}
// Range will collapse after cutting or copying text.
if (aReason & (nsISelectionListener::COLLAPSETOSTART_REASON |
nsISelectionListener::COLLAPSETOEND_REASON)) {
@ -472,8 +479,10 @@ AccessibleCaretManager::OnScrollPositionChanged()
return;
}
AC_LOG("%s: UpdateCarets(RespectOldAppearance)", __FUNCTION__);
UpdateCarets(UpdateCaretsHint::RespectOldAppearance);
if (mFirstCaret->IsLogicallyVisible() || mSecondCaret->IsLogicallyVisible()) {
AC_LOG("%s: UpdateCarets(RespectOldAppearance)", __FUNCTION__);
UpdateCarets(UpdateCaretsHint::RespectOldAppearance);
}
}
void
@ -483,9 +492,9 @@ AccessibleCaretManager::OnReflow()
return;
}
if (mFirstCaret->IsVisuallyVisible() || mSecondCaret->IsVisuallyVisible()) {
AC_LOG("%s: UpdateCarets()", __FUNCTION__);
UpdateCarets();
if (mFirstCaret->IsLogicallyVisible() || mSecondCaret->IsLogicallyVisible()) {
AC_LOG("%s: UpdateCarets(RespectOldAppearance)", __FUNCTION__);
UpdateCarets(UpdateCaretsHint::RespectOldAppearance);
}
}

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

@ -65,11 +65,6 @@ public:
mSecondCaret = MakeUnique<MockAccessibleCaret>();
}
CaretMode LastUpdateCaretMode() const
{
return mLastUpdateCaretMode;
}
MockAccessibleCaret& FirstCaret()
{
return static_cast<MockAccessibleCaret&>(*mFirstCaret);
@ -117,13 +112,14 @@ public:
.WillRepeatedly(Return(PositionChangedResult::Changed));
}
void CheckStates(CaretMode aCaretMode,
Appearance aFirstCaretAppearance,
Appearance aSecondCaretAppearance)
AccessibleCaret::Appearance FirstCaretAppearance()
{
EXPECT_EQ(mManager.LastUpdateCaretMode(), aCaretMode);
EXPECT_EQ(mManager.FirstCaret().GetAppearance(), aFirstCaretAppearance);
EXPECT_EQ(mManager.SecondCaret().GetAppearance(), aSecondCaretAppearance);
return mManager.FirstCaret().GetAppearance();
}
AccessibleCaret::Appearance SecondCaretAppearance()
{
return mManager.SecondCaret().GetAppearance();
}
// Member variables
@ -140,16 +136,19 @@ TEST_F(AccessibleCaretManagerTester, TestUpdatesInSelectionMode)
CaretChangedReason::Updateposition)).Times(3);
mManager.UpdateCarets();
CheckStates(CaretMode::Selection, Appearance::Normal, Appearance::Normal);
EXPECT_EQ(FirstCaretAppearance(), Appearance::Normal);
EXPECT_EQ(SecondCaretAppearance(), Appearance::Normal);
mManager.OnReflow();
CheckStates(CaretMode::Selection, Appearance::Normal, Appearance::Normal);
EXPECT_EQ(FirstCaretAppearance(), Appearance::Normal);
EXPECT_EQ(SecondCaretAppearance(), Appearance::Normal);
mManager.OnScrollPositionChanged();
CheckStates(CaretMode::Selection, Appearance::Normal, Appearance::Normal);
EXPECT_EQ(FirstCaretAppearance(), Appearance::Normal);
EXPECT_EQ(SecondCaretAppearance(), Appearance::Normal);
}
TEST_F(AccessibleCaretManagerTester, TestUpdatesInCursorModeOnNonEmptyContent)
TEST_F(AccessibleCaretManagerTester, TestSingleTapOnNonEmptyInput)
{
EXPECT_CALL(mManager, GetCaretMode())
.WillRepeatedly(Return(CaretMode::Cursor));
@ -163,46 +162,172 @@ TEST_F(AccessibleCaretManagerTester, TestUpdatesInCursorModeOnNonEmptyContent)
EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
CaretChangedReason::Updateposition)).Times(1);
EXPECT_CALL(check, Call("mouse down"));
EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
CaretChangedReason::Updateposition)).Times(1);
EXPECT_CALL(check, Call("reflow"));
EXPECT_CALL(check, Call("update"));
EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
CaretChangedReason::Visibilitychange)).Times(1);
EXPECT_CALL(check, Call("mouse down"));
EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(_)).Times(0);
EXPECT_CALL(check, Call("reflow"));
EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(_)).Times(0);
EXPECT_CALL(check, Call("blur"));
EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
CaretChangedReason::Updateposition)).Times(1);
EXPECT_CALL(check, Call("mouse up"));
EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
CaretChangedReason::Updateposition)).Times(1);
EXPECT_CALL(check, Call("reflow2"));
EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
CaretChangedReason::Updateposition)).Times(1);
}
// Simulate a single tap on a non-empty input.
mManager.UpdateCarets();
EXPECT_EQ(FirstCaretAppearance(), Appearance::Normal);
check.Call("update");
mManager.OnSelectionChanged(nullptr, nullptr,
nsISelectionListener::DRAG_REASON |
nsISelectionListener::MOUSEDOWN_REASON);
CheckStates(CaretMode::Cursor, Appearance::Normal, Appearance::None);
EXPECT_EQ(FirstCaretAppearance(), Appearance::None);
check.Call("mouse down");
mManager.OnReflow();
CheckStates(CaretMode::Cursor, Appearance::Normal, Appearance::None);
EXPECT_EQ(FirstCaretAppearance(), Appearance::None);
check.Call("reflow");
mManager.OnBlur();
CheckStates(CaretMode::Cursor, Appearance::None, Appearance::None);
EXPECT_EQ(FirstCaretAppearance(), Appearance::None);
check.Call("blur");
mManager.OnSelectionChanged(nullptr, nullptr,
nsISelectionListener::MOUSEUP_REASON);
CheckStates(CaretMode::Cursor, Appearance::Normal, Appearance::None);
EXPECT_EQ(FirstCaretAppearance(), Appearance::Normal);
check.Call("mouse up");
mManager.OnReflow();
EXPECT_EQ(FirstCaretAppearance(), Appearance::Normal);
check.Call("reflow2");
mManager.OnScrollPositionChanged();
CheckStates(CaretMode::Cursor, Appearance::Normal, Appearance::None);
EXPECT_EQ(FirstCaretAppearance(), Appearance::Normal);
}
TEST_F(AccessibleCaretManagerTester, TestSingleTapOnEmptyInput)
{
EXPECT_CALL(mManager, GetCaretMode())
.WillRepeatedly(Return(CaretMode::Cursor));
EXPECT_CALL(mManager, HasNonEmptyTextContent(_))
.WillRepeatedly(Return(false));
MockFunction<void(std::string aCheckPointName)> check;
{
InSequence dummy;
EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
CaretChangedReason::Updateposition)).Times(1);
EXPECT_CALL(check, Call("update"));
EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
CaretChangedReason::Visibilitychange)).Times(1);
EXPECT_CALL(check, Call("mouse down"));
EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(_)).Times(0);
EXPECT_CALL(check, Call("reflow"));
EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(_)).Times(0);
EXPECT_CALL(check, Call("blur"));
EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
CaretChangedReason::Updateposition)).Times(1);
EXPECT_CALL(check, Call("mouse up"));
EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
CaretChangedReason::Updateposition)).Times(1);
EXPECT_CALL(check, Call("reflow2"));
EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
CaretChangedReason::Updateposition)).Times(1);
}
// Simulate a single tap on an empty input.
mManager.UpdateCarets();
EXPECT_EQ(FirstCaretAppearance(), Appearance::NormalNotShown);
check.Call("update");
mManager.OnSelectionChanged(nullptr, nullptr,
nsISelectionListener::DRAG_REASON |
nsISelectionListener::MOUSEDOWN_REASON);
EXPECT_EQ(FirstCaretAppearance(), Appearance::None);
check.Call("mouse down");
mManager.OnReflow();
EXPECT_EQ(FirstCaretAppearance(), Appearance::None);
check.Call("reflow");
mManager.OnBlur();
EXPECT_EQ(FirstCaretAppearance(), Appearance::None);
check.Call("blur");
mManager.OnSelectionChanged(nullptr, nullptr,
nsISelectionListener::MOUSEUP_REASON);
EXPECT_EQ(FirstCaretAppearance(), Appearance::NormalNotShown);
check.Call("mouse up");
mManager.OnReflow();
EXPECT_EQ(FirstCaretAppearance(), Appearance::NormalNotShown);
check.Call("reflow2");
mManager.OnScrollPositionChanged();
EXPECT_EQ(FirstCaretAppearance(), Appearance::NormalNotShown);
}
TEST_F(AccessibleCaretManagerTester, TestTypingAtEndOfInput)
{
EXPECT_CALL(mManager, GetCaretMode())
.WillRepeatedly(Return(CaretMode::Cursor));
EXPECT_CALL(mManager, HasNonEmptyTextContent(_))
.WillRepeatedly(Return(true));
MockFunction<void(std::string aCheckPointName)> check;
{
InSequence dummy;
EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
CaretChangedReason::Updateposition)).Times(1);
EXPECT_CALL(check, Call("update"));
EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
CaretChangedReason::Visibilitychange)).Times(1);
EXPECT_CALL(check, Call("keyboard"));
// No CaretStateChanged events should be dispatched since the caret has
// being hidden in cursor mode.
EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(_)).Times(0);
}
// Simulate typing the end of the input.
mManager.UpdateCarets();
EXPECT_EQ(FirstCaretAppearance(), Appearance::Normal);
check.Call("update");
mManager.OnKeyboardEvent();
EXPECT_EQ(FirstCaretAppearance(), Appearance::None);
check.Call("keyboard");
mManager.OnSelectionChanged(nullptr, nullptr,
nsISelectionListener::NO_REASON);
EXPECT_EQ(FirstCaretAppearance(), Appearance::None);
mManager.OnScrollPositionChanged();
EXPECT_EQ(FirstCaretAppearance(), Appearance::None);
}
} // namespace mozilla

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

@ -22,7 +22,7 @@ const FLOATY_ICON_XXHDPI = "chrome://browser/skin/images/icon_floaty_xxhdpi.png"
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/Messaging.jsm");
Cu.import("resource://gre/modules/UpdateChannel.jsm");
Cu.import("resource://gre/modules/UpdateUtils.jsm");
document.addEventListener("DOMContentLoaded", init, false);
function dump(a) {
@ -138,7 +138,7 @@ function sendFeedback(aEvent) {
data["platform"] = Services.appinfo.OS;
data["version"] = Services.appinfo.version;
data["locale"] = Services.locale.getSystemLocale().getCategory("NSILOCALE_CTYPE");
data["channel"] = UpdateChannel.get();
data["channel"] = UpdateUtils.UpdateChannel;
// Source field is added only when Fennec prompts the user.
let getParam = window.location.href.split("?");

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

@ -27,7 +27,7 @@ XPCOMUtils.defineLazyModuleGetter(
this, "Promise", "resource://gre/modules/Promise.jsm");
XPCOMUtils.defineLazyModuleGetter(
this, "UpdateChannel", "resource://gre/modules/UpdateChannel.jsm");
this, "UpdateUtils", "resource://gre/modules/UpdateUtils.jsm");
XPCOMUtils.defineLazyServiceGetter(
this, "gUpdateTimer", "@mozilla.org/updates/timer-manager;1", "nsIUpdateTimerManager");
@ -192,7 +192,7 @@ this.UserAgentUpdates = {
"%APP_VERSION%": function() { return gApp.version; },
"%BUILD_ID%": function() { return gApp.appBuildID; },
"%OS%": function() { return gApp.OS; },
"%CHANNEL%": function() { return UpdateChannel.get(); },
"%CHANNEL%": function() { return UpdateUtils.UpdateChannel; },
"%DISTRIBUTION%": function() { return this._getPref(PREF_APP_DISTRIBUTION, ""); },
"%DISTRIBUTION_VERSION%": function() { return this._getPref(PREF_APP_DISTRIBUTION_VERSION, ""); },
};

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

@ -25,7 +25,7 @@ Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/Promise.jsm");
Cu.import("resource://gre/modules/Log.jsm");
Cu.import("resource://services-common/utils.js");
Cu.import("resource://gre/modules/UpdateChannel.jsm");
Cu.import("resource://gre/modules/UpdateUtils.jsm");
// The current policy version number. If the version number stored in the prefs
// is smaller than this, data upload will be disabled until the user is re-notified
@ -388,7 +388,7 @@ this.DataReportingPolicy.prototype = Object.freeze({
*/
get minimumPolicyVersion() {
// First check if the current channel has an ove
let channel = UpdateChannel.get(false);
let channel = UpdateUtils.getUpdateChannel(false);
let channelPref = this._prefs.get("minimumPolicyVersion.channel-" + channel);
return channelPref !== undefined ?
channelPref : this._prefs.get("minimumPolicyVersion", 1);

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

@ -8,7 +8,7 @@ const {utils: Cu} = Components;
Cu.import("resource://gre/modules/Preferences.jsm");
Cu.import("resource://gre/modules/services/datareporting/policy.jsm");
Cu.import("resource://testing-common/services/datareporting/mocks.jsm");
Cu.import("resource://gre/modules/UpdateChannel.jsm");
Cu.import("resource://gre/modules/UpdateUtils.jsm");
Cu.import("resource://gre/modules/Task.jsm");
function getPolicy(name,
@ -23,7 +23,7 @@ function getPolicy(name,
, defaultBranch: true });
defaultPolicyPrefs.set("currentPolicyVersion", aCurrentPolicyVersion);
defaultPolicyPrefs.set("minimumPolicyVersion", aMinimumPolicyVersion);
let branchOverridePrefName = "minimumPolicyVersion.channel-" + UpdateChannel.get(false);
let branchOverridePrefName = "minimumPolicyVersion.channel-" + UpdateUtils.getUpdateChannel(false);
if (aBranchMinimumVersionOverride !== undefined)
defaultPolicyPrefs.set(branchOverridePrefName, aBranchMinimumVersionOverride);
else

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

@ -30,8 +30,8 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "TelemetryController",
"resource://gre/modules/TelemetryController.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "UpdateChannel",
"resource://gre/modules/UpdateChannel.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "UpdateUtils",
"resource://gre/modules/UpdateUtils.jsm");
// Oldest year to allow in date preferences. This module was implemented in
// 2012 and no dates older than that should be encountered.
@ -1103,7 +1103,7 @@ AbstractHealthReporter.prototype = Object.freeze({
}
try {
out["updateChannel"] = UpdateChannel.get();
out["updateChannel"] = UpdateUtils.UpdateChannel;
} catch (ex) {
this._log.warn("Could not obtain update channel: " +
CommonUtils.exceptionStr(ex));

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

@ -46,8 +46,8 @@ Cu.import("resource://services-common/utils.js");
XPCOMUtils.defineLazyModuleGetter(this, "AddonManager",
"resource://gre/modules/AddonManager.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "UpdateChannel",
"resource://gre/modules/UpdateChannel.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "UpdateUtils",
"resource://gre/modules/UpdateUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PlacesDBUtils",
"resource://gre/modules/PlacesDBUtils.jsm");
@ -333,7 +333,7 @@ AppInfoProvider.prototype = Object.freeze({
}
try {
yield m.setLastText("updateChannel", UpdateChannel.get());
yield m.setLastText("updateChannel", UpdateUtils.UpdateChannel);
} catch (ex) {
this._log.warn("Could not obtain update channel: " +
CommonUtils.exceptionStr(ex));

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

@ -451,5 +451,31 @@ this.BrowserTestUtils = {
tab.ownerDocument.defaultView.gBrowser.removeTab(tab);
}
});
},
/**
* Version of EventUtils' `sendChar` function; it will synthesize a keypress
* event in a child process and returns a Promise that will result when the
* event was fired. Instead of a Window, a Browser object is required to be
* passed to this function.
*
* @param {String} char
* A character for the keypress event that is sent to the browser.
* @param {Browser} browser
* Browser element, must not be null.
*
* @returns {Promise}
* @resolves True if the keypress event was synthesized.
*/
sendChar(char, browser) {
return new Promise(resolve => {
let mm = browser.messageManager;
mm.addMessageListener("Test:SendCharDone", function charMsg(message) {
mm.removeMessageListener("Test:SendCharDone", charMsg);
resolve(message.data.sendCharResult);
});
mm.sendAsyncMessage("Test:SendChar", { char: char });
});
}
};

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

@ -11,6 +11,10 @@ EventUtils.window = {};
EventUtils.parent = EventUtils.window;
EventUtils._EU_Ci = Components.interfaces;
EventUtils._EU_Cc = Components.classes;
// EventUtils' `sendChar` function relies on the navigator to synthetize events.
EventUtils.navigator = content.document.defaultView.navigator;
EventUtils.KeyboardEvent = content.document.defaultView.KeyboardEvent;
Services.scriptloader.loadSubScript("chrome://mochikit/content/tests/SimpleTest/EventUtils.js", EventUtils);
addMessageListener("Test:SynthesizeMouse", (message) => {
@ -39,3 +43,8 @@ addMessageListener("Test:SynthesizeMouse", (message) => {
let result = EventUtils.synthesizeMouseAtPoint(left, top, data.event, content);
sendAsyncMessage("Test:SynthesizeMouseDone", { defaultPrevented: result });
});
addMessageListener("Test:SendChar", message => {
let result = EventUtils.sendChar(message.data.char, content);
sendAsyncMessage("Test:SendCharDone", { sendCharResult: result });
});

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

@ -95,6 +95,7 @@ user_pref("extensions.update.url", "http://%(server)s/extensions-dummy/updateURL
user_pref("extensions.update.background.url", "http://%(server)s/extensions-dummy/updateBackgroundURL");
user_pref("extensions.blocklist.url", "http://%(server)s/extensions-dummy/blocklistURL");
user_pref("extensions.hotfix.url", "http://%(server)s/extensions-dummy/hotfixURL");
user_pref("extensions.systemAddon.update.url", "http://%(server)s/dummy-system-addons.xml");
// Turn off extension updates so they don't bother tests
user_pref("extensions.update.enabled", false);
// Make sure opening about:addons won't hit the network

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

@ -140,6 +140,8 @@ DEFAULTS = dict(
'http://127.0.0.1/plugins-dummy/updateCheckURL',
'media.gmp-manager.url':
'http://127.0.0.1/gmpmanager-dummy/update.xml',
'extensions.systemAddon.update.url':
'http://127.0.0.1/dummy-system-addons.xml',
'media.navigator.enabled': True,
'media.peerconnection.enabled': True,
'media.navigator.permission.disabled': True,

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

@ -1505,6 +1505,7 @@ try {
.getService(Components.interfaces.nsIPrefBranch);
prefs.setCharPref("media.gmp-manager.url.override", "http://%(server)s/dummy-gmp-manager.xml");
prefs.setCharPref("extensions.systemAddon.update.url", "http://%(server)s/dummy-system-addons.xml");
prefs.setCharPref("browser.selfsupport.url", "https://%(server)s/selfsupport-dummy/");
prefs.setCharPref("toolkit.telemetry.server", "https://%(server)s/telemetry-dummy");
prefs.setCharPref("browser.search.geoip.url", "https://%(server)s/geoip-dummy");

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

@ -5314,12 +5314,6 @@
"kind": "flag",
"description": "Whether enablePrivilege has ever been called during the current session"
},
"READ_SAVED_PING_SUCCESS": {
"alert_emails": ["perf-telemetry-alerts@mozilla.com"],
"expires_in_version": "never",
"kind": "boolean",
"description": "Successfully reading a saved ping file"
},
"TOUCH_ENABLED_DEVICE": {
"expires_in_version": "never",
"kind": "boolean",

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

@ -80,8 +80,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "TelemetryEnvironment",
"resource://gre/modules/TelemetryEnvironment.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "SessionRecorder",
"resource://gre/modules/SessionRecorder.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "UpdateChannel",
"resource://gre/modules/UpdateChannel.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "UpdateUtils",
"resource://gre/modules/UpdateUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "TelemetryArchive",
"resource://gre/modules/TelemetryArchive.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "TelemetrySession",
@ -412,7 +412,7 @@ var Impl = {
let updateChannel = null;
try {
updateChannel = UpdateChannel.get(false);
updateChannel = UpdateUtils.getUpdateChannel(false);
} catch (e) {
this._log.trace("assemblePing - Unable to get update channel.", e);
}

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

@ -32,8 +32,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "LightweightThemeManager",
#endif
XPCOMUtils.defineLazyModuleGetter(this, "ProfileAge",
"resource://gre/modules/ProfileAge.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "UpdateChannel",
"resource://gre/modules/UpdateChannel.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "UpdateUtils",
"resource://gre/modules/UpdateUtils.jsm");
const CHANGE_THROTTLE_INTERVAL_MS = 5 * 60 * 1000;
@ -1007,7 +1007,7 @@ EnvironmentCache.prototype = {
_updateSettings: function () {
let updateChannel = null;
try {
updateChannel = UpdateChannel.get(false);
updateChannel = UpdateUtils.getUpdateChannel(false);
} catch (e) {}
this._currentEnvironment.settings = {

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

@ -19,8 +19,8 @@ Cu.import("resource://services-common/observers.js", this);
XPCOMUtils.defineLazyModuleGetter(this, "TelemetrySend",
"resource://gre/modules/TelemetrySend.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "UpdateChannel",
"resource://gre/modules/UpdateChannel.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "UpdateUtils",
"resource://gre/modules/UpdateUtils.jsm");
const LOGGER_NAME = "Toolkit.Telemetry";
const LOGGER_PREFIX = "TelemetryReportingPolicy::";
@ -251,7 +251,7 @@ var TelemetryReportingPolicyImpl = {
// use the general minimum policy version.
let channel = "";
try {
channel = UpdateChannel.get(false);
channel = UpdateUtils.getUpdateChannel(false);
} catch(e) {
this._log.error("minimumPolicyVersion - Unable to retrieve the current channel.");
return minPolicyVersion;

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

@ -143,8 +143,6 @@ XPCOMUtils.defineLazyModuleGetter(this, "ThirdPartyCookieProbe",
"resource://gre/modules/ThirdPartyCookieProbe.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "UITelemetry",
"resource://gre/modules/UITelemetry.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "UpdateChannel",
"resource://gre/modules/UpdateChannel.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "TelemetryEnvironment",
"resource://gre/modules/TelemetryEnvironment.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "CommonUtils",

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

@ -374,19 +374,6 @@ this.TelemetryStorage = {
return TelemetryStorageImpl.addPendingPing(pingData);
},
/**
* Add a ping from an existing file to the saved pings directory so that it gets saved
* and sent along with other pings.
* Note: that the original ping file will not be modified.
*
* @param {String} pingPath The path to the ping file that needs to be added to the
* saved pings directory.
* @return {Promise} A promise resolved when the ping is saved to the pings directory.
*/
addPendingPingFromFile: function(pingPath) {
return TelemetryStorageImpl.addPendingPingFromFile(pingPath);
},
/**
* Remove the file for a ping
*
@ -397,16 +384,6 @@ this.TelemetryStorage = {
return TelemetryStorageImpl.cleanupPingFile(ping);
},
/**
* Load the histograms from a file.
*
* @param {string} file The file to load.
* @returns {promise}
*/
loadHistograms: function loadHistograms(file) {
return TelemetryStorageImpl.loadHistograms(file);
},
/**
* The number of pending pings on disk.
*/
@ -414,10 +391,6 @@ this.TelemetryStorage = {
return TelemetryStorageImpl.pendingPingCount;
},
testLoadHistograms: function(file) {
return TelemetryStorageImpl.testLoadHistograms(file);
},
/**
* Loads a ping file.
* @param {String} aFilePath The path of the ping file.
@ -1175,26 +1148,6 @@ var TelemetryStorageImpl = {
return file;
}),
/**
* Add a ping from an existing file to the saved pings directory so that it gets saved
* and sent along with other pings.
* Note: that the original ping file will not be modified.
*
* @param {String} pingPath The path to the ping file that needs to be added to the
* saved pings directory.
* @return {Promise} A promise resolved when the ping is saved to the pings directory.
*/
addPendingPingFromFile: function(pingPath) {
// Pings in the saved ping directory need to have the ping id or slug (old format) as
// the file name. We load the ping content, check that it is valid, and use it to save
// the ping file with the correct file name.
return this.loadPingFile(pingPath).then(ping => {
// Since we read a ping successfully, update the related histogram.
Telemetry.getHistogramById("READ_SAVED_PING_SUCCESS").add(1);
return this.addPendingPing(ping);
});
},
/**
* Add a ping to the saved pings directory so that it gets saved
* and sent along with other pings.
@ -1395,37 +1348,10 @@ var TelemetryStorageImpl = {
return list;
},
/**
* Load the histograms from a file.
*
* Once loaded, the saved pings can be accessed (destructively only)
* through |popPendingPings|.
*
* @param {string} file The file to load.
* @returns {promise}
*/
loadHistograms: Task.async(function*(file) {
let success = true;
try {
const ping = yield this.loadPingfile(file);
return ping;
} catch (ex) {
success = false;
yield OS.File.remove(file);
} finally {
const success_histogram = Telemetry.getHistogramById("READ_SAVED_PING_SUCCESS");
success_histogram.add(success);
}
}),
get pendingPingCount() {
return this._pendingPings.size;
},
testLoadHistograms: function(file) {
return this.loadHistograms(file.path);
},
/**
* Loads a ping file.
* @param {String} aFilePath The path of the ping file.

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

@ -286,12 +286,10 @@ function checkPayload(payload, reason, successfulPings, savedPings) {
const TELEMETRY_TEST_COUNT = "TELEMETRY_TEST_COUNT";
const TELEMETRY_TEST_KEYED_FLAG = "TELEMETRY_TEST_KEYED_FLAG";
const TELEMETRY_TEST_KEYED_COUNT = "TELEMETRY_TEST_KEYED_COUNT";
const READ_SAVED_PING_SUCCESS = "READ_SAVED_PING_SUCCESS";
if (successfulPings > 0) {
Assert.ok(TELEMETRY_PING in payload.histograms);
}
Assert.ok(READ_SAVED_PING_SUCCESS in payload.histograms);
Assert.ok(TELEMETRY_TEST_FLAG in payload.histograms);
Assert.ok(TELEMETRY_TEST_COUNT in payload.histograms);
@ -346,9 +344,6 @@ function checkPayload(payload, reason, successfulPings, savedPings) {
Assert.equal(uneval(tc), uneval(expected_tc));
}
let h = payload.histograms[READ_SAVED_PING_SUCCESS];
Assert.equal(h.values[0], 1);
// The ping should include data from memory reporters. We can't check that
// this data is correct, because we can't control the values returned by the
// memory reporters. But we can at least check that the data is there.
@ -487,17 +482,6 @@ add_task(function* test_expiredHistogram() {
do_check_eq(TelemetrySession.getPayload()["histograms"]["TELEMETRY_TEST_EXPIRED"], undefined);
});
// Checks that an invalid histogram file is deleted if TelemetryStorage fails to parse it.
add_task(function* test_runInvalidJSON() {
let pingFile = getSavedPingFile("invalid-histograms.dat");
writeStringToFile(pingFile, "this.is.invalid.JSON");
do_check_true(pingFile.exists());
yield TelemetryStorage.testLoadHistograms(pingFile);
do_check_false(pingFile.exists());
});
// Sends a ping to a non existing server. If we remove this test, we won't get
// all the histograms we need in the main ping.
add_task(function* test_noServerPing() {

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

@ -25,8 +25,8 @@ Cu.import("resource://gre/modules/Services.jsm");
const PREF_APP_DISTRIBUTION = "distribution.id";
const PREF_APP_DISTRIBUTION_VERSION = "distribution.version";
XPCOMUtils.defineLazyModuleGetter(this, "UpdateChannel",
"resource://gre/modules/UpdateChannel.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "UpdateUtils",
"resource://gre/modules/UpdateUtils.jsm");
function nsURLFormatterService() {
XPCOMUtils.defineLazyGetter(this, "appInfo", function UFS_appInfo() {
@ -111,7 +111,7 @@ nsURLFormatterService.prototype = {
XPCOMABI: function() this.ABI,
BUILD_TARGET: function() this.appInfo.OS + "_" + this.ABI,
OS_VERSION: function() this.OSVersion,
CHANNEL: function() UpdateChannel.get(),
CHANNEL: function() UpdateUtils.UpdateChannel,
MOZILLA_API_KEY: function() "@MOZ_MOZILLA_API_KEY@",
GOOGLE_API_KEY: function() "@MOZ_GOOGLE_API_KEY@",
GOOGLE_OAUTH_API_CLIENTID:function() "@MOZ_GOOGLE_OAUTH_API_CLIENTID@",

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

@ -19,6 +19,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "Deprecated",
"resource://gre/modules/Deprecated.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
"resource://gre/modules/PrivateBrowsingUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Services",
"resource://gre/modules/Services.jsm");
var gViewSourceUtils = {

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

@ -18,7 +18,6 @@ skip-if = e10s # Bug 1064580
[browser_f7_caret_browsing.js]
skip-if = e10s
[browser_findbar.js]
skip-if = e10s # Disabled for e10s: Bug ?????? - seems to be a timing issue with RemoteFinder.jsm messages coming later than the tests expect.
[browser_input_file_tooltips.js]
skip-if = e10s # Bug ?????? - test directly manipulates content (TypeError: doc.createElement is not a function)
[browser_isSynthetic.js]

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

@ -2,6 +2,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "Promise",
"resource://gre/modules/Promise.jsm");
Components.utils.import("resource://gre/modules/Timer.jsm", this);
const TEST_PAGE_URI = "data:text/html;charset=utf-8,The letter s.";
/**
* Makes sure that the findbar hotkeys (' and /) event listeners
* are added to the system event group and do not get blocked
@ -11,7 +13,7 @@ add_task(function* test_hotkey_event_propagation() {
info("Ensure hotkeys are not affected by stopPropagation.");
// Opening new tab
let tab = yield promiseTestPageLoad();
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_PAGE_URI);
let browser = gBrowser.getBrowserForTab(tab);
let findbar = gBrowser.getFindBar();
@ -23,24 +25,29 @@ add_task(function* test_hotkey_event_propagation() {
is(findbar.hidden, true, "Findbar is hidden now.");
gBrowser.selectedTab = tab;
yield promiseFocus();
EventUtils.sendChar(key, browser.contentWindow);
yield BrowserTestUtils.sendChar(key, browser);
is(findbar.hidden, false, "Findbar should not be hidden.");
yield closeFindbarAndWait(findbar);
}
// Stop propagation for all keyboard events.
let window = browser.contentWindow;
let stopPropagation = function(e) { e.stopImmediatePropagation(); };
window.addEventListener("keydown", stopPropagation, true);
window.addEventListener("keypress", stopPropagation, true);
window.addEventListener("keyup", stopPropagation, true);
let frameScript = () => {
const stopPropagation = e => e.stopImmediatePropagation();
let window = content.document.defaultView;
window.removeEventListener("keydown", stopPropagation);
window.removeEventListener("keypress", stopPropagation);
window.removeEventListener("keyup", stopPropagation);
};
let mm = browser.messageManager;
mm.loadFrameScript("data:,(" + frameScript.toString() + ")();", false);
// Checking if findbar still appears when any hotkey is pressed.
for (let key of HOTKEYS) {
is(findbar.hidden, true, "Findbar is hidden now.");
gBrowser.selectedTab = tab;
yield promiseFocus();
EventUtils.sendChar(key, browser.contentWindow);
yield BrowserTestUtils.sendChar(key, browser);
is(findbar.hidden, false, "Findbar should not be hidden.");
yield closeFindbarAndWait(findbar);
}
@ -51,7 +58,7 @@ add_task(function* test_hotkey_event_propagation() {
add_task(function* test_not_found() {
info("Check correct 'Phrase not found' on new tab");
let tab = yield promiseTestPageLoad();
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_PAGE_URI);
// Search for the first word.
yield promiseFindFinished("--- THIS SHOULD NEVER MATCH ---", false);
@ -63,7 +70,7 @@ add_task(function* test_not_found() {
});
add_task(function* test_found() {
let tab = yield promiseTestPageLoad();
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_PAGE_URI);
// Search for a string that WILL be found, with 'Highlight All' on
yield promiseFindFinished("S", true);
@ -76,10 +83,10 @@ add_task(function* test_found() {
// Setting first findbar to case-sensitive mode should not affect
// new tab find bar.
add_task(function* test_tabwise_case_sensitive() {
let tab1 = yield promiseTestPageLoad();
let tab1 = yield BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_PAGE_URI);
let findbar1 = gBrowser.getFindBar();
let tab2 = yield promiseTestPageLoad();
let tab2 = yield BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_PAGE_URI);
let findbar2 = gBrowser.getFindBar();
// Toggle case sensitivity for first findbar
@ -102,22 +109,33 @@ add_task(function* test_tabwise_case_sensitive() {
gBrowser.removeTab(tab2);
});
function promiseTestPageLoad() {
let deferred = Promise.defer();
/**
* Navigating from a web page (for example mozilla.org) to an internal page
* (like about:addons) might trigger a change of browser's remoteness.
* 'Remoteness change' means that rendering page content moves from child
* process into the parent process or the other way around.
* This test ensures that findbar properly handles such a change.
*/
add_task(function * test_reinitialization_at_remoteness_change() {
info("Ensure findbar re-initialization at remoteness change.");
let tab = gBrowser.selectedTab = gBrowser.addTab("data:text/html;charset=utf-8,The letter s.");
let browser = gBrowser.selectedBrowser;
browser.addEventListener("load", function listener() {
if (browser.currentURI.spec == "about:blank")
return;
info("Page loaded: " + browser.currentURI.spec);
browser.removeEventListener("load", listener, true);
// Load a remote page and trigger findbar construction.
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_PAGE_URI);
let browser = gBrowser.getBrowserForTab(tab);
let findbar = gBrowser.getFindBar();
deferred.resolve(tab);
}, true);
// Findbar should operate normally.
yield promiseFindFinished("s", false);
ok(!findbar._findStatusDesc.textContent, "Findbar status should be empty");
return deferred.promise;
}
gBrowser.updateBrowserRemoteness(browser, false);
// Findbar should keep operating normally.
yield promiseFindFinished("s", false);
ok(!findbar._findStatusDesc.textContent, "Findbar status should be empty");
yield BrowserTestUtils.removeTab(tab);
});
function promiseFindFinished(searchText, highlightOn) {
let deferred = Promise.defer();
@ -131,8 +149,17 @@ function promiseFindFinished(searchText, highlightOn) {
findbar._findField.value = searchText;
let resultListener;
// When highlighting is on the finder sends a second "FOUND" message after
// the search wraps. This causes timing problems with e10s. waitMore
// forces foundOrTimeout wait for the second "FOUND" message before
// resolving the promise.
let waitMore = highlightOn;
let findTimeout = setTimeout(() => foundOrTimedout(null), 2000);
let foundOrTimedout = function(aData) {
if (aData !== null && waitMore) {
waitMore = false;
return;
}
if (aData === null)
info("Result listener not called, timeout reached.");
clearTimeout(findTimeout);

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

@ -4,4 +4,3 @@ tail =
skip-if = toolkit == 'gonk'
[test_contentAreaUtils.js]
[test_updateChannelModule.js]

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

@ -373,12 +373,28 @@
// browser property
if (this.getAttribute("browserid"))
setTimeout(function(aSelf) { aSelf.browser = aSelf.browser; }, 0, this);
if (typeof gBrowser !== 'undefined')
gBrowser.tabContainer.addEventListener("TabRemotenessChange", this);
]]></constructor>
<destructor><![CDATA[
this.destroy();
]]></destructor>
<method name="handleEvent">
<parameter name="aEvent"/>
<body><![CDATA[
switch(aEvent.type) {
case "onRemotenessChange":
// Reinitializing browser to re-attach listeners.
this.browser._lastSearchString = this._findField.value;
this.browser = this.browser;
break;
}
]]></body>
</method>
<!-- This is necessary because the destructor isn't called when
we are removed from a document that is not destroyed. This
needs to be explicitly called in this case -->
@ -402,6 +418,9 @@
// Clear all timers that might still be running.
this._cancelTimers();
if (typeof gBrowser !== 'undefined')
gBrowser.tabContainer.removeEventListener("TabRemotenessChange", this);
]]></body>
</method>

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

@ -213,8 +213,10 @@ this.AppConstants = Object.freeze({
MOZ_APP_VERSION_DISPLAY: "@MOZ_APP_VERSION_DISPLAY@",
MOZ_BUILD_APP: "@MOZ_BUILD_APP@",
MOZ_UPDATE_CHANNEL: "@MOZ_UPDATE_CHANNEL@",
INSTALL_LOCALE: "@AB_CD@",
MOZ_WIDGET_TOOLKIT: "@MOZ_WIDGET_TOOLKIT@",
ANDROID_PACKAGE_NAME: "@ANDROID_PACKAGE_NAME@",
MOZ_ANDROID_APZ:
#ifdef MOZ_ANDROID_APZ
true,

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

@ -8,10 +8,6 @@ this.EXPORTED_SYMBOLS = [];
const {classes: Cc, interfaces: Ci, results: Cr, utils: Cu, manager: Cm} =
Components;
// Chunk size for the incremental downloader
const DOWNLOAD_CHUNK_BYTES_SIZE = 300000;
// Incremental downloader interval
const DOWNLOAD_INTERVAL = 0;
// 1 day default
const DEFAULT_SECONDS_BETWEEN_CHECKS = 60 * 60 * 24;
@ -30,15 +26,12 @@ Cu.import("resource://gre/modules/Preferences.jsm");
Cu.import("resource://gre/modules/Log.jsm");
Cu.import("resource://gre/modules/osfile.jsm");
Cu.import("resource://gre/modules/Task.jsm");
Cu.import("resource://gre/modules/ctypes.jsm");
Cu.import("resource://gre/modules/GMPUtils.jsm");
Cu.import("resource://gre/modules/AppConstants.jsm");
Cu.import("resource://gre/modules/addons/ProductAddonChecker.jsm");
this.EXPORTED_SYMBOLS = ["GMPInstallManager", "GMPExtractor", "GMPDownloader",
"GMPAddon"];
var gLocale = null;
// Shared code for suppressing bad cert dialogs
XPCOMUtils.defineLazyGetter(this, "gCertUtils", function() {
let temp = { };
@ -46,18 +39,8 @@ XPCOMUtils.defineLazyGetter(this, "gCertUtils", function() {
return temp;
});
XPCOMUtils.defineLazyModuleGetter(this, "UpdateChannel",
"resource://gre/modules/UpdateChannel.jsm");
/**
* Number of milliseconds after which we need to cancel `checkForAddons`.
*
* Bug 1087674 suggests that the XHR we use in `checkForAddons` may
* never terminate in presence of network nuisances (e.g. strange
* antivirus behavior). This timeout is a defensive measure to ensure
* that we fail cleanly in such case.
*/
const CHECK_FOR_ADDONS_TIMEOUT_DELAY_MS = 20000;
XPCOMUtils.defineLazyModuleGetter(this, "UpdateUtils",
"resource://gre/modules/UpdateUtils.jsm");
function getScopedLogger(prefix) {
// `PARENT_LOGGER_ID.` being passed here effectively links this logger
@ -65,138 +48,6 @@ function getScopedLogger(prefix) {
return Log.repository.getLoggerWithMessagePrefix("Toolkit.GMP", prefix + " ");
}
// This is copied directly from nsUpdateService.js
// It is used for calculating the URL string w/ var replacement.
// TODO: refactor this out somewhere else
XPCOMUtils.defineLazyGetter(this, "gOSVersion", function aus_gOSVersion() {
let osVersion;
try {
osVersion = Services.sysinfo.getProperty("name") + " " +
Services.sysinfo.getProperty("version");
}
catch (e) {
LOG("gOSVersion - OS Version unknown: updates are not possible.");
}
if (osVersion) {
if (AppConstants.platform == "win") {
const BYTE = ctypes.uint8_t;
const WORD = ctypes.uint16_t;
const DWORD = ctypes.uint32_t;
const WCHAR = ctypes.char16_t;
const BOOL = ctypes.int;
// This structure is described at:
// http://msdn.microsoft.com/en-us/library/ms724833%28v=vs.85%29.aspx
const SZCSDVERSIONLENGTH = 128;
const OSVERSIONINFOEXW = new ctypes.StructType('OSVERSIONINFOEXW',
[
{dwOSVersionInfoSize: DWORD},
{dwMajorVersion: DWORD},
{dwMinorVersion: DWORD},
{dwBuildNumber: DWORD},
{dwPlatformId: DWORD},
{szCSDVersion: ctypes.ArrayType(WCHAR, SZCSDVERSIONLENGTH)},
{wServicePackMajor: WORD},
{wServicePackMinor: WORD},
{wSuiteMask: WORD},
{wProductType: BYTE},
{wReserved: BYTE}
]);
// This structure is described at:
// http://msdn.microsoft.com/en-us/library/ms724958%28v=vs.85%29.aspx
const SYSTEM_INFO = new ctypes.StructType('SYSTEM_INFO',
[
{wProcessorArchitecture: WORD},
{wReserved: WORD},
{dwPageSize: DWORD},
{lpMinimumApplicationAddress: ctypes.voidptr_t},
{lpMaximumApplicationAddress: ctypes.voidptr_t},
{dwActiveProcessorMask: DWORD.ptr},
{dwNumberOfProcessors: DWORD},
{dwProcessorType: DWORD},
{dwAllocationGranularity: DWORD},
{wProcessorLevel: WORD},
{wProcessorRevision: WORD}
]);
let kernel32 = false;
try {
kernel32 = ctypes.open("Kernel32");
} catch (e) {
LOG("gOSVersion - Unable to open kernel32! " + e);
osVersion += ".unknown (unknown)";
}
if(kernel32) {
try {
// Get Service pack info
try {
let GetVersionEx = kernel32.declare("GetVersionExW",
ctypes.default_abi,
BOOL,
OSVERSIONINFOEXW.ptr);
let winVer = OSVERSIONINFOEXW();
winVer.dwOSVersionInfoSize = OSVERSIONINFOEXW.size;
if(0 !== GetVersionEx(winVer.address())) {
osVersion += "." + winVer.wServicePackMajor
+ "." + winVer.wServicePackMinor;
} else {
LOG("gOSVersion - Unknown failure in GetVersionEX (returned 0)");
osVersion += ".unknown";
}
} catch (e) {
LOG("gOSVersion - error getting service pack information. Exception: " + e);
osVersion += ".unknown";
}
// Get processor architecture
let arch = "unknown";
try {
let GetNativeSystemInfo = kernel32.declare("GetNativeSystemInfo",
ctypes.default_abi,
ctypes.void_t,
SYSTEM_INFO.ptr);
let sysInfo = SYSTEM_INFO();
// Default to unknown
sysInfo.wProcessorArchitecture = 0xffff;
GetNativeSystemInfo(sysInfo.address());
switch(sysInfo.wProcessorArchitecture) {
case 9:
arch = "x64";
break;
case 6:
arch = "IA64";
break;
case 0:
arch = "x86";
break;
}
} catch (e) {
LOG("gOSVersion - error getting processor architecture. Exception: " + e);
} finally {
osVersion += " (" + arch + ")";
}
} finally {
kernel32.close();
}
}
}
try {
osVersion += " (" + sysInfo.getProperty("secondaryLibrary") + ")";
}
catch (e) {
// Not all platforms have a secondary widget library, so an error is nothing to worry about.
}
osVersion = encodeURIComponent(osVersion);
}
return osVersion;
});
/**
* Provides an easy API for downloading and installing GMP Addons
*/
@ -221,24 +72,8 @@ GMPInstallManager.prototype = {
log.info("Using url: " + url);
}
url =
url.replace(/%PRODUCT%/g, Services.appinfo.name)
.replace(/%VERSION%/g, Services.appinfo.version)
.replace(/%BUILD_ID%/g, Services.appinfo.appBuildID)
.replace(/%BUILD_TARGET%/g, Services.appinfo.OS + "_" + GMPUtils.ABI())
.replace(/%OS_VERSION%/g, gOSVersion);
if (/%LOCALE%/.test(url)) {
// TODO: Get the real local, does it actually matter for GMP plugins?
url = url.replace(/%LOCALE%/g, "en-US");
}
url =
url.replace(/%CHANNEL%/g, UpdateChannel.get())
.replace(/%PLATFORM_VERSION%/g, Services.appinfo.platformVersion)
.replace(/%DISTRIBUTION%/g,
GMPPrefs.get(GMPPrefs.KEY_APP_DISTRIBUTION))
.replace(/%DISTRIBUTION_VERSION%/g,
GMPPrefs.get(GMPPrefs.KEY_APP_DISTRIBUTION_VERSION))
.replace(/\+/g, "%2B");
url = UpdateUtils.formatUpdateURL(url);
log.info("Using url (with replacement): " + url);
return url;
},
@ -260,38 +95,27 @@ GMPInstallManager.prototype = {
this._deferred = Promise.defer();
let url = this._getURL();
this._request = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].
createInstance(Ci.nsISupports);
// This is here to let unit test code override XHR
if (this._request.wrappedJSObject) {
this._request = this._request.wrappedJSObject;
let allowNonBuiltIn = true;
let certs = null;
if (!Services.prefs.prefHasUserValue(GMPPrefs.KEY_URL_OVERRIDE)) {
allowNonBuiltIn = !GMPPrefs.get(GMPPrefs.KEY_CERT_REQUIREBUILTIN, true);
if (GMPPrefs.get(GMPPrefs.KEY_CERT_CHECKATTRS, true)) {
certs = gCertUtils.readCertPrefs(GMPPrefs.KEY_CERTS_BRANCH);
}
}
this._request.open("GET", url, true);
let allowNonBuiltIn = !GMPPrefs.get(GMPPrefs.KEY_CERT_CHECKATTRS, true);
this._request.channel.notificationCallbacks =
new gCertUtils.BadCertHandler(allowNonBuiltIn);
// Prevent the request from reading from the cache.
this._request.channel.loadFlags |= Ci.nsIRequest.LOAD_BYPASS_CACHE;
// Prevent the request from writing to the cache.
this._request.channel.loadFlags |= Ci.nsIRequest.INHIBIT_CACHING;
this._request.overrideMimeType("text/xml");
// The Cache-Control header is only interpreted by proxies and the
// final destination. It does not help if a resource is already
// cached locally.
this._request.setRequestHeader("Cache-Control", "no-cache");
// HTTP/1.0 servers might not implement Cache-Control and
// might only implement Pragma: no-cache
this._request.setRequestHeader("Pragma", "no-cache");
this._request.timeout = CHECK_FOR_ADDONS_TIMEOUT_DELAY_MS;
this._request.addEventListener("error", event => this.onFailXML("onErrorXML", event), false);
this._request.addEventListener("abort", event => this.onFailXML("onAbortXML", event), false);
this._request.addEventListener("timeout", event => this.onFailXML("onTimeoutXML", event), false);
this._request.addEventListener("load", event => this.onLoadXML(event), false);
log.info("sending request to: " + url);
this._request.send(null);
ProductAddonChecker.getProductAddonList(url, allowNonBuiltIn, certs).then((addons) => {
if (!addons) {
this._deferred.resolve([]);
}
else {
this._deferred.resolve([for (a of addons) new GMPAddon(a)]);
}
delete this._deferred;
}, (ex) => {
this._deferred.reject(ex);
delete this._deferred;
});
return this._deferred.promise;
},
@ -493,132 +317,6 @@ GMPInstallManager.prototype = {
* This is useful for tests.
*/
overrideLeaveDownloadedZip: false,
/**
* The XMLHttpRequest succeeded and the document was loaded.
* @param event The nsIDOMEvent for the load
*/
onLoadXML: function(event) {
let log = getScopedLogger("GMPInstallManager.onLoadXML");
try {
log.info("request completed downloading document");
let certs = null;
if (!Services.prefs.prefHasUserValue(GMPPrefs.KEY_URL_OVERRIDE) &&
GMPPrefs.get(GMPPrefs.KEY_CERT_CHECKATTRS, true)) {
certs = gCertUtils.readCertPrefs(GMPPrefs.KEY_CERTS_BRANCH);
}
let allowNonBuiltIn = !GMPPrefs.get(GMPPrefs.KEY_CERT_REQUIREBUILTIN,
true);
log.info("allowNonBuiltIn: " + allowNonBuiltIn);
gCertUtils.checkCert(this._request.channel, allowNonBuiltIn, certs);
this.parseResponseXML();
} catch (ex) {
log.error("could not load xml: " + ex);
this._deferred.reject({
target: event.target,
status: this._getChannelStatus(event.target),
message: "" + ex,
});
delete this._deferred;
}
},
/**
* Returns the status code for the XMLHttpRequest
*/
_getChannelStatus: function(request) {
let log = getScopedLogger("GMPInstallManager._getChannelStatus");
let status = null;
try {
status = request.status;
log.info("request.status is: " + request.status);
}
catch (e) {
}
if (status == null) {
status = request.channel.QueryInterface(Ci.nsIRequest).status;
}
return status;
},
/**
* There was an error of some kind during the XMLHttpRequest. This
* error may have been caused by external factors (e.g. network
* issues) or internally (by a timeout).
*
* @param event The nsIDOMEvent for the error
*/
onFailXML: function(failure, event) {
let log = getScopedLogger("GMPInstallManager.onFailXML " + failure);
let request = event.target;
let status = this._getChannelStatus(request);
let message = "request.status: " + status + " (" + event.type + ")";
log.warn(message);
this._deferred.reject({
target: request,
status: status,
message: message
});
delete this._deferred;
},
/**
* Returns an array of GMPAddon objects discovered by the update check.
* Or returns an empty array if there were any problems with parsing.
* If there's an error, it will be logged if logging is enabled.
*/
parseResponseXML: function() {
try {
let log = getScopedLogger("GMPInstallManager.parseResponseXML");
let updatesElement = this._request.responseXML.documentElement;
if (!updatesElement) {
let message = "empty updates document";
log.warn(message);
this._deferred.reject({
target: this._request,
message: message
});
delete this._deferred;
return;
}
if (updatesElement.nodeName != "updates") {
let message = "got node name: " + updatesElement.nodeName +
", expected: updates";
log.warn(message);
this._deferred.reject({
target: this._request,
message: message
});
delete this._deferred;
return;
}
const ELEMENT_NODE = Ci.nsIDOMNode.ELEMENT_NODE;
let gmpResults = [];
for (let i = 0; i < updatesElement.childNodes.length; ++i) {
let updatesChildElement = updatesElement.childNodes.item(i);
if (updatesChildElement.nodeType != ELEMENT_NODE) {
continue;
}
if (updatesChildElement.localName == "addons") {
gmpResults = GMPAddon.parseGMPAddonsNode(updatesChildElement);
}
}
this._deferred.resolve(gmpResults);
delete this._deferred;
} catch (e) {
this._deferred.reject({
target: this._request,
message: e
});
delete this._deferred;
}
},
};
/**
@ -626,49 +324,16 @@ GMPInstallManager.prototype = {
* GMPAddon objects are returns from GMPInstallManager.checkForAddons
* GMPAddon objects can also be used in calls to GMPInstallManager.installAddon
*
* @param gmpAddon The AUS response XML's DOM element `addon`
* @param addon The ProductAddonChecker `addon` object
*/
function GMPAddon(gmpAddon) {
function GMPAddon(addon) {
let log = getScopedLogger("GMPAddon.constructor");
gmpAddon.QueryInterface(Ci.nsIDOMElement);
["id", "URL", "hashFunction",
"hashValue", "version", "size"].forEach(name => {
if (gmpAddon.hasAttribute(name)) {
this[name] = gmpAddon.getAttribute(name);
}
});
this.size = Number(this.size) || undefined;
for (let name of Object.keys(addon)) {
this[name] = addon[name];
}
log.info ("Created new addon: " + this.toString());
}
/**
* Parses an XML GMP addons node from AUS into an array
* @param addonsElement An nsIDOMElement compatible node with XML from AUS
* @return An array of GMPAddon results
*/
GMPAddon.parseGMPAddonsNode = function(addonsElement) {
let log = getScopedLogger("GMPAddon.parseGMPAddonsNode");
let gmpResults = [];
if (addonsElement.localName !== "addons") {
return;
}
addonsElement.QueryInterface(Ci.nsIDOMElement);
let addonCount = addonsElement.childNodes.length;
for (let i = 0; i < addonCount; ++i) {
let addonElement = addonsElement.childNodes.item(i);
if (addonElement.localName !== "addon") {
continue;
}
addonElement.QueryInterface(Ci.nsIDOMElement);
try {
gmpResults.push(new GMPAddon(addonElement));
} catch (e) {
log.warn("invalid addon: " + e);
continue;
}
}
return gmpResults;
};
GMPAddon.prototype = {
/**
* Returns a string representation of the addon
@ -799,38 +464,7 @@ function GMPDownloader(gmpAddon)
{
this._gmpAddon = gmpAddon;
}
/**
* Computes the file hash of fileToHash with the specified hash function
* @param hashFunctionName A hash function name such as sha512
* @param fileToHash An nsIFile to hash
* @return a promise which resolve to a digest in binary hex format
*/
GMPDownloader.computeHash = function(hashFunctionName, fileToHash) {
let log = getScopedLogger("GMPDownloader.computeHash");
let digest;
let fileStream = Cc["@mozilla.org/network/file-input-stream;1"].
createInstance(Ci.nsIFileInputStream);
fileStream.init(fileToHash, FileUtils.MODE_RDONLY,
FileUtils.PERMS_FILE, 0);
try {
let hash = Cc["@mozilla.org/security/hash;1"].
createInstance(Ci.nsICryptoHash);
let hashFunction =
Ci.nsICryptoHash[hashFunctionName.toUpperCase()];
if (!hashFunction) {
log.error("could not get hash function");
return Promise.reject();
}
hash.init(hashFunction);
hash.updateFromStream(fileStream, -1);
digest = binaryToHex(hash.finish(false));
} catch (e) {
log.warn("failed to compute hash: " + e);
digest = "";
}
fileStream.close();
return Promise.resolve(digest);
},
GMPDownloader.prototype = {
/**
* Starts the download process for an addon.
@ -838,9 +472,10 @@ GMPDownloader.prototype = {
* See GMPInstallManager.installAddon for resolve/rejected info
*/
start: function() {
let log = getScopedLogger("GMPDownloader.start");
this._deferred = Promise.defer();
if (!this._gmpAddon.isValid) {
let log = getScopedLogger("GMPDownloader");
let gmpAddon = this._gmpAddon;
if (!gmpAddon.isValid) {
log.info("gmpAddon is not valid, will not continue");
return Promise.reject({
target: this,
@ -849,55 +484,14 @@ GMPDownloader.prototype = {
});
}
let uri = Services.io.newURI(this._gmpAddon.URL, null, null);
this._request = Cc["@mozilla.org/network/incremental-download;1"].
createInstance(Ci.nsIIncrementalDownload);
let gmpFile = FileUtils.getFile("TmpD", [this._gmpAddon.id + ".zip"]);
if (gmpFile.exists()) {
gmpFile.remove(false);
}
log.info("downloading from " + uri.spec + " to " + gmpFile.path);
this._request.init(uri, gmpFile, DOWNLOAD_CHUNK_BYTES_SIZE,
DOWNLOAD_INTERVAL);
this._request.start(this, null);
return this._deferred.promise;
},
// For nsIRequestObserver
onStartRequest: function(request, context) {
},
// For nsIRequestObserver
// Called when the GMP addon zip file is downloaded
onStopRequest: function(request, context, status) {
let log = getScopedLogger("GMPDownloader.onStopRequest");
log.info("onStopRequest called");
if (!Components.isSuccessCode(status)) {
log.info("status failed: " + status);
this._deferred.reject({
target: this,
status: status,
type: "downloaderr"
});
return;
}
let promise = this._verifyDownload();
promise.then(() => {
log.info("GMP file is ready to unzip");
let destination = this._request.destination;
let zipPath = destination.path;
let gmpAddon = this._gmpAddon;
let installToDirPath = Cc["@mozilla.org/file/local;1"].
createInstance(Ci.nsIFile);
return ProductAddonChecker.downloadAddon(gmpAddon).then((zipPath) => {
let path = OS.Path.join(OS.Constants.Path.profileDir,
gmpAddon.id,
gmpAddon.version);
installToDirPath.initWithPath(path);
log.info("install to directory path: " + installToDirPath.path);
let gmpInstaller = new GMPExtractor(zipPath, installToDirPath.path);
log.info("install to directory path: " + path);
let gmpInstaller = new GMPExtractor(zipPath, path);
let installPromise = gmpInstaller.install();
installPromise.then(extractedPaths => {
return installPromise.then(extractedPaths => {
// Success, set the prefs
let now = Math.round(Date.now() / 1000);
GMPPrefs.set(GMPPrefs.KEY_PLUGIN_LAST_UPDATE, now, gmpAddon.id);
@ -908,78 +502,13 @@ GMPDownloader.prototype = {
// Remember our ABI, so that if the profile is migrated to another
// platform or from 32 -> 64 bit, we notice and don't try to load the
// unexecutable plugin library.
GMPPrefs.set(GMPPrefs.KEY_PLUGIN_ABI, GMPUtils.ABI(), gmpAddon.id);
GMPPrefs.set(GMPPrefs.KEY_PLUGIN_ABI, UpdateUtils.ABI, gmpAddon.id);
// Setting the version pref signals installation completion to consumers,
// if you need to set other prefs etc. do it before this.
GMPPrefs.set(GMPPrefs.KEY_PLUGIN_VERSION, gmpAddon.version,
gmpAddon.id);
this._deferred.resolve(extractedPaths);
}, err => {
this._deferred.reject(err);
});
}, err => {
log.warn("verifyDownload check failed");
this._deferred.reject({
target: this,
status: 200,
type: "verifyerr"
return extractedPaths;
});
});
},
/**
* Verifies that the downloaded zip file's hash matches the GMPAddon hash.
* @return a promise which resolves if the download verifies
*/
_verifyDownload: function() {
let verifyDownloadDeferred = Promise.defer();
let log = getScopedLogger("GMPDownloader._verifyDownload");
log.info("_verifyDownload called");
if (!this._request) {
return Promise.reject();
}
let destination = this._request.destination;
log.info("for path: " + destination.path);
// Ensure that the file size matches the expected file size.
if (this._gmpAddon.size !== undefined &&
destination.fileSize != this._gmpAddon.size) {
log.warn("Downloader:_verifyDownload downloaded size " +
destination.fileSize + " != expected size " +
this._gmpAddon.size + ".");
return Promise.reject();
}
let promise = GMPDownloader.computeHash(this._gmpAddon.hashFunction, destination);
promise.then(digest => {
let expectedDigest = this._gmpAddon.hashValue.toLowerCase();
if (digest !== expectedDigest) {
log.warn("hashes do not match! Got: `" +
digest + "`, expected: `" + expectedDigest + "`");
this._deferred.reject();
return;
}
log.info("hashes match!");
verifyDownloadDeferred.resolve();
}, err => {
verifyDownloadDeferred.reject();
});
return verifyDownloadDeferred.promise;
},
QueryInterface: XPCOMUtils.generateQI([Ci.nsIRequestObserver])
};
/**
* Convert a string containing binary values to hex.
*/
function binaryToHex(input) {
let result = "";
for (let i = 0; i < input.length; ++i) {
let hex = input.charCodeAt(i).toString(16);
if (hex.length == 1)
hex = "0" + hex;
result += hex;
}
return result;
}

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

@ -126,27 +126,6 @@ this.GMPUtils = {
hist.add(value);
}
},
ABI: function() {
// This is copied directly from nsUpdateService.js
let abi = null;
try {
abi = Services.appinfo.XPCOMABI;
}
catch (e) {
return "unknown";
}
if (AppConstants.platform == "macosx") {
// Mac universal build should report a different ABI than either macppc
// or mactel.
let macutils = Cc["@mozilla.org/xpcom/mac-utils;1"].
getService(Ci.nsIMacUtils);
if (macutils.isUniversalBinary)
abi += "-u-" + macutils.architecturesInBinary;
}
return abi;
}
};
/**

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

@ -181,7 +181,7 @@ var dataProviders = {
};
if (AppConstants.MOZ_UPDATER)
data.updateChannel = Cu.import("resource://gre/modules/UpdateChannel.jsm", {}).UpdateChannel.get();
data.updateChannel = Cu.import("resource://gre/modules/UpdateUtils.jsm", {}).UpdateUtils.UpdateChannel;
try {
data.vendor = Services.prefs.getCharPref("app.support.vendor");

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

@ -1,46 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
this.EXPORTED_SYMBOLS = ["UpdateChannel"];
const Cu = Components.utils;
Cu.import("resource://gre/modules/AppConstants.jsm");
Cu.import("resource://gre/modules/Services.jsm");
this.UpdateChannel = {
/**
* Read the update channel from defaults only. We do this to ensure that
* the channel is tightly coupled with the application and does not apply
* to other instances of the application that may use the same profile.
*
* @param [optional] aIncludePartners
* Whether or not to include the partner bits. Default: true.
*/
get: function UpdateChannel_get(aIncludePartners = true) {
let channel = AppConstants.MOZ_UPDATE_CHANNEL;
let defaults = Services.prefs.getDefaultBranch(null);
try {
channel = defaults.getCharPref("app.update.channel");
} catch (e) {
// use default value when pref not found
}
if (aIncludePartners) {
try {
let partners = Services.prefs.getChildList("app.partner.").sort();
if (partners.length) {
channel += "-cck";
partners.forEach(function (prefName) {
channel += "-" + Services.prefs.getCharPref(prefName);
});
}
} catch (e) {
Cu.reportError(e);
}
}
return channel;
}
};

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

@ -0,0 +1,347 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
this.EXPORTED_SYMBOLS = ["UpdateUtils"];
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
Cu.import("resource://gre/modules/AppConstants.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/NetUtil.jsm");
Cu.import("resource://gre/modules/Preferences.jsm");
Cu.import("resource://gre/modules/ctypes.jsm");
const FILE_UPDATE_LOCALE = "update.locale";
const PREF_APP_DISTRIBUTION = "distribution.id";
const PREF_APP_DISTRIBUTION_VERSION = "distribution.version";
const PREF_APP_B2G_VERSION = "b2g.version";
const PREF_APP_UPDATE_CUSTOM = "app.update.custom";
const PREF_APP_UPDATE_IMEI_HASH = "app.update.imei_hash";
this.UpdateUtils = {
/**
* Read the update channel from defaults only. We do this to ensure that
* the channel is tightly coupled with the application and does not apply
* to other instances of the application that may use the same profile.
*
* @param [optional] aIncludePartners
* Whether or not to include the partner bits. Default: true.
*/
getUpdateChannel(aIncludePartners = true) {
let channel = AppConstants.MOZ_UPDATE_CHANNEL;
let defaults = Services.prefs.getDefaultBranch(null);
try {
channel = defaults.getCharPref("app.update.channel");
} catch (e) {
// use default value when pref not found
}
if (aIncludePartners) {
try {
let partners = Services.prefs.getChildList("app.partner.").sort();
if (partners.length) {
channel += "-cck";
partners.forEach(function (prefName) {
channel += "-" + Services.prefs.getCharPref(prefName);
});
}
} catch (e) {
Cu.reportError(e);
}
}
return channel;
},
get UpdateChannel() {
return this.getUpdateChannel();
},
/**
* Formats a URL by replacing %...% values with OS, build and locale specific
* values.
*
* @param url
* The URL to format.
* @return The formatted URL.
*/
formatUpdateURL(url) {
url = url.replace(/%PRODUCT%/g, Services.appinfo.name);
url = url.replace(/%VERSION%/g, Services.appinfo.version);
url = url.replace(/%BUILD_ID%/g, Services.appinfo.appBuildID);
url = url.replace(/%BUILD_TARGET%/g, Services.appinfo.OS + "_" + this.ABI);
url = url.replace(/%OS_VERSION%/g, this.OSVersion);
if (/%LOCALE%/.test(url)) {
url = url.replace(/%LOCALE%/g, this.Locale);
}
url = url.replace(/%CHANNEL%/g, this.UpdateChannel);
url = url.replace(/%PLATFORM_VERSION%/g, Services.appinfo.platformVersion);
url = url.replace(/%DISTRIBUTION%/g,
getDistributionPrefValue(PREF_APP_DISTRIBUTION));
url = url.replace(/%DISTRIBUTION_VERSION%/g,
getDistributionPrefValue(PREF_APP_DISTRIBUTION_VERSION));
url = url.replace(/%CUSTOM%/g, Preferences.get(PREF_APP_UPDATE_CUSTOM, ""));
url = url.replace(/\+/g, "%2B");
if (AppConstants.platform == "gonk") {
let sysLibs = {};
Cu.import("resource://gre/modules/systemlibs.js", sysLibs);
let productDevice = sysLibs.libcutils.property_get("ro.product.device");
let buildType = sysLibs.libcutils.property_get("ro.build.type");
url = url.replace(/%PRODUCT_MODEL%/g,
sysLibs.libcutils.property_get("ro.product.model"));
if (buildType == "user" || buildType == "userdebug") {
url = url.replace(/%PRODUCT_DEVICE%/g, productDevice);
} else {
url = url.replace(/%PRODUCT_DEVICE%/g, productDevice + "-" + buildType);
}
url = url.replace(/%B2G_VERSION%/g,
Preferences.get(PREF_APP_B2G_VERSION, null));
url = url.replace(/%IMEI%/g,
Preferences.get(PREF_APP_UPDATE_IMEI_HASH, "default"));
}
return url;
}
};
/* Get the distribution pref values, from defaults only */
function getDistributionPrefValue(aPrefName) {
var prefValue = "default";
try {
prefValue = Services.prefs.getDefaultBranch(null).getCharPref(aPrefName);
} catch (e) {
// use default when pref not found
}
return prefValue;
}
/**
* Gets the locale from the update.locale file for replacing %LOCALE% in the
* update url. The update.locale file can be located in the application
* directory or the GRE directory with preference given to it being located in
* the application directory.
*/
XPCOMUtils.defineLazyGetter(UpdateUtils, "Locale", function() {
let channel;
let locale;
for (let res of ['app', 'gre']) {
channel = Services.io.newChannel2("resource://" + res + "/" + FILE_UPDATE_LOCALE,
null,
null,
null, // aLoadingNode
Services.scriptSecurityManager.getSystemPrincipal(),
null, // aTriggeringPrincipal
Ci.nsILoadInfo.SEC_NORMAL,
Ci.nsIContentPolicy.TYPE_INTERNAL_XMLHTTPREQUEST);
try {
let inputStream = channel.open();
locale = NetUtil.readInputStreamToString(inputStream, inputStream.available());
} catch(e) {}
if (locale)
return locale.trim();
}
Cu.reportError(FILE_UPDATE_LOCALE + " file doesn't exist in either the " +
"application or GRE directories");
return null;
});
/* Windows only getter that returns the processor architecture. */
XPCOMUtils.defineLazyGetter(this, "gWinCPUArch", function aus_gWinCPUArch() {
// Get processor architecture
let arch = "unknown";
const WORD = ctypes.uint16_t;
const DWORD = ctypes.uint32_t;
// This structure is described at:
// http://msdn.microsoft.com/en-us/library/ms724958%28v=vs.85%29.aspx
const SYSTEM_INFO = new ctypes.StructType('SYSTEM_INFO',
[
{wProcessorArchitecture: WORD},
{wReserved: WORD},
{dwPageSize: DWORD},
{lpMinimumApplicationAddress: ctypes.voidptr_t},
{lpMaximumApplicationAddress: ctypes.voidptr_t},
{dwActiveProcessorMask: DWORD.ptr},
{dwNumberOfProcessors: DWORD},
{dwProcessorType: DWORD},
{dwAllocationGranularity: DWORD},
{wProcessorLevel: WORD},
{wProcessorRevision: WORD}
]);
let kernel32 = false;
try {
kernel32 = ctypes.open("Kernel32");
} catch (e) {
Cu.reportError("Unable to open kernel32! Exception: " + e);
}
if (kernel32) {
try {
let GetNativeSystemInfo = kernel32.declare("GetNativeSystemInfo",
ctypes.default_abi,
ctypes.void_t,
SYSTEM_INFO.ptr);
let winSystemInfo = SYSTEM_INFO();
// Default to unknown
winSystemInfo.wProcessorArchitecture = 0xffff;
GetNativeSystemInfo(winSystemInfo.address());
switch (winSystemInfo.wProcessorArchitecture) {
case 9:
arch = "x64";
break;
case 6:
arch = "IA64";
break;
case 0:
arch = "x86";
break;
}
} catch (e) {
Cu.reportError("Error getting processor architecture. " +
"Exception: " + e);
} finally {
kernel32.close();
}
}
return arch;
});
XPCOMUtils.defineLazyGetter(UpdateUtils, "ABI", function() {
let abi = null;
try {
abi = Services.appinfo.XPCOMABI;
}
catch (e) {
Cu.reportError("XPCOM ABI unknown");
}
if (AppConstants.platform == "macosx") {
// Mac universal build should report a different ABI than either macppc
// or mactel.
let macutils = Cc["@mozilla.org/xpcom/mac-utils;1"].
getService(Ci.nsIMacUtils);
if (macutils.isUniversalBinary) {
abi += "-u-" + macutils.architecturesInBinary;
}
} else if (AppConstants.platform == "win") {
// Windows build should report the CPU architecture that it's running on.
abi += "-" + gWinCPUArch;
}
return abi;
});
XPCOMUtils.defineLazyGetter(UpdateUtils, "OSVersion", function() {
let osVersion;
try {
osVersion = Services.sysinfo.getProperty("name") + " " +
Services.sysinfo.getProperty("version");
}
catch (e) {
Cu.reportError("OS Version unknown.");
}
if (osVersion) {
if (AppConstants.platform == "win") {
const BYTE = ctypes.uint8_t;
const WORD = ctypes.uint16_t;
const DWORD = ctypes.uint32_t;
const WCHAR = ctypes.char16_t;
const BOOL = ctypes.int;
// This structure is described at:
// http://msdn.microsoft.com/en-us/library/ms724833%28v=vs.85%29.aspx
const SZCSDVERSIONLENGTH = 128;
const OSVERSIONINFOEXW = new ctypes.StructType('OSVERSIONINFOEXW',
[
{dwOSVersionInfoSize: DWORD},
{dwMajorVersion: DWORD},
{dwMinorVersion: DWORD},
{dwBuildNumber: DWORD},
{dwPlatformId: DWORD},
{szCSDVersion: ctypes.ArrayType(WCHAR, SZCSDVERSIONLENGTH)},
{wServicePackMajor: WORD},
{wServicePackMinor: WORD},
{wSuiteMask: WORD},
{wProductType: BYTE},
{wReserved: BYTE}
]);
// This structure is described at:
// http://msdn.microsoft.com/en-us/library/ms724958%28v=vs.85%29.aspx
const SYSTEM_INFO = new ctypes.StructType('SYSTEM_INFO',
[
{wProcessorArchitecture: WORD},
{wReserved: WORD},
{dwPageSize: DWORD},
{lpMinimumApplicationAddress: ctypes.voidptr_t},
{lpMaximumApplicationAddress: ctypes.voidptr_t},
{dwActiveProcessorMask: DWORD.ptr},
{dwNumberOfProcessors: DWORD},
{dwProcessorType: DWORD},
{dwAllocationGranularity: DWORD},
{wProcessorLevel: WORD},
{wProcessorRevision: WORD}
]);
let kernel32 = false;
try {
kernel32 = ctypes.open("Kernel32");
} catch (e) {
Cu.reportError("Unable to open kernel32! " + e);
osVersion += ".unknown (unknown)";
}
if (kernel32) {
try {
// Get Service pack info
try {
let GetVersionEx = kernel32.declare("GetVersionExW",
ctypes.default_abi,
BOOL,
OSVERSIONINFOEXW.ptr);
let winVer = OSVERSIONINFOEXW();
winVer.dwOSVersionInfoSize = OSVERSIONINFOEXW.size;
if(0 !== GetVersionEx(winVer.address())) {
osVersion += "." + winVer.wServicePackMajor +
"." + winVer.wServicePackMinor;
} else {
Cu.reportError("Unknown failure in GetVersionEX (returned 0)");
osVersion += ".unknown";
}
} catch (e) {
Cu.reportError("Error getting service pack information. Exception: " + e);
osVersion += ".unknown";
}
} finally {
kernel32.close();
}
// Add processor architecture
osVersion += " (" + gWinCPUArch + ")";
}
}
try {
osVersion += " (" + Services.sysinfo.getProperty("secondaryLibrary") + ")";
}
catch (e) {
// Not all platforms have a secondary widget library, so an error is nothing to worry about.
}
osVersion = encodeURIComponent(osVersion);
}
return osVersion;
});

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

@ -75,7 +75,7 @@ EXTRA_JS_MODULES += [
'TelemetryTimestamps.jsm',
'Timer.jsm',
'Troubleshoot.jsm',
'UpdateChannel.jsm',
'UpdateUtils.jsm',
'WebChannel.jsm',
'WindowDraggingUtils.jsm',
'ZipUtils.jsm',

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

@ -11,6 +11,9 @@ Cu.import("resource://gre/modules/FileUtils.jsm");
Cu.import("resource://testing-common/httpd.js");
Cu.import("resource://gre/modules/Promise.jsm");
Cu.import("resource://gre/modules/Preferences.jsm")
Cu.import("resource://gre/modules/UpdateUtils.jsm");
let { computeHash } = Cu.import("resource://gre/modules/addons/ProductAddonChecker.jsm");
do_get_profile();
@ -430,7 +433,7 @@ function* test_checkForAddons_installAddon(id, includeSize, wantInstallReject) {
let data = "e~=0.5772156649";
let zipFile = createNewZipFile(zipFileName, data);
let hashFunc = "sha256";
let expectedDigest = yield GMPDownloader.computeHash(hashFunc, zipFile);
let expectedDigest = yield computeHash(hashFunc, zipFile.path);
let fileSize = zipFile.fileSize;
if (wantInstallReject) {
fileSize = 1;
@ -456,7 +459,6 @@ function* test_checkForAddons_installAddon(id, includeSize, wantInstallReject) {
let gmpAddon = gmpAddons[0];
do_check_false(gmpAddon.isInstalled);
GMPInstallManager.overrideLeaveDownloadedZip = true;
try {
let extractedPaths = yield installManager.installAddon(gmpAddon);
if (wantInstallReject) {
@ -474,14 +476,6 @@ function* test_checkForAddons_installAddon(id, includeSize, wantInstallReject) {
let readData = readStringFromFile(extractedFile);
do_check_eq(readData, data);
// Check that the downloaded zip matches the offered zip exactly
let downloadedGMPFile = FileUtils.getFile("TmpD",
[gmpAddon.id + ".zip"]);
do_check_true(downloadedGMPFile.exists());
let downloadedBytes = getBinaryFileData(downloadedGMPFile);
let sourceBytes = getBinaryFileData(zipFile);
do_check_true(compareBinaryData(downloadedBytes, sourceBytes));
// Make sure the prefs are set correctly
do_check_true(!!GMPScope.GMPPrefs.get(
GMPScope.GMPPrefs.KEY_PLUGIN_LAST_UPDATE, "", gmpAddon.id));
@ -490,7 +484,7 @@ function* test_checkForAddons_installAddon(id, includeSize, wantInstallReject) {
"1.1");
do_check_eq(GMPScope.GMPPrefs.get(GMPScope.GMPPrefs.KEY_PLUGIN_ABI, "",
gmpAddon.id),
GMPScope.GMPUtils.ABI());
UpdateUtils.ABI);
// Make sure it reports as being installed
do_check_true(gmpAddon.isInstalled);
@ -498,16 +492,9 @@ function* test_checkForAddons_installAddon(id, includeSize, wantInstallReject) {
extractedFile.parent.remove(true);
zipFile.remove(false);
httpServer.stop(function() {});
do_print("Removing downloaded GMP file: " + downloadedGMPFile.path);
downloadedGMPFile.remove(false);
installManager.uninit();
} catch(ex) {
zipFile.remove(false);
let downloadedGMPFile = FileUtils.getFile("TmpD",
[gmpAddon.id + ".zip"]);
do_print("Removing downloaded GMP file from exception handler: " +
downloadedGMPFile.path);
downloadedGMPFile.remove(false);
if (!wantInstallReject) {
do_throw("install update should not reject");
}
@ -798,45 +785,6 @@ function overrideXHR(status, response, options) {
return overrideXHR.myxhr;
}
/**
* Compares binary data of 2 arrays and returns true if they are the same
*
* @param arr1 The first array to compare
* @param arr2 The second array to compare
*/
function compareBinaryData(arr1, arr2) {
do_check_eq(arr1.length, arr2.length);
for (let i = 0; i < arr1.length; i++) {
if (arr1[i] != arr2[i]) {
do_print("Data differs at index " + i +
", arr1: " + arr1[i] + ", arr2: " + arr2[i]);
return false;
}
}
return true;
}
/**
* Reads a file's data and returns it
*
* @param file The file to read the data from
* @return array of bytes for the data in the file.
*/
function getBinaryFileData(file) {
let fileStream = Cc["@mozilla.org/network/file-input-stream;1"].
createInstance(Ci.nsIFileInputStream);
// Open as RD_ONLY with default permissions.
fileStream.init(file, FileUtils.MODE_RDONLY, FileUtils.PERMS_FILE, 0);
// Check the returned size versus the expected size.
let stream = Cc["@mozilla.org/binaryinputstream;1"].
createInstance(Ci.nsIBinaryInputStream);
stream.setInputStream(fileStream);
let bytes = stream.readByteArray(stream.available());
fileStream.close();
return bytes;
}
/**
* Creates a new zip file containing a file with the specified data
* @param zipName The name of the zip file

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

@ -3,8 +3,10 @@
* 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/. */
Components.utils.import("resource://gre/modules/Preferences.jsm");
Components.utils.import("resource://gre/modules/UpdateChannel.jsm");
const { utils: Cu } = Components;
Cu.import("resource://gre/modules/Preferences.jsm");
Cu.import("resource://gre/modules/UpdateUtils.jsm");
const PREF_APP_UPDATE_CHANNEL = "app.update.channel";
const TEST_CHANNEL = "TestChannel";
@ -13,24 +15,24 @@ const TEST_PARTNER_A = "TestPartnerA";
const PREF_PARTNER_B = "app.partner.test_partner_b";
const TEST_PARTNER_B = "TestPartnerB";
function test_get() {
add_task(function* test_updatechannel() {
let defaultPrefs = new Preferences({ defaultBranch: true });
let currentChannel = defaultPrefs.get(PREF_APP_UPDATE_CHANNEL);
do_check_eq(UpdateChannel.get(), currentChannel);
do_check_eq(UpdateChannel.get(false), currentChannel);
do_check_eq(UpdateUtils.UpdateChannel, currentChannel);
do_check_eq(UpdateUtils.getUpdateChannel(true), currentChannel);
do_check_eq(UpdateUtils.getUpdateChannel(false), currentChannel);
defaultPrefs.set(PREF_APP_UPDATE_CHANNEL, TEST_CHANNEL);
do_check_eq(UpdateChannel.get(), TEST_CHANNEL);
do_check_eq(UpdateChannel.get(false), TEST_CHANNEL);
do_check_eq(UpdateUtils.UpdateChannel, TEST_CHANNEL);
do_check_eq(UpdateUtils.getUpdateChannel(true), TEST_CHANNEL);
do_check_eq(UpdateUtils.getUpdateChannel(false), TEST_CHANNEL);
defaultPrefs.set(PREF_PARTNER_A, TEST_PARTNER_A);
defaultPrefs.set(PREF_PARTNER_B, TEST_PARTNER_B);
do_check_eq(UpdateChannel.get(),
do_check_eq(UpdateUtils.UpdateChannel,
TEST_CHANNEL + "-cck-" + TEST_PARTNER_A + "-" + TEST_PARTNER_B);
do_check_eq(UpdateChannel.get(false), TEST_CHANNEL);
}
function run_test() {
test_get();
}
do_check_eq(UpdateUtils.getUpdateChannel(true),
TEST_CHANNEL + "-cck-" + TEST_PARTNER_A + "-" + TEST_PARTNER_B);
do_check_eq(UpdateUtils.getUpdateChannel(false), TEST_CHANNEL);
});

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

@ -0,0 +1,292 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
Cu.import("resource://gre/modules/UpdateUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/AppConstants.jsm");
Cu.import("resource://testing-common/AppInfo.jsm");
Cu.import("resource://gre/modules/ctypes.jsm");
const PREF_APP_UPDATE_CHANNEL = "app.update.channel";
const PREF_APP_PARTNER_BRANCH = "app.partner.";
const PREF_DISTRIBUTION_ID = "distribution.id";
const PREF_DISTRIBUTION_VERSION = "distribution.version";
const URL_PREFIX = "http://localhost/";
const MSG_SHOULD_EQUAL = " should equal the expected value";
updateAppInfo();
const gAppInfo = getAppInfo();
const gDefaultPrefBranch = Services.prefs.getDefaultBranch(null);
function setUpdateChannel(aChannel) {
gDefaultPrefBranch.setCharPref(PREF_APP_UPDATE_CHANNEL, aChannel);
}
function getServicePack() {
// NOTE: This function is a helper function and not a test. Thus,
// it uses throw() instead of do_throw(). Any tests that use this function
// should catch exceptions thrown in this function and deal with them
// appropriately (usually by calling do_throw).
const BYTE = ctypes.uint8_t;
const WORD = ctypes.uint16_t;
const DWORD = ctypes.uint32_t;
const WCHAR = ctypes.char16_t;
const BOOL = ctypes.int;
// This structure is described at:
// http://msdn.microsoft.com/en-us/library/ms724833%28v=vs.85%29.aspx
const SZCSDVERSIONLENGTH = 128;
const OSVERSIONINFOEXW = new ctypes.StructType('OSVERSIONINFOEXW',
[
{dwOSVersionInfoSize: DWORD},
{dwMajorVersion: DWORD},
{dwMinorVersion: DWORD},
{dwBuildNumber: DWORD},
{dwPlatformId: DWORD},
{szCSDVersion: ctypes.ArrayType(WCHAR, SZCSDVERSIONLENGTH)},
{wServicePackMajor: WORD},
{wServicePackMinor: WORD},
{wSuiteMask: WORD},
{wProductType: BYTE},
{wReserved: BYTE}
]);
let kernel32 = ctypes.open("kernel32");
try {
let GetVersionEx = kernel32.declare("GetVersionExW",
ctypes.default_abi,
BOOL,
OSVERSIONINFOEXW.ptr);
let winVer = OSVERSIONINFOEXW();
winVer.dwOSVersionInfoSize = OSVERSIONINFOEXW.size;
if (0 === GetVersionEx(winVer.address())) {
// Using "throw" instead of "do_throw" (see NOTE above)
throw("Failure in GetVersionEx (returned 0)");
}
return winVer.wServicePackMajor + "." + winVer.wServicePackMinor;
} finally {
kernel32.close();
}
}
function getProcArchitecture() {
// NOTE: This function is a helper function and not a test. Thus,
// it uses throw() instead of do_throw(). Any tests that use this function
// should catch exceptions thrown in this function and deal with them
// appropriately (usually by calling do_throw).
const WORD = ctypes.uint16_t;
const DWORD = ctypes.uint32_t;
// This structure is described at:
// http://msdn.microsoft.com/en-us/library/ms724958%28v=vs.85%29.aspx
const SYSTEM_INFO = new ctypes.StructType('SYSTEM_INFO',
[
{wProcessorArchitecture: WORD},
{wReserved: WORD},
{dwPageSize: DWORD},
{lpMinimumApplicationAddress: ctypes.voidptr_t},
{lpMaximumApplicationAddress: ctypes.voidptr_t},
{dwActiveProcessorMask: DWORD.ptr},
{dwNumberOfProcessors: DWORD},
{dwProcessorType: DWORD},
{dwAllocationGranularity: DWORD},
{wProcessorLevel: WORD},
{wProcessorRevision: WORD}
]);
let kernel32 = ctypes.open("kernel32");
try {
let GetNativeSystemInfo = kernel32.declare("GetNativeSystemInfo",
ctypes.default_abi,
ctypes.void_t,
SYSTEM_INFO.ptr);
let sysInfo = SYSTEM_INFO();
// Default to unknown
sysInfo.wProcessorArchitecture = 0xffff;
GetNativeSystemInfo(sysInfo.address());
switch(sysInfo.wProcessorArchitecture) {
case 9:
return "x64";
case 6:
return "IA64";
case 0:
return "x86";
default:
// Using "throw" instead of "do_throw" (see NOTE above)
throw("Unknown architecture returned from GetNativeSystemInfo: " + sysInfo.wProcessorArchitecture);
}
} finally {
kernel32.close();
}
}
// Helper function for formatting a url and getting the result we're
// interested in
function getResult(url) {
url = UpdateUtils.formatUpdateURL(url);
return url.substr(URL_PREFIX.length).split("/")[0];
}
// url constructed with %PRODUCT%
add_task(function* test_product() {
let url = URL_PREFIX + "%PRODUCT%/";
Assert.equal(getResult(url), gAppInfo.name,
"the url param for %PRODUCT%" + MSG_SHOULD_EQUAL);
});
// url constructed with %VERSION%
add_task(function* test_version() {
let url = URL_PREFIX + "%VERSION%/";
Assert.equal(getResult(url), gAppInfo.version,
"the url param for %VERSION%" + MSG_SHOULD_EQUAL);
});
// url constructed with %BUILD_ID%
add_task(function* test_build_id() {
let url = URL_PREFIX + "%BUILD_ID%/";
Assert.equal(getResult(url), gAppInfo.appBuildID,
"the url param for %BUILD_ID%" + MSG_SHOULD_EQUAL);
});
// url constructed with %BUILD_TARGET%
// XXX TODO - it might be nice if we tested the actual ABI
add_task(function* test_build_target() {
let url = URL_PREFIX + "%BUILD_TARGET%/";
let abi;
try {
abi = gAppInfo.XPCOMABI;
} catch (e) {
do_throw("nsIXULAppInfo:XPCOMABI not defined\n");
}
if (AppConstants.platform == "macosx") {
// Mac universal build should report a different ABI than either macppc
// or mactel. This is necessary since nsUpdateService.js will set the ABI to
// Universal-gcc3 for Mac universal builds.
let macutils = Cc["@mozilla.org/xpcom/mac-utils;1"].
getService(Ci.nsIMacUtils);
if (macutils.isUniversalBinary) {
abi += "-u-" + macutils.architecturesInBinary;
}
} else if (AppConstants.platform == "win") {
// Windows build should report the CPU architecture that it's running on.
abi += "-" + getProcArchitecture();
}
Assert.equal(getResult(url), gAppInfo.OS + "_" + abi,
"the url param for %BUILD_TARGET%" + MSG_SHOULD_EQUAL);
});
// url constructed with %LOCALE%
// Bug 488936 added the update.locale file that stores the update locale
add_task(function* test_locale() {
// The code that gets the locale accesses the profile which is only available
// after calling do_get_profile in xpcshell tests. This prevents an error from
// being logged.
do_get_profile();
let url = URL_PREFIX + "%LOCALE%/";
Assert.equal(getResult(url), AppConstants.INSTALL_LOCALE,
"the url param for %LOCALE%" + MSG_SHOULD_EQUAL);
});
// url constructed with %CHANNEL%
add_task(function* test_channel() {
let url = URL_PREFIX + "%CHANNEL%/";
setUpdateChannel("test_channel");
Assert.equal(getResult(url), "test_channel",
"the url param for %CHANNEL%" + MSG_SHOULD_EQUAL);
});
// url constructed with %CHANNEL% with distribution partners
add_task(function* test_channel_distribution() {
let url = URL_PREFIX + "%CHANNEL%/";
gDefaultPrefBranch.setCharPref(PREF_APP_PARTNER_BRANCH + "test_partner1",
"test_partner1");
gDefaultPrefBranch.setCharPref(PREF_APP_PARTNER_BRANCH + "test_partner2",
"test_partner2");
Assert.equal(getResult(url),
"test_channel-cck-test_partner1-test_partner2",
"the url param for %CHANNEL%" + MSG_SHOULD_EQUAL);
});
// url constructed with %PLATFORM_VERSION%
add_task(function* test_platform_version() {
let url = URL_PREFIX + "%PLATFORM_VERSION%/";
Assert.equal(getResult(url), gAppInfo.platformVersion,
"the url param for %PLATFORM_VERSION%" + MSG_SHOULD_EQUAL);
});
// url constructed with %OS_VERSION%
add_task(function* test_os_version() {
let url = URL_PREFIX + "%OS_VERSION%/";
let osVersion;
let sysInfo = Cc["@mozilla.org/system-info;1"].getService(Ci.nsIPropertyBag2);
osVersion = sysInfo.getProperty("name") + " " + sysInfo.getProperty("version");
if (AppConstants.platform == "win") {
try {
let servicePack = getServicePack();
osVersion += "." + servicePack;
} catch (e) {
do_throw("Failure obtaining service pack: " + e);
}
if ("5.0" === sysInfo.getProperty("version")) { // Win2K
osVersion += " (unknown)";
} else {
try {
osVersion += " (" + getProcArchitecture() + ")";
} catch (e) {
do_throw("Failed to obtain processor architecture: " + e);
}
}
}
if (osVersion) {
try {
osVersion += " (" + sysInfo.getProperty("secondaryLibrary") + ")";
} catch (e) {
// Not all platforms have a secondary widget library, so an error is
// nothing to worry about.
}
osVersion = encodeURIComponent(osVersion);
}
Assert.equal(getResult(url), osVersion,
"the url param for %OS_VERSION%" + MSG_SHOULD_EQUAL);
});
// url constructed with %DISTRIBUTION%
add_task(function* test_distribution() {
let url = URL_PREFIX + "%DISTRIBUTION%/";
gDefaultPrefBranch.setCharPref(PREF_DISTRIBUTION_ID, "test_distro");
Assert.equal(getResult(url), "test_distro",
"the url param for %DISTRIBUTION%" + MSG_SHOULD_EQUAL);
});
// url constructed with %DISTRIBUTION_VERSION%
add_task(function* test_distribution_version() {
let url = URL_PREFIX + "%DISTRIBUTION_VERSION%/";
gDefaultPrefBranch.setCharPref(PREF_DISTRIBUTION_VERSION, "test_distro_version");
Assert.equal(getResult(url), "test_distro_version",
"the url param for %DISTRIBUTION_VERSION%" + MSG_SHOULD_EQUAL);
});
add_task(function* test_custom() {
Services.prefs.setCharPref("app.update.custom", "custom");
let url = URL_PREFIX + "%CUSTOM%/";
Assert.equal(getResult(url), "custom",
"the url query string for %CUSTOM%" + MSG_SHOULD_EQUAL);
});

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

@ -57,6 +57,8 @@ skip-if = toolkit == 'android'
skip-if = toolkit == 'android'
[test_timer.js]
skip-if = toolkit == 'android'
[test_UpdateUtils_url.js]
[test_UpdateUtils_updatechannel.js]
[test_web_channel.js]
[test_web_channel_broker.js]
[test_ZipUtils.js]

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

@ -859,6 +859,13 @@ var AddonManagerInternal = {
logger.debug(`Provider finished startup: ${providerName(aProvider)}`);
},
_getProviderByName(aName) {
for (let provider of this.providers) {
if (providerName(provider) == aName)
return provider;
}
},
/**
* Initializes the AddonManager, loading any known providers and initializing
* them.
@ -1464,9 +1471,9 @@ var AddonManagerInternal = {
let buPromise = Task.spawn(function* backgroundUpdateTask() {
let hotfixID = this.hotfixID;
let checkHotfix = hotfixID &&
Services.prefs.getBoolPref(PREF_APP_UPDATE_ENABLED) &&
Services.prefs.getBoolPref(PREF_APP_UPDATE_AUTO);
let appUpdateEnabled = Services.prefs.getBoolPref(PREF_APP_UPDATE_ENABLED) &&
Services.prefs.getBoolPref(PREF_APP_UPDATE_AUTO);
let checkHotfix = hotfixID && appUpdateEnabled;
logger.debug("Background update check beginning");
@ -1613,6 +1620,15 @@ var AddonManagerInternal = {
}
}
if (appUpdateEnabled) {
try {
yield AddonManagerInternal._getProviderByName("XPIProvider").updateSystemAddons();
}
catch (e) {
logger.warn("Failed to update system addons", e);
}
}
logger.debug("Background update check complete");
Services.obs.notifyObservers(null,
"addons-background-update-complete",

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

@ -19,6 +19,7 @@ Cu.import("resource://gre/modules/Log.jsm");
Cu.import("resource://gre/modules/Task.jsm");
Cu.import("resource://gre/modules/GMPUtils.jsm");
Cu.import("resource://gre/modules/AppConstants.jsm");
Cu.import("resource://gre/modules/UpdateUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(
this, "GMPInstallManager", "resource://gre/modules/GMPInstallManager.jsm");
@ -490,8 +491,8 @@ GMPWrapper.prototype = {
return { installed: false, valid: true };
}
let abi = GMPPrefs.get(GMPPrefs.KEY_PLUGIN_ABI, GMPUtils.ABI(), this._plugin.id);
if (abi != GMPUtils.ABI()) {
let abi = GMPPrefs.get(GMPPrefs.KEY_PLUGIN_ABI, UpdateUtils.ABI, this._plugin.id);
if (abi != UpdateUtils.ABI) {
// ABI doesn't match. Possibly this is a profile migrated across platforms
// or from 32 -> 64 bit.
return {

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

@ -0,0 +1,322 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
this.EXPORTED_SYMBOLS = [ "ProductAddonChecker" ];
Cu.import("resource://gre/modules/Task.jsm");
Cu.import("resource://gre/modules/Log.jsm");
Cu.import("resource://gre/modules/CertUtils.jsm");
Cu.import("resource://gre/modules/FileUtils.jsm");
Cu.import("resource://gre/modules/NetUtil.jsm");
Cu.import("resource://gre/modules/osfile.jsm");
let logger = Log.repository.getLogger("addons.productaddons");
/**
* Number of milliseconds after which we need to cancel `downloadXML`.
*
* Bug 1087674 suggests that the XHR we use in `downloadXML` may
* never terminate in presence of network nuisances (e.g. strange
* antivirus behavior). This timeout is a defensive measure to ensure
* that we fail cleanly in such case.
*/
const TIMEOUT_DELAY_MS = 20000;
// Chunk size for the incremental downloader
const DOWNLOAD_CHUNK_BYTES_SIZE = 300000;
// Incremental downloader interval
const DOWNLOAD_INTERVAL = 0;
// How much of a file to read into memory at a time for hashing
const HASH_CHUNK_SIZE = 8192;
/**
* Gets the status of an XMLHttpRequest either directly or from its underlying
* channel.
*
* @param request
* The XMLHttpRequest.
* @return an integer status value.
*/
function getRequestStatus(request) {
let status = null;
try {
status = request.status;
}
catch (e) {
}
if (status != null) {
return status;
}
return request.channel.QueryInterface(Ci.nsIRequest).status;
}
/**
* Downloads an XML document from a URL optionally testing the SSL certificate
* for certain attributes.
*
* @param url
* The url to download from.
* @param allowNonBuiltIn
* Whether to trust SSL certificates without a built-in CA issuer.
* @param allowedCerts
* The list of certificate attributes to match the SSL certificate
* against or null to skip checks.
* @return a promise that resolves to the DOM document downloaded or rejects
* with a JS exception in case of error.
*/
function downloadXML(url, allowNonBuiltIn = false, allowedCerts = null) {
return new Promise((resolve, reject) => {
let request = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].
createInstance(Ci.nsISupports);
// This is here to let unit test code override XHR
if (request.wrappedJSObject) {
request = request.wrappedJSObject;
}
request.open("GET", url, true);
request.channel.notificationCallbacks = new BadCertHandler(allowNonBuiltIn);
// Prevent the request from reading from the cache.
request.channel.loadFlags |= Ci.nsIRequest.LOAD_BYPASS_CACHE;
// Prevent the request from writing to the cache.
request.channel.loadFlags |= Ci.nsIRequest.INHIBIT_CACHING;
request.timeout = TIMEOUT_DELAY_MS;
request.overrideMimeType("text/xml");
// The Cache-Control header is only interpreted by proxies and the
// final destination. It does not help if a resource is already
// cached locally.
request.setRequestHeader("Cache-Control", "no-cache");
// HTTP/1.0 servers might not implement Cache-Control and
// might only implement Pragma: no-cache
request.setRequestHeader("Pragma", "no-cache");
let fail = (event) => {
let request = event.target;
let status = getRequestStatus(request);
let message = "Failed downloading XML, status: " + status + ", reason: " + event.type;
logger.warn(message);
let ex = new Error(message);
ex.status = status;
reject(ex);
};
let success = (event) => {
logger.info("Completed downloading document");
let request = event.target;
try {
checkCert(request.channel, allowNonBuiltIn, allowedCerts);
} catch (ex) {
logger.error("Request failed certificate checks: " + ex);
ex.status = getRequestStatus(request);
reject(ex);
return;
}
resolve(request.responseXML);
};
request.addEventListener("error", fail, false);
request.addEventListener("abort", fail, false);
request.addEventListener("timeout", fail, false);
request.addEventListener("load", success, false);
logger.info("sending request to: " + url);
request.send(null);
});
}
/**
* Parses a list of add-ons from a DOM document.
*
* @param document
* The DOM document to parse.
* @return null if there is no <addons> element otherwise an array of the addons
* listed.
*/
function parseXML(document) {
// Check that the root element is correct
if (document.documentElement.localName != "updates") {
throw new Error("got node name: " + document.documentElement.localName +
", expected: updates");
}
// Check if there are any addons elements in the updates element
let addons = document.querySelector("updates:root > addons");
if (!addons) {
return null;
}
let results = [];
let addonList = document.querySelectorAll("updates:root > addons > addon");
for (let addonElement of addonList) {
let addon = {};
for (let name of ["id", "URL", "hashFunction", "hashValue", "version", "size"]) {
if (addonElement.hasAttribute(name)) {
addon[name] = addonElement.getAttribute(name);
}
}
addon.size = Number(addon.size) || undefined;
results.push(addon);
}
return results;
}
/**
* Downloads file from a URL using the incremental file downloader.
*
* @param url
* The url to download from.
* @return a promise that resolves to the path of a temporary file or rejects
* with a JS exception in case of error.
*/
function downloadFile(url) {
return new Promise((resolve, reject) => {
let observer = {
onStartRequest: function() {},
onStopRequest: function(request, context, status) {
if (!Components.isSuccessCode(status)) {
logger.warn("File download failed: 0x" + status.toString(16));
tmpFile.remove(true);
reject(Components.Exception("File download failed", status));
return;
}
resolve(tmpFile.path);
}
};
let uri = NetUtil.newURI(url);
let request = Cc["@mozilla.org/network/incremental-download;1"].
createInstance(Ci.nsIIncrementalDownload);
let tmpFile = FileUtils.getFile("TmpD", ["tmpaddon"]);
tmpFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, FileUtils.PERMS_FILE);
logger.info("Downloading from " + uri.spec + " to " + tmpFile.path);
request.init(uri, tmpFile, DOWNLOAD_CHUNK_BYTES_SIZE, DOWNLOAD_INTERVAL);
request.start(observer, null);
});
}
/**
* Convert a string containing binary values to hex.
*/
function binaryToHex(input) {
let result = "";
for (let i = 0; i < input.length; ++i) {
let hex = input.charCodeAt(i).toString(16);
if (hex.length == 1) {
hex = "0" + hex;
}
result += hex;
}
return result;
}
/**
* Calculates the hash of a file.
*
* @param hashFunction
* The type of hash function to use, must be supported by nsICryptoHash.
* @param path
* The path of the file to hash.
* @return a promise that resolves to hash of the file or rejects with a JS
* exception in case of error.
*/
let computeHash = Task.async(function*(hashFunction, path) {
let file = yield OS.File.open(path, { existing: true, read: true });
try {
let hasher = Cc["@mozilla.org/security/hash;1"].
createInstance(Ci.nsICryptoHash);
hasher.initWithString(hashFunction);
let bytes;
do {
bytes = yield file.read(HASH_CHUNK_SIZE);
hasher.update(bytes, bytes.length);
} while (bytes.length == HASH_CHUNK_SIZE);
return binaryToHex(hasher.finish(false));
}
finally {
yield file.close();
}
});
/**
* Verifies that a downloaded file matches what was expected.
*
* @param properties
* The properties to check, `size` and `hashFunction` with `hashValue`
* are supported. Any properties missing won't be checked.
* @param path
* The path of the file to check.
* @return a promise that resolves if the file matched or rejects with a JS
* exception in case of error.
*/
let verifyFile = Task.async(function*(properties, path) {
if (properties.size !== undefined) {
let stat = yield OS.File.stat(path);
if (stat.size != properties.size) {
throw new Error("Downloaded file was " + stat.size + " bytes but expected " + properties.size + " bytes.");
}
}
if (properties.hashFunction !== undefined) {
let expectedDigest = properties.hashValue.toLowerCase();
let digest = yield computeHash(properties.hashFunction, path);
if (digest != expectedDigest) {
throw new Error("Hash was `" + digest + "` but expected `" + expectedDigest + "`.");
}
}
});
const ProductAddonChecker = {
/**
* Downloads a list of add-ons from a URL optionally testing the SSL
* certificate for certain attributes.
*
* @param url
* The url to download from.
* @param allowNonBuiltIn
* Whether to trust SSL certificates without a built-in CA issuer.
* @param allowedCerts
* The list of certificate attributes to match the SSL certificate
* against or null to skip checks.
* @return a promise that resolves to the list of add-ons or rejects with a JS
* exception in case of error.
*/
getProductAddonList: function(url, allowNonBuiltIn = false, allowedCerts = null) {
return downloadXML(url, allowNonBuiltIn, allowedCerts).then(parseXML);
},
/**
* Downloads an add-on to a local file and checks that it matches the expected
* file. The caller is responsible for deleting the temporary file returned.
*
* @param addon
* The addon to download.
* @return a promise that resolves to the temporary file downloaded or rejects
* with a JS exception in case of error.
*/
downloadAddon: Task.async(function*(addon) {
let path = yield downloadFile(addon.URL);
try {
yield verifyFile(addon, path);
return path;
}
catch (e) {
yield OS.File.remove(path);
throw e;
}
})
}

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

@ -42,6 +42,10 @@ XPCOMUtils.defineLazyModuleGetter(this, "BrowserToolboxProcess",
"resource:///modules/devtools/client/framework/ToolboxProcess.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "ConsoleAPI",
"resource://gre/modules/devtools/shared/Console.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "ProductAddonChecker",
"resource://gre/modules/addons/ProductAddonChecker.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "UpdateUtils",
"resource://gre/modules/UpdateUtils.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "Blocklist",
"@mozilla.org/extensions/blocklist;1",
@ -99,6 +103,7 @@ const PREF_BRANCH_INSTALLED_ADDON = "extensions.installedDistroAddon.";
const PREF_SHOWN_SELECTION_UI = "extensions.shownSelectionUI";
const PREF_INTERPOSITION_ENABLED = "extensions.interposition.enabled";
const PREF_SYSTEM_ADDON_SET = "extensions.systemAddonSet";
const PREF_SYSTEM_ADDON_UPDATE_URL = "extensions.systemAddon.update.url";
const PREF_EM_MIN_COMPAT_APP_VERSION = "extensions.minCompatibleAppVersion";
const PREF_EM_MIN_COMPAT_PLATFORM_VERSION = "extensions.minCompatiblePlatformVersion";
@ -310,6 +315,25 @@ LAZY_OBJECTS.forEach(name => {
});
// Behaves like Promise.all except waits for all promises to resolve/reject
// before resolving/rejecting itself
function waitForAllPromises(promises) {
return new Promise((resolve, reject) => {
let shouldReject = false;
let rejectValue = null;
let newPromises = [
for (p of promises)
p.catch(value => {
shouldReject = true;
rejectValue = value;
})
]
Promise.all(newPromises)
.then((results) => shouldReject ? reject(rejectValue) : resolve(results));
});
}
function findMatchingStaticBlocklistItem(aAddon) {
for (let item of STATIC_BLOCKLIST_PATTERNS) {
if ("creator" in item && typeof item.creator == "string") {
@ -2759,6 +2783,91 @@ this.XPIProvider = {
!XPIDatabase.writeAddonsList());
},
updateSystemAddons: Task.async(function XPI_updateSystemAddons() {
// Download the list of system add-ons
let url = Preferences.get(PREF_SYSTEM_ADDON_UPDATE_URL, null);
if (!url)
return;
url = UpdateUtils.formatUpdateURL(url);
logger.info(`Starting system add-on update check from ${url}.`);
let addonList = yield ProductAddonChecker.getProductAddonList(url);
// If there was no list then do nothing.
if (!addonList) {
logger.info("No system add-ons list was returned.");
return;
}
addonList = [for (spec of addonList) { spec, path: null, addon: null }];
// Bug 1204159: If this matches the current set in the profile or app locations
// then just switch to those
let systemAddonLocation = XPIProvider.installLocationsByName[KEY_APP_SYSTEM_ADDONS];
// Download all the add-ons
// Bug 1204158: If we already have some of these locally then just use those
let downloadAddon = Task.async(function*(item) {
try {
item.path = yield ProductAddonChecker.downloadAddon(item.spec);
item.addon = yield loadManifestFromFile(nsIFile(item.path), systemAddonLocation);
}
catch (e) {
logger.error(`Failed to download system add-on ${item.spec.id}`, e);
}
});
yield Promise.all([for (item of addonList) downloadAddon(item)]);
// The download promises all resolve regardless, now check if they all
// succeeded
let validateAddon = (item) => {
if (item.spec.id != item.addon.id) {
logger.warn(`Downloaded system add-on expected to be ${item.spec.id} but was ${item.addon.id}.`);
return false;
}
if (item.spec.version != item.addon.version) {
logger.warn(`Expected system add-on ${item.spec.id} to be version ${item.version} but was ${item.addon.version}.`);
return false;
}
if (!systemAddonLocation.isValidAddon(item.addon))
return false;
return true;
}
try {
if (!addonList.every(item => item.path && item.addon && validateAddon(item))) {
throw new Error("Rejecting updated system add-on set that either could not " +
"be downloaded or contained unusable add-ons.");
}
// Install into the install location
logger.info("Installing new system add-on set");
yield systemAddonLocation.installAddonSet([for (item of addonList) item.addon]);
// Bug 1204156: Switch to the new system add-ons without requiring a restart
}
finally {
// Delete the temporary files
logger.info("Deleting temporary files");
for (let item of addonList) {
// If this item downloaded delete the temporary file.
if (item.path) {
try {
yield OS.File.remove(item.path);
}
catch (e) {
logger.warn(`Failed to remove temporary file ${item.path}.`, e);
}
}
}
}
}),
/**
* Verifies that all installed add-ons are still correctly signed.
*/
@ -7356,40 +7465,110 @@ Object.assign(SystemAddonInstallLocation.prototype, {
return this._directory != null;
},
isValidAddon: function(aAddon) {
if (aAddon.appDisabled) {
logger.warn(`System add-on ${aAddon.id} isn't compatible with the application.`);
return false;
}
if (aAddon.unpack) {
logger.warn(`System add-on ${aAddon.id} isn't a packed add-on.`);
return false;
}
if (!aAddon.bootstrap) {
logger.warn(`System add-on ${aAddon.id} isn't restartless.`);
return false;
}
return true;
},
/**
* Tests whether the loaded add-on information matches what is expected.
*/
isValid: function(aAddons) {
for (let id of Object.keys(this._addonSet.addons)) {
if (!aAddons.has(id)) {
logger.warn("Expected add-on " + id + " is missing from the system add-on location.");
logger.warn(`Expected add-on ${id} is missing from the system add-on location.`);
return false;
}
let addon = aAddons.get(id);
if (addon.appDisabled) {
logger.warn("System add-on " + id + " isn't compatible with the application.");
return false;
}
if (addon.unpack) {
logger.warn("System add-on " + id + " isn't a packed add-on.");
return false;
}
if (!addon.bootstrap) {
logger.warn("System add-on " + id + " isn't restartless.");
return false;
}
if (addon.version != this._addonSet.addons[id].version) {
logger.warn("System add-on " + id + " wasn't the correct version.");
logger.warn(`Expected system add-on ${id} to be version ${this._addonSet.addons[id].version} but was ${addon.version}.`);
return false;
}
if (!this.isValidAddon(addon))
return false;
}
return true;
},
/**
* Installs a new set of system add-ons into the location and updates the
* add-on set in prefs. We wait to switch state until a restart.
*/
installAddonSet: Task.async(function(aAddons) {
// Make sure the base dir exists
yield OS.File.makeDir(this._baseDir.path, { ignoreExisting: true });
let newDir = this._baseDir.clone();
let uuidGen = Cc["@mozilla.org/uuid-generator;1"].
getService(Ci.nsIUUIDGenerator);
newDir.append("blank");
while (true) {
newDir.leafName = uuidGen.generateUUID().toString();
try {
yield OS.File.makeDir(newDir.path, { ignoreExisting: false });
break;
}
catch (e) {
// Directory already exists, pick another
}
}
let copyAddon = Task.async(function*(addon) {
let target = OS.Path.join(newDir.path, addon.id + ".xpi");
logger.info(`Copying ${addon.id} from ${addon._sourceBundle.path} to ${target}.`);
try {
yield OS.File.copy(addon._sourceBundle.path, target);
}
catch (e) {
logger.error(`Failed to copy ${addon.id} from ${addon._sourceBundle.path} to ${target}.`, e);
throw e;
}
addon._sourceBundle = new nsIFile(target);
});
try {
yield waitForAllPromises([for (addon of aAddons) copyAddon(addon)]);
}
catch (e) {
try {
yield OS.File.removeDir(newDir.path, { ignorePermissions: true });
}
catch (e) {
logger.warn(`Failed to remove new system add-on directory ${newDir.path}.`, e);
}
throw e;
}
// All add-ons in position, create the new state and store it in prefs
let state = { schema: 1, directory: newDir.leafName, addons: {} };
for (let addon of aAddons) {
state.addons[addon.id] = {
version: addon.version
}
}
this._saveAddonSet(state);
}),
});
#ifdef XP_WIN

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

@ -12,6 +12,7 @@ EXTRA_JS_MODULES.addons += [
'Content.js',
'GMPProvider.jsm',
'LightweightThemeImageOptimizer.jsm',
'ProductAddonChecker.jsm',
'SpellCheckDictionaryBootstrap.js',
'WebExtensionBootstrap.js',
]

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

@ -23,8 +23,8 @@ try {
XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
"resource://gre/modules/FileUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "UpdateChannel",
"resource://gre/modules/UpdateChannel.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "UpdateUtils",
"resource://gre/modules/UpdateUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "OS",
"resource://gre/modules/osfile.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Task",
@ -559,7 +559,7 @@ Blocklist.prototype = {
dsURI = dsURI.replace(/%BUILD_TARGET%/g, gApp.OS + "_" + gABI);
dsURI = dsURI.replace(/%OS_VERSION%/g, gOSVersion);
dsURI = dsURI.replace(/%LOCALE%/g, getLocale());
dsURI = dsURI.replace(/%CHANNEL%/g, UpdateChannel.get());
dsURI = dsURI.replace(/%CHANNEL%/g, UpdateUtils.UpdateChannel);
dsURI = dsURI.replace(/%PLATFORM_VERSION%/g, gApp.platformVersion);
dsURI = dsURI.replace(/%DISTRIBUTION%/g,
getDistributionPrefValue(PREF_APP_DISTRIBUTION));

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

@ -0,0 +1 @@
Not an xml file!

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

@ -0,0 +1,3 @@
<?xml version="1.0" encoding="UTF-8"?>
<foobar></barfoo>

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

@ -0,0 +1,3 @@
<?xml version="1.0" encoding="UTF-8"?>
<test></test>

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

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<updates>
<addons></addons>
</updates>

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

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<updates>
<addons>
<addon id="test1" URL="http://example.com/test1.xpi"/>
<addon id="test2" URL="http://example.com/test2.xpi" hashFunction="md5" hashValue="djhfgsjdhf"/>
<addon id="test3" URL="http://example.com/test3.xpi" version="1.0" size="45"/>
<addon id="test4"/>
<addon URL="http://example.com/test5.xpi"/>
</addons>
</updates>

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

@ -0,0 +1,3 @@
<?xml version="1.0" encoding="UTF-8"?>
<updates></updates>

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

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

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

@ -1,18 +0,0 @@
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) {
}

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

@ -1,23 +0,0 @@
<?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>

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

@ -1,18 +0,0 @@
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) {
}

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

@ -1,23 +0,0 @@
<?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>

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

@ -1,18 +0,0 @@
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) {
}

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

@ -1,23 +0,0 @@
<?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>

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

@ -1,18 +0,0 @@
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) {
}

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

@ -1,23 +0,0 @@
<?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>

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

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

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

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

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

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