Merge mozilla-central to mozilla-inbound

This commit is contained in:
Ed Morley 2011-12-02 18:55:28 +00:00
Родитель 9d7715e47c 22cd186b2f
Коммит dabaf3038a
43 изменённых файлов: 2576 добавлений и 324 удалений

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

@ -203,7 +203,7 @@ pref("app.update.incompatible.mode", 0);
// .. etc ..
//
pref("extensions.update.enabled", true);
pref("extensions.update.url", "https://versioncheck.addons.mozilla.org/update/VersionCheck.php?reqVersion=%REQ_VERSION%&id=%ITEM_ID%&version=%ITEM_VERSION%&maxAppVersion=%ITEM_MAXAPPVERSION%&status=%ITEM_STATUS%&appID=%APP_ID%&appVersion=%APP_VERSION%&appOS=%APP_OS%&appABI=%APP_ABI%&locale=%APP_LOCALE%&currentAppVersion=%CURRENT_APP_VERSION%&updateType=%UPDATE_TYPE%");
pref("extensions.update.url", "https://versioncheck.addons.mozilla.org/update/VersionCheck.php?reqVersion=%REQ_VERSION%&id=%ITEM_ID%&version=%ITEM_VERSION%&maxAppVersion=%ITEM_MAXAPPVERSION%&status=%ITEM_STATUS%&appID=%APP_ID%&appVersion=%APP_VERSION%&appOS=%APP_OS%&appABI=%APP_ABI%&locale=%APP_LOCALE%&currentAppVersion=%CURRENT_APP_VERSION%&updateType=%UPDATE_TYPE%&compatMode=%COMPATIBILITY_MODE%");
pref("extensions.update.interval", 86400); // Check for updates to Extensions and
// Themes every day
// Non-symmetric (not shared by extensions) extension-specific [update] preferences

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

@ -208,6 +208,7 @@ let TabView = {
this._iframe = document.createElement("iframe");
this._iframe.id = "tab-view";
this._iframe.setAttribute("transparent", "true");
this._iframe.setAttribute("tooltip", "tab-view-tooltip");
this._iframe.flex = 1;
let self = this;
@ -235,6 +236,12 @@ let TabView = {
this._iframe.setAttribute("src", "chrome://browser/content/tabview.html");
this._deck.appendChild(this._iframe);
// ___ create tooltip
let tooltip = document.createElement("tooltip");
tooltip.id = "tab-view-tooltip";
tooltip.setAttribute("onpopupshowing", "return TabView.fillInTooltip(document.tooltipNode);");
document.getElementById("mainPopupSet").appendChild(tooltip);
},
// ----------
@ -353,8 +360,10 @@ let TabView = {
if (!tabItem)
return;
// Switch to the new tab
window.gBrowser.selectedTab = tabItem.tab;
if (gBrowser.selectedTab.pinned)
groupItems.updateActiveGroupItemAndTabBar(tabItem, {dontSetActiveTabInGroup: true});
else
gBrowser.selectedTab = tabItem.tab;
});
}
}, true);
@ -440,5 +449,29 @@ let TabView = {
// show banner
this._window.UI.notifySessionRestoreEnabled();
}
},
// ----------
// Function: fillInTooltip
// Fills in the tooltip text.
fillInTooltip: function fillInTooltip(tipElement) {
let retVal = false;
let titleText = null;
let direction = tipElement.ownerDocument.dir;
while (!titleText && tipElement) {
if (tipElement.nodeType == Node.ELEMENT_NODE)
titleText = tipElement.getAttribute("title");
tipElement = tipElement.parentNode;
}
let tipNode = document.getElementById("tab-view-tooltip");
tipNode.style.direction = direction;
if (titleText) {
tipNode.setAttribute("label", titleText);
retVal = true;
}
return retVal;
}
};

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

@ -148,6 +148,7 @@ function GroupItem(listOfEls, options) {
.click(function() {
self.closeAll();
})
.attr("title", tabviewString("groupItem.closeGroup"))
.appendTo($container);
// ___ Title
@ -198,7 +199,8 @@ function GroupItem(listOfEls, options) {
e.stopPropagation();
})
.keypress(handleKeyPress)
.keyup(handleKeyUp);
.keyup(handleKeyUp)
.attr("title", tabviewString("groupItem.defaultName"));
this.$titleShield
.mousedown(function(e) {
@ -212,7 +214,8 @@ function GroupItem(listOfEls, options) {
if (!self.isDragging)
self.focusTitle();
});
})
.attr("title", tabviewString("groupItem.defaultName"));
if (options.focusTitle)
this.focusTitle();
@ -904,6 +907,7 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
.appendTo(this.$undoContainer);
let undoClose = iQ("<span/>")
.addClass("close")
.attr("title", tabviewString("groupItem.discardClosedGroup"))
.appendTo(this.$undoContainer);
this.$undoContainer.css({
@ -1143,7 +1147,7 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
let closed = options.dontClose ? false : this.closeIfEmpty();
if (closed ||
(this._children.length == 0 && !gBrowser.selectedTab.pinned &&
(this._children.length == 0 && !gBrowser._numPinnedTabs &&
!item.isDragging)) {
this._makeLastActiveGroupItemActive();
} else if (!options.dontArrange) {
@ -2230,29 +2234,31 @@ let GroupItems = {
}
toClose.forEach(function(groupItem) {
// All remaining children in to-be-closed groups are re-used by
// session restore. Reconnect them so that they're put into their
// right groups.
let children = groupItem.getChildren().concat();
children.forEach(function (tabItem) {
if (tabItem.parent && tabItem.parent.hidden)
// all tabs still existing in closed groups will be moved to new
// groups. prepare them to be reconnected later.
groupItem.getChildren().forEach(function (tabItem) {
if (tabItem.parent.hidden)
iQ(tabItem.container).show();
tabItem._reconnected = false;
// sanity check the tab's groupID
let tabData = Storage.getTabData(tabItem.tab);
let parentGroup = GroupItems.groupItem(tabData.groupID);
// correct the tab's groupID if necessary
if (!parentGroup || -1 < toClose.indexOf(parentGroup)) {
tabData.groupID = activeGroupId || Object.keys(groupItemData)[0];
Storage.saveTab(tabItem.tab, tabData);
if (tabData) {
let parentGroup = GroupItems.groupItem(tabData.groupID);
// the tab's group id could be invalid or point to a non-existing
// group. correct it by assigning the active group id or the first
// group of the just restored session.
if (!parentGroup || -1 < toClose.indexOf(parentGroup)) {
tabData.groupID = activeGroupId || Object.keys(groupItemData)[0];
Storage.saveTab(tabItem.tab, tabData);
}
}
tabItem._reconnected = false;
tabItem._reconnect();
});
// this closes the group but not its children
groupItem.close({immediately: true});
});
}
@ -2466,10 +2472,14 @@ let GroupItems = {
// ----------
// Function: updateActiveGroupItemAndTabBar
// Sets active TabItem and GroupItem, and updates tab bar appropriately.
updateActiveGroupItemAndTabBar: function GroupItems_updateActiveGroupItemAndTabBar(tabItem) {
// Parameters:
// tabItem - the tab item
// options - is passed to UI.setActive() directly
updateActiveGroupItemAndTabBar:
function GroupItems_updateActiveGroupItemAndTabBar(tabItem, options) {
Utils.assertThrow(tabItem && tabItem.isATabItem, "tabItem must be a TabItem");
UI.setActive(tabItem);
UI.setActive(tabItem, options);
this._updateTabBar();
},

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

@ -431,13 +431,15 @@ let Search = {
iQ("#searchbox").keyup(function Search_init_box_keyup() {
self.perform();
});
})
.attr("title", tabviewString("button.searchTabs"));
iQ("#searchbutton").mousedown(function Search_init_button_mousedown() {
self._initiatedBy = "buttonclick";
self.ensureShown();
self.switchToInMode();
});
})
.attr("title", tabviewString("button.searchTabs"));
window.addEventListener("focus", function Search_init_window_focus() {
if (self.isEnabled()) {

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

@ -148,6 +148,8 @@ function TabItem(tab, options) {
this.droppable(true);
this.$close.attr("title", tabbrowserString("tabs.closeTab"));
TabItems.register(this);
// ___ reconnect to data from Storage
@ -204,7 +206,15 @@ TabItem.prototype = Utils.extend(new Item(), new Subscribable(), {
this._cachedImageData = imageData;
this.$cachedThumb.attr("src", this._cachedImageData).show();
this.$canvas.css({opacity: 0});
this.$tabTitle.text(tabData.title ? tabData.title : "");
let label = "";
let title;
if (tabData.title) {
label = tabData.title;
title = label + "\n" + tabData.url;
} else {
title = tabData.url;
}
this.$tabTitle.text(label).attr("title", title);
this._sendToSubscribers("showingCachedData");
},
@ -1003,10 +1013,10 @@ let TabItems = {
// ___ URL
let tabUrl = tab.linkedBrowser.currentURI.spec;
if (tabUrl != tabItem.url) {
let oldURL = tabItem.url;
tabItem.url = tabUrl;
tabItem.save();
}
tabItem.$container.attr("title", label + "\n" + tabUrl);
// ___ Make sure the tab is complete and ready for updating.
if (!this.isComplete(tab) && (!options || !options.force)) {

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

@ -13,8 +13,13 @@ XPCOMUtils.defineLazyGetter(this, "tabviewBundle", function() {
return Services.strings.
createBundle("chrome://browser/locale/tabview.properties");
});
XPCOMUtils.defineLazyGetter(this, "tabbrowserBundle", function() {
return Services.strings.
createBundle("chrome://browser/locale/tabbrowser.properties");
});
function tabviewString(name) tabviewBundle.GetStringFromName('tabview.' + name);
function tabbrowserString(name) tabbrowserBundle.GetStringFromName(name);
XPCOMUtils.defineLazyGetter(this, "gPrefBranch", function() {
return Services.prefs.getBranch("browser.panorama.");

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

@ -87,8 +87,9 @@ _BROWSER_FILES = \
browser_tabview_bug606905.js \
browser_tabview_bug607108.js \
browser_tabview_bug608037.js \
browser_tabview_bug608184.js \
browser_tabview_bug608153.js \
browser_tabview_bug608158.js \
browser_tabview_bug608184.js \
browser_tabview_bug608405.js \
browser_tabview_bug610208.js \
browser_tabview_bug610242.js \
@ -165,6 +166,8 @@ _BROWSER_FILES = \
browser_tabview_bug686654.js \
browser_tabview_bug697390.js \
browser_tabview_bug705621.js \
browser_tabview_bug706430.js \
browser_tabview_bug706736.js \
browser_tabview_click_group.js \
browser_tabview_dragdrop.js \
browser_tabview_exit_button.js \

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

@ -0,0 +1,48 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function test() {
waitForExplicitFinish();
let pinnedTab = gBrowser.addTab();
gBrowser.pinTab(pinnedTab);
registerCleanupFunction(function() {
gBrowser.unpinTab(pinnedTab);
while (gBrowser.tabs[1])
gBrowser.removeTab(gBrowser.tabs[1]);
hideTabView();
});
showTabView(function() {
let cw = TabView.getContentWindow();
let groupItemOne = cw.GroupItems.groupItems[0];
let groupItemTwo = createGroupItemWithBlankTabs(window, 250, 250, 40, 1);
is(cw.GroupItems.groupItems.length, 2, "Two group items");
hideTabView(function() {
gBrowser.selectedTab = pinnedTab;
is(cw.GroupItems.getActiveGroupItem(), groupItemTwo, "Group two is active");
is(gBrowser.selectedTab, pinnedTab, "Selected tab is the pinned tab");
goToNextGroup();
is(cw.GroupItems.getActiveGroupItem(), groupItemOne, "Group one is active");
is(gBrowser.selectedTab, pinnedTab, "Selected tab is the pinned tab");
finish();
});
});
}
function goToNextGroup() {
let utils =
QueryInterface(Ci.nsIInterfaceRequestor).
getInterface(Ci.nsIDOMWindowUtils);
const masks = Ci.nsIDOMNSEvent;
let mval = 0;
mval |= masks.CONTROL_MASK;
utils.sendKeyEvent("keypress", 0, 96, mval);
}

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

@ -15,7 +15,7 @@ function test() {
is(groupItemOne.getChildren().length, 1, "Group one has 1 tab item");
let groupItemTwo = createGroupItemWithBlankTabs(win, 300, 300, 40, 1);
is(groupItemTwo.getChildren().length, 1, "Group two has 2 tab items");
is(groupItemTwo.getChildren().length, 1, "Group two has 1 tab item");
whenTabViewIsHidden(function() {
executeSoon(function() {

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

@ -0,0 +1,65 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
let state1 = {
windows: [{
tabs: [{
entries: [{ url: "about:blank#1" }],
hidden: true,
extData: {"tabview-tab": '{"url":"about:blank#1","groupID":1,"bounds":{"left":120,"top":20,"width":20,"height":20}}'}
},{
entries: [{ url: "about:blank#2" }],
hidden: false,
extData: {"tabview-tab": '{"url":"about:blank#2","groupID":2,"bounds":{"left":20,"top":20,"width":20,"height":20}}'},
}],
selected: 2,
extData: {
"tabview-groups": '{"nextID":3,"activeGroupId":2, "totalNumber":2}',
"tabview-group":
'{"1":{"bounds":{"left":15,"top":5,"width":280,"height":232},"id":1},' +
'"2":{"bounds":{"left":309,"top":5,"width":267,"height":226},"id":2}}'
}
}]
};
let state2 = {
windows: [{
tabs: [{entries: [{ url: "about:blank#1" }], hidden: true},
{entries: [{ url: "about:blank#2" }], hidden: false}],
selected: 2
}]
};
let ss = Cc["@mozilla.org/browser/sessionstore;1"]
.getService(Ci.nsISessionStore);
function test() {
waitForExplicitFinish();
newWindowWithState(state1, function (win) {
registerCleanupFunction(function () win.close());
showTabView(function () {
let cw = win.TabView.getContentWindow();
let [group1, group2] = cw.GroupItems.groupItems;
let [tab1, tab2] = win.gBrowser.tabs;
checkUrl(group1.getChild(0), "about:blank#1", "tab1 is in first group");
checkUrl(group2.getChild(0), "about:blank#2", "tab2 is in second group");
whenWindowStateReady(win, function () {
let groups = cw.GroupItems.groupItems;
is(groups.length, 1, "one groupItem");
is(groups[0].getChildren().length, 2, "single groupItem has two children");
finish();
});
ss.setWindowState(win, JSON.stringify(state2), true);
}, win);
});
}
function checkUrl(aTabItem, aUrl, aMsg) {
is(aTabItem.tab.linkedBrowser.currentURI.spec, aUrl, aMsg);
}

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

@ -0,0 +1,40 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function test() {
waitForExplicitFinish();
newWindowWithTabView(function(win) {
registerCleanupFunction(function() {
win.close();
});
let cw = win.TabView.getContentWindow();
let groupItemOne = cw.GroupItems.groupItems[0];
is(groupItemOne.getChildren().length, 1, "Group one has 1 tab item");
let groupItemTwo = createGroupItemWithBlankTabs(win, 300, 300, 40, 1);
is(groupItemTwo.getChildren().length, 1, "Group two has 1 tab items");
whenTabViewIsHidden(function() {
win.gBrowser.removeTab(win.gBrowser.selectedTab);
executeSoon(function() {
win.undoCloseTab();
groupItemTwo.addSubscriber("childAdded", function onChildAdded(data) {
groupItemTwo.removeSubscriber("childAdded", onChildAdded);
is(groupItemOne.getChildren().length, 1, "Group one still has 1 tab item");
is(groupItemTwo.getChildren().length, 1, "Group two still has 1 tab item");
});
finish();
});
}, win);
groupItemTwo.getChild(0).zoomIn();
}, function(win) {
let newTab = win.gBrowser.addTab();
win.gBrowser.pinTab(newTab);
});
}

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

@ -195,7 +195,8 @@ let UI = {
iQ("#exit-button").click(function() {
self.exit();
self.blurAll();
});
})
.attr("title", tabviewString("button.exitTabGroups"));
// When you click on the background/empty part of TabView,
// we create a new groupItem.
@ -465,7 +466,8 @@ let UI = {
if (item.isATabItem) {
if (item.parent)
GroupItems.setActiveGroupItem(item.parent);
this._setActiveTab(item);
if (!options || !options.dontSetActiveTabInGroup)
this._setActiveTab(item);
} else {
GroupItems.setActiveGroupItem(item);
if (!options || !options.dontSetActiveTabInGroup) {

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

@ -1,4 +1,8 @@
tabview.groupItem.defaultName=Name this tab group…
tabview.button.searchTabs=Search tab groups
tabview.button.exitTabGroups=Exit tab groups
tabview.groupItem.defaultName=Name this tab group
tabview.groupItem.closeGroup=Close group
tabview.groupItem.undoCloseGroup=Undo Close Group
tabview.groupItem.discardClosedGroup=Discard closed group
tabview.search.otherWindowTabs=Tabs from other windows
tabview.notification.sessionStore=Tabs and groups will automatically be restored the next time you start %S.

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

@ -21,6 +21,7 @@
#
# Contributor(s):
# Dave Townsend <dtownsend@oxymoronical.com>
# Blair McBride <bmcbride@mozilla.com>
#
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the "GPL"), or
@ -50,8 +51,11 @@ const PREF_EM_LAST_PLATFORM_VERSION = "extensions.lastPlatformVersion";
const PREF_EM_AUTOUPDATE_DEFAULT = "extensions.update.autoUpdateDefault";
const PREF_EM_STRICT_COMPATIBILITY = "extensions.strictCompatibility";
// Note: This has to be kept in sync with the same constant in AddonRepository.jsm
const STRICT_COMPATIBILITY_DEFAULT = true;
const TOOLKIT_ID = "toolkit@mozilla.org";
const VALID_TYPES_REGEXP = /^[\w\-]+$/;
Components.utils.import("resource://gre/modules/Services.jsm");
@ -235,6 +239,67 @@ AddonScreenshot.prototype = {
}
}
/**
* This represents a compatibility override for an addon.
*
* @param aType
* Overrride type - "compatible" or "incompatible"
* @param aMinVersion
* Minimum version of the addon to match
* @param aMaxVersion
* Maximum version of the addon to match
* @param aAppID
* Application ID used to match appMinVersion and appMaxVersion
* @param aAppMinVersion
* Minimum version of the application to match
* @param aAppMaxVersion
* Maximum version of the application to match
*/
function AddonCompatibilityOverride(aType, aMinVersion, aMaxVersion, aAppID,
aAppMinVersion, aAppMaxVersion) {
this.type = aType;
this.minVersion = aMinVersion;
this.maxVersion = aMaxVersion;
this.appID = aAppID;
this.appMinVersion = aAppMinVersion;
this.appMaxVersion = aAppMaxVersion;
}
AddonCompatibilityOverride.prototype = {
/**
* Type of override - "incompatible" or "compatible".
* Only "incompatible" is supported for now.
*/
type: null,
/**
* Min version of the addon to match.
*/
minVersion: null,
/**
* Max version of the addon to match.
*/
maxVersion: null,
/**
* Application ID to match.
*/
appID: null,
/**
* Min version of the application to match.
*/
appMinVersion: null,
/**
* Max version of the application to match.
*/
appMaxVersion: null
};
/**
* A type of add-on, used by the UI to determine how to display different types
* of add-ons.
@ -552,11 +617,14 @@ var AddonManagerInternal = {
return;
Services.obs.notifyObservers(null, "addons-background-update-start", null);
let pendingUpdates = 1;
let pendingUpdates = 0;
function notifyComplete() {
if (--pendingUpdates == 0)
Services.obs.notifyObservers(null, "addons-background-update-complete", null);
if (--pendingUpdates == 0) {
Services.obs.notifyObservers(null,
"addons-background-update-complete",
null);
}
}
let scope = {};
@ -565,30 +633,34 @@ var AddonManagerInternal = {
scope.LightweightThemeManager.updateCurrentTheme();
this.getAllAddons(function getAddonsCallback(aAddons) {
pendingUpdates++;
// Repopulate repository cache first, to ensure compatibility overrides
// are up to date before checking for addon updates.
var ids = [a.id for each (a in aAddons)];
scope.AddonRepository.repopulateCache(ids, notifyComplete);
scope.AddonRepository.repopulateCache(ids, function BUC_repopulateCacheCallback() {
AddonManagerInternal.updateAddonRepositoryData(function BUC_updateAddonCallback() {
pendingUpdates += aAddons.length;
pendingUpdates += aAddons.length;
aAddons.forEach(function BUC_forEachCallback(aAddon) {
// Check all add-ons for updates so that any compatibility updates will
// be applied
aAddon.findUpdates({
onUpdateAvailable: function BUC_onUpdateAvailable(aAddon, aInstall) {
// Start installing updates when the add-on can be updated and
// background updates should be applied.
if (aAddon.permissions & AddonManager.PERM_CAN_UPGRADE &&
AddonManager.shouldAutoUpdate(aAddon)) {
aInstall.install();
}
},
onUpdateFinished: notifyComplete
}, AddonManager.UPDATE_WHEN_PERIODIC_UPDATE);
aAddons.forEach(function BUC_forEachCallback(aAddon) {
// Check all add-ons for updates so that any compatibility updates will
// be applied
aAddon.findUpdates({
onUpdateAvailable: function BUC_onUpdateAvailable(aAddon, aInstall) {
// Start installing updates when the add-on can be updated and
// background updates should be applied.
if (aAddon.permissions & AddonManager.PERM_CAN_UPGRADE &&
AddonManager.shouldAutoUpdate(aAddon)) {
aInstall.install();
}
},
onUpdateFinished: notifyComplete
}, AddonManager.UPDATE_WHEN_PERIODIC_UPDATE);
});
notifyComplete();
});
});
notifyComplete();
});
},
@ -715,7 +787,31 @@ var AddonManagerInternal = {
callProvider(provider, "updateAddonAppDisabledStates");
});
},
/**
* Notifies all providers that the repository has updated its data for
* installed add-ons.
*
* @param aCallback
* Function to call when operation is complete.
*/
updateAddonRepositoryData: function AMI_updateAddonRepositoryData(aCallback) {
if (!aCallback)
throw Components.Exception("Must specify aCallback",
Cr.NS_ERROR_INVALID_ARG);
new AsyncObjectCaller(this.providers, "updateAddonRepositoryData", {
nextObject: function(aCaller, aProvider) {
callProvider(aProvider,
"updateAddonRepositoryData",
null,
aCaller.callNext.bind(aCaller));
},
noMoreObjects: function(aCaller) {
safeCall(aCallback);
}
});
},
/**
* Asynchronously gets an AddonInstall for a URL.
*
@ -1225,6 +1321,8 @@ var AddonManagerPrivate = {
AddonScreenshot: AddonScreenshot,
AddonCompatibilityOverride: AddonCompatibilityOverride,
AddonType: AddonType
};

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

@ -21,6 +21,7 @@
# Contributor(s):
# Dave Townsend <dtownsend@oxymoronical.com>
# Ben Parr <bparr@bparr.com>
# Blair McBride <bmcbride@mozilla.com>
#
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the "GPL"), or
@ -74,6 +75,10 @@ XPCOMUtils.defineLazyGetter(this, "PREF_CHECK_COMPATIBILITY", function () {
#endif
});
const PREF_EM_STRICT_COMPATIBILITY = "extensions.strictCompatibility";
// Note: This has to be kept in sync with the same constant in AddonManager.jsm
const STRICT_COMPATIBILITY_DEFAULT = true;
const XMLURI_PARSE_ERROR = "http://www.mozilla.org/newlayout/xml/parsererror.xml";
const API_VERSION = "1.5";
@ -81,7 +86,9 @@ const DEFAULT_CACHE_TYPES = "extension,theme,locale,dictionary";
const KEY_PROFILEDIR = "ProfD";
const FILE_DATABASE = "addons.sqlite";
const DB_SCHEMA = 2;
const DB_SCHEMA = 3;
const TOOLKIT_ID = "toolkit@mozilla.org";
["LOG", "WARN", "ERROR"].forEach(function(aName) {
this.__defineGetter__(aName, function() {
@ -356,6 +363,12 @@ AddonSearchResult.prototype = {
*/
isPlatformCompatible: true,
/**
* Array of AddonCompatibilityOverride objects, that describe overrides for
* compatibility with an application versions.
**/
compatibilityOverrides: null,
/**
* True if the add-on has a secure means of updating
*/
@ -609,8 +622,8 @@ var AddonRepository = {
getAddonsToCache(aIds, function(aAddons) {
// Completely remove cache if there are no add-ons to cache
if (aAddons.length == 0) {
this._addons = null;
this._pendingCallbacks = null;
self._addons = null;
self._pendingCallbacks = null;
AddonDatabase.delete(aCallback);
return;
}
@ -744,12 +757,12 @@ var AddonRepository = {
let url = this._formatURLPref(PREF_GETADDONS_BYIDS, params);
let self = this;
function handleResults(aElements, aTotalResults) {
function handleResults(aElements, aTotalResults, aCompatData) {
// Don't use this._parseAddons() so that, for example,
// incompatible add-ons are not filtered out
let results = [];
for (let i = 0; i < aElements.length && results.length < self._maxResults; i++) {
let result = self._parseAddon(aElements[i]);
let result = self._parseAddon(aElements[i], null, aCompatData);
if (result == null)
continue;
@ -763,6 +776,24 @@ var AddonRepository = {
ids.splice(idIndex, 1);
}
// Include any compatibility overrides for addons not hosted by the
// remote repository.
for each (let addonCompat in aCompatData) {
if (addonCompat.hosted)
continue;
let addon = new AddonSearchResult(addonCompat.id);
// Compatibility overrides can only be for extensions.
addon.type = "extension";
addon.compatibilityOverrides = addonCompat.compatRanges;
let result = {
addon: addon,
xpiURL: null,
xpiHash: null
};
results.push(result);
}
// aTotalResults irrelevant
self._reportSuccess(results, -1);
}
@ -865,6 +896,14 @@ var AddonRepository = {
return (elementsList.length == 1) ? elementsList[0] : null;
},
// Get direct descendant by unique tag name.
// Returns null if not unique tag name.
_getUniqueDirectDescendant: function(aElement, aTagName) {
let elementsList = Array.filter(aElement.children,
function(aChild) aChild.tagName == aTagName);
return (elementsList.length == 1) ? elementsList[0] : null;
},
// Parse out trimmed text content. Returns null if text content empty.
_getTextContent: function(aElement) {
let textContent = aElement.textContent.trim();
@ -878,6 +917,14 @@ var AddonRepository = {
return (descendant != null) ? this._getTextContent(descendant) : null;
},
// Parse out trimmed text content of a direct descendant with the specified
// tag name.
// Returns null if the parsing unsuccessful.
_getDirectDescendantTextContent: function(aElement, aTagName) {
let descendant = this._getUniqueDirectDescendant(aElement, aTagName);
return (descendant != null) ? this._getTextContent(descendant) : null;
},
/*
* Creates an AddonSearchResult by parsing an <addon> element
*
@ -885,10 +932,13 @@ var AddonRepository = {
* The <addon> element to parse
* @param aSkip
* Object containing ids and sourceURIs of add-ons to skip.
* @param aCompatData
* Array of parsed addon_compatibility elements to accosiate with the
* resulting AddonSearchResult. Optional.
* @return Result object containing the parsed AddonSearchResult, xpiURL and
* xpiHash if the parsing was successful. Otherwise returns null.
*/
_parseAddon: function(aElement, aSkip) {
_parseAddon: function(aElement, aSkip, aCompatData) {
let skipIDs = (aSkip && aSkip.ids) ? aSkip.ids : [];
let skipSourceURIs = (aSkip && aSkip.sourceURIs) ? aSkip.sourceURIs : [];
@ -903,6 +953,9 @@ var AddonRepository = {
xpiHash: null
};
if (aCompatData && guid in aCompatData)
addon.compatibilityOverrides = aCompatData[guid].compatRanges;
let self = this;
for (let node = aElement.firstChild; node; node = node.nextSibling) {
if (!(node instanceof Ci.nsIDOMElement))
@ -1095,6 +1148,11 @@ var AddonRepository = {
checkCompatibility = Services.prefs.getBoolPref(PREF_CHECK_COMPATIBILITY);
} catch(e) { }
let strictCompatibility = STRICT_COMPATIBILITY_DEFAULT;
try {
strictCompatibility = Services.prefs.getBoolPref(PREF_EM_STRICT_COMPATIBILITY);
} catch (e) {}
function isSameApplication(aAppNode) {
return self._getTextContent(aAppNode) == Services.appinfo.ID;
}
@ -1119,7 +1177,8 @@ var AddonRepository = {
let currentVersion = Services.appinfo.version;
return (Services.vc.compare(minVersion, currentVersion) <= 0 &&
Services.vc.compare(currentVersion, maxVersion) <= 0);
((!strictCompatibility) ||
Services.vc.compare(currentVersion, maxVersion) <= 0));
});
// Ignore add-ons not compatible with this Application
@ -1131,7 +1190,9 @@ var AddonRepository = {
continue;
}
// Add-on meets all requirements, so parse out data
// Add-on meets all requirements, so parse out data.
// Don't pass in compatiblity override data, because that's only returned
// in GUID searches, which don't use _parseAddons().
let result = this._parseAddon(element, aSkip);
if (result == null)
continue;
@ -1186,6 +1247,83 @@ var AddonRepository = {
});
},
// Parses addon_compatibility nodes, that describe compatibility overrides.
_parseAddonCompatElement: function(aResultObj, aElement) {
let guid = this._getDescendantTextContent(aElement, "guid");
if (!guid)
return;
let compat = {id: guid};
compat.hosted = aElement.getAttribute("hosted") != "false";
function findMatchingAppRange(aNodes) {
let toolkitAppRange = null;
for (let i = 0; i < aNodes.length; i++) {
let node = aNodes[i];
let appID = this._getDescendantTextContent(node, "appID");
if (appID != Services.appinfo.ID && appID != TOOLKIT_ID)
continue;
let minVersion = this._getDescendantTextContent(node, "min_version");
let maxVersion = this._getDescendantTextContent(node, "max_version");
if (minVersion == null || maxVersion == null)
continue;
let appRange = { appID: appID,
appMinVersion: minVersion,
appMaxVersion: maxVersion };
// Only use Toolkit app ranges if no ranges match the application ID.
if (appID == TOOLKIT_ID)
toolkitAppRange = appRange;
else
return appRange;
}
return toolkitAppRange;
}
function parseRangeNode(aNode) {
let type = aNode.getAttribute("type");
// Only "incompatible" (blacklisting) is supported for now.
if (type != "incompatible")
return null;
let override = new AddonManagerPrivate.AddonCompatibilityOverride(type);
override.minVersion = this._getDirectDescendantTextContent(aNode, "min_version");
override.maxVersion = this._getDirectDescendantTextContent(aNode, "max_version");
if (!override.minVersion || !override.maxVersion)
return null;
let appRanges = aNode.querySelectorAll("compatible_applications > application");
let appRange = findMatchingAppRange.bind(this)(appRanges);
if (!appRange)
return null;
override.appID = appRange.appID;
override.appMinVersion = appRange.appMinVersion;
override.appMaxVersion = appRange.appMaxVersion;
return override;
}
let rangeNodes = aElement.querySelectorAll("version_ranges > version_range");
compat.compatRanges = Array.map(rangeNodes, parseRangeNode.bind(this))
.filter(function(aItem) !!aItem);
if (compat.compatRanges.length == 0)
return;
aResultObj[compat.id] = compat;
},
// Parses addon_compatibility elements.
_parseAddonCompatData: function(aElements) {
let compatData = {};
Array.forEach(aElements, this._parseAddonCompatElement.bind(this, compatData));
return compatData;
},
// Begins a new search if one isn't currently executing
_beginSearch: function(aURI, aMaxResults, aCallback, aHandleResults) {
if (this._searching || aURI == null || aMaxResults <= 0) {
@ -1227,7 +1365,10 @@ var AddonRepository = {
if (parsedTotalResults >= totalResults)
totalResults = parsedTotalResults;
aHandleResults(elements, totalResults);
let compatElements = documentElement.getElementsByTagName("addon_compatibility");
let compatData = self._parseAddonCompatData(compatElements);
aHandleResults(elements, totalResults, compatData);
}, false);
this._request.send(null);
},
@ -1271,7 +1412,33 @@ var AddonRepository = {
});
return Services.urlFormatter.formatURL(url);
},
// Find a AddonCompatibilityOverride that matches a given aAddonVersion and
// application/platform version.
findMatchingCompatOverride: function AR_findMatchingCompatOverride(aAddonVersion,
aCompatOverrides,
aAppVersion,
aPlatformVersion) {
for (let i = 0; i < aCompatOverrides.length; i++) {
let override = aCompatOverrides[i];
let appVersion = null;
if (override.appID == TOOLKIT_ID)
appVersion = aPlatformVersion || Services.appinfo.platformVersion;
else
appVersion = aAppVersion || Services.appinfo.version;
if (Services.vc.compare(override.minVersion, aAddonVersion) <= 0 &&
Services.vc.compare(aAddonVersion, override.maxVersion) <= 0 &&
Services.vc.compare(override.appMinVersion, appVersion) <= 0 &&
Services.vc.compare(appVersion, override.appMaxVersion) <= 0) {
return override;
}
}
return null;
}
};
AddonRepository.initialize();
@ -1300,6 +1467,11 @@ var AddonDatabase = {
"thumbnailURL, thumbnailWidth, thumbnailHeight, caption " +
"FROM screenshot ORDER BY addon_internal_id, num",
getAllCompatOverrides: "SELECT addon_internal_id, type, minVersion, " +
"maxVersion, appID, appMinVersion, appMaxVersion " +
"FROM compatibility_override " +
"ORDER BY addon_internal_id, num",
insertAddon: "INSERT INTO addon VALUES (NULL, :id, :type, :name, :version, " +
":creator, :creatorURL, :description, :fullDescription, " +
":developerComments, :eula, :iconURL, :homepageURL, :supportURL, " +
@ -1319,6 +1491,11 @@ var AddonDatabase = {
":num, :url, :width, :height, :thumbnailURL, " +
":thumbnailWidth, :thumbnailHeight, :caption)",
insertCompatibilityOverride: "INSERT INTO compatibility_override VALUES " +
"(:addon_internal_id, :num, :type, " +
":minVersion, :maxVersion, :appID, " +
":appMinVersion, :appMaxVersion)",
emptyAddon: "DELETE FROM addon"
},
@ -1384,29 +1561,42 @@ var AddonDatabase = {
if (dbMissing)
this._createSchema();
switch (this.connection.schemaVersion) {
case 0:
this._createSchema();
break;
case 1:
try {
try {
switch (this.connection.schemaVersion) {
case 0:
LOG("Recreating database schema");
this._createSchema();
break;
case 1:
LOG("Upgrading database schema");
this.connection.executeSimpleSQL("ALTER TABLE screenshot ADD COLUMN width INTEGER");
this.connection.executeSimpleSQL("ALTER TABLE screenshot ADD COLUMN height INTEGER");
this.connection.executeSimpleSQL("ALTER TABLE screenshot ADD COLUMN thumbnailWidth INTEGER");
this.connection.executeSimpleSQL("ALTER TABLE screenshot ADD COLUMN thumbnailHeight INTEGER");
this._createIndices();
this.connection.schemaVersion = DB_SCHEMA;
} catch (e) {
ERROR("Failed to create database schema", e);
this.logSQLError(this.connection.lastError, this.connection.lastErrorString);
this.connection.rollbackTransaction();
case 2:
this.connection.createTable("compatibility_override",
"addon_internal_id INTEGER, " +
"num INTEGER, " +
"type TEXT, " +
"minVersion TEXT, " +
"maxVersion TEXT, " +
"appID TEXT, " +
"appMinVersion TEXT, " +
"appMaxVersion TEXT, " +
"PRIMARY KEY (addon_internal_id, num)");
this._createIndices();
this._createTriggers();
this.connection.schemaVersion = DB_SCHEMA;
case 3:
break;
default:
return tryAgain();
}
break;
case 2:
break;
default:
return tryAgain();
}
} catch (e) {
ERROR("Failed to create database schema", e);
this.logSQLError(this.connection.lastError, this.connection.lastErrorString);
this.connection.rollbackTransaction();
return tryAgain();
}
return this.connection;
@ -1595,6 +1785,38 @@ var AddonDatabase = {
return;
}
getAllCompatOverrides();
}
});
}
function getAllCompatOverrides() {
self.getAsyncStatement("getAllCompatOverrides").executeAsync({
handleResult: function(aResults) {
let row = null;
while (row = aResults.getNextRow()) {
let addon_internal_id = row.getResultByName("addon_internal_id");
if (!(addon_internal_id in addons)) {
WARN("Found a compatibility override not linked to an add-on in database");
continue;
}
let addon = addons[addon_internal_id];
if (!addon.compatibilityOverrides)
addon.compatibilityOverrides = [];
addon.compatibilityOverrides.push(self._makeCompatOverrideFromAsyncRow(row));
}
},
handleError: self.asyncErrorLogger,
handleCompletion: function(aReason) {
if (aReason != Ci.mozIStorageStatementCallback.REASON_FINISHED) {
ERROR("Error retrieving compatibility overrides from database. Returning empty results");
aCallback({});
return;
}
let returnedAddons = {};
for each (let addon in addons)
returnedAddons[addon.id] = addon;
@ -1677,8 +1899,9 @@ var AddonDatabase = {
let internal_id = null;
this.connection.beginTransaction();
// Simultaneously insert the developers and screenshots of the add-on
function insertDevelopersAndScreenshots() {
// Simultaneously insert the developers, screenshots, and compatibility
// overrides of the add-on.
function insertAdditionalData() {
let stmts = [];
// Initialize statement and parameters for inserting an array
@ -1696,11 +1919,15 @@ var AddonDatabase = {
stmts.push(stmt);
}
// Initialize statements to insert developers and screenshots
// Initialize statements to insert developers, screenshots, and
// compatibility overrides
initializeArrayInsert("insertDeveloper", aAddon.developers,
self._addDeveloperParams);
initializeArrayInsert("insertScreenshot", aAddon.screenshots,
self._addScreenshotParams);
initializeArrayInsert("insertCompatibilityOverride",
aAddon.compatibilityOverrides,
self._addCompatOverrideParams);
// Immediately call callback if nothing to insert
if (stmts.length == 0) {
@ -1714,7 +1941,7 @@ var AddonDatabase = {
handleError: self.asyncErrorLogger,
handleCompletion: function(aReason) {
if (aReason != Ci.mozIStorageStatementCallback.REASON_FINISHED) {
ERROR("Error inserting developers and screenshots into database. Attempting to continue");
ERROR("Error inserting additional addon metadata into database. Attempting to continue");
self.connection.rollbackTransaction();
}
else {
@ -1740,7 +1967,7 @@ var AddonDatabase = {
}
internal_id = self.connection.lastInsertRowID;
insertDevelopersAndScreenshots();
insertAdditionalData();
}
});
},
@ -1826,6 +2053,35 @@ var AddonDatabase = {
aParams.addParams(bp);
},
/**
* Add compatibility override parameters to the specified
* mozIStorageBindingParamsArray.
*
* @param aParams
* The mozIStorageBindingParamsArray to add the parameters to
* @param aInternalID
* The internal_id of the add-on that this override is for
* @param aOverride
* The override to make the parameters from
* @param aIndex
* The index of this override
*/
_addCompatOverrideParams: function AD_addCompatOverrideParams(aParams,
aInternalID,
aOverride,
aIndex) {
let bp = aParams.newBindingParams();
bp.bindByName("addon_internal_id", aInternalID);
bp.bindByName("num", aIndex);
bp.bindByName("type", aOverride.type);
bp.bindByName("minVersion", aOverride.minVersion);
bp.bindByName("maxVersion", aOverride.maxVersion);
bp.bindByName("appID", aOverride.appID);
bp.bindByName("appMinVersion", aOverride.appMinVersion);
bp.bindByName("appMaxVersion", aOverride.appMaxVersion);
aParams.addParams(bp);
},
/**
* Make add-on from an asynchronous row
* Note: This add-on will be lacking both developers and screenshots
@ -1894,6 +2150,28 @@ var AddonDatabase = {
thumbnailWidth, thumbnailHeight, caption);
},
/**
* Make a CompatibilityOverride from an asynchronous row
*
* @param aRow
* The asynchronous row to use
* @return The created CompatibilityOverride
*/
_makeCompatOverrideFromAsyncRow: function AD_makeCompatOverrideFromAsyncRow(aRow) {
let type = aRow.getResultByName("type");
let minVersion = aRow.getResultByName("minVersion");
let maxVersion = aRow.getResultByName("maxVersion");
let appID = aRow.getResultByName("appID");
let appMinVersion = aRow.getResultByName("appMinVersion");
let appMaxVersion = aRow.getResultByName("appMaxVersion");
return new AddonManagerPrivate.AddonCompatibilityOverride(type,
minVersion,
maxVersion,
appID,
appMinVersion,
appMaxVersion);
},
/**
* Synchronously creates the schema in the database.
*/
@ -1950,13 +2228,19 @@ var AddonDatabase = {
"caption TEXT, " +
"PRIMARY KEY (addon_internal_id, num)");
this._createIndices();
this.connection.createTable("compatibility_override",
"addon_internal_id INTEGER, " +
"num INTEGER, " +
"type TEXT, " +
"minVersion TEXT, " +
"maxVersion TEXT, " +
"appID TEXT, " +
"appMinVersion TEXT, " +
"appMaxVersion TEXT, " +
"PRIMARY KEY (addon_internal_id, num)");
this.connection.executeSimpleSQL("CREATE TRIGGER delete_addon AFTER DELETE " +
"ON addon BEGIN " +
"DELETE FROM developer WHERE addon_internal_id=old.internal_id; " +
"DELETE FROM screenshot WHERE addon_internal_id=old.internal_id; " +
"END");
this._createIndices();
this._createTriggers();
this.connection.schemaVersion = DB_SCHEMA;
this.connection.commitTransaction();
@ -1968,6 +2252,19 @@ var AddonDatabase = {
}
},
/**
* Synchronously creates the triggers in the database.
*/
_createTriggers: function AD__createTriggers() {
this.connection.executeSimpleSQL("DROP TRIGGER IF EXISTS delete_addon");
this.connection.executeSimpleSQL("CREATE TRIGGER delete_addon AFTER DELETE " +
"ON addon BEGIN " +
"DELETE FROM developer WHERE addon_internal_id=old.internal_id; " +
"DELETE FROM screenshot WHERE addon_internal_id=old.internal_id; " +
"DELETE FROM compatibility_override WHERE addon_internal_id=old.internal_id; " +
"END");
},
/**
* Synchronously creates the indices in the database.
*/
@ -1976,5 +2273,7 @@ var AddonDatabase = {
"ON developer (addon_internal_id)");
this.connection.executeSimpleSQL("CREATE INDEX IF NOT EXISTS screenshot_idx " +
"ON screenshot (addon_internal_id)");
this.connection.executeSimpleSQL("CREATE INDEX IF NOT EXISTS compatibility_override_idx " +
"ON compatibility_override (addon_internal_id)");
}
};

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

@ -21,6 +21,7 @@
#
# Contributor(s):
# Dave Townsend <dtownsend@oxymoronical.com>
# Blair McBride <bmcbride@mozilla.com>
#
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the "GPL"), or
@ -61,6 +62,7 @@ const XMLURI_PARSE_ERROR = "http://www.mozilla.org/newlayout/xml/parsererror.
const PREF_UPDATE_REQUIREBUILTINCERTS = "extensions.update.requireBuiltInCerts";
Components.utils.import("resource://gre/modules/Services.jsm");
Components.utils.import("resource://gre/modules/AddonRepository.jsm");
// shared code for suppressing bad cert dialogs
Components.utils.import("resource://gre/modules/CertUtils.jsm");
@ -393,6 +395,7 @@ function parseRDFManifest(aId, aType, aUpdateKey, aRequest) {
updateURL: getProperty(ds, targetApp, "updateLink"),
updateHash: getProperty(ds, targetApp, "updateHash"),
updateInfoURL: getProperty(ds, targetApp, "updateInfoURL"),
strictCompatibility: getProperty(ds, targetApp, "strictCompatibility") == "true",
targetApplications: [appEntry]
};
@ -594,19 +597,39 @@ UpdateParser.prototype = {
* The application version to use
* @param aPlatformVersion
* The platform version to use
* @param aIgnoreMaxVersion
* Ignore maxVersion when testing if an update matches. Optional.
* @param aIgnoreStrictCompat
* Ignore strictCompatibility when testing if an update matches. Optional.
* @param aCompatOverrides
* AddonCompatibilityOverride objects to match against. Optional.
* @return true if the update is compatible with the application/platform
*/
function matchesVersions(aUpdate, aAppVersion, aPlatformVersion) {
function matchesVersions(aUpdate, aAppVersion, aPlatformVersion,
aIgnoreMaxVersion, aIgnoreStrictCompat,
aCompatOverrides) {
if (aCompatOverrides) {
let override = AddonRepository.findMatchingCompatOverride(aUpdate.version,
aCompatOverrides,
aAppVersion,
aPlatformVersion);
if (override && override.type == "incompatible")
return false;
}
if (aUpdate.strictCompatibility && !aIgnoreStrictCompat)
aIgnoreMaxVersion = false;
let result = false;
for (let i = 0; i < aUpdate.targetApplications.length; i++) {
let app = aUpdate.targetApplications[i];
if (app.id == Services.appinfo.ID) {
return (Services.vc.compare(aAppVersion, app.minVersion) >= 0) &&
(Services.vc.compare(aAppVersion, app.maxVersion) <= 0);
(aIgnoreMaxVersion || (Services.vc.compare(aAppVersion, app.maxVersion) <= 0));
}
if (app.id == TOOLKIT_ID) {
result = (Services.vc.compare(aPlatformVersion, app.minVersion) >= 0) &&
(Services.vc.compare(aPlatformVersion, app.maxVersion) <= 0);
(aIgnoreMaxVersion || (Services.vc.compare(aPlatformVersion, app.maxVersion) <= 0));
}
}
return result;
@ -640,12 +663,18 @@ var AddonUpdateChecker = {
* The version of the application or null to use the current version
* @param aPlatformVersion
* The version of the platform or null to use the current version
* @param aIgnoreMaxVersion
* Ignore maxVersion when testing if an update matches. Optional.
* @param aIgnoreStrictCompat
* Ignore strictCompatibility when testing if an update matches. Optional.
* @return an update object if one matches or null if not
*/
getCompatibilityUpdate: function AUC_getCompatibilityUpdate(aUpdates, aVersion,
aIgnoreCompatibility,
aAppVersion,
aPlatformVersion) {
aPlatformVersion,
aIgnoreMaxVersion,
aIgnoreStrictCompat) {
if (!aAppVersion)
aAppVersion = Services.appinfo.version;
if (!aPlatformVersion)
@ -660,7 +689,8 @@ var AddonUpdateChecker = {
return aUpdates[i];
}
}
else if (matchesVersions(aUpdates[i], aAppVersion, aPlatformVersion)) {
else if (matchesVersions(aUpdates[i], aAppVersion, aPlatformVersion,
aIgnoreMaxVersion, aIgnoreStrictCompat)) {
return aUpdates[i];
}
}
@ -677,11 +707,20 @@ var AddonUpdateChecker = {
* The version of the application or null to use the current version
* @param aPlatformVersion
* The version of the platform or null to use the current version
* @param aIgnoreMaxVersion
* When determining compatible updates, ignore maxVersion. Optional.
* @param aIgnoreMaxVersion
* When determining compatible updates, ignore strictCompatibility. Optional.
* @param aCompatOverrides
* Array of AddonCompatibilityOverride to take into account. Optional.
* @return an update object if one matches or null if not
*/
getNewestCompatibleUpdate: function AUC_getNewestCompatibleUpdate(aUpdates,
aAppVersion,
aPlatformVersion) {
aPlatformVersion,
aIgnoreMaxVersion,
aIgnoreStrictCompat,
aCompatOverrides) {
if (!aAppVersion)
aAppVersion = Services.appinfo.version;
if (!aPlatformVersion)
@ -699,8 +738,11 @@ var AddonUpdateChecker = {
if (state != Ci.nsIBlocklistService.STATE_NOT_BLOCKED)
continue;
if ((newest == null || (Services.vc.compare(newest.version, aUpdates[i].version) < 0)) &&
matchesVersions(aUpdates[i], aAppVersion, aPlatformVersion))
matchesVersions(aUpdates[i], aAppVersion, aPlatformVersion,
aIgnoreMaxVersion, aIgnoreStrictCompat,
aCompatOverrides)) {
newest = aUpdates[i];
}
}
return newest;
},

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

@ -1174,6 +1174,13 @@ function escapeAddonURI(aAddon, aUri, aUpdateType, aAppVersion)
maxVersion = "";
uri = uri.replace(/%ITEM_MAXAPPVERSION%/g, maxVersion);
let compatMode = "normal";
if (!XPIProvider.checkCompatibility)
compatMode = "ignore";
else if (AddonManager.strictCompatibility)
compatMode = "strict";
uri = uri.replace(/%COMPATIBILITY_MODE%/g, compatMode);
// Replace custom parameters (names of custom parameters must have at
// least 3 characters to prevent lookups for something like %D0%C8)
var catMan = null;
@ -3346,6 +3353,36 @@ var XPIProvider = {
}, this);
},
/**
* Update the repositoryAddon property for all add-ons.
*
* @param aCallback
* Function to call when operation is complete.
*/
updateAddonRepositoryData: function XPI_updateAddonRepositoryData(aCallback) {
let self = this;
XPIDatabase.getVisibleAddons(null, function UARD_getVisibleAddonsCallback(aAddons) {
let pending = aAddons.length;
function notifyComplete() {
if (--pending == 0)
aCallback();
}
aAddons.forEach(function UARD_forEachCallback(aAddon) {
AddonRepository.getCachedAddonByID(aAddon.id,
function UARD_getCachedAddonCallback(aRepoAddon) {
if (aRepoAddon) {
aAddon._repositoryAddon = aRepoAddon;
aAddon.compatibilityOverrides = aRepoAddon.compatibilityOverrides;
self.updateAddonDisabledState(aAddon);
}
notifyComplete();
});
});
});
},
/**
* When the previously selected theme is removed this method will be called
* to enable the default theme.
@ -4052,6 +4089,9 @@ AsyncAddonListCallback.prototype = {
XPIDatabase.makeAddonFromRowAsync(row, function(aAddon) {
function completeAddon(aRepositoryAddon) {
aAddon._repositoryAddon = aRepositoryAddon;
aAddon.compatibilityOverrides = aRepositoryAddon ?
aRepositoryAddon.compatibilityOverrides :
null;
self.addons.push(aAddon);
if (self.complete && self.addons.length == self.count)
self.callback(self.addons);
@ -6152,6 +6192,7 @@ AddonInstall.prototype = {
AddonRepository.getCachedAddonByID(aAddon.id, function(aRepoAddon) {
if (aRepoAddon) {
aAddon._repositoryAddon = aRepoAddon;
aAddon.compatibilityOverrides = aRepoAddon.compatibilityOverrides;
aCallback();
return;
}
@ -6160,6 +6201,9 @@ AddonInstall.prototype = {
AddonRepository.cacheAddons([aAddon.id], function() {
AddonRepository.getCachedAddonByID(aAddon.id, function(aRepoAddon) {
aAddon._repositoryAddon = aRepoAddon;
aAddon.compatibilityOverrides = aRepoAddon ?
aRepoAddon.compatibilityOverrides :
null;
aCallback();
});
});
@ -6970,10 +7014,24 @@ UpdateChecker.prototype = {
onUpdateCheckComplete: function UC_onUpdateCheckComplete(aUpdates) {
let AUC = AddonUpdateChecker;
let ignoreMaxVersion = false;
let ignoreStrictCompat = false;
if (!XPIProvider.checkCompatibility) {
ignoreMaxVersion = true;
ignoreStrictCompat = true;
} else if (this.addon.type == "extension" &&
!AddonManager.strictCompatibility &&
!this.addon.strictCompatibility &&
!this.addon.hasBinaryComponents) {
ignoreMaxVersion = true;
}
// Always apply any compatibility update for the current version
let compatUpdate = AUC.getCompatibilityUpdate(aUpdates, this.addon.version,
this.syncCompatibility);
this.syncCompatibility,
null, null,
ignoreMaxVersion,
ignoreStrictCompat);
// Apply the compatibility update to the database
if (compatUpdate)
this.addon.applyCompatibilityUpdate(compatUpdate, this.syncCompatibility);
@ -6987,7 +7045,9 @@ UpdateChecker.prototype = {
Services.vc.compare(this.platformVersion, Services.appinfo.platformVersion) != 0)) {
compatUpdate = AUC.getCompatibilityUpdate(aUpdates, this.addon.version,
false, this.appVersion,
this.platformVersion);
this.platformVersion,
ignoreMaxVersion,
ignoreStrictCompat);
}
if (compatUpdate)
@ -7007,9 +7067,16 @@ UpdateChecker.prototype = {
AddonManager.UPDATE_STATUS_NO_ERROR);
}
let compatOverrides = AddonManager.strictCompatibility ?
null :
this.addon.compatibilityOverrides;
let update = AUC.getNewestCompatibleUpdate(aUpdates,
this.appVersion,
this.platformVersion);
this.platformVersion,
ignoreMaxVersion,
ignoreStrictCompat,
compatOverrides);
if (update && Services.vc.compare(this.addon.version, update.version) < 0) {
for (let i = 0; i < XPIProvider.installs.length; i++) {
@ -7149,6 +7216,17 @@ AddonInternal.prototype = {
if (this.type == "extension" && !AddonManager.strictCompatibility &&
!this.strictCompatibility && !this.hasBinaryComponents) {
// The repository can specify compatibility overrides.
// Note: For now, only blacklisting is supported by overrides.
if (this._repositoryAddon &&
this._repositoryAddon.compatibilityOverrides) {
let overrides = this._repositoryAddon.compatibilityOverrides;
let override = AddonRepository.findMatchingCompatOverride(this.version,
overrides);
if (override && override.type == "incompatible")
return false;
}
// Extremely old extensions should not be compatible by default.
let minCompatVersion;
if (app.id == Services.appinfo.ID)
@ -7252,7 +7330,7 @@ AddonInternal.prototype = {
importMetadata: function(aObj) {
["targetApplications", "userDisabled", "softDisabled", "existingAddonID",
"sourceURI", "releaseNotesURI", "installDate", "updateDate",
"applyBackgroundUpdates"].forEach(function(aProp) {
"applyBackgroundUpdates", "compatibilityOverrides"].forEach(function(aProp) {
if (!(aProp in aObj))
return;
@ -7368,7 +7446,7 @@ function AddonWrapper(aAddon) {
["id", "syncGUID", "version", "type", "isCompatible", "isPlatformCompatible",
"providesUpdatesSecurely", "blocklistState", "blocklistURL", "appDisabled",
"softDisabled", "skinnable", "size", "foreignInstall", "hasBinaryComponents",
"strictCompatibility"].forEach(function(aProp) {
"strictCompatibility", "compatibilityOverrides"].forEach(function(aProp) {
this.__defineGetter__(aProp, function() aAddon[aProp]);
}, this);

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

@ -39,6 +39,7 @@ function test() {
requestLongerTimeout(2);
// Turn on searching for this test
Services.prefs.setIntPref(PREF_SEARCH_MAXRESULTS, 15);
Services.prefs.setBoolPref(PREF_STRICT_COMPAT, true);
waitForExplicitFinish();
@ -621,6 +622,28 @@ add_test(function() {
});
});
// Tests that compatible-by-default addons are shown if strict compatibility checking is disabled
add_test(function() {
restart_manager(gManagerWindow, null, function(aWindow) {
gManagerWindow = aWindow;
gCategoryUtilities = new CategoryUtilities(gManagerWindow);
Services.prefs.setBoolPref(PREF_STRICT_COMPAT, false);
search("incompatible", false, function() {
var item = get_addon_item("remote5");
is_element_visible(item, "Incompatible addon should be visible");
isnot(item.getAttribute("notification"), "warning", "Compatibility warning should not be shown");
var item = get_addon_item("remote6");
is(item, null, "Addon incompatible with the product should not be visible");
Services.prefs.setBoolPref(PREF_STRICT_COMPAT, true);
run_next_test();
});
});
});
// Tests that restarting the manager doesn't change search results
add_test(function() {
restart_manager(gManagerWindow, null, function(aWindow) {

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

@ -122,8 +122,6 @@ function setupUI(aFailDownloads, aFailInstalls, aCallback) {
function test() {
waitForExplicitFinish();
requestLongerTimeout(100);
run_next_test();
}

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

@ -115,5 +115,68 @@
</preview>
</previews>
</addon>
<addon_compatibility hosted="true" id="123">
<guid>test_AddonRepository_1@tests.mozilla.org</guid>
<name>PASS</name>
<version_ranges>
<!-- Will be included -->
<version_range type="incompatible">
<min_version>0.1</min_version>
<max_version>0.2</max_version>
<compatible_applications>
<application>
<name>XPCShell</name>
<application_id>666</application_id>
<min_version>3.0</min_version>
<max_version>4.0</max_version>
<appID>xpcshell@tests.mozilla.org</appID>
</application>
</compatible_applications>
</version_range>
<!-- Will be included -->
<version_range type="incompatible">
<min_version>0.2</min_version>
<max_version>0.3</max_version>
<compatible_applications>
<application>
<name>XPCShell</name>
<application_id>666</application_id>
<min_version>5.0</min_version>
<max_version>6.0</max_version>
<appID>xpcshell@tests.mozilla.org</appID>
</application>
</compatible_applications>
</version_range>
<!-- Won't be included - invalid type attribute -->
<version_range type="unknown">
<min_version>9</min_version>
<max_version>10</max_version>
<compatible_applications>
<application>
<name>XPCShell</name>
<application_id>666</application_id>
<min_version>10.0</min_version>
<max_version>11.0</max_version>
<appID>xpcshell@tests.mozilla.org</appID>
</application>
</compatible_applications>
</version_range>
<!-- Won't be included - no matching appID -->
<version_range type="incompatible">
<min_version>0.2</min_version>
<max_version>0.3</max_version>
<compatible_applications>
<application>
<name>Unknown App</name>
<application_id>123</application_id>
<min_version>1.0</min_version>
<max_version>999.0</max_version>
<appID>unknown-app@tests.mozilla.org</appID>
</application>
</compatible_applications>
</version_range>
</version_ranges>
</addon_compatibility>
</searchresults>

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

@ -62,6 +62,69 @@
<install size="5555">http://localhost:4444/addons/test_AddonRepository_2.xpi</install>
</addon>
<addon_compatibility hosted="true" id="123">
<guid>test1@tests.mozilla.org</guid>
<name>PASS</name>
<version_ranges>
<!-- Will be included -->
<version_range type="incompatible">
<min_version>0.1</min_version>
<max_version>0.2</max_version>
<compatible_applications>
<application>
<name>XPCShell</name>
<application_id>666</application_id>
<min_version>3.0</min_version>
<max_version>4.0</max_version>
<appID>xpcshell@tests.mozilla.org</appID>
</application>
</compatible_applications>
</version_range>
<!-- Will be included -->
<version_range type="incompatible">
<min_version>0.2</min_version>
<max_version>0.3</max_version>
<compatible_applications>
<application>
<name>XPCShell</name>
<application_id>666</application_id>
<min_version>5.0</min_version>
<max_version>6.0</max_version>
<appID>xpcshell@tests.mozilla.org</appID>
</application>
</compatible_applications>
</version_range>
<!-- Won't be included - invalid type attribute -->
<version_range type="unknown">
<min_version>9</min_version>
<max_version>10</max_version>
<compatible_applications>
<application>
<name>XPCShell</name>
<application_id>666</application_id>
<min_version>10.0</min_version>
<max_version>11.0</max_version>
<appID>xpcshell@tests.mozilla.org</appID>
</application>
</compatible_applications>
</version_range>
<!-- Won't be included - no matching appID -->
<version_range type="incompatible">
<min_version>0.2</min_version>
<max_version>0.3</max_version>
<compatible_applications>
<application>
<name>Unknown App</name>
<application_id>123</application_id>
<min_version>1.0</min_version>
<max_version>999.0</max_version>
<appID>unknown-app@tests.mozilla.org</appID>
</application>
</compatible_applications>
</version_range>
</version_ranges>
</addon_compatibility>
<!-- Fails because guid matches previously successful result -->
<addon>
<name>FAIL</name>

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

@ -0,0 +1,228 @@
<?xml version="1.0" encoding="utf-8" ?>
<searchresults total_results="9">
<addon>
<name>Test addon 2</name>
<type id="1">Extension</type>
<guid>addon2@tests.mozilla.org</guid>
<version>1.0</version>
</addon>
<addon>
<name>Test addon 3</name>
<type id="1">Extension</type>
<guid>addon3@tests.mozilla.org</guid>
<version>1.0</version>
</addon>
<addon_compatibility hosted="true">
<name>Test addon 3</name>
<guid>addon3@tests.mozilla.org</guid>
<version_ranges>
<version_range type="incompatible">
<min_version>0.9</min_version>
<max_version>1.0</max_version>
<compatible_applications>
<application>
<name>XPCShell</name>
<appID>xpcshell@tests.mozilla.org</appID>
<min_version>1</min_version>
<max_version>2</max_version>
</application>
</compatible_applications>
</version_range>
</version_ranges>
</addon_compatibility>
<addon>
<name>Test addon 4</name>
<type id="1">Extension</type>
<guid>addon4@tests.mozilla.org</guid>
<version>1.0</version>
</addon>
<addon_compatibility hosted="true">
<name>Test addon 4</name>
<guid>addon4@tests.mozilla.org</guid>
<version_ranges>
<version_range type="incompatible">
<min_version>0.9</min_version>
<max_version>1.0</max_version>
<compatible_applications>
<application>
<name>XPCShell</name>
<appID>xpcshell@tests.mozilla.org</appID>
<min_version>1</min_version>
<max_version>2</max_version>
</application>
</compatible_applications>
</version_range>
</version_ranges>
</addon_compatibility>
<addon>
<name>Test addon 5</name>
<type id="1">Extension</type>
<guid>addon5@tests.mozilla.org</guid>
<version>1.0</version>
</addon>
<addon_compatibility hosted="true">
<name>Test addon 5</name>
<guid>addon5@tests.mozilla.org</guid>
<version_ranges>
<version_range type="incompatible">
<min_version>0.9</min_version>
<max_version>1.0</max_version>
<compatible_applications>
<application>
<name>Unknown App</name>
<appID>unknown-app@tests.mozilla.org</appID>
<min_version>1</min_version>
<max_version>2</max_version>
</application>
</compatible_applications>
</version_range>
</version_ranges>
</addon_compatibility>
<addon>
<name>Test addon 6</name>
<type id="1">Extension</type>
<guid>addon6@tests.mozilla.org</guid>
<version>1.0</version>
</addon>
<addon_compatibility hosted="true">
<name>Test addon 6</name>
<guid>addon6@tests.mozilla.org</guid>
<version_ranges>
<version_range type="incompatible">
<min_version>0.5</min_version>
<max_version>0.9</max_version>
<compatible_applications>
<application>
<name>XPCShell</name>
<appID>xpcshell@tests.mozilla.org</appID>
<min_version>1</min_version>
<max_version>2</max_version>
</application>
</compatible_applications>
</version_range>
</version_ranges>
</addon_compatibility>
<addon>
<name>Test addon 7</name>
<type id="1">Extension</type>
<guid>addon7@tests.mozilla.org</guid>
<version>1.0</version>
</addon>
<addon_compatibility hosted="true">
<name>Test addon 7</name>
<guid>addon7@tests.mozilla.org</guid>
<version_ranges>
<version_range type="incompatible">
<min_version>0.5</min_version>
<max_version>1.0</max_version>
<compatible_applications>
<application>
<name>XPCShell</name>
<appID>xpcshell@tests.mozilla.org</appID>
<min_version>0.1</min_version>
<max_version>0.9</max_version>
</application>
</compatible_applications>
</version_range>
</version_ranges>
</addon_compatibility>
<addon>
<name>Test addon 8</name>
<type id="1">Extension</type>
<guid>addon8@tests.mozilla.org</guid>
<version>1.0</version>
</addon>
<addon_compatibility hosted="true">
<name>Test addon 8</name>
<guid>addon8@tests.mozilla.org</guid>
<version_ranges>
<version_range type="incompatible">
<min_version>6</min_version>
<max_version>6.2</max_version>
<compatible_applications>
<application>
<name>XPCShell</name>
<appID>xpcshell@tests.mozilla.org</appID>
<min_version>0.9</min_version>
<max_version>9</max_version>
</application>
</compatible_applications>
</version_range>
<version_range type="incompatible">
<min_version>0.5</min_version>
<max_version>1.0</max_version>
<compatible_applications>
<application>
<name>XPCShell</name>
<appID>xpcshell@tests.mozilla.org</appID>
<min_version>0.1</min_version>
<max_version>9</max_version>
</application>
<application>
<name>Unknown app</name>
<appID>unknown-app@tests.mozilla.org</appID>
<min_version>0.1</min_version>
<max_version>9</max_version>
</application>
</compatible_applications>
</version_range>
<version_range type="incompatible">
<min_version>0.1</min_version>
<max_version>0.2</max_version>
<compatible_applications>
<application>
<name>XPCShell</name>
<appID>xpcshell@tests.mozilla.org</appID>
<min_version>0.1</min_version>
<max_version>0.9</max_version>
</application>
</compatible_applications>
</version_range>
</version_ranges>
</addon_compatibility>
<addon_compatibility hosted="false">
<name>Test addon 9</name>
<guid>addon9@tests.mozilla.org</guid>
<version_ranges>
<version_range type="incompatible">
<min_version>0.5</min_version>
<max_version>1.0</max_version>
<compatible_applications>
<application>
<name>XPCShell</name>
<appID>xpcshell@tests.mozilla.org</appID>
<min_version>1</min_version>
<max_version>2</max_version>
</application>
</compatible_applications>
</version_range>
</version_ranges>
</addon_compatibility>
<addon_compatibility hosted="false">
<name>Test addon 10</name>
<guid>addon10@tests.mozilla.org</guid>
<version_ranges>
<version_range type="compatible">
<min_version>0.5</min_version>
<max_version>1.0</max_version>
<compatible_applications>
<application>
<name>XPCShell</name>
<appID>xpcshell@tests.mozilla.org</appID>
<min_version>1</min_version>
<max_version>2</max_version>
</application>
</compatible_applications>
</version_range>
</version_ranges>
</addon_compatibility>
</searchresults>

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

@ -144,4 +144,107 @@
</Seq>
</em:updates>
</Description>
<Description about="urn:mozilla:extension:addon9@tests.mozilla.org">
<em:updates>
<Seq>
<li>
<Description>
<em:version>2.0</em:version>
<em:targetApplication>
<Description>
<em:id>xpcshell@tests.mozilla.org</em:id>
<em:minVersion>1</em:minVersion>
<em:maxVersion>1</em:maxVersion>
<em:updateLink>http://localhost:4444/addons/test_update9_2.xpi</em:updateLink>
</Description>
</em:targetApplication>
</Description>
</li>
<!-- Incompatible when strict compatibility is enabled -->
<li>
<Description>
<em:version>3.0</em:version>
<em:targetApplication>
<Description>
<em:id>xpcshell@tests.mozilla.org</em:id>
<em:minVersion>0.9</em:minVersion>
<em:maxVersion>0.9</em:maxVersion>
<em:updateLink>http://localhost:4444/addons/test_update9_3.xpi</em:updateLink>
</Description>
</em:targetApplication>
</Description>
</li>
<!-- Incompatible due to compatibility override -->
<li>
<Description>
<em:version>4.0</em:version>
<em:targetApplication>
<Description>
<em:id>xpcshell@tests.mozilla.org</em:id>
<em:minVersion>0.9</em:minVersion>
<em:maxVersion>0.9</em:maxVersion>
<em:updateLink>http://localhost:4444/addons/test_update9_4.xpi</em:updateLink>
</Description>
</em:targetApplication>
</Description>
</li>
<!-- Addon for future version of app -->
<li>
<Description>
<em:version>5.0</em:version>
<em:targetApplication>
<Description>
<em:id>xpcshell@tests.mozilla.org</em:id>
<em:minVersion>5</em:minVersion>
<em:maxVersion>6</em:maxVersion>
<em:updateLink>http://localhost:4444/addons/test_update9_5.xpi</em:updateLink>
</Description>
</em:targetApplication>
</Description>
</li>
</Seq>
</em:updates>
</Description>
<Description about="urn:mozilla:extension:addon10@tests.mozilla.org">
<em:updates>
<Seq>
<li>
<Description>
<em:version>1.0</em:version>
<em:targetApplication>
<Description>
<em:id>xpcshell@tests.mozilla.org</em:id>
<em:minVersion>0.1</em:minVersion>
<em:maxVersion>0.4</em:maxVersion>
<em:updateLink>http://localhost:4444/addons/test_update10.xpi</em:updateLink>
</Description>
</em:targetApplication>
</Description>
</li>
</Seq>
</em:updates>
</Description>
<Description about="urn:mozilla:extension:addon11@tests.mozilla.org">
<em:updates>
<Seq>
<li>
<Description>
<em:version>2.0</em:version>
<em:targetApplication>
<Description>
<em:id>xpcshell@tests.mozilla.org</em:id>
<em:minVersion>0.1</em:minVersion>
<em:maxVersion>0.2</em:maxVersion>
<em:strictCompatibility>true</em:strictCompatibility>
<em:updateLink>http://localhost:4444/addons/test_update11.xpi</em:updateLink>
</Description>
</em:targetApplication>
</Description>
</li>
</Seq>
</em:updates>
</Description>
</RDF>

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

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8" ?>
<searchresults total_results="11">
<addon>
<name>Test Addon 9</name>
<type id="1">Extension</type>
<guid>addon9@tests.mozilla.org</guid>
</addon>
<addon_compatibility hosted="true">
<guid>addon9@tests.mozilla.org</guid>
<name>Test Addon 9</name>
<version_ranges>
<version_range type="incompatible">
<min_version>4</min_version>
<max_version>4</max_version>
<compatible_applications>
<application>
<name>XPCShell</name>
<min_version>1</min_version>
<max_version>1</max_version>
<appID>xpcshell@tests.mozilla.org</appID>
</application>
</compatible_applications>
</version_range>
</version_ranges>
</addon_compatibility>
</searchresults>

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

@ -296,4 +296,124 @@
<RDF:Description about="urn:mozilla:extension:test_bug378216_15@tests.mozilla.org">
<em:updates>Foo</em:updates>
</RDF:Description>
<!-- Various updates available - one is not compatible, but compatibility checking is disabled -->
<Description about="urn:mozilla:extension:ignore-compat@tests.mozilla.org">
<em:updates>
<Seq>
<li>
<Description>
<em:version>1.0</em:version>
<em:targetApplication>
<Description>
<em:id>xpcshell@tests.mozilla.org</em:id>
<em:minVersion>0.1</em:minVersion>
<em:maxVersion>0.2</em:maxVersion>
<em:updateLink>https://localhost:4444/addons/test1.xpi</em:updateLink>
</Description>
</em:targetApplication>
</Description>
</li>
<li>
<Description>
<em:version>2.0</em:version>
<em:targetApplication>
<Description>
<em:id>xpcshell@tests.mozilla.org</em:id>
<em:minVersion>0.5</em:minVersion>
<em:maxVersion>0.6</em:maxVersion>
<em:updateLink>https://localhost:4444/addons/test2.xpi</em:updateLink>
</Description>
</em:targetApplication>
</Description>
</li>
<!-- Update for future app versions - should never be compatible -->
<li>
<Description>
<em:version>3.0</em:version>
<em:targetApplication>
<Description>
<em:id>xpcshell@tests.mozilla.org</em:id>
<em:minVersion>2</em:minVersion>
<em:maxVersion>3</em:maxVersion>
<em:updateLink>https://localhost:4444/addons/test3.xpi</em:updateLink>
</Description>
</em:targetApplication>
</Description>
</li>
</Seq>
</em:updates>
</Description>
<!-- Various updates available - one is not compatible, but compatibility checking is disabled -->
<Description about="urn:mozilla:extension:compat-override@tests.mozilla.org">
<em:updates>
<Seq>
<!-- Has compatibility override, but it doesn't match this app version -->
<li>
<Description>
<em:version>1.0</em:version>
<em:targetApplication>
<Description>
<em:id>xpcshell@tests.mozilla.org</em:id>
<em:minVersion>0.1</em:minVersion>
<em:maxVersion>0.2</em:maxVersion>
<em:updateLink>https://localhost:4444/addons/test1.xpi</em:updateLink>
</Description>
</em:targetApplication>
</Description>
</li>
<!-- Has compatibility override, so is incompaible -->
<li>
<Description>
<em:version>2.0</em:version>
<em:targetApplication>
<Description>
<em:id>xpcshell@tests.mozilla.org</em:id>
<em:minVersion>0.5</em:minVersion>
<em:maxVersion>0.6</em:maxVersion>
<em:updateLink>https://localhost:4444/addons/test2.xpi</em:updateLink>
</Description>
</em:targetApplication>
</Description>
</li>
<!-- Update for future app versions - should never be compatible -->
<li>
<Description>
<em:version>3.0</em:version>
<em:targetApplication>
<Description>
<em:id>xpcshell@tests.mozilla.org</em:id>
<em:minVersion>2</em:minVersion>
<em:maxVersion>3</em:maxVersion>
<em:updateLink>https://localhost:4444/addons/test3.xpi</em:updateLink>
</Description>
</em:targetApplication>
</Description>
</li>
</Seq>
</em:updates>
</Description>
<!-- Opt-in to strict compatibility checking -->
<Description about="urn:mozilla:extension:compat-strict-optin@tests.mozilla.org">
<em:updates>
<Seq>
<li>
<Description>
<em:version>1.0</em:version>
<em:targetApplication>
<Description>
<em:id>xpcshell@tests.mozilla.org</em:id>
<em:minVersion>0.1</em:minVersion>
<em:maxVersion>0.2</em:maxVersion>
<em:strictCompatibility>true</em:strictCompatibility>
<em:updateLink>https://localhost:4444/addons/test1.xpi</em:updateLink>
</Description>
</em:targetApplication>
</Description>
</li>
</Seq>
</em:updates>
</Description>
</RDF>

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

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:RDF="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
<Description about="urn:mozilla:extension:compatmode-ignore@tests.mozilla.org">
<em:updates>
<Seq>
<li>
<Description>
<em:version>2.0</em:version>
<em:targetApplication>
<Description>
<em:id>xpcshell@tests.mozilla.org</em:id>
<em:minVersion>1</em:minVersion>
<em:maxVersion>2</em:maxVersion>
<em:updateLink>https://localhost:4444/addons/test1.xpi</em:updateLink>
</Description>
</em:targetApplication>
</Description>
</li>
</Seq>
</em:updates>
</Description>
</RDF>

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

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:RDF="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
<Description about="urn:mozilla:extension:compatmode-normal@tests.mozilla.org">
<em:updates>
<Seq>
<li>
<Description>
<em:version>2.0</em:version>
<em:targetApplication>
<Description>
<em:id>xpcshell@tests.mozilla.org</em:id>
<em:minVersion>1</em:minVersion>
<em:maxVersion>2</em:maxVersion>
<em:updateLink>https://localhost:4444/addons/test1.xpi</em:updateLink>
</Description>
</em:targetApplication>
</Description>
</li>
</Seq>
</em:updates>
</Description>
</RDF>

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

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:RDF="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
<Description about="urn:mozilla:extension:compatmode-strict@tests.mozilla.org">
<em:updates>
<Seq>
<li>
<Description>
<em:version>2.0</em:version>
<em:targetApplication>
<Description>
<em:id>xpcshell@tests.mozilla.org</em:id>
<em:minVersion>1</em:minVersion>
<em:maxVersion>2</em:maxVersion>
<em:updateLink>https://localhost:4444/addons/test1.xpi</em:updateLink>
</Description>
</em:targetApplication>
</Description>
</li>
</Seq>
</em:updates>
</Description>
</RDF>

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

@ -244,6 +244,12 @@ function do_check_addon(aActualAddon, aExpectedAddon, aProperties) {
do_check_eq(actualValue.getTime(), expectedValue.getTime());
break;
case "compatibilityOverrides":
do_check_eq(actualValue.length, expectedValue.length);
for (let i = 0; i < actualValue.length; i++)
do_check_compatibilityoverride(actualValue[i], expectedValue[i]);
break;
default:
if (actualValue !== expectedValue)
do_throw("Failed for " + aProperty + " for add-on " + aExpectedAddon.id +
@ -285,6 +291,24 @@ function do_check_screenshot(aActual, aExpected) {
do_check_eq(aActual.caption, aExpected.caption);
}
/**
* Check that the actual compatibility override is the same as the expected
* compatibility override.
*
* @param aAction
* The actual compatibility override to check.
* @param aExpected
* The expected compatibility override to check against.
*/
function do_check_compatibilityoverride(aActual, aExpected) {
do_check_eq(aActual.type, aExpected.type);
do_check_eq(aActual.minVersion, aExpected.minVersion);
do_check_eq(aActual.maxVersion, aExpected.maxVersion);
do_check_eq(aActual.appID, aExpected.appID);
do_check_eq(aActual.appMinVersion, aExpected.appMinVersion);
do_check_eq(aActual.appMaxVersion, aExpected.appMaxVersion);
}
/**
* Starts up the add-on manager as if it was started by the application.
*

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

@ -36,7 +36,8 @@ var ADDON_PROPERTIES = ["id", "type", "version", "creator", "developers",
"averageRating", "reviewCount", "reviewURL",
"totalDownloads", "weeklyDownloads", "dailyUsers",
"sourceURI", "repositoryStatus", "size", "updateDate",
"purchaseURL", "purchaseAmount", "purchaseDisplayAmount"];
"purchaseURL", "purchaseAmount", "purchaseDisplayAmount",
"compatibilityOverrides"];
// Results of getAddonsByIDs
var GET_RESULTS = [{
@ -82,7 +83,22 @@ var GET_RESULTS = [{
sourceURI: BASE_URL + INSTALL_URL2,
repositoryStatus: 8,
size: 5555,
updateDate: new Date(1265033045000)
updateDate: new Date(1265033045000),
compatibilityOverrides: [{
type: "incompatible",
minVersion: 0.1,
maxVersion: 0.2,
appID: "xpcshell@tests.mozilla.org",
appMinVersion: 3.0,
appMaxVersion: 4.0
}, {
type: "incompatible",
minVersion: 0.2,
maxVersion: 0.3,
appID: "xpcshell@tests.mozilla.org",
appMinVersion: 5.0,
appMaxVersion: 6.0
}]
}, {
id: "test_AddonRepository_1@tests.mozilla.org",
version: "1.4",
@ -176,7 +192,8 @@ var SEARCH_RESULTS = [{
sourceURI: BASE_URL + "/test3.xpi",
repositoryStatus: 8,
size: 5555,
updateDate: new Date(1265033045000)
updateDate: new Date(1265033045000),
}, {
id: "purchase1@tests.mozilla.org",
type: "extension",

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

@ -39,7 +39,8 @@ const ADDON_PROPERTIES = ["id", "type", "name", "version", "creator",
"optionsURL", "aboutURL", "contributionURL",
"contributionAmount", "averageRating", "reviewCount",
"reviewURL", "totalDownloads", "weeklyDownloads",
"dailyUsers", "sourceURI", "repositoryStatus"];
"dailyUsers", "sourceURI", "repositoryStatus",
"compatibilityOverrides"];
// The size and updateDate properties are annoying to test for XPI add-ons.
// However, since we only care about whether the repository value vs. the
@ -90,7 +91,22 @@ const REPOSITORY_ADDONS = [{
weeklyDownloads: 3331,
dailyUsers: 4441,
sourceURI: BASE_URL + "/repo/1/install.xpi",
repositoryStatus: 4
repositoryStatus: 4,
compatibilityOverrides: [{
type: "incompatible",
minVersion: 0.1,
maxVersion: 0.2,
appID: "xpcshell@tests.mozilla.org",
appMinVersion: 3.0,
appMaxVersion: 4.0
}, {
type: "incompatible",
minVersion: 0.2,
maxVersion: 0.3,
appID: "xpcshell@tests.mozilla.org",
appMinVersion: 5.0,
appMaxVersion: 6.0
}]
}, {
id: ADDON_IDS[1],
type: "theme",
@ -222,7 +238,22 @@ const WITH_CACHE = [{
weeklyDownloads: 3331,
dailyUsers: 4441,
sourceURI: NetUtil.newURI(ADDON_FILES[0]).spec,
repositoryStatus: 4
repositoryStatus: 4,
compatibilityOverrides: [{
type: "incompatible",
minVersion: 0.1,
maxVersion: 0.2,
appID: "xpcshell@tests.mozilla.org",
appMinVersion: 3.0,
appMaxVersion: 4.0
}, {
type: "incompatible",
minVersion: 0.2,
maxVersion: 0.3,
appID: "xpcshell@tests.mozilla.org",
appMinVersion: 5.0,
appMaxVersion: 6.0
}]
}, {
id: ADDON_IDS[1],
type: "theme",
@ -319,7 +350,22 @@ const WITH_EXTENSION_CACHE = [{
weeklyDownloads: 3331,
dailyUsers: 4441,
sourceURI: NetUtil.newURI(ADDON_FILES[0]).spec,
repositoryStatus: 4
repositoryStatus: 4,
compatibilityOverrides: [{
type: "incompatible",
minVersion: 0.1,
maxVersion: 0.2,
appID: "xpcshell@tests.mozilla.org",
appMinVersion: 3.0,
appMaxVersion: 4.0
}, {
type: "incompatible",
minVersion: 0.2,
maxVersion: 0.3,
appID: "xpcshell@tests.mozilla.org",
appMinVersion: 5.0,
appMaxVersion: 6.0
}]
}, {
id: ADDON_IDS[1],
type: "theme",

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

@ -0,0 +1,275 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// Tests compatibility overrides, for when strict compatibility checking is
// disabled. See bug 693906.
const PREF_GETADDONS_CACHE_ENABLED = "extensions.getAddons.cache.enabled";
const PREF_GETADDONS_BYIDS = "extensions.getAddons.get.url";
const PORT = 4444;
const BASE_URL = "http://localhost:" + PORT;
const DEFAULT_URL = "about:blank";
const REQ_URL = "/data.xml";
Services.prefs.setBoolPref(PREF_EM_STRICT_COMPATIBILITY, false);
Services.prefs.setBoolPref(PREF_GETADDONS_CACHE_ENABLED, true);
Services.prefs.setCharPref(PREF_GETADDONS_BYIDS,
BASE_URL + REQ_URL);
do_load_httpd_js();
var gServer;
// Not hosted, no overrides
var addon1 = {
id: "addon1@tests.mozilla.org",
version: "1.0",
name: "Test addon 1",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "1"
}]
};
// Hosted, no overrides
var addon2 = {
id: "addon2@tests.mozilla.org",
version: "1.0",
name: "Test addon 2",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "1"
}]
};
// Hosted, matching override
var addon3 = {
id: "addon3@tests.mozilla.org",
version: "1.0",
name: "Test addon 3",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "1"
}]
};
// Hosted, matching override, wouldn't be compatible if strict chekcing is enabled
var addon4 = {
id: "addon4@tests.mozilla.org",
version: "1.0",
name: "Test addon 4",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "0.1",
maxVersion: "0.2"
}]
};
// Hosted, app ID doesn't match in override
var addon5 = {
id: "addon5@tests.mozilla.org",
version: "1.0",
name: "Test addon 5",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "1"
}]
};
// Hosted, addon version range doesn't match in override
var addon6 = {
id: "addon6@tests.mozilla.org",
version: "1.0",
name: "Test addon 6",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "1"
}]
};
// Hosted, app version range doesn't match in override
var addon7 = {
id: "addon7@tests.mozilla.org",
version: "1.0",
name: "Test addon 7",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "1"
}]
};
// Hosted, multiple overrides
var addon8 = {
id: "addon8@tests.mozilla.org",
version: "1.0",
name: "Test addon 8",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "1"
}]
};
// Not hosted, matching override
var addon9 = {
id: "addon9@tests.mozilla.org",
version: "1.0",
name: "Test addon 9",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "1"
}]
};
// Not hosted, override is of unsupported type (compatible)
var addon10 = {
id: "addon10@tests.mozilla.org",
version: "1.0",
name: "Test addon 10",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "1"
}]
};
const profileDir = gProfD.clone();
profileDir.append("extensions");
/*
* Trigger an AddonManager background update check
*
* @param aCallback
* Callback to call once the background update is complete
*/
function trigger_background_update(aCallback) {
Services.obs.addObserver({
observe: function(aSubject, aTopic, aData) {
Services.obs.removeObserver(this, "addons-background-update-complete");
aCallback();
}
}, "addons-background-update-complete", false);
gInternalManager.notify(null);
}
function run_test() {
do_test_pending();
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "2");
writeInstallRDFForExtension(addon1, profileDir);
writeInstallRDFForExtension(addon2, profileDir);
writeInstallRDFForExtension(addon3, profileDir);
writeInstallRDFForExtension(addon4, profileDir);
writeInstallRDFForExtension(addon5, profileDir);
writeInstallRDFForExtension(addon6, profileDir);
writeInstallRDFForExtension(addon7, profileDir);
writeInstallRDFForExtension(addon8, profileDir);
writeInstallRDFForExtension(addon9, profileDir);
writeInstallRDFForExtension(addon10, profileDir);
gServer = new nsHttpServer();
gServer.registerFile(REQ_URL, do_get_file("data/test_compatoverrides.xml"));
gServer.start(PORT);
startupManager();
trigger_background_update(run_test_1);
}
function end_test() {
gServer.stop(do_test_finished);
}
function check_compat_status(aCallback) {
AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",
"addon2@tests.mozilla.org",
"addon3@tests.mozilla.org",
"addon4@tests.mozilla.org",
"addon5@tests.mozilla.org",
"addon6@tests.mozilla.org",
"addon7@tests.mozilla.org",
"addon8@tests.mozilla.org",
"addon9@tests.mozilla.org",
"addon10@tests.mozilla.org"],
function([a1, a2, a3, a4, a5, a6, a7, a8, a9, a10]) {
do_check_neq(a1, null);
do_check_eq(a1.compatibilityOverrides, null);
do_check_true(a1.isCompatible);
do_check_false(a1.appDisabled);
do_check_neq(a2, null);
do_check_eq(a2.compatibilityOverrides, null);
do_check_true(a2.isCompatible);
do_check_false(a2.appDisabled);
do_check_neq(a3, null);
do_check_neq(a3.compatibilityOverrides, null);
do_check_eq(a3.compatibilityOverrides.length, 1);
do_check_false(a3.isCompatible);
do_check_true(a3.appDisabled);
do_check_neq(a4, null);
do_check_neq(a4.compatibilityOverrides, null);
do_check_eq(a4.compatibilityOverrides.length, 1);
do_check_false(a4.isCompatible);
do_check_true(a4.appDisabled);
do_check_neq(a5, null);
do_check_eq(a5.compatibilityOverrides, null);
do_check_true(a5.isCompatible);
do_check_false(a5.appDisabled);
do_check_neq(a6, null);
do_check_neq(a6.compatibilityOverrides, null);
do_check_eq(a6.compatibilityOverrides.length, 1);
do_check_true(a6.isCompatible);
do_check_false(a6.appDisabled);
do_check_neq(a7, null);
do_check_neq(a7.compatibilityOverrides, null);
do_check_eq(a7.compatibilityOverrides.length, 1);
do_check_true(a7.isCompatible);
do_check_false(a7.appDisabled);
do_check_neq(a8, null);
do_check_neq(a8.compatibilityOverrides, null);
do_check_eq(a8.compatibilityOverrides.length, 3);
do_check_false(a8.isCompatible);
do_check_true(a8.appDisabled);
do_check_neq(a9, null);
do_check_neq(a9.compatibilityOverrides, null);
do_check_eq(a9.compatibilityOverrides.length, 1);
do_check_false(a9.isCompatible);
do_check_true(a9.appDisabled);
do_check_neq(a10, null);
do_check_eq(a10.compatibilityOverrides, null);
do_check_true(a10.isCompatible);
do_check_false(a10.appDisabled);
aCallback();
});
}
function run_test_1() {
check_compat_status(run_test_2);
}
function run_test_2() {
restartManager();
check_compat_status(end_test);
}

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

@ -2,7 +2,7 @@
* http://creativecommons.org/publicdomain/zero/1.0/
*/
const EXPECTED_SCHEMA_VERSION = 2;
const EXPECTED_SCHEMA_VERSION = 3;
let dbfile;
function run_test() {
@ -88,6 +88,24 @@ function run_test() {
do_check_eq(db.schemaVersion, EXPECTED_SCHEMA_VERSION);
do_check_true(db.indexExists("developer_idx"));
do_check_true(db.indexExists("screenshot_idx"));
do_check_true(db.indexExists("compatibility_override_idx"));
do_check_true(db.tableExists("compatibility_override"));
// Check the trigger is working
db.executeSimpleSQL("INSERT INTO addon (id, type, name) VALUES('test_addon', 'extension', 'Test Addon')");
let internalID = db.lastInsertRowID;
db.executeSimpleSQL("INSERT INTO compatibility_override (addon_internal_id, num, type) VALUES('" + internalID + "', '1', 'incompatible')");
let stmt = db.createStatement("SELECT COUNT(*) AS count FROM compatibility_override");
stmt.executeStep();
do_check_eq(stmt.row.count, 1);
stmt.reset();
db.executeSimpleSQL("DELETE FROM addon");
stmt.executeStep();
do_check_eq(stmt.row.count, 0);
stmt.finalize();
db.close();
run_test_2();
}

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

@ -6,6 +6,8 @@
const PREF_MATCH_OS_LOCALE = "intl.locale.matchOS";
const PREF_SELECTED_LOCALE = "general.useragent.locale";
const PREF_GETADDONS_BYIDS = "extensions.getAddons.get.url";
const PREF_GETADDONS_CACHE_ENABLED = "extensions.getAddons.cache.enabled";
// The test extension uses an insecure update url.
Services.prefs.setBoolPref(PREF_EM_CHECK_UPDATE_SECURITY, false);
@ -771,9 +773,10 @@ function run_test_12() {
});
}
// Tests that no compatibility update is passed to the listener when there is
// Tests that a compatibility update is passed to the listener when there is
// compatibility info for the current version of the app but not for the
// version of the app that the caller requested an update check for.
// version of the app that the caller requested an update check for, when
// strict compatibility checking is disabled.
function run_test_13() {
// Not initially compatible but the update check will make it compatible
writeInstallRDFForExtension({
@ -798,8 +801,8 @@ function run_test_13() {
a7.findUpdates({
sawUpdate: false,
onCompatibilityUpdateAvailable: function(addon) {
do_throw("Should have not have seen compatibility information");
onNoCompatibilityUpdateAvailable: function(addon) {
do_throw("Should have seen compatibility information");
},
onUpdateAvailable: function(addon, install) {
@ -1052,7 +1055,7 @@ function run_test_16() {
a2.uninstall();
restartManager();
end_test();
run_test_17();
});
}
});
@ -1064,3 +1067,106 @@ function run_test_16() {
aInstall.install();
}, "application/x-xpinstall");
}
// Test that the update check correctly observes the
// extensions.strictCompatibility pref and compatibility overrides.
function run_test_17() {
writeInstallRDFForExtension({
id: "addon9@tests.mozilla.org",
version: "1.0",
updateURL: "http://localhost:4444/data/test_update.rdf",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "0.1",
maxVersion: "0.2"
}],
name: "Test Addon 9",
}, profileDir);
restartManager();
AddonManager.addInstallListener({
onNewInstall: function(aInstall) {
if (aInstall.existingAddon.id != "addon9@tests.mozilla.org")
do_throw("Saw unexpected onNewInstall for " + aInstall.existingAddon.id);
do_check_eq(aInstall.version, "3.0");
},
onDownloadFailed: function(aInstall) {
do_execute_soon(run_test_18);
}
});
Services.prefs.setCharPref(PREF_GETADDONS_BYIDS, "http://localhost:4444/data/test_update.xml");
Services.prefs.setBoolPref(PREF_GETADDONS_CACHE_ENABLED, true);
// Fake a timer event
gInternalManager.notify(null);
}
// Tests that compatibility updates are applied to addons when the updated
// compatibility data wouldn't match with strict compatibility enabled.
function run_test_18() {
writeInstallRDFForExtension({
id: "addon10@tests.mozilla.org",
version: "1.0",
updateURL: "http://localhost:4444/data/test_update.rdf",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "0.1",
maxVersion: "0.2"
}],
name: "Test Addon 10",
}, profileDir);
restartManager();
AddonManager.getAddonByID("addon10@tests.mozilla.org", function(a10) {
do_check_neq(a10, null);
a10.findUpdates({
onNoCompatibilityUpdateAvailable: function() {
do_throw("Should have seen compatibility information");
},
onUpdateAvailable: function() {
do_throw("Should not have seen an available update");
},
onUpdateFinished: function() {
run_test_19();
}
}, AddonManager.UPDATE_WHEN_USER_REQUESTED);
});
}
// Test that the update check correctly observes when an addon opts-in to
// strict compatibility checking.
function run_test_19() {
writeInstallRDFForExtension({
id: "addon11@tests.mozilla.org",
version: "1.0",
updateURL: "http://localhost:4444/data/test_update.rdf",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "0.1",
maxVersion: "0.2"
}],
name: "Test Addon 11",
}, profileDir);
restartManager();
AddonManager.getAddonByID("addon11@tests.mozilla.org", function(a11) {
do_check_neq(a11, null);
a11.findUpdates({
onCompatibilityUpdateAvailable: function() {
do_throw("Should have not have seen compatibility information");
},
onUpdateAvailable: function() {
do_throw("Should not have seen an available update");
},
onUpdateFinished: function() {
end_test();
}
}, AddonManager.UPDATE_WHEN_USER_REQUESTED);
});
}

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

@ -0,0 +1,198 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
// This verifies that add-on update check correctly fills in the
// %COMPATIBILITY_MODE% token in the update URL.
// The test extension uses an insecure update url.
Services.prefs.setBoolPref(PREF_EM_CHECK_UPDATE_SECURITY, false);
do_load_httpd_js();
var testserver;
const profileDir = gProfD.clone();
profileDir.append("extensions");
var COMPATIBILITY_PREF;
function run_test() {
do_test_pending();
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2");
var channel = "default";
try {
channel = Services.prefs.getCharPref("app.update.channel");
} catch (e) { }
if (channel != "aurora" &&
channel != "beta" &&
channel != "release") {
var version = "nightly";
} else {
version = Services.appinfo.version.replace(/^([^\.]+\.[0-9]+[a-z]*).*/gi, "$1");
}
COMPATIBILITY_PREF = "extensions.checkCompatibility." + version;
// Create and configure the HTTP server.
testserver = new nsHttpServer();
testserver.registerDirectory("/data/", do_get_file("data"));
testserver.registerDirectory("/addons/", do_get_file("addons"));
testserver.start(4444);
writeInstallRDFForExtension({
id: "compatmode-normal@tests.mozilla.org",
version: "1.0",
updateURL: "http://localhost:4444/data/test_updatecompatmode_%COMPATIBILITY_MODE%.rdf",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "1"
}],
name: "Test Addon - normal"
}, profileDir);
writeInstallRDFForExtension({
id: "compatmode-strict@tests.mozilla.org",
version: "1.0",
updateURL: "http://localhost:4444/data/test_updatecompatmode_%COMPATIBILITY_MODE%.rdf",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "1"
}],
name: "Test Addon - strict"
}, profileDir);
writeInstallRDFForExtension({
id: "compatmode-strict-optin@tests.mozilla.org",
version: "1.0",
updateURL: "http://localhost:4444/data/test_updatecompatmode_%COMPATIBILITY_MODE%.rdf",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "1"
}],
name: "Test Addon - strict opt-in",
strictCompatibility: true
}, profileDir);
writeInstallRDFForExtension({
id: "compatmode-ignore@tests.mozilla.org",
version: "1.0",
updateURL: "http://localhost:4444/data/test_updatecompatmode_%COMPATIBILITY_MODE%.rdf",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "1"
}],
name: "Test Addon - ignore",
}, profileDir);
startupManager();
run_test_1();
}
function end_test() {
testserver.stop(do_test_finished);
}
// Strict compatibility checking disabled.
function run_test_1() {
do_print("Testing with strict compatibility checking disabled");
Services.prefs.setBoolPref(PREF_EM_STRICT_COMPATIBILITY, false);
AddonManager.getAddonByID("compatmode-normal@tests.mozilla.org", function(addon) {
do_check_neq(addon, null);
addon.findUpdates({
onCompatibilityUpdateAvailable: function() {
do_throw("Should have not have seen compatibility information");
},
onNoUpdateAvailable: function() {
do_throw("Should have seen an available update");
},
onUpdateAvailable: function(addon, install) {
do_check_eq(install.version, "2.0")
},
onUpdateFinished: function() {
run_test_2();
}
}, AddonManager.UPDATE_WHEN_USER_REQUESTED);
});
}
// Strict compatibility checking enabled.
function run_test_2() {
do_print("Testing with strict compatibility checking enabled");
Services.prefs.setBoolPref(PREF_EM_STRICT_COMPATIBILITY, true);
AddonManager.getAddonByID("compatmode-strict@tests.mozilla.org", function(addon) {
do_check_neq(addon, null);
addon.findUpdates({
onCompatibilityUpdateAvailable: function() {
do_throw("Should have not have seen compatibility information");
},
onNoUpdateAvailable: function() {
do_throw("Should have seen an available update");
},
onUpdateAvailable: function(addon, install) {
do_check_eq(install.version, "2.0")
},
onUpdateFinished: function() {
run_test_3();
}
}, AddonManager.UPDATE_WHEN_USER_REQUESTED);
});
}
// Strict compatibility checking opt-in.
function run_test_3() {
do_print("Testing with strict compatibility disabled, but addon opt-in");
Services.prefs.setBoolPref(PREF_EM_STRICT_COMPATIBILITY, false);
AddonManager.getAddonByID("compatmode-strict-optin@tests.mozilla.org", function(addon) {
do_check_neq(addon, null);
addon.findUpdates({
onCompatibilityUpdateAvailable: function() {
do_throw("Should have not have seen compatibility information");
},
onUpdateAvailable: function(addon, install) {
do_throw("Should not have seen an available update");
},
onUpdateFinished: function() {
run_test_4();
}
}, AddonManager.UPDATE_WHEN_USER_REQUESTED);
});
}
// Compatibility checking disabled.
function run_test_4() {
do_print("Testing with all compatibility checking disabled");
Services.prefs.setBoolPref(COMPATIBILITY_PREF, false);
AddonManager.getAddonByID("compatmode-ignore@tests.mozilla.org", function(addon) {
do_check_neq(addon, null);
addon.findUpdates({
onCompatibilityUpdateAvailable: function() {
do_throw("Should have not have seen compatibility information");
},
onNoUpdateAvailable: function() {
do_throw("Should have seen an available update");
},
onUpdateAvailable: function(addon, install) {
do_check_eq(install.version, "2.0")
},
onUpdateFinished: function() {
end_test();
}
}, AddonManager.UPDATE_WHEN_USER_REQUESTED);
});
}

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

@ -0,0 +1,99 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
// This verifies that add-on update checks work correctly when compatibility
// check is disabled.
const PREF_GETADDONS_BYIDS = "extensions.getAddons.get.url";
const PREF_GETADDONS_CACHE_ENABLED = "extensions.getAddons.cache.enabled";
// The test extension uses an insecure update url.
Services.prefs.setBoolPref(PREF_EM_CHECK_UPDATE_SECURITY, false);
do_load_httpd_js();
var testserver;
const profileDir = gProfD.clone();
profileDir.append("extensions");
function run_test() {
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2");
// Create and configure the HTTP server.
testserver = new nsHttpServer();
testserver.registerDirectory("/data/", do_get_file("data"));
testserver.registerDirectory("/addons/", do_get_file("addons"));
testserver.start(4444);
run_test_1();
}
// Test that the update check correctly observes the
// extensions.strictCompatibility pref and compatibility overrides.
function run_test_1() {
writeInstallRDFForExtension({
id: "addon9@tests.mozilla.org",
version: "1.0",
updateURL: "http://localhost:4444/data/test_update.rdf",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "0.1",
maxVersion: "0.2"
}],
name: "Test Addon 9",
}, profileDir);
restartManager();
AddonManager.addInstallListener({
onNewInstall: function(aInstall) {
if (aInstall.existingAddon.id != "addon9@tests.mozilla.org")
do_throw("Saw unexpected onNewInstall for " + aInstall.existingAddon.id);
do_check_eq(aInstall.version, "4.0");
},
onDownloadFailed: function(aInstall) {
do_execute_soon(run_test_2);
}
});
Services.prefs.setCharPref(PREF_GETADDONS_BYIDS, "http://localhost:4444/data/test_update.xml");
Services.prefs.setBoolPref(PREF_GETADDONS_CACHE_ENABLED, true);
// Fake a timer event
gInternalManager.notify(null);
}
// Test that the update check correctly observes when an addon opts-in to
// strict compatibility checking.
function run_test_2() {
writeInstallRDFForExtension({
id: "addon11@tests.mozilla.org",
version: "1.0",
updateURL: "http://localhost:4444/data/test_update.rdf",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "0.1",
maxVersion: "0.2"
}],
name: "Test Addon 11",
}, profileDir);
restartManager();
AddonManager.getAddonByID("addon11@tests.mozilla.org", function(a11) {
do_check_neq(a11, null);
a11.findUpdates({
onCompatibilityUpdateAvailable: function() {
do_throw("Should have not have seen compatibility information");
},
onNoUpdateAvailable: function() {
do_throw("Should have seen an available update");
},
onUpdateFinished: function() {
end_test();
}
}, AddonManager.UPDATE_WHEN_USER_REQUESTED);
});
}

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

@ -6,6 +6,8 @@
const PREF_MATCH_OS_LOCALE = "intl.locale.matchOS";
const PREF_SELECTED_LOCALE = "general.useragent.locale";
const PREF_GETADDONS_BYIDS = "extensions.getAddons.get.url";
const PREF_GETADDONS_CACHE_ENABLED = "extensions.getAddons.cache.enabled";
// The test extension uses an insecure update url.
Services.prefs.setBoolPref("extensions.checkUpdateSecurity", false);
@ -1016,6 +1018,75 @@ function check_test_15(aInstall) {
restartManager();
end_test();
run_test_16();
});
}
// Test that the update check correctly observes the
// extensions.strictCompatibility pref and compatibility overrides.
function run_test_16() {
writeInstallRDFForExtension({
id: "addon9@tests.mozilla.org",
version: "1.0",
updateURL: "http://localhost:4444/data/test_update.rdf",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "0.1",
maxVersion: "0.2"
}],
name: "Test Addon 9",
}, profileDir);
restartManager();
AddonManager.addInstallListener({
onNewInstall: function(aInstall) {
if (aInstall.existingAddon.id != "addon9@tests.mozilla.org")
do_throw("Saw unexpected onNewInstall for " + aInstall.existingAddon.id);
do_check_eq(aInstall.version, "2.0");
},
onDownloadFailed: function(aInstall) {
do_execute_soon(run_test_17);
}
});
Services.prefs.setCharPref(PREF_GETADDONS_BYIDS, "http://localhost:4444/data/test_update.xml");
Services.prefs.setBoolPref(PREF_GETADDONS_CACHE_ENABLED, true);
// Fake a timer event
gInternalManager.notify(null);
}
// Test that the update check correctly observes when an addon opts-in to
// strict compatibility checking.
function run_test_17() {
writeInstallRDFForExtension({
id: "addon11@tests.mozilla.org",
version: "1.0",
updateURL: "http://localhost:4444/data/test_update.rdf",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "0.1",
maxVersion: "0.2"
}],
name: "Test Addon 11",
}, profileDir);
restartManager();
AddonManager.getAddonByID("addon11@tests.mozilla.org", function(a11) {
do_check_neq(a11, null);
a11.findUpdates({
onCompatibilityUpdateAvailable: function() {
do_throw("Should have not have seen compatibility information");
},
onUpdateAvailable: function() {
do_throw("Should not have seen an available update");
},
onUpdateFinished: function() {
end_test();
}
}, AddonManager.UPDATE_WHEN_USER_REQUESTED);
});
}

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

@ -6,6 +6,18 @@
Components.utils.import("resource://gre/modules/AddonUpdateChecker.jsm");
var channel = "default";
try {
channel = Services.prefs.getCharPref("app.update.channel");
} catch (e) { }
if (channel != "aurora" && channel != "beta" && channel != "release")
var version = "nightly";
else
version = Services.appinfo.version.replace(/^([^\.]+\.[0-9]+[a-z]*).*/gi, "$1");
const COMPATIBILITY_PREF = "extensions.checkCompatibility." + version;
do_load_httpd_js();
var testserver;
@ -226,7 +238,87 @@ function run_test_11() {
onUpdateCheckError: function(status) {
do_check_eq(status, AddonUpdateChecker.ERROR_PARSE_ERROR);
end_test();
run_test_12();
}
});
}
function run_test_12() {
AddonUpdateChecker.checkForUpdates("ignore-compat@tests.mozilla.org",
"extension", null,
"http://localhost:4444/data/test_updatecheck.rdf", {
onUpdateCheckComplete: function(updates) {
do_check_eq(updates.length, 3);
let update = AddonUpdateChecker.getNewestCompatibleUpdate(updates,
null,
null,
true);
do_check_neq(update, null);
do_check_eq(update.version, 2);
run_test_13();
},
onUpdateCheckError: function(status) {
do_throw("Update check failed with status " + status);
}
});
}
function run_test_13() {
AddonUpdateChecker.checkForUpdates("compat-override@tests.mozilla.org",
"extension", null,
"http://localhost:4444/data/test_updatecheck.rdf", {
onUpdateCheckComplete: function(updates) {
do_check_eq(updates.length, 3);
let overrides = [{
type: "incompatible",
minVersion: 1,
maxVersion: 2,
appID: "xpcshell@tests.mozilla.org",
appMinVersion: 0.1,
appMaxVersion: 0.2
}, {
type: "incompatible",
minVersion: 2,
maxVersion: 2,
appID: "xpcshell@tests.mozilla.org",
appMinVersion: 1,
appMaxVersion: 2
}];
let update = AddonUpdateChecker.getNewestCompatibleUpdate(updates,
null,
null,
true,
false,
overrides);
do_check_neq(update, null);
do_check_eq(update.version, 1);
run_test_14();
},
onUpdateCheckError: function(status) {
do_throw("Update check failed with status " + status);
}
});
}
function run_test_14() {
AddonUpdateChecker.checkForUpdates("compat-strict-optin@tests.mozilla.org",
"extension", null,
"http://localhost:4444/data/test_updatecheck.rdf", {
onUpdateCheckComplete: function(updates) {
do_check_eq(updates.length, 1);
let update = AddonUpdateChecker.getNewestCompatibleUpdate(updates,
null,
null,
true,
false);
do_check_eq(update, null);
end_test();
},
onUpdateCheckError: function(status) {
do_throw("Update check failed with status " + status);
}
});
}

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

@ -127,6 +127,7 @@ fail-if = os == "android"
[test_cacheflush.js]
[test_checkcompatibility.js]
[test_ChromeManifestParser.js]
[test_compatoverrides.js]
[test_corrupt.js]
[test_corrupt_strictcompat.js]
[test_dictionary.js]
@ -198,12 +199,16 @@ skip-if = os == "android"
[test_update_strictcompat.js]
# Bug 676992: test consistently hangs on Android
skip-if = os == "android"
[test_update_ignorecompat.js]
# Bug 676992: test consistently hangs on Android
skip-if = os == "android"
[test_updatecheck.js]
# Bug 676992: test consistently hangs on Android
skip-if = os == "android"
[test_updateid.js]
# Bug 676992: test consistently hangs on Android
skip-if = os == "android"
[test_update_compatmode.js]
[test_upgrade.js]
# Bug 676992: test consistently hangs on Android
skip-if = os == "android"

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

@ -957,7 +957,7 @@ backtrace(tm_thread *t, int skip, int *immediate_abort)
t->suppress_tracing++;
if (!stacks_enabled) {
#if defined(XP_MACOSX)
#if defined(XP_MACOSX) && defined(__i386)
/* Walk the stack, even if stacks_enabled is false. We do this to
check if we must set immediate_abort. */
info->entries = 0;

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

@ -41,147 +41,9 @@
/* API for getting a stack trace of the C/C++ stack on the current thread */
#include "mozilla/Util.h"
#include "nsDebug.h"
#include "nsStackWalkPrivate.h"
#include "nsStackWalk.h"
// The presence of this address is the stack must stop the stack walk. If
// there is no such address, the structure will be {NULL, true}.
struct CriticalAddress {
void* mAddr;
bool mInit;
};
static CriticalAddress gCriticalAddress;
#if defined(HAVE_DLOPEN) || defined(XP_MACOSX)
#include <dlfcn.h>
#endif
#ifdef XP_MACOSX
#include <pthread.h>
#include <errno.h>
#include <CoreServices/CoreServices.h>
typedef void
malloc_logger_t(uint32_t type, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3,
uintptr_t result, uint32_t num_hot_frames_to_skip);
extern malloc_logger_t *malloc_logger;
static void
stack_callback(void *pc, void *closure)
{
const char *name = reinterpret_cast<char *>(closure);
Dl_info info;
// On Leopard dladdr returns the wrong value for "new_sem_from_pool". The
// stack shows up as having two pthread_cond_wait$UNIX2003 frames. The
// correct one is the first that we find on our way up, so the
// following check for gCriticalAddress.mAddr is critical.
if(gCriticalAddress.mAddr || dladdr(pc, &info) == 0 ||
info.dli_sname == NULL || strcmp(info.dli_sname, name) != 0)
return;
gCriticalAddress.mAddr = pc;
}
#define MAC_OS_X_VERSION_10_7_HEX 0x00001070
#define MAC_OS_X_VERSION_10_6_HEX 0x00001060
static PRInt32 OSXVersion()
{
static PRInt32 gOSXVersion = 0x0;
if (gOSXVersion == 0x0) {
OSErr err = ::Gestalt(gestaltSystemVersion, (SInt32*)&gOSXVersion);
MOZ_ASSERT(err == noErr);
}
return gOSXVersion;
}
static bool OnLionOrLater()
{
return (OSXVersion() >= MAC_OS_X_VERSION_10_7_HEX);
}
static bool OnSnowLeopardOrLater()
{
return (OSXVersion() >= MAC_OS_X_VERSION_10_6_HEX);
}
static void
my_malloc_logger(uint32_t type, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3,
uintptr_t result, uint32_t num_hot_frames_to_skip)
{
static bool once = false;
if (once)
return;
once = true;
// On Leopard dladdr returns the wrong value for "new_sem_from_pool". The
// stack shows up as having two pthread_cond_wait$UNIX2003 frames.
const char *name = OnSnowLeopardOrLater() ? "new_sem_from_pool" :
"pthread_cond_wait$UNIX2003";
NS_StackWalk(stack_callback, 0, const_cast<char*>(name));
}
void
StackWalkInitCriticalAddress()
{
if(gCriticalAddress.mInit)
return;
gCriticalAddress.mInit = true;
// We must not do work when 'new_sem_from_pool' calls realloc, since
// it holds a non-reentrant spin-lock and we will quickly deadlock.
// new_sem_from_pool is not directly accessible using dlsym, so
// we force a situation where new_sem_from_pool is on the stack and
// use dladdr to check the addresses.
MOZ_ASSERT(malloc_logger == NULL);
malloc_logger = my_malloc_logger;
pthread_cond_t cond;
int r = pthread_cond_init(&cond, 0);
MOZ_ASSERT(r == 0);
pthread_mutex_t mutex;
r = pthread_mutex_init(&mutex,0);
MOZ_ASSERT(r == 0);
r = pthread_mutex_lock(&mutex);
MOZ_ASSERT(r == 0);
struct timespec abstime = {0, 1};
r = pthread_cond_timedwait_relative_np(&cond, &mutex, &abstime);
malloc_logger = NULL;
// On Lion, malloc is no longer called from pthread_cond_*wait*. This prevents
// us from finding the address, but that is fine, since with no call to malloc
// there is no critical address.
MOZ_ASSERT(OnLionOrLater() || gCriticalAddress.mAddr != NULL);
MOZ_ASSERT(r == ETIMEDOUT);
r = pthread_mutex_unlock(&mutex);
MOZ_ASSERT(r == 0);
r = pthread_mutex_destroy(&mutex);
MOZ_ASSERT(r == 0);
r = pthread_cond_destroy(&cond);
MOZ_ASSERT(r == 0);
}
static bool IsCriticalAddress(void* aPC)
{
return gCriticalAddress.mAddr == aPC;
}
#else
static bool IsCriticalAddress(void* aPC)
{
return false;
}
// We still initialize gCriticalAddress.mInit so that this code behaves
// the same on all platforms. Otherwise a failure to init would be visible
// only on OS X.
void
StackWalkInitCriticalAddress()
{
gCriticalAddress.mInit = true;
}
#endif
#if defined(_WIN32) && (defined(_M_IX86) || defined(_M_AMD64) || defined(_M_IA64)) // WIN32 x86 stack walking code
#include "nscore.h"
@ -793,7 +655,6 @@ EXPORT_XPCOM_API(nsresult)
NS_StackWalk(NS_WalkStackCallback aCallback, PRUint32 aSkipFrames,
void *aClosure)
{
MOZ_ASSERT(gCriticalAddress.mInit);
HANDLE myProcess, myThread;
DWORD walkerReturn;
struct WalkStackData data;
@ -1279,6 +1140,12 @@ NS_FormatCodeAddressDetails(void *aPC, const nsCodeAddressDetails *aDetails,
#define __USE_GNU
#endif
#if defined(HAVE_DLOPEN) || defined(XP_MACOSX)
#include <dlfcn.h>
#endif
// This thing is exported by libstdc++
// Yes, this is a gcc only hack
#if defined(MOZ_DEMANGLE_SYMBOLS)
@ -1481,7 +1348,6 @@ EXPORT_XPCOM_API(nsresult)
NS_StackWalk(NS_WalkStackCallback aCallback, PRUint32 aSkipFrames,
void *aClosure)
{
MOZ_ASSERT(gCriticalAddress.mInit);
struct my_user_args args;
if (!initialized)
@ -1556,12 +1422,58 @@ NS_FormatCodeAddressDetails(void *aPC, const nsCodeAddressDetails *aDetails,
extern void *__libc_stack_end; // from ld-linux.so
#endif
#ifdef XP_MACOSX
struct AddressRange {
void* mStart;
void* mEnd;
};
// Addresses in this range must stop the stack walk
static AddressRange gCriticalRange;
static void FindFunctionAddresses(const char* aName, AddressRange* aRange)
{
aRange->mStart = dlsym(RTLD_DEFAULT, aName);
if (!aRange->mStart)
return;
aRange->mEnd = aRange->mStart;
while (true) {
Dl_info info;
if (!dladdr(aRange->mEnd, &info))
break;
if (strcmp(info.dli_sname, aName))
break;
aRange->mEnd = (char*)aRange->mEnd + 1;
}
}
static void InitCriticalRanges()
{
if (gCriticalRange.mStart)
return;
// We must not do work when 'new_sem_from_pool' calls realloc, since
// it holds a non-reentrant spin-lock and we will quickly deadlock.
// new_sem_from_pool is not directly accessible using dladdr but its
// code is bundled with pthread_cond_wait$UNIX2003 (on
// Leopard anyway).
FindFunctionAddresses("pthread_cond_wait$UNIX2003", &gCriticalRange);
}
static bool InCriticalRange(void* aPC)
{
return gCriticalRange.mStart &&
gCriticalRange.mStart <= aPC && aPC < gCriticalRange.mEnd;
}
#else
static void InitCriticalRanges() {}
static bool InCriticalRange(void* aPC) { return false; }
#endif
EXPORT_XPCOM_API(nsresult)
NS_StackWalk(NS_WalkStackCallback aCallback, PRUint32 aSkipFrames,
void *aClosure)
{
MOZ_ASSERT(gCriticalAddress.mInit);
// Stack walking code courtesy Kipp's "leaky".
InitCriticalRanges();
// Get the frame pointer
void **bp;
@ -1594,8 +1506,8 @@ NS_StackWalk(NS_WalkStackCallback aCallback, PRUint32 aSkipFrames,
#else // i386 or powerpc32 linux
void *pc = *(bp+1);
#endif
if (IsCriticalAddress(pc)) {
printf("Aborting stack trace, PC is critical\n");
if (InCriticalRange(pc)) {
printf("Aborting stack trace, PC in critical range\n");
return NS_ERROR_UNEXPECTED;
}
if (--skip < 0) {
@ -1621,13 +1533,10 @@ static _Unwind_Reason_Code
unwind_callback (struct _Unwind_Context *context, void *closure)
{
unwind_info *info = static_cast<unwind_info *>(closure);
void *pc = reinterpret_cast<void *>(_Unwind_GetIP(context));
if (IsCriticalAddress(pc)) {
printf("Aborting stack trace, PC is critical\n");
return _URC_NORMAL_STOP;
}
if (--info->skip < 0)
if (--info->skip < 0) {
void *pc = reinterpret_cast<void *>(_Unwind_GetIP(context));
(*info->callback)(pc, info->closure);
}
return _URC_NO_REASON;
}
@ -1635,15 +1544,13 @@ EXPORT_XPCOM_API(nsresult)
NS_StackWalk(NS_WalkStackCallback aCallback, PRUint32 aSkipFrames,
void *aClosure)
{
MOZ_ASSERT(gCriticalAddress.mInit);
unwind_info info;
info.callback = aCallback;
info.skip = aSkipFrames + 1;
info.closure = aClosure;
_Unwind_Reason_Code t = _Unwind_Backtrace(unwind_callback, &info);
if (t != _URC_END_OF_STACK)
return NS_ERROR_UNEXPECTED;
_Unwind_Backtrace(unwind_callback, &info);
return NS_OK;
}
@ -1713,7 +1620,6 @@ EXPORT_XPCOM_API(nsresult)
NS_StackWalk(NS_WalkStackCallback aCallback, PRUint32 aSkipFrames,
void *aClosure)
{
MOZ_ASSERT(gCriticalAddress.mInit);
return NS_ERROR_NOT_IMPLEMENTED;
}

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

@ -1,43 +0,0 @@
/* vim: set shiftwidth=4 tabstop=8 autoindent cindent expandtab: */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is NS_WalkTheStack.
*
* The Initial Developer of the Original Code is the Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2007
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Mozilla Corporation (original author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
/**
* Initialize the critical sections for this platform so that we can
* abort stack walks when needed.
*/
void
StackWalkInitCriticalAddress(void);

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

@ -50,7 +50,6 @@
#include "nsCOMPtr.h"
#include "nsCRT.h"
#include <math.h>
#include "nsStackWalkPrivate.h"
#include "nsStackWalk.h"
#include "nsString.h"
@ -924,8 +923,6 @@ nsTraceRefcntImpl::DemangleSymbol(const char * aSymbol,
EXPORT_XPCOM_API(void)
NS_LogInit()
{
// FIXME: This is called multiple times, we should probably not allow that.
StackWalkInitCriticalAddress();
#ifdef NS_IMPL_REFCNT_LOGGING
if (++gInitCount)
nsTraceRefcntImpl::SetActivityIsLegal(true);