Backed out 15 changesets (bug 1358846, bug 1356826) for talos error. a=backout

Backed out changeset 96ea13bb00c5 (bug 1358846)
Backed out changeset b533d7f9b9c2 (bug 1358846)
Backed out changeset 7dcb80a051a3 (bug 1358846)
Backed out changeset 26825f1e33dd (bug 1358846)
Backed out changeset 98b57ff82a54 (bug 1358846)
Backed out changeset b9088593e34f (bug 1358846)
Backed out changeset cb2518673c56 (bug 1358846)
Backed out changeset 889c487a5d41 (bug 1358846)
Backed out changeset 459b36092b7a (bug 1356826)
Backed out changeset c861e23ec8ef (bug 1356826)
Backed out changeset d47998fa24cd (bug 1356826)
Backed out changeset b02e89c67132 (bug 1356826)
Backed out changeset c46fed6e4f6a (bug 1356826)
Backed out changeset 237268e3d9d2 (bug 1356826)
Backed out changeset 527435fc20db (bug 1356826)
This commit is contained in:
Iris Hsiao 2017-05-12 17:45:21 +08:00
Родитель fcd9a5550a
Коммит 6559420d58
77 изменённых файлов: 3344 добавлений и 2650 удалений

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

@ -1,7 +1,6 @@
[addon-manager.xpi] [addon-manager.xpi]
[author-email.xpi] [author-email.xpi]
[child_process.xpi] [child_process.xpi]
skip-if = true
[chrome.xpi] [chrome.xpi]
[content-permissions.xpi] [content-permissions.xpi]
[content-script-messages-latency.xpi] [content-script-messages-latency.xpi]

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

@ -69,8 +69,6 @@ pref("extensions.screenshots.system-disabled", true);
// Disable add-ons that are not installed by the user in all scopes by default. // Disable add-ons that are not installed by the user in all scopes by default.
// See the SCOPE constants in AddonManager.jsm for values to use here. // See the SCOPE constants in AddonManager.jsm for values to use here.
pref("extensions.autoDisableScopes", 15); pref("extensions.autoDisableScopes", 15);
// Scopes to scan for changes at startup.
pref("extensions.startupScanScopes", 0);
// This is where the profiler WebExtension API will look for breakpad symbols. // This is where the profiler WebExtension API will look for breakpad symbols.
// NOTE: deliberately http right now since https://symbols.mozilla.org is not supported. // NOTE: deliberately http right now since https://symbols.mozilla.org is not supported.

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

@ -1143,11 +1143,6 @@ addEventListener("DOMContentLoaded", function onDCL() {
gBrowser.updateBrowserRemoteness(initBrowser, gMultiProcessBrowser); gBrowser.updateBrowserRemoteness(initBrowser, gMultiProcessBrowser);
}); });
let _resolveDelayedStartup;
var delayedStartupPromise = new Promise(resolve => {
_resolveDelayedStartup = resolve;
});
var gBrowserInit = { var gBrowserInit = {
delayedStartupFinished: false, delayedStartupFinished: false,
@ -1624,7 +1619,6 @@ var gBrowserInit = {
this.delayedStartupFinished = true; this.delayedStartupFinished = true;
_resolveDelayedStartup();
Services.obs.notifyObservers(window, "browser-delayed-startup-finished"); Services.obs.notifyObservers(window, "browser-delayed-startup-finished");
TelemetryTimestamps.add("delayedStartupFinished"); TelemetryTimestamps.add("delayedStartupFinished");
}, },

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

@ -1,89 +1,155 @@
const {AddonManagerPrivate} = Cu.import("resource://gre/modules/AddonManager.jsm", {}); const {AddonManagerPrivate} = Cu.import("resource://gre/modules/AddonManager.jsm", {});
const {AddonTestUtils} = Cu.import("resource://testing-common/AddonTestUtils.jsm", {}); // MockAddon mimics the AddonInternal interface and MockProvider implements
// just enough of the AddonManager provider interface to make it look like
// we have sideloaded webextensions so the sideloading flow can be tested.
AddonTestUtils.initMochitest(this); // MockAddon -> callback
let setCallbacks = new Map();
async function createWebExtension(details) { class MockAddon {
let options = { constructor(props) {
manifest: { this._userDisabled = false;
applications: {gecko: {id: details.id}}, this.pendingOperations = 0;
this.type = "extension";
name: details.name, for (let name in props) {
if (name == "userDisabled") {
permissions: details.permissions, this._userDisabled = props[name];
}, }
}; this[name] = props[name];
}
if (details.iconURL) {
options.manifest.icons = {"64": details.iconURL};
} }
let xpi = AddonTestUtils.createTempWebExtensionFile(options); markAsSeen() {
this.seen = true;
}
await AddonTestUtils.manuallyInstall(xpi); get userDisabled() {
return this._userDisabled;
}
set userDisabled(val) {
this._userDisabled = val;
AddonManagerPrivate.callAddonListeners(val ? "onDisabled" : "onEnabled", this);
let fn = setCallbacks.get(this);
if (fn) {
setCallbacks.delete(this);
fn(val);
}
return val;
}
get permissions() {
return this._userDisabled ? AddonManager.PERM_CAN_ENABLE : AddonManager.PERM_CAN_DISABLE;
}
} }
async function createXULExtension(details) { class MockProvider {
let xpi = AddonTestUtils.createTempXPIFile({ constructor(...addons) {
"install.rdf": { this.addons = new Set(addons);
id: details.id, }
name: details.name,
version: "0.1",
targetApplications: [{
id: "toolkit@mozilla.org",
minVersion: "0",
maxVersion: "*",
}],
},
});
await AddonTestUtils.manuallyInstall(xpi); startup() { }
shutdown() { }
getAddonByID(id, callback) {
for (let addon of this.addons) {
if (addon.id == id) {
callback(addon);
return;
}
}
callback(null);
}
getAddonsByTypes(types, callback) {
let addons = [];
if (!types || types.includes("extension")) {
addons = [...this.addons];
}
callback(addons);
}
}
function promiseSetDisabled(addon) {
return new Promise(resolve => {
setCallbacks.set(addon, resolve);
});
} }
let cleanup; let cleanup;
add_task(function* test_sideloading() { add_task(function* () {
// ICON_URL wouldn't ever appear as an actual webextension icon, but
// we're just mocking out the addon here, so all we care about is that
// that it propagates correctly to the popup.
const ICON_URL = "chrome://mozapps/skin/extensions/category-extensions.svg";
const DEFAULT_ICON_URL = "chrome://mozapps/skin/extensions/extensionGeneric.svg"; const DEFAULT_ICON_URL = "chrome://mozapps/skin/extensions/extensionGeneric.svg";
yield SpecialPowers.pushPrefEnv({
set: [
["xpinstall.signatures.required", false],
["extensions.autoDisableScopes", 15],
["extensions.ui.ignoreUnsigned", true],
],
});
const ID1 = "addon1@tests.mozilla.org"; const ID1 = "addon1@tests.mozilla.org";
yield createWebExtension({ let mock1 = new MockAddon({
id: ID1, id: ID1,
name: "Test 1", name: "Test 1",
userDisabled: true, userDisabled: true,
permissions: ["history", "https://*/*"], seen: false,
iconURL: "foo-icon.png", userPermissions: {
permissions: ["history"],
origins: ["https://*/*"],
},
iconURL: ICON_URL,
}); });
const ID2 = "addon2@tests.mozilla.org"; const ID2 = "addon2@tests.mozilla.org";
yield createXULExtension({ let mock2 = new MockAddon({
id: ID2, id: ID2,
name: "Test 2", name: "Test 2",
userDisabled: true,
seen: false,
userPermissions: {
permissions: [],
origins: [],
},
}); });
const ID3 = "addon3@tests.mozilla.org"; const ID3 = "addon3@tests.mozilla.org";
yield createWebExtension({ let mock3 = new MockAddon({
id: ID3, id: ID3,
name: "Test 3", name: "Test 3",
permissions: ["<all_urls>"], isWebExtension: true,
userDisabled: true,
seen: false,
userPermissions: {
permissions: [],
origins: ["<all_urls>"],
}
}); });
const ID4 = "addon4@tests.mozilla.org"; const ID4 = "addon4@tests.mozilla.org";
yield createWebExtension({ let mock4 = new MockAddon({
id: ID4, id: ID4,
name: "Test 4", name: "Test 4",
permissions: ["<all_urls>"], isWebExtension: true,
userDisabled: true,
seen: false,
userPermissions: {
permissions: [],
origins: ["<all_urls>"],
}
}); });
let provider = new MockProvider(mock1, mock2, mock3, mock4);
AddonManagerPrivate.registerProvider(provider, [{
id: "extension",
name: "Extensions",
uiPriority: 4000,
flags: AddonManager.TYPE_UI_VIEW_LIST |
AddonManager.TYPE_SUPPORTS_UNDO_RESTARTLESS_UNINSTALL,
}]);
testCleanup = async function() { testCleanup = async function() {
AddonManagerPrivate.unregisterProvider(provider);
// clear out ExtensionsUI state about sideloaded extensions so // clear out ExtensionsUI state about sideloaded extensions so
// subsequent tests don't get confused. // subsequent tests don't get confused.
ExtensionsUI.sideloaded.clear(); ExtensionsUI.sideloaded.clear();
@ -137,13 +203,17 @@ add_task(function* test_sideloading() {
is(win.gViewController.currentViewId, VIEW, "about:addons is at extensions list"); is(win.gViewController.currentViewId, VIEW, "about:addons is at extensions list");
// Check the contents of the notification, then choose "Cancel" // Check the contents of the notification, then choose "Cancel"
checkNotification(panel, /\/foo-icon\.png$/, [ checkNotification(panel, ICON_URL, [
["webextPerms.hostDescription.allUrls"], ["webextPerms.hostDescription.allUrls"],
["webextPerms.description.history"], ["webextPerms.description.history"],
]); ]);
let disablePromise = promiseSetDisabled(mock1);
panel.secondaryButton.click(); panel.secondaryButton.click();
let value = yield disablePromise;
is(value, true, "Addon should remain disabled");
let [addon1, addon2, addon3, addon4] = yield AddonManager.getAddonsByIDs([ID1, ID2, ID3, ID4]); let [addon1, addon2, addon3, addon4] = yield AddonManager.getAddonsByIDs([ID1, ID2, ID3, ID4]);
ok(addon1.seen, "Addon should be marked as seen"); ok(addon1.seen, "Addon should be marked as seen");
is(addon1.userDisabled, true, "Addon 1 should still be disabled"); is(addon1.userDisabled, true, "Addon 1 should still be disabled");
@ -175,8 +245,12 @@ add_task(function* test_sideloading() {
checkNotification(panel, DEFAULT_ICON_URL, []); checkNotification(panel, DEFAULT_ICON_URL, []);
// This time accept the install. // This time accept the install.
disablePromise = promiseSetDisabled(mock2);
panel.button.click(); panel.button.click();
value = yield disablePromise;
is(value, false, "Addon should be set to enabled");
[addon1, addon2, addon3, addon4] = yield AddonManager.getAddonsByIDs([ID1, ID2, ID3, ID4]); [addon1, addon2, addon3, addon4] = yield AddonManager.getAddonsByIDs([ID1, ID2, ID3, ID4]);
is(addon1.userDisabled, true, "Addon 1 should still be disabled"); is(addon1.userDisabled, true, "Addon 1 should still be disabled");
is(addon2.userDisabled, false, "Addon 2 should now be enabled"); is(addon2.userDisabled, false, "Addon 2 should now be enabled");
@ -214,7 +288,10 @@ add_task(function* test_sideloading() {
checkNotification(panel, DEFAULT_ICON_URL, [["webextPerms.hostDescription.allUrls"]]); checkNotification(panel, DEFAULT_ICON_URL, [["webextPerms.hostDescription.allUrls"]]);
// Accept the permissions // Accept the permissions
disablePromise = promiseSetDisabled(mock3);
panel.button.click(); panel.button.click();
value = yield disablePromise;
is(value, false, "userDisabled should be set on addon 3");
addon3 = yield AddonManager.getAddonByID(ID3); addon3 = yield AddonManager.getAddonByID(ID3);
is(addon3.userDisabled, false, "Addon 3 should be enabled"); is(addon3.userDisabled, false, "Addon 3 should be enabled");
@ -239,7 +316,10 @@ add_task(function* test_sideloading() {
checkNotification(panel, DEFAULT_ICON_URL, [["webextPerms.hostDescription.allUrls"]]); checkNotification(panel, DEFAULT_ICON_URL, [["webextPerms.hostDescription.allUrls"]]);
// Accept the permissions // Accept the permissions
disablePromise = promiseSetDisabled(mock4);
panel.button.click(); panel.button.click();
value = yield disablePromise;
is(value, false, "userDisabled should be set on addon 4");
addon4 = yield AddonManager.getAddonByID(ID4); addon4 = yield AddonManager.getAddonByID(ID4);
is(addon4.userDisabled, false, "Addon 4 should be enabled"); is(addon4.userDisabled, false, "Addon 4 should be enabled");
@ -249,11 +329,5 @@ add_task(function* test_sideloading() {
isnot(menuButton.getAttribute("badge-status"), "addon-alert", "Should no longer have addon alert badge"); isnot(menuButton.getAttribute("badge-status"), "addon-alert", "Should no longer have addon alert badge");
yield new Promise(resolve => setTimeout(resolve, 100));
for (let addon of [addon1, addon2, addon3, addon4]) {
addon.uninstall();
}
yield BrowserTestUtils.removeTab(gBrowser.selectedTab); yield BrowserTestUtils.removeTab(gBrowser.selectedTab);
}); });

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

@ -218,7 +218,7 @@ function checkNotification(panel, checkIcon, permissions) {
let header = document.getElementById("addon-webext-perm-intro"); let header = document.getElementById("addon-webext-perm-intro");
if (checkIcon instanceof RegExp) { if (checkIcon instanceof RegExp) {
ok(checkIcon.test(icon), `Notification icon is correct ${JSON.stringify(icon)} ~= ${checkIcon}`); ok(checkIcon.test(icon), "Notification icon is correct");
} else if (typeof checkIcon == "function") { } else if (typeof checkIcon == "function") {
ok(checkIcon(icon), "Notification icon is correct"); ok(checkIcon(icon), "Notification icon is correct");
} else { } else {

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

@ -12,8 +12,6 @@ Cu.import("resource://gre/modules/EventEmitter.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "AddonManager", XPCOMUtils.defineLazyModuleGetter(this, "AddonManager",
"resource://gre/modules/AddonManager.jsm"); "resource://gre/modules/AddonManager.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "AddonManagerPrivate",
"resource://gre/modules/AddonManager.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PluralForm", XPCOMUtils.defineLazyModuleGetter(this, "PluralForm",
"resource://gre/modules/PluralForm.jsm"); "resource://gre/modules/PluralForm.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "RecentWindow", XPCOMUtils.defineLazyModuleGetter(this, "RecentWindow",
@ -37,7 +35,7 @@ this.ExtensionsUI = {
sideloadListener: null, sideloadListener: null,
histogram: null, histogram: null,
async init() { init() {
this.histogram = Services.telemetry.getHistogramById("EXTENSION_INSTALL_PROMPT_RESULT"); this.histogram = Services.telemetry.getHistogramById("EXTENSION_INSTALL_PROMPT_RESULT");
Services.obs.addObserver(this, "webextension-permission-prompt"); Services.obs.addObserver(this, "webextension-permission-prompt");
@ -45,55 +43,53 @@ this.ExtensionsUI = {
Services.obs.addObserver(this, "webextension-install-notify"); Services.obs.addObserver(this, "webextension-install-notify");
Services.obs.addObserver(this, "webextension-optional-permission-prompt"); Services.obs.addObserver(this, "webextension-optional-permission-prompt");
await RecentWindow.getMostRecentBrowserWindow().delayedStartupPromise;
this._checkForSideloaded(); this._checkForSideloaded();
}, },
async _checkForSideloaded() { _checkForSideloaded() {
let sideloaded = await AddonManagerPrivate.getNewSideloads(); AddonManager.getAllAddons(addons => {
// Check for any side-loaded addons that the user is allowed
// to enable.
let sideloaded = addons.filter(
addon => addon.seen === false && (addon.permissions & AddonManager.PERM_CAN_ENABLE));
if (!sideloaded.length) { if (!sideloaded.length) {
// No new side-loads. We're done. return;
return;
}
// The ordering shouldn't matter, but tests depend on notifications
// happening in a specific order.
sideloaded.sort((a, b) => a.id.localeCompare(b.id));
if (WEBEXT_PERMISSION_PROMPTS) {
if (!this.sideloadListener) {
this.sideloadListener = {
onEnabled: addon => {
if (!this.sideloaded.has(addon)) {
return;
}
this.sideloaded.delete(addon);
this.emit("change");
if (this.sideloaded.size == 0) {
AddonManager.removeAddonListener(this.sideloadListener);
this.sideloadListener = null;
}
},
};
AddonManager.addAddonListener(this.sideloadListener);
} }
for (let addon of sideloaded) { if (WEBEXT_PERMISSION_PROMPTS) {
this.sideloaded.add(addon); if (!this.sideloadListener) {
this.sideloadListener = {
onEnabled: addon => {
if (!this.sideloaded.has(addon)) {
return;
}
this.sideloaded.delete(addon);
this.emit("change");
if (this.sideloaded.size == 0) {
AddonManager.removeAddonListener(this.sideloadListener);
this.sideloadListener = null;
}
},
};
AddonManager.addAddonListener(this.sideloadListener);
}
for (let addon of sideloaded) {
this.sideloaded.add(addon);
}
this.emit("change");
} else {
// This and all the accompanying about:newaddon code can eventually
// be removed. See bug 1331521.
let win = RecentWindow.getMostRecentBrowserWindow();
for (let addon of sideloaded) {
win.openUILinkIn(`about:newaddon?id=${addon.id}`, "tab");
}
} }
this.emit("change"); });
} else {
// This and all the accompanying about:newaddon code can eventually
// be removed. See bug 1331521.
let win = RecentWindow.getMostRecentBrowserWindow();
for (let addon of sideloaded) {
win.openUILinkIn(`about:newaddon?id=${addon.id}`, "tab");
}
}
}, },
showAddonsManager(browser, strings, icon, histkey) { showAddonsManager(browser, strings, icon, histkey) {
@ -150,11 +146,6 @@ this.ExtensionsUI = {
} }
info.unsigned = info.addon.signedState <= AddonManager.SIGNEDSTATE_MISSING; info.unsigned = info.addon.signedState <= AddonManager.SIGNEDSTATE_MISSING;
if (info.unsigned && Cu.isInAutomation &&
Services.prefs.getBoolPref("extensions.ui.ignoreUnsigned", false)) {
info.unsigned = false;
}
let strings = this._buildStrings(info); let strings = this._buildStrings(info);
// If this is an update with no promptable permissions, just apply it // If this is an update with no promptable permissions, just apply it

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

@ -529,12 +529,6 @@ interface nsIXPCComponents_Utils : nsISupports
[implicit_jscontext] [implicit_jscontext]
attribute boolean ion; attribute boolean ion;
// Returns true if we're running in automation and certain security
// restrictions can be eased.
readonly attribute boolean isInAutomation;
void crashIfNotInAutomation();
[implicit_jscontext] [implicit_jscontext]
void setGCZeal(in long zeal); void setGCZeal(in long zeal);

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

@ -2916,7 +2916,7 @@ nsXPCComponents_Utils::SetWantXrays(HandleValue vscope, JSContext* cx)
NS_IMETHODIMP NS_IMETHODIMP
nsXPCComponents_Utils::ForcePermissiveCOWs(JSContext* cx) nsXPCComponents_Utils::ForcePermissiveCOWs(JSContext* cx)
{ {
xpc::CrashIfNotInAutomation(); CrashIfNotInAutomation();
CompartmentPrivate::Get(CurrentGlobalOrNull(cx))->forcePermissiveCOWs = true; CompartmentPrivate::Get(CurrentGlobalOrNull(cx))->forcePermissiveCOWs = true;
return NS_OK; return NS_OK;
} }
@ -2927,7 +2927,7 @@ nsXPCComponents_Utils::ForcePrivilegedComponentsForScope(HandleValue vscope,
{ {
if (!vscope.isObject()) if (!vscope.isObject())
return NS_ERROR_INVALID_ARG; return NS_ERROR_INVALID_ARG;
xpc::CrashIfNotInAutomation(); CrashIfNotInAutomation();
JSObject* scopeObj = js::UncheckedUnwrap(&vscope.toObject()); JSObject* scopeObj = js::UncheckedUnwrap(&vscope.toObject());
XPCWrappedNativeScope* scope = ObjectScope(scopeObj); XPCWrappedNativeScope* scope = ObjectScope(scopeObj);
scope->ForcePrivilegedComponents(); scope->ForcePrivilegedComponents();
@ -3012,22 +3012,6 @@ nsXPCComponents_Utils::SetGCZeal(int32_t aValue, JSContext* cx)
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP
nsXPCComponents_Utils::GetIsInAutomation(bool* aResult)
{
NS_ENSURE_ARG_POINTER(aResult);
*aResult = xpc::IsInAutomation();
return NS_OK;
}
NS_IMETHODIMP
nsXPCComponents_Utils::CrashIfNotInAutomation()
{
xpc::CrashIfNotInAutomation();
return NS_OK;
}
NS_IMETHODIMP NS_IMETHODIMP
nsXPCComponents_Utils::NukeSandbox(HandleValue obj, JSContext* cx) nsXPCComponents_Utils::NukeSandbox(HandleValue obj, JSContext* cx)
{ {

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

@ -612,8 +612,8 @@ SpecialPowersObserverAPI.prototype = {
let id = aMessage.data.id; let id = aMessage.data.id;
let extension = this._extensions.get(id); let extension = this._extensions.get(id);
this._extensions.delete(id); this._extensions.delete(id);
let done = () => this._sendReply(aMessage, "SPExtensionMessage", {id, type: "extensionUnloaded", args: []}); extension.shutdown();
extension.shutdown().then(done, done); this._sendReply(aMessage, "SPExtensionMessage", {id, type: "extensionUnloaded", args: []});
return undefined; return undefined;
} }

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

@ -36,7 +36,6 @@
#include "mozilla/FinalizationWitnessService.h" #include "mozilla/FinalizationWitnessService.h"
#include "mozilla/NativeOSFileInternals.h" #include "mozilla/NativeOSFileInternals.h"
#include "mozilla/AddonContentPolicy.h" #include "mozilla/AddonContentPolicy.h"
#include "mozilla/AddonManagerStartup.h"
#include "mozilla/AddonPathService.h" #include "mozilla/AddonPathService.h"
#if defined(XP_WIN) #if defined(XP_WIN)
@ -127,7 +126,6 @@ NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(NativeFileWatcherService, Init)
NS_GENERIC_FACTORY_CONSTRUCTOR(AddonContentPolicy) NS_GENERIC_FACTORY_CONSTRUCTOR(AddonContentPolicy)
NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(AddonPathService, AddonPathService::GetInstance) NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(AddonPathService, AddonPathService::GetInstance)
NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(AddonManagerStartup, AddonManagerStartup::GetInstance)
NS_GENERIC_FACTORY_CONSTRUCTOR(nsWebRequestListener) NS_GENERIC_FACTORY_CONSTRUCTOR(nsWebRequestListener)
@ -163,7 +161,6 @@ NS_DEFINE_NAMED_CID(FINALIZATIONWITNESSSERVICE_CID);
NS_DEFINE_NAMED_CID(NATIVE_OSFILE_INTERNALS_SERVICE_CID); NS_DEFINE_NAMED_CID(NATIVE_OSFILE_INTERNALS_SERVICE_CID);
NS_DEFINE_NAMED_CID(NS_ADDONCONTENTPOLICY_CID); NS_DEFINE_NAMED_CID(NS_ADDONCONTENTPOLICY_CID);
NS_DEFINE_NAMED_CID(NS_ADDON_PATH_SERVICE_CID); NS_DEFINE_NAMED_CID(NS_ADDON_PATH_SERVICE_CID);
NS_DEFINE_NAMED_CID(NS_ADDON_MANAGER_STARTUP_CID);
NS_DEFINE_NAMED_CID(NATIVE_FILEWATCHER_SERVICE_CID); NS_DEFINE_NAMED_CID(NATIVE_FILEWATCHER_SERVICE_CID);
NS_DEFINE_NAMED_CID(NS_WEBREQUESTLISTENER_CID); NS_DEFINE_NAMED_CID(NS_WEBREQUESTLISTENER_CID);
@ -199,7 +196,6 @@ static const Module::CIDEntry kToolkitCIDs[] = {
{ &kNATIVE_OSFILE_INTERNALS_SERVICE_CID, false, nullptr, NativeOSFileInternalsServiceConstructor }, { &kNATIVE_OSFILE_INTERNALS_SERVICE_CID, false, nullptr, NativeOSFileInternalsServiceConstructor },
{ &kNS_ADDONCONTENTPOLICY_CID, false, nullptr, AddonContentPolicyConstructor }, { &kNS_ADDONCONTENTPOLICY_CID, false, nullptr, AddonContentPolicyConstructor },
{ &kNS_ADDON_PATH_SERVICE_CID, false, nullptr, AddonPathServiceConstructor }, { &kNS_ADDON_PATH_SERVICE_CID, false, nullptr, AddonPathServiceConstructor },
{ &kNS_ADDON_MANAGER_STARTUP_CID, false, nullptr, AddonManagerStartupConstructor },
{ &kNATIVE_FILEWATCHER_SERVICE_CID, false, nullptr, NativeFileWatcherServiceConstructor }, { &kNATIVE_FILEWATCHER_SERVICE_CID, false, nullptr, NativeFileWatcherServiceConstructor },
{ &kNS_WEBREQUESTLISTENER_CID, false, nullptr, nsWebRequestListenerConstructor }, { &kNS_WEBREQUESTLISTENER_CID, false, nullptr, nsWebRequestListenerConstructor },
{ nullptr } { nullptr }
@ -237,7 +233,6 @@ static const Module::ContractIDEntry kToolkitContracts[] = {
{ NATIVE_OSFILE_INTERNALS_SERVICE_CONTRACTID, &kNATIVE_OSFILE_INTERNALS_SERVICE_CID }, { NATIVE_OSFILE_INTERNALS_SERVICE_CONTRACTID, &kNATIVE_OSFILE_INTERNALS_SERVICE_CID },
{ NS_ADDONCONTENTPOLICY_CONTRACTID, &kNS_ADDONCONTENTPOLICY_CID }, { NS_ADDONCONTENTPOLICY_CONTRACTID, &kNS_ADDONCONTENTPOLICY_CID },
{ NS_ADDONPATHSERVICE_CONTRACTID, &kNS_ADDON_PATH_SERVICE_CID }, { NS_ADDONPATHSERVICE_CONTRACTID, &kNS_ADDON_PATH_SERVICE_CID },
{ NS_ADDONMANAGERSTARTUP_CONTRACTID, &kNS_ADDON_MANAGER_STARTUP_CID },
{ NATIVE_FILEWATCHER_SERVICE_CONTRACTID, &kNATIVE_FILEWATCHER_SERVICE_CID }, { NATIVE_FILEWATCHER_SERVICE_CONTRACTID, &kNATIVE_FILEWATCHER_SERVICE_CID },
{ NS_WEBREQUESTLISTENER_CONTRACTID, &kNS_WEBREQUESTLISTENER_CID }, { NS_WEBREQUESTLISTENER_CONTRACTID, &kNS_WEBREQUESTLISTENER_CID },
{ nullptr } { nullptr }

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

@ -958,19 +958,14 @@ this.Extension = class extends ExtensionData {
return super.initLocale(locale); return super.initLocale(locale);
} }
startup() { async startup() {
this.startupPromise = this._startup(); let started = false;
return this.startupPromise;
}
async _startup() {
this.started = false;
try { try {
let [, perms] = await Promise.all([this.loadManifest(), ExtensionPermissions.get(this)]); let [, perms] = await Promise.all([this.loadManifest(), ExtensionPermissions.get(this)]);
ExtensionManagement.startupExtension(this.uuid, this.addonData.resourceURI, this); ExtensionManagement.startupExtension(this.uuid, this.addonData.resourceURI, this);
this.started = true; started = true;
if (!this.hasShutdown) { if (!this.hasShutdown) {
await this.initLocale(); await this.initLocale();
@ -1009,8 +1004,7 @@ this.Extension = class extends ExtensionData {
dump(`Extension error: ${e.message} ${e.filename || e.fileName}:${e.lineNumber} :: ${e.stack || new Error().stack}\n`); dump(`Extension error: ${e.message} ${e.filename || e.fileName}:${e.lineNumber} :: ${e.stack || new Error().stack}\n`);
Cu.reportError(e); Cu.reportError(e);
if (this.started) { if (started) {
this.started = false;
ExtensionManagement.shutdownExtension(this.uuid); ExtensionManagement.shutdownExtension(this.uuid);
} }
@ -1018,8 +1012,6 @@ this.Extension = class extends ExtensionData {
throw e; throw e;
} }
this.startupPromise = null;
} }
cleanupGeneratedFile() { cleanupGeneratedFile() {
@ -1041,22 +1033,10 @@ this.Extension = class extends ExtensionData {
}).catch(Cu.reportError); }).catch(Cu.reportError);
} }
async shutdown(reason) { shutdown(reason) {
try {
if (this.startupPromise) {
await this.startupPromise;
}
} catch (e) {
Cu.reportError(e);
}
this.shutdownReason = reason; this.shutdownReason = reason;
this.hasShutdown = true; this.hasShutdown = true;
if (!this.started) {
return;
}
if (this.cleanupFile || if (this.cleanupFile ||
["ADDON_INSTALL", "ADDON_UNINSTALL", "ADDON_UPGRADE", "ADDON_DOWNGRADE"].includes(reason)) { ["ADDON_INSTALL", "ADDON_UNINSTALL", "ADDON_UPGRADE", "ADDON_DOWNGRADE"].includes(reason)) {
StartupCache.clearAddonData(this.id); StartupCache.clearAddonData(this.id);

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

@ -112,9 +112,6 @@ var Service = {
// Called when an extension is unloaded. // Called when an extension is unloaded.
shutdownExtension(uuid) { shutdownExtension(uuid) {
let extension = this.uuidMap.get(uuid); let extension = this.uuidMap.get(uuid);
if (!extension) {
return;
}
this.uuidMap.delete(uuid); this.uuidMap.delete(uuid);
this.aps.setAddonHasPermissionCallback(extension.id, null); this.aps.setAddonHasPermissionCallback(extension.id, null);
this.aps.setAddonLoadURICallback(extension.id, null); this.aps.setAddonLoadURICallback(extension.id, null);

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

@ -50,7 +50,7 @@ class BackgroundPage extends HiddenExtensionPage {
// console. // console.
if (this.extension.addonData.instanceID) { if (this.extension.addonData.instanceID) {
AddonManager.getAddonByInstanceID(this.extension.addonData.instanceID) AddonManager.getAddonByInstanceID(this.extension.addonData.instanceID)
.then(addon => addon && addon.setDebugGlobal(window)); .then(addon => addon.setDebugGlobal(window));
} }
} }
@ -67,7 +67,7 @@ class BackgroundPage extends HiddenExtensionPage {
shutdown() { shutdown() {
if (this.extension.addonData.instanceID) { if (this.extension.addonData.instanceID) {
AddonManager.getAddonByInstanceID(this.extension.addonData.instanceID) AddonManager.getAddonByInstanceID(this.extension.addonData.instanceID)
.then(addon => addon && addon.setDebugGlobal(null)); .then(addon => addon.setDebugGlobal(null));
} }
super.shutdown(); super.shutdown();

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

@ -64,9 +64,7 @@ this.runtime = class extends ExtensionAPI {
fire.sync(details); fire.sync(details);
}); });
return () => { return () => {
AddonManager.removeUpgradeListener(instanceID).catch(e => { AddonManager.removeUpgradeListener(instanceID);
// This can happen if we try this after shutdown is complete.
});
}; };
}).api(), }).api(),

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

@ -638,11 +638,9 @@ ExtensionManager = {
let extension = this.extensions.get(data.id); let extension = this.extensions.get(data.id);
this.extensions.delete(data.id); this.extensions.delete(data.id);
if (extension) { extension.shutdown();
extension.shutdown();
DocumentManager.uninitExtension(extension); DocumentManager.uninitExtension(extension);
}
break; break;
} }

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

@ -129,7 +129,5 @@ add_task(async function test_management_themes() {
theme.unload(), theme.unload(),
extension.awaitMessage("onUninstalled"), extension.awaitMessage("onUninstalled"),
]); ]);
is(await extension.awaitMessage("onEnabled"), "Default", "default enabled");
await extension.unload(); await extension.unload();
}); });

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

@ -90,8 +90,6 @@ const kSaveDelayMs = 1500;
* automatically finalize the file when triggered. Defaults * automatically finalize the file when triggered. Defaults
* to `profileBeforeChange`; exposed as an option for * to `profileBeforeChange`; exposed as an option for
* testing. * testing.
* - compression: A compression algorithm to use when reading and
* writing the data.
*/ */
function JSONFile(config) { function JSONFile(config) {
this.path = config.path; this.path = config.path;
@ -108,11 +106,6 @@ function JSONFile(config) {
} }
this._saver = new DeferredTask(() => this._save(), config.saveDelayMs); this._saver = new DeferredTask(() => this._save(), config.saveDelayMs);
this._options = {};
if (config.compression) {
this._options.compression = config.compression;
}
this._finalizeAt = config.finalizeAt || AsyncShutdown.profileBeforeChange; this._finalizeAt = config.finalizeAt || AsyncShutdown.profileBeforeChange;
this._finalizeInternalBound = this._finalizeInternal.bind(this); this._finalizeInternalBound = this._finalizeInternal.bind(this);
this._finalizeAt.addBlocker("JSON store: writing data", this._finalizeAt.addBlocker("JSON store: writing data",
@ -183,7 +176,7 @@ JSONFile.prototype = {
let data = {}; let data = {};
try { try {
let bytes = yield OS.File.read(this.path, this._options); let bytes = yield OS.File.read(this.path);
// If synchronous loading happened in the meantime, exit now. // If synchronous loading happened in the meantime, exit now.
if (this.dataReady) { if (this.dataReady) {
@ -293,9 +286,7 @@ JSONFile.prototype = {
yield Promise.resolve(this._beforeSave()); yield Promise.resolve(this._beforeSave());
} }
yield OS.File.writeAtomic(this.path, bytes, yield OS.File.writeAtomic(this.path, bytes,
Object.assign( { tmpPath: this.path + ".tmp" });
{ tmpPath: this.path + ".tmp" },
this._options));
}), }),
/** /**

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

@ -2250,7 +2250,7 @@ var AddonManagerInternal = {
throw Components.Exception("aInstanceID must be a symbol", throw Components.Exception("aInstanceID must be a symbol",
Cr.NS_ERROR_INVALID_ARG); Cr.NS_ERROR_INVALID_ARG);
return this.getAddonByInstanceID(aInstanceID).then(addon => { this.getAddonByInstanceID(aInstanceID).then(addon => {
if (!addon) { if (!addon) {
throw Error("No addon for instanceID:", aInstanceID.toString()); throw Error("No addon for instanceID:", aInstanceID.toString());
} }
@ -3086,17 +3086,6 @@ this.AddonManagerPrivate = {
.addonIsActive(addonId); .addonIsActive(addonId);
}, },
/**
* Gets an array of add-ons which were side-loaded prior to the last
* startup, and are currently disabled.
*
* @returns {Promise<Array<Addon>>}
*/
getNewSideloads() {
return AddonManagerInternal._getProviderByName("XPIProvider")
.getNewSideloads();
},
get browserUpdated() { get browserUpdated() {
return gBrowserUpdated; return gBrowserUpdated;
}, },
@ -3665,7 +3654,7 @@ this.AddonManager = {
}, },
removeUpgradeListener(aInstanceID) { removeUpgradeListener(aInstanceID) {
return AddonManagerInternal.removeUpgradeListener(aInstanceID); AddonManagerInternal.removeUpgradeListener(aInstanceID);
}, },
addAddonListener(aListener) { addAddonListener(aListener) {

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

@ -1,281 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef AddonManagerStartup_inlines_h
#define AddonManagerStartup_inlines_h
#include "jsapi.h"
#include "nsJSUtils.h"
#include "mozilla/Maybe.h"
#include "mozilla/Move.h"
namespace mozilla {
class ArrayIterElem;
class PropertyIterElem;
/*****************************************************************************
* Object iterator base classes
*****************************************************************************/
template<class T, class PropertyType>
class MOZ_STACK_CLASS BaseIter {
public:
typedef T SelfType;
PropertyType begin() const
{
PropertyType elem(Self());
return Move(elem);
}
PropertyType end() const
{
PropertyType elem(Self());
return elem.End();
}
void* Context() const { return mContext; }
protected:
BaseIter(JSContext* cx, JS::HandleObject object, void* context = nullptr)
: mCx(cx)
, mObject(object)
, mContext(context)
{}
const SelfType& Self() const
{
return *static_cast<const SelfType*>(this);
}
SelfType& Self()
{
return *static_cast<SelfType*>(this);
}
JSContext* mCx;
JS::HandleObject mObject;
void* mContext;
};
template<class T, class IterType>
class MOZ_STACK_CLASS BaseIterElem {
public:
typedef T SelfType;
explicit BaseIterElem(const IterType& iter, uint32_t index = 0)
: mIter(iter)
, mIndex(index)
{}
uint32_t Length() const
{
return mIter.Length();
}
JS::Value Value()
{
JS::RootedValue value(mIter.mCx, JS::UndefinedValue());
auto& self = Self();
if (!self.GetValue(&value)) {
JS_ClearPendingException(mIter.mCx);
}
return value;
}
SelfType& operator*() { return Self(); }
SelfType& operator++()
{
MOZ_ASSERT(mIndex < Length());
mIndex++;
return Self();
}
bool operator!=(const SelfType& other) const
{
return &mIter != &other.mIter || mIndex != other.mIndex;
}
SelfType End() const
{
SelfType end(mIter);
end.mIndex = Length();
return Move(end);
}
void* Context() const { return mIter.Context(); }
protected:
const SelfType& Self() const
{
return *static_cast<const SelfType*>(this);
}
SelfType& Self() {
return *static_cast<SelfType*>(this);
}
const IterType& mIter;
uint32_t mIndex;
};
/*****************************************************************************
* Property iteration
*****************************************************************************/
class MOZ_STACK_CLASS PropertyIter
: public BaseIter<PropertyIter, PropertyIterElem>
{
friend class PropertyIterElem;
friend class BaseIterElem<PropertyIterElem, PropertyIter>;
public:
PropertyIter(JSContext* cx, JS::HandleObject object, void* context = nullptr)
: BaseIter(cx, object, context)
, mIds(cx, JS::IdVector(cx))
{
if (!JS_Enumerate(cx, object, &mIds)) {
JS_ClearPendingException(cx);
}
}
PropertyIter(const PropertyIter& other)
: PropertyIter(other.mCx, other.mObject, other.mContext)
{}
PropertyIter& operator=(const PropertyIter& other)
{
MOZ_ASSERT(other.mObject == mObject);
mCx = other.mCx;
mContext = other.mContext;
mIds.clear();
if (!JS_Enumerate(mCx, mObject, &mIds)) {
JS_ClearPendingException(mCx);
}
return *this;
}
int32_t Length() const
{
return mIds.length();
}
protected:
JS::Rooted<JS::IdVector> mIds;
};
class MOZ_STACK_CLASS PropertyIterElem
: public BaseIterElem<PropertyIterElem, PropertyIter>
{
friend class BaseIterElem<PropertyIterElem, PropertyIter>;
public:
using BaseIterElem::BaseIterElem;
PropertyIterElem(const PropertyIterElem& other)
: BaseIterElem(other.mIter, other.mIndex)
{}
jsid Id()
{
MOZ_ASSERT(mIndex < mIter.mIds.length());
return mIter.mIds[mIndex];
}
const nsAString& Name()
{
if(mName.isNothing()) {
mName.emplace();
mName.ref().init(mIter.mCx, Id());
}
return mName.ref();
}
JSContext* Cx() { return mIter.mCx; }
protected:
bool GetValue(JS::MutableHandleValue value)
{
MOZ_ASSERT(mIndex < Length());
JS::Rooted<jsid> id(mIter.mCx, Id());
return JS_GetPropertyById(mIter.mCx, mIter.mObject, id, value);
}
private:
Maybe<nsAutoJSString> mName;
};
/*****************************************************************************
* Array iteration
*****************************************************************************/
class MOZ_STACK_CLASS ArrayIter
: public BaseIter<ArrayIter, ArrayIterElem>
{
friend class ArrayIterElem;
friend class BaseIterElem<ArrayIterElem, ArrayIter>;
public:
ArrayIter(JSContext* cx, JS::HandleObject object)
: BaseIter(cx, object)
, mLength(0)
{
bool isArray;
if (!JS_IsArrayObject(cx, object, &isArray) || !isArray) {
JS_ClearPendingException(cx);
return;
}
if (!JS_GetArrayLength(cx, object, &mLength)) {
JS_ClearPendingException(cx);
}
}
uint32_t Length() const
{
return mLength;
}
private:
uint32_t mLength;
};
class MOZ_STACK_CLASS ArrayIterElem
: public BaseIterElem<ArrayIterElem, ArrayIter>
{
friend class BaseIterElem<ArrayIterElem, ArrayIter>;
public:
using BaseIterElem::BaseIterElem;
ArrayIterElem(const ArrayIterElem& other)
: BaseIterElem(other.mIter, other.mIndex)
{}
protected:
bool
GetValue(JS::MutableHandleValue value)
{
MOZ_ASSERT(mIndex < Length());
return JS_GetElement(mIter.mCx, mIter.mObject, mIndex, value);
}
};
}
#endif // AddonManagerStartup_inlines_h

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

@ -1,595 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "AddonManagerStartup.h"
#include "AddonManagerStartup-inlines.h"
#include "jsapi.h"
#include "js/TracingAPI.h"
#include "xpcpublic.h"
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/EndianUtils.h"
#include "mozilla/Compression.h"
#include "mozilla/Preferences.h"
#include "mozilla/ScopeExit.h"
#include "mozilla/Services.h"
#include "mozilla/Unused.h"
#include "nsAppDirectoryServiceDefs.h"
#include "nsAppRunner.h"
#include "nsIAddonInterposition.h"
#include "nsXULAppAPI.h"
#include <stdlib.h>
namespace mozilla {
template <>
class MOZ_MUST_USE_TYPE GenericErrorResult<nsresult>
{
nsresult mErrorValue;
template<typename V, typename E2> friend class Result;
public:
explicit GenericErrorResult(nsresult aErrorValue) : mErrorValue(aErrorValue) {}
operator nsresult() { return mErrorValue; }
};
static inline Result<Ok, nsresult>
WrapNSResult(PRStatus aRv)
{
if (aRv != PR_SUCCESS) {
return Err(NS_ERROR_FAILURE);
}
return Ok();
}
static inline Result<Ok, nsresult>
WrapNSResult(nsresult aRv)
{
if (NS_FAILED(aRv)) {
return Err(aRv);
}
return Ok();
}
#define NS_TRY(expr) MOZ_TRY(WrapNSResult(expr))
using Compression::LZ4;
#ifdef XP_WIN
# define READ_BINARYMODE "rb"
#else
# define READ_BINARYMODE "r"
#endif
AddonManagerStartup&
AddonManagerStartup::GetSingleton()
{
static RefPtr<AddonManagerStartup> singleton;
if (!singleton) {
singleton = new AddonManagerStartup();
ClearOnShutdown(&singleton);
}
return *singleton;
}
AddonManagerStartup::AddonManagerStartup()
: mInitialized(false)
{}
nsIFile*
AddonManagerStartup::ProfileDir()
{
if (!mProfileDir) {
nsresult rv;
rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(mProfileDir));
MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
}
return mProfileDir;
}
NS_IMPL_ISUPPORTS(AddonManagerStartup, amIAddonManagerStartup)
/*****************************************************************************
* File utils
*****************************************************************************/
static already_AddRefed<nsIFile>
CloneAndAppend(nsIFile* aFile, const char* name)
{
nsCOMPtr<nsIFile> file;
aFile->Clone(getter_AddRefs(file));
file->AppendNative(nsDependentCString(name));
return file.forget();
}
static bool
IsNormalFile(nsIFile* file)
{
bool result;
return NS_SUCCEEDED(file->IsFile(&result)) && result;
}
static nsCString
ReadFile(const char* path)
{
nsCString result;
FILE* fd = fopen(path, READ_BINARYMODE);
if (!fd) {
return result;
}
auto cleanup = MakeScopeExit([&] () {
fclose(fd);
});
if (fseek(fd, 0, SEEK_END) != 0) {
return result;
}
size_t len = ftell(fd);
if (len <= 0 || fseek(fd, 0, SEEK_SET) != 0) {
return result;
}
result.SetLength(len);
size_t rd = fread(result.BeginWriting(), sizeof(char), len, fd);
if (rd != len) {
result.Truncate();
}
return result;
}
/**
* Reads the contents of a LZ4-compressed file, as stored by the OS.File
* module, and returns the decompressed contents on success.
*
* A nonexistent or empty file is treated as success. A corrupt or non-LZ4
* file is treated as failure.
*/
static Result<nsCString, nsresult>
ReadFileLZ4(const char* path)
{
static const char MAGIC_NUMBER[] = "mozLz40";
constexpr auto HEADER_SIZE = sizeof(MAGIC_NUMBER) + 4;
nsCString result;
nsCString lz4 = ReadFile(path);
if (lz4.IsEmpty()) {
return result;
}
// Note: We want to include the null terminator here.
nsDependentCSubstring magic(MAGIC_NUMBER, sizeof(MAGIC_NUMBER));
if (lz4.Length() < HEADER_SIZE || StringHead(lz4, magic.Length()) != magic) {
return Err(NS_ERROR_UNEXPECTED);
}
auto size = LittleEndian::readUint32(lz4.get() + magic.Length());
if (!result.SetLength(size, fallible) ||
!LZ4::decompress(lz4.get() + HEADER_SIZE, result.BeginWriting(), size)) {
return Err(NS_ERROR_UNEXPECTED);
}
return result;
}
static bool
ParseJSON(JSContext* cx, nsACString& jsonData, JS::MutableHandleValue result)
{
NS_ConvertUTF8toUTF16 str(jsonData);
jsonData.Truncate();
return JS_ParseJSON(cx, str.Data(), str.Length(), result);
}
/*****************************************************************************
* JSON data handling
*****************************************************************************/
class MOZ_STACK_CLASS WrapperBase {
protected:
WrapperBase(JSContext* cx, JSObject* object)
: mCx(cx)
, mObject(cx, object)
{}
WrapperBase(JSContext* cx, const JS::Value& value)
: mCx(cx)
, mObject(cx)
{
if (value.isObject()) {
mObject = &value.toObject();
} else {
mObject = JS_NewPlainObject(cx);
}
}
protected:
JSContext* mCx;
JS::RootedObject mObject;
bool GetBool(const char* name, bool defVal = false);
double GetNumber(const char* name, double defVal = 0);
nsString GetString(const char* name, const char* defVal = "");
JSObject* GetObject(const char* name);
};
bool
WrapperBase::GetBool(const char* name, bool defVal)
{
JS::RootedObject obj(mCx, mObject);
JS::RootedValue val(mCx, JS::UndefinedValue());
if (!JS_GetProperty(mCx, obj, name, &val)) {
JS_ClearPendingException(mCx);
}
if (val.isBoolean()) {
return val.toBoolean();
}
return defVal;
}
double
WrapperBase::GetNumber(const char* name, double defVal)
{
JS::RootedObject obj(mCx, mObject);
JS::RootedValue val(mCx, JS::UndefinedValue());
if (!JS_GetProperty(mCx, obj, name, &val)) {
JS_ClearPendingException(mCx);
}
if (val.isNumber()) {
return val.toNumber();
}
return defVal;
}
nsString
WrapperBase::GetString(const char* name, const char* defVal)
{
JS::RootedObject obj(mCx, mObject);
JS::RootedValue val(mCx, JS::UndefinedValue());
if (!JS_GetProperty(mCx, obj, name, &val)) {
JS_ClearPendingException(mCx);
}
nsString res;
if (val.isString()) {
AssignJSString(mCx, res, val.toString());
} else {
res.AppendASCII(defVal);
}
return res;
}
JSObject*
WrapperBase::GetObject(const char* name)
{
JS::RootedObject obj(mCx, mObject);
JS::RootedValue val(mCx, JS::UndefinedValue());
if (!JS_GetProperty(mCx, obj, name, &val)) {
JS_ClearPendingException(mCx);
}
if (val.isObject()) {
return &val.toObject();
}
return nullptr;
}
class MOZ_STACK_CLASS InstallLocation : public WrapperBase {
public:
InstallLocation(JSContext* cx, const JS::Value& value);
MOZ_IMPLICIT InstallLocation(PropertyIterElem& iter)
: InstallLocation(iter.Cx(), iter.Value())
{}
InstallLocation(const InstallLocation& other)
: InstallLocation(other.mCx, JS::ObjectValue(*other.mObject))
{}
void SetChanged(bool changed)
{
JS::RootedObject obj(mCx, mObject);
JS::RootedValue val(mCx, JS::BooleanValue(changed));
if (!JS_SetProperty(mCx, obj, "changed", val)) {
JS_ClearPendingException(mCx);
}
}
PropertyIter& Addons() { return mAddonsIter.ref(); }
nsString Path() { return GetString("path"); }
bool ShouldCheckStartupModifications() { return GetBool("checkStartupModifications"); }
private:
JS::RootedObject mAddonsObj;
Maybe<PropertyIter> mAddonsIter;
};
class MOZ_STACK_CLASS Addon : public WrapperBase {
public:
Addon(JSContext* cx, InstallLocation& location, const nsAString& id, JSObject* object)
: WrapperBase(cx, object)
, mId(id)
, mLocation(location)
{}
MOZ_IMPLICIT Addon(PropertyIterElem& iter)
: WrapperBase(iter.Cx(), iter.Value())
, mId(iter.Name())
, mLocation(*static_cast<InstallLocation*>(iter.Context()))
{}
Addon(const Addon& other)
: WrapperBase(other.mCx, other.mObject)
, mId(other.mId)
, mLocation(other.mLocation)
{}
const nsString& Id() { return mId; }
nsString Path() { return GetString("path"); }
bool Bootstrapped() { return GetBool("bootstrapped"); }
bool Enabled() { return GetBool("enabled"); }
bool ShimsEnabled() { return GetBool("enableShims"); }
double LastModifiedTime() { return GetNumber("lastModifiedTime"); }
already_AddRefed<nsIFile> FullPath();
NSLocationType LocationType();
bool UpdateLastModifiedTime();
private:
nsString mId;
InstallLocation& mLocation;
};
already_AddRefed<nsIFile>
Addon::FullPath()
{
nsString path = mLocation.Path();
nsCOMPtr<nsIFile> file;
NS_NewLocalFile(path, false, getter_AddRefs(file));
MOZ_RELEASE_ASSERT(file);
path = Path();
file->AppendRelativePath(path);
return file.forget();
}
NSLocationType
Addon::LocationType()
{
nsString type = GetString("type", "extension");
if (type.LowerCaseEqualsLiteral("theme")) {
return NS_SKIN_LOCATION;
}
return NS_EXTENSION_LOCATION;
}
bool
Addon::UpdateLastModifiedTime()
{
nsCOMPtr<nsIFile> file = FullPath();
bool result;
if (NS_FAILED(file->Exists(&result)) || !result) {
return true;
}
PRTime time;
nsCOMPtr<nsIFile> manifest = file;
if (!IsNormalFile(manifest)) {
manifest = CloneAndAppend(file, "install.rdf");
if (!IsNormalFile(manifest)) {
manifest = CloneAndAppend(file, "manifest.json");
if (!IsNormalFile(manifest)) {
return true;
}
}
}
if (NS_FAILED(manifest->GetLastModifiedTime(&time))) {
return true;
}
JS::RootedObject obj(mCx, mObject);
double lastModified = time;
JS::RootedValue value(mCx, JS::NumberValue(lastModified));
if (!JS_SetProperty(mCx, obj, "currentModifiedTime", value)) {
JS_ClearPendingException(mCx);
}
return lastModified != LastModifiedTime();;
}
InstallLocation::InstallLocation(JSContext* cx, const JS::Value& value)
: WrapperBase(cx, value)
, mAddonsObj(cx)
, mAddonsIter()
{
mAddonsObj = GetObject("addons");
if (!mAddonsObj) {
mAddonsObj = JS_NewPlainObject(cx);
}
mAddonsIter.emplace(cx, mAddonsObj, this);
}
/*****************************************************************************
* XPC interfacing
*****************************************************************************/
static void
EnableShims(const nsAString& addonId)
{
NS_ConvertUTF16toUTF8 id(addonId);
nsCOMPtr<nsIAddonInterposition> interposition =
do_GetService("@mozilla.org/addons/multiprocess-shims;1");
if (!interposition || !xpc::SetAddonInterposition(id, interposition)) {
return;
}
Unused << xpc::AllowCPOWsInAddon(id, true);
}
void
AddonManagerStartup::AddInstallLocation(Addon& addon)
{
nsCOMPtr<nsIFile> file = addon.FullPath();
nsString path;
if (NS_FAILED(file->GetPath(path))) {
return;
}
auto type = addon.LocationType();
if (type == NS_SKIN_LOCATION) {
mThemePaths.AppendElement(file);
} else {
mExtensionPaths.AppendElement(file);
}
if (StringTail(path, 4).LowerCaseEqualsLiteral(".xpi")) {
XRE_AddJarManifestLocation(type, file);
} else {
nsCOMPtr<nsIFile> manifest = CloneAndAppend(file, "chrome.manifest");
XRE_AddManifestLocation(type, manifest);
}
}
nsresult
AddonManagerStartup::ReadStartupData(JSContext* cx, JS::MutableHandleValue locations)
{
locations.set(JS::UndefinedValue());
nsCOMPtr<nsIFile> file = CloneAndAppend(ProfileDir(), "addonStartup.json.lz4");
nsCString path;
NS_TRY(file->GetNativePath(path));
nsCString data;
MOZ_TRY_VAR(data, ReadFileLZ4(path.get()));
if (data.IsEmpty() || !ParseJSON(cx, data, locations)) {
return NS_OK;
}
if (!locations.isObject()) {
return NS_ERROR_UNEXPECTED;
}
JS::RootedObject locs(cx, &locations.toObject());
for (auto& e1 : PropertyIter(cx, locs)) {
InstallLocation loc(e1);
if (!loc.ShouldCheckStartupModifications()) {
continue;
}
for (auto& e2 : loc.Addons()) {
Addon addon(e2);
if (addon.Enabled() && addon.UpdateLastModifiedTime()) {
loc.SetChanged(true);
}
}
}
return NS_OK;
}
nsresult
AddonManagerStartup::InitializeExtensions(JS::HandleValue locations, JSContext* cx)
{
NS_ENSURE_FALSE(mInitialized, NS_ERROR_UNEXPECTED);
NS_ENSURE_TRUE(locations.isObject(), NS_ERROR_INVALID_ARG);
mInitialized = true;
if (!Preferences::GetBool("extensions.defaultProviders.enabled", true)) {
return NS_OK;
}
bool enableInterpositions = Preferences::GetBool("extensions.interposition.enabled", false);
JS::RootedObject locs(cx, &locations.toObject());
for (auto& e1 : PropertyIter(cx, locs)) {
InstallLocation loc(e1);
for (auto& e2 : loc.Addons()) {
Addon addon(e2);
if (!addon.Bootstrapped()) {
AddInstallLocation(addon);
}
if (enableInterpositions && addon.ShimsEnabled()) {
EnableShims(addon.Id());
}
}
}
return NS_OK;
}
nsresult
AddonManagerStartup::Reset()
{
MOZ_RELEASE_ASSERT(xpc::IsInAutomation());
mInitialized = false;
mExtensionPaths.Clear();
mThemePaths.Clear();
return NS_OK;
}
} // namespace mozilla

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

@ -1,73 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef AddonManagerStartup_h
#define AddonManagerStartup_h
#include "amIAddonManagerStartup.h"
#include "nsCOMArray.h"
#include "nsCOMPtr.h"
#include "nsIFile.h"
#include "nsISupports.h"
#include "jsapi.h"
namespace mozilla {
class Addon;
class AddonManagerStartup final : public amIAddonManagerStartup
{
public:
NS_DECL_ISUPPORTS
NS_DECL_AMIADDONMANAGERSTARTUP
AddonManagerStartup();
static AddonManagerStartup& GetSingleton();
static already_AddRefed<AddonManagerStartup> GetInstance()
{
RefPtr<AddonManagerStartup> inst = &GetSingleton();
return inst.forget();
}
const nsCOMArray<nsIFile>& ExtensionPaths()
{
return mExtensionPaths;
}
const nsCOMArray<nsIFile>& ThemePaths()
{
return mExtensionPaths;
}
private:
void AddInstallLocation(Addon& addon);
nsIFile* ProfileDir();
nsCOMPtr<nsIFile> mProfileDir;
nsCOMArray<nsIFile> mExtensionPaths;
nsCOMArray<nsIFile> mThemePaths;
bool mInitialized;
protected:
virtual ~AddonManagerStartup() = default;
};
} // namespace mozilla
#define NS_ADDONMANAGERSTARTUP_CONTRACTID \
"@mozilla.org/addons/addon-manager-startup;1"
// {17a59a6b-92b8-42e5-bce0-ab434c7a7135
#define NS_ADDON_MANAGER_STARTUP_CID \
{ 0x17a59a6b, 0x92b8, 0x42e5, \
{ 0xbc, 0xe0, 0xab, 0x43, 0x4c, 0x7a, 0x71, 0x35 } }
#endif // AddonManagerStartup_h

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

@ -1,36 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsISupports.idl"
[scriptable, builtinclass, uuid(01dfa47b-87e4-4135-877b-586d033e1b5d)]
interface amIAddonManagerStartup : nsISupports
{
/**
* Reads and parses startup data from the addonState.json.lz4 file, checks
* for modifications, and returns the result.
*
* Returns null for an empty or nonexistent state file, but throws for an
* invalid one.
*/
[implicit_jscontext]
jsval readStartupData();
/**
* Initializes the chrome registry for the enabled, non-restartless add-on
* in the given state data.
*/
[implicit_jscontext]
void initializeExtensions(in jsval locations);
/**
* Resets the internal state of the startup service, and allows
* initializeExtensions() to be called again. Does *not* fully unregister
* chrome registry locations for previously registered add-ons.
*
* NOT FOR USE OUTSIDE OF UNIT TESTS.
*/
void reset();
};

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

@ -30,9 +30,6 @@ const {OS} = Cu.import("resource://gre/modules/osfile.jsm", {});
XPCOMUtils.defineLazyModuleGetter(this, "Extension", XPCOMUtils.defineLazyModuleGetter(this, "Extension",
"resource://gre/modules/Extension.jsm"); "resource://gre/modules/Extension.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "aomStartup",
"@mozilla.org/addons/addon-manager-startup;1",
"amIAddonManagerStartup");
XPCOMUtils.defineLazyServiceGetter(this, "rdfService", XPCOMUtils.defineLazyServiceGetter(this, "rdfService",
"@mozilla.org/rdf/rdf-service;1", "nsIRDFService"); "@mozilla.org/rdf/rdf-service;1", "nsIRDFService");
XPCOMUtils.defineLazyServiceGetter(this, "uuidGen", XPCOMUtils.defineLazyServiceGetter(this, "uuidGen",
@ -45,8 +42,6 @@ XPCOMUtils.defineLazyGetter(this, "AppInfo", () => {
return AppInfo; return AppInfo;
}); });
const PREF_DISABLE_SECURITY = ("security.turn_off_all_security_so_that_" +
"viruses_can_take_over_this_computer");
const ArrayBufferInputStream = Components.Constructor( const ArrayBufferInputStream = Components.Constructor(
"@mozilla.org/io/arraybuffer-input-stream;1", "@mozilla.org/io/arraybuffer-input-stream;1",
@ -134,46 +129,46 @@ function escaped(strings, ...values) {
class AddonsList { class AddonsList {
constructor(file) { constructor(extensionsINI) {
this.multiprocessIncompatibleIDs = new Set(); this.multiprocessIncompatibleIDs = new Set();
this.extensions = [];
this.themes = [];
if (!file.exists()) { if (!extensionsINI.exists()) {
this.extensions = [];
this.themes = [];
return; return;
} }
let data = aomStartup.readStartupData(); let factory = Cc["@mozilla.org/xpcom/ini-parser-factory;1"]
.getService(Ci.nsIINIParserFactory);
for (let loc of Object.values(data)) { let parser = factory.createINIParser(extensionsINI);
let dir = loc.path && new nsFile(loc.path);
for (let [id, addon] of Object.entries(loc.addons)) { function readDirectories(section) {
if (addon.enabled && !addon.bootstrapped) { var dirs = [];
let file; var keys = parser.getKeys(section);
if (dir) { for (let key of XPCOMUtils.IterStringEnumerator(keys)) {
file = dir.clone(); let descriptor = parser.getString(section, key);
try {
file.appendRelativePath(addon.path);
} catch (e) {
file = new nsFile(addon.path);
}
} else {
file = new nsFile(addon.path);
}
addon.type = addon.type || "extension"; let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
try {
if (addon.type == "theme") { file.persistentDescriptor = descriptor;
this.themes.push(file); } catch (e) {
} else { // Throws if the directory doesn't exist, we can ignore this since the
this.extensions.push(file); // platform will too.
if (addon.enableShims) { continue;
this.multiprocessIncompatibleIDs.add(id);
}
}
} }
dirs.push(file);
} }
return dirs;
}
this.extensions = readDirectories("ExtensionDirs");
this.themes = readDirectories("ThemeDirs");
var keys = parser.getKeys("MultiprocessIncompatibleExtensions");
for (let key of XPCOMUtils.IterStringEnumerator(keys)) {
let id = parser.getString("MultiprocessIncompatibleExtensions", key);
this.multiprocessIncompatibleIDs.add(id);
} }
} }
@ -186,7 +181,7 @@ class AddonsList {
return this[type].some(file => { return this[type].some(file => {
if (!file.exists()) if (!file.exists())
throw new Error(`Non-existent path found in addonStartup.json: ${file.path}`); throw new Error(`Non-existent path found in extensions.ini: ${file.path}`);
if (file.isDirectory()) if (file.isDirectory())
return file.equals(path); return file.equals(path);
@ -213,7 +208,7 @@ var AddonTestUtils = {
addonIntegrationService: null, addonIntegrationService: null,
addonsList: null, addonsList: null,
appInfo: null, appInfo: null,
addonStartup: null, extensionsINI: null,
testUnpacked: false, testUnpacked: false,
useRealCertChecks: false, useRealCertChecks: false,
@ -223,11 +218,8 @@ var AddonTestUtils = {
// Get the profile directory for tests to use. // Get the profile directory for tests to use.
this.profileDir = testScope.do_get_profile(); this.profileDir = testScope.do_get_profile();
this.profileExtensions = this.profileDir.clone(); this.extensionsINI = this.profileDir.clone();
this.profileExtensions.append("extensions"); this.extensionsINI.append("extensions.ini");
this.addonStartup = this.profileDir.clone();
this.addonStartup.append("addonStartup.json.lz4");
// Register a temporary directory for the tests. // Register a temporary directory for the tests.
this.tempDir = this.profileDir.clone(); this.tempDir = this.profileDir.clone();
@ -251,9 +243,6 @@ var AddonTestUtils = {
// By default don't disable add-ons from any scope // By default don't disable add-ons from any scope
Services.prefs.setIntPref("extensions.autoDisableScopes", 0); Services.prefs.setIntPref("extensions.autoDisableScopes", 0);
// And scan for changes at startup
Services.prefs.setIntPref("extensions.startupScanScopes", 15);
// By default, don't cache add-ons in AddonRepository.jsm // By default, don't cache add-ons in AddonRepository.jsm
Services.prefs.setBoolPref("extensions.getAddons.cache.enabled", false); Services.prefs.setBoolPref("extensions.getAddons.cache.enabled", false);
@ -295,7 +284,10 @@ var AddonTestUtils = {
} }
testScope.do_register_cleanup(() => { testScope.do_register_cleanup(() => {
this.cleanupTempXPIs(); for (let file of this.tempXPIs) {
if (file.exists())
file.remove(false);
}
// Check that the temporary directory is empty // Check that the temporary directory is empty
var dirEntries = this.tempDir.directoryEntries var dirEntries = this.tempDir.directoryEntries
@ -347,37 +339,6 @@ var AddonTestUtils = {
}); });
}, },
initMochitest(testScope) {
this.profileDir = FileUtils.getDir("ProfD", []);
this.profileExtensions = FileUtils.getDir("ProfD", ["extensions"]);
this.tempDir = FileUtils.getDir("TmpD", []);
this.tempDir.append("addons-mochitest");
this.tempDir.createUnique(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY);
testScope.registerCleanupFunction(() => {
this.cleanupTempXPIs();
try {
this.tempDir.remove(true);
} catch (e) {
Cu.reportError(e);
}
});
},
cleanupTempXPIs() {
for (let file of this.tempXPIs.splice(0)) {
if (file.exists()) {
try {
file.remove(false);
} catch (e) {
Cu.reportError(e);
}
}
}
},
/** /**
* Helper to spin the event loop until a promise resolves or rejects * Helper to spin the event loop until a promise resolves or rejects
* *
@ -448,10 +409,6 @@ var AddonTestUtils = {
} }
}, },
getIDFromExtension(file) {
return this.getIDFromManifest(this.getManifestURI(file));
},
getIDFromManifest: Task.async(function*(manifestURI) { getIDFromManifest: Task.async(function*(manifestURI) {
let body = yield fetch(manifestURI.spec); let body = yield fetch(manifestURI.spec);
@ -560,13 +517,15 @@ var AddonTestUtils = {
* An optional boolean parameter to simulate the case where the * An optional boolean parameter to simulate the case where the
* application has changed version since the last run. If not passed it * application has changed version since the last run. If not passed it
* defaults to true * defaults to true
* @returns {Promise}
* Resolves when the add-on manager's startup has completed.
*/ */
async promiseStartupManager(appChanged = true) { promiseStartupManager(appChanged = true) {
if (this.addonIntegrationService) if (this.addonIntegrationService)
throw new Error("Attempting to startup manager that was already started."); throw new Error("Attempting to startup manager that was already started.");
if (appChanged && this.addonStartup.exists()) if (appChanged && this.extensionsINI.exists())
this.addonStartup.remove(true); this.extensionsINI.remove(true);
this.addonIntegrationService = Cc["@mozilla.org/addons/integration;1"] this.addonIntegrationService = Cc["@mozilla.org/addons/integration;1"]
.getService(Ci.nsIObserver); .getService(Ci.nsIObserver);
@ -576,7 +535,9 @@ var AddonTestUtils = {
this.emit("addon-manager-started"); this.emit("addon-manager-started");
// Load the add-ons list as it was after extension registration // Load the add-ons list as it was after extension registration
await this.loadAddonsList(true); this.loadAddonsList();
return Promise.resolve();
}, },
promiseShutdownManager() { promiseShutdownManager() {
@ -606,12 +567,6 @@ var AddonTestUtils = {
AddonManagerPrivate.unregisterProvider(XPIscope.XPIProvider); AddonManagerPrivate.unregisterProvider(XPIscope.XPIProvider);
Cu.unload("resource://gre/modules/addons/XPIProvider.jsm"); Cu.unload("resource://gre/modules/addons/XPIProvider.jsm");
// We need to set this in order reset the startup service, which
// is only possible when running in automation.
Services.prefs.setBoolPref(PREF_DISABLE_SECURITY, true);
aomStartup.reset();
if (shutdownError) if (shutdownError)
throw shutdownError; throw shutdownError;
@ -629,14 +584,8 @@ var AddonTestUtils = {
}); });
}, },
async loadAddonsList(flush = false) { loadAddonsList() {
if (flush) { this.addonsList = new AddonsList(this.extensionsINI);
let XPIScope = Cu.import("resource://gre/modules/addons/XPIProvider.jsm", {});
XPIScope.XPIStates.save();
await XPIScope.XPIStates._jsonFile._save();
}
this.addonsList = new AddonsList(this.addonStartup);
}, },
/** /**
@ -900,9 +849,9 @@ var AddonTestUtils = {
* *
* @param {nsIFile} xpiFile * @param {nsIFile} xpiFile
* The XPI file to install. * The XPI file to install.
* @param {nsIFile} [installLocation = this.profileExtensions] * @param {nsIFile} installLocation
* The install location (an nsIFile) to install into. * The install location (an nsIFile) to install into.
* @param {string} [id] * @param {string} id
* The ID to install as. * The ID to install as.
* @param {boolean} [unpacked = this.testUnpacked] * @param {boolean} [unpacked = this.testUnpacked]
* If true, install as an unpacked directory, rather than a * If true, install as an unpacked directory, rather than a
@ -911,11 +860,7 @@ var AddonTestUtils = {
* A file pointing to the installed location of the XPI file or * A file pointing to the installed location of the XPI file or
* unpacked directory. * unpacked directory.
*/ */
async manuallyInstall(xpiFile, installLocation = this.profileExtensions, id = null, unpacked = this.testUnpacked) { manuallyInstall(xpiFile, installLocation, id, unpacked = this.testUnpacked) {
if (id == null) {
id = await this.getIDFromExtension(xpiFile);
}
if (unpacked) { if (unpacked) {
let dir = installLocation.clone(); let dir = installLocation.clone();
dir.append(id); dir.append(id);

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

@ -31,7 +31,6 @@ function startup(data, reason) {
function shutdown(data, reason) { function shutdown(data, reason) {
extension.shutdown(BOOTSTRAP_REASON_TO_STRING_MAP[reason]); extension.shutdown(BOOTSTRAP_REASON_TO_STRING_MAP[reason]);
extension = null;
} }
function uninstall(data, reason) { function uninstall(data, reason) {

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

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

@ -8,7 +8,7 @@
/* globals ADDON_SIGNING, SIGNED_TYPES, BOOTSTRAP_REASONS, DB_SCHEMA, /* globals ADDON_SIGNING, SIGNED_TYPES, BOOTSTRAP_REASONS, DB_SCHEMA,
AddonInternal, XPIProvider, XPIStates, syncLoadManifestFromFile, AddonInternal, XPIProvider, XPIStates, syncLoadManifestFromFile,
isUsableAddon, recordAddonTelemetry, applyBlocklistChanges, isUsableAddon, recordAddonTelemetry, applyBlocklistChanges,
flushChromeCaches, descriptorToPath */ flushChromeCaches, canRunInSafeMode*/
var Cc = Components.classes; var Cc = Components.classes;
var Ci = Components.interfaces; var Ci = Components.interfaces;
@ -41,20 +41,23 @@ XPCOMUtils.defineLazyPreferenceGetter(this, "ALLOW_NON_MPC",
Cu.import("resource://gre/modules/Log.jsm"); Cu.import("resource://gre/modules/Log.jsm");
const LOGGER_ID = "addons.xpi-utils"; const LOGGER_ID = "addons.xpi-utils";
const nsIFile = Components.Constructor("@mozilla.org/file/local;1", "nsIFile", const nsIFile = Components.Constructor("@mozilla.org/file/local;1", "nsIFile");
"initWithPath");
// Create a new logger for use by the Addons XPI Provider Utils // Create a new logger for use by the Addons XPI Provider Utils
// (Requires AddonManager.jsm) // (Requires AddonManager.jsm)
var logger = Log.repository.getLogger(LOGGER_ID); var logger = Log.repository.getLogger(LOGGER_ID);
const KEY_PROFILEDIR = "ProfD"; const KEY_PROFILEDIR = "ProfD";
const FILE_DATABASE = "extensions.sqlite";
const FILE_JSON_DB = "extensions.json"; const FILE_JSON_DB = "extensions.json";
const FILE_OLD_DATABASE = "extensions.rdf";
const FILE_XPI_ADDONS_LIST = "extensions.ini";
// The last version of DB_SCHEMA implemented in SQLITE // The last version of DB_SCHEMA implemented in SQLITE
const LAST_SQLITE_DB_SCHEMA = 14; const LAST_SQLITE_DB_SCHEMA = 14;
const PREF_DB_SCHEMA = "extensions.databaseSchema"; const PREF_DB_SCHEMA = "extensions.databaseSchema";
const PREF_PENDING_OPERATIONS = "extensions.pendingOperations"; const PREF_PENDING_OPERATIONS = "extensions.pendingOperations";
const PREF_EM_ENABLED_ADDONS = "extensions.enabledAddons";
const PREF_EM_AUTO_DISABLED_SCOPES = "extensions.autoDisableScopes"; const PREF_EM_AUTO_DISABLED_SCOPES = "extensions.autoDisableScopes";
const PREF_E10S_BLOCKED_BY_ADDONS = "extensions.e10sBlockedByAddons"; const PREF_E10S_BLOCKED_BY_ADDONS = "extensions.e10sBlockedByAddons";
const PREF_E10S_MULTI_BLOCKED_BY_ADDONS = "extensions.e10sMultiBlockedByAddons"; const PREF_E10S_MULTI_BLOCKED_BY_ADDONS = "extensions.e10sMultiBlockedByAddons";
@ -66,13 +69,26 @@ const KEY_APP_SYSTEM_DEFAULTS = "app-system-defaults";
const KEY_APP_GLOBAL = "app-global"; const KEY_APP_GLOBAL = "app-global";
const KEY_APP_TEMPORARY = "app-temporary"; const KEY_APP_TEMPORARY = "app-temporary";
// Properties that only exist in the database
const DB_METADATA = ["syncGUID",
"installDate",
"updateDate",
"size",
"sourceURI",
"releaseNotesURI",
"applyBackgroundUpdates"];
const DB_BOOL_METADATA = ["visible", "active", "userDisabled", "appDisabled",
"pendingUninstall", "bootstrap", "skinnable",
"softDisabled", "isForeignInstall",
"hasBinaryComponents", "strictCompatibility"];
// Properties to save in JSON file // Properties to save in JSON file
const PROP_JSON_FIELDS = ["id", "syncGUID", "location", "version", "type", const PROP_JSON_FIELDS = ["id", "syncGUID", "location", "version", "type",
"internalName", "updateURL", "updateKey", "optionsURL", "internalName", "updateURL", "updateKey", "optionsURL",
"optionsType", "optionsBrowserStyle", "aboutURL", "optionsType", "optionsBrowserStyle", "aboutURL",
"defaultLocale", "visible", "active", "userDisabled", "defaultLocale", "visible", "active", "userDisabled",
"appDisabled", "pendingUninstall", "installDate", "appDisabled", "pendingUninstall", "descriptor", "installDate",
"updateDate", "applyBackgroundUpdates", "bootstrap", "path", "updateDate", "applyBackgroundUpdates", "bootstrap",
"skinnable", "size", "sourceURI", "releaseNotesURI", "skinnable", "size", "sourceURI", "releaseNotesURI",
"softDisabled", "foreignInstall", "hasBinaryComponents", "softDisabled", "foreignInstall", "hasBinaryComponents",
"strictCompatibility", "locales", "targetApplications", "strictCompatibility", "locales", "targetApplications",
@ -80,9 +96,59 @@ const PROP_JSON_FIELDS = ["id", "syncGUID", "location", "version", "type",
"seen", "dependencies", "hasEmbeddedWebExtension", "mpcOptedOut", "seen", "dependencies", "hasEmbeddedWebExtension", "mpcOptedOut",
"userPermissions", "icons", "iconURL", "icon64URL"]; "userPermissions", "icons", "iconURL", "icon64URL"];
// Properties that should be migrated where possible from an old database. These
// shouldn't include properties that can be read directly from install.rdf files
// or calculated
const DB_MIGRATE_METADATA = ["installDate", "userDisabled", "softDisabled",
"sourceURI", "applyBackgroundUpdates",
"releaseNotesURI", "foreignInstall", "syncGUID"];
// Time to wait before async save of XPI JSON database, in milliseconds // Time to wait before async save of XPI JSON database, in milliseconds
const ASYNC_SAVE_DELAY_MS = 20; const ASYNC_SAVE_DELAY_MS = 20;
const PREFIX_ITEM_URI = "urn:mozilla:item:";
const RDFURI_ITEM_ROOT = "urn:mozilla:item:root"
const PREFIX_NS_EM = "http://www.mozilla.org/2004/em-rdf#";
XPCOMUtils.defineLazyServiceGetter(this, "gRDF", "@mozilla.org/rdf/rdf-service;1",
Ci.nsIRDFService);
function EM_R(aProperty) {
return gRDF.GetResource(PREFIX_NS_EM + aProperty);
}
/**
* Converts an RDF literal, resource or integer into a string.
*
* @param aLiteral
* The RDF object to convert
* @return a string if the object could be converted or null
*/
function getRDFValue(aLiteral) {
if (aLiteral instanceof Ci.nsIRDFLiteral)
return aLiteral.Value;
if (aLiteral instanceof Ci.nsIRDFResource)
return aLiteral.Value;
if (aLiteral instanceof Ci.nsIRDFInt)
return aLiteral.Value;
return null;
}
/**
* Gets an RDF property as a string
*
* @param aDs
* The RDF datasource to read the property from
* @param aResource
* The RDF resource to read the property from
* @param aProperty
* The property to read
* @return a string if the property existed or null
*/
function getRDFProperty(aDs, aResource, aProperty) {
return getRDFValue(aDs.GetTarget(aResource, EM_R(aProperty), true));
}
/** /**
* Asynchronously fill in the _repositoryAddon field for one addon * Asynchronously fill in the _repositoryAddon field for one addon
*/ */
@ -157,6 +223,50 @@ function asyncMap(aObjects, aMethod, aCallback) {
}); });
} }
/**
* A generator to synchronously return result rows from an mozIStorageStatement.
*
* @param aStatement
* The statement to execute
*/
function* resultRows(aStatement) {
try {
while (stepStatement(aStatement))
yield aStatement.row;
} finally {
aStatement.reset();
}
}
/**
* A helper function to log an SQL error.
*
* @param aError
* The storage error code associated with the error
* @param aErrorString
* An error message
*/
function logSQLError(aError, aErrorString) {
logger.error("SQL error " + aError + ": " + aErrorString);
}
/**
* A helper function to step a statement synchronously and log any error that
* occurs.
*
* @param aStatement
* A mozIStorageStatement to execute
*/
function stepStatement(aStatement) {
try {
return aStatement.executeStep();
} catch (e) {
logSQLError(XPIDatabase.connection.lastError,
XPIDatabase.connection.lastErrorString);
throw e;
}
}
/** /**
* Copies properties from one object to another. If no target object is passed * Copies properties from one object to another. If no target object is passed
* a new object will be created and returned. * a new object will be created and returned.
@ -191,13 +301,6 @@ function copyProperties(aObject, aProperties, aTarget) {
function DBAddonInternal(aLoaded) { function DBAddonInternal(aLoaded) {
AddonInternal.call(this); AddonInternal.call(this);
if (aLoaded.descriptor) {
if (!aLoaded.path) {
aLoaded.path = descriptorToPath(aLoaded.descriptor);
}
delete aLoaded.descriptor;
}
copyProperties(aLoaded, PROP_JSON_FIELDS, this); copyProperties(aLoaded, PROP_JSON_FIELDS, this);
if (!this.dependencies) if (!this.dependencies)
@ -214,7 +317,7 @@ function DBAddonInternal(aLoaded) {
this._key = this.location + ":" + this.id; this._key = this.location + ":" + this.id;
if (!aLoaded._sourceBundle) { if (!aLoaded._sourceBundle) {
throw new Error("Expected passed argument to contain a path"); throw new Error("Expected passed argument to contain a descriptor");
} }
this._sourceBundle = aLoaded._sourceBundle; this._sourceBundle = aLoaded._sourceBundle;
@ -395,6 +498,32 @@ this.XPIDatabase = {
return toSave; return toSave;
}, },
/**
* Pull upgrade information from an existing SQLITE database
*
* @return false if there is no SQLITE database
* true and sets this.migrateData to null if the SQLITE DB exists
* but does not contain useful information
* true and sets this.migrateData to
* {location: {id1:{addon1}, id2:{addon2}}, location2:{...}, ...}
* if there is useful information
*/
getMigrateDataFromSQLITE() {
let connection = null;
let dbfile = FileUtils.getFile(KEY_PROFILEDIR, [FILE_DATABASE], true);
// Attempt to open the database
try {
connection = Services.storage.openUnsharedDatabase(dbfile);
} catch (e) {
logger.warn("Failed to open sqlite database " + dbfile.path + " for upgrade", e);
return null;
}
logger.debug("Migrating data from sqlite");
let migrateData = this.getMigrateDataFromDatabase(connection);
connection.close();
return migrateData;
},
/** /**
* Synchronously opens and reads the database file, upgrading from old * Synchronously opens and reads the database file, upgrading from old
* databases or making a new DB if needed. * databases or making a new DB if needed.
@ -501,10 +630,11 @@ this.XPIDatabase = {
// Make AddonInternal instances from the loaded data and save them // Make AddonInternal instances from the loaded data and save them
let addonDB = new Map(); let addonDB = new Map();
for (let loadedAddon of inputAddons.addons) { for (let loadedAddon of inputAddons.addons) {
loadedAddon._sourceBundle = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
try { try {
loadedAddon._sourceBundle = new nsIFile(loadedAddon.path); loadedAddon._sourceBundle.persistentDescriptor = loadedAddon.descriptor;
} catch (e) { } catch (e) {
// We can fail here when the path is invalid, usually from the // We can fail here when the descriptor is invalid, usually from the
// wrong OS // wrong OS
logger.warn("Could not find source bundle for add-on " + loadedAddon.id, e); logger.warn("Could not find source bundle for add-on " + loadedAddon.id, e);
} }
@ -538,12 +668,21 @@ this.XPIDatabase = {
*/ */
upgradeDB(aRebuildOnError) { upgradeDB(aRebuildOnError) {
let upgradeTimer = AddonManagerPrivate.simpleTimer("XPIDB_upgradeDB_MS"); let upgradeTimer = AddonManagerPrivate.simpleTimer("XPIDB_upgradeDB_MS");
try {
let schemaVersion = Services.prefs.getIntPref(PREF_DB_SCHEMA, 0); let schemaVersion = Services.prefs.getIntPref(PREF_DB_SCHEMA);
if (schemaVersion > LAST_SQLITE_DB_SCHEMA) { if (schemaVersion <= LAST_SQLITE_DB_SCHEMA) {
// we've upgraded before but the JSON file is gone, fall through // we should have an older SQLITE database
// and rebuild from scratch logger.debug("Attempting to upgrade from SQLITE database");
AddonManagerPrivate.recordSimpleMeasure("XPIDB_startupError", "dbMissing"); this.migrateData = this.getMigrateDataFromSQLITE();
} else {
// we've upgraded before but the JSON file is gone, fall through
// and rebuild from scratch
AddonManagerPrivate.recordSimpleMeasure("XPIDB_startupError", "dbMissing");
}
} catch (e) {
// No schema version pref means either a really old upgrade (RDF) or
// a new profile
this.migrateData = this.getMigrateDataFromRDF();
} }
this.rebuildDatabase(aRebuildOnError); this.rebuildDatabase(aRebuildOnError);
@ -640,13 +779,8 @@ this.XPIDatabase = {
// If there is no migration data then load the list of add-on directories // If there is no migration data then load the list of add-on directories
// that were active during the last run // that were active during the last run
if (!this.migrateData) { if (!this.migrateData)
this.activeBundles = Array.from(XPIStates.initialEnabledAddons(), this.activeBundles = this.getActiveBundles();
addon => addon.path);
if (!this.activeBundles.length)
this.activeBundles = null;
}
if (aRebuildOnError) { if (aRebuildOnError) {
logger.warn("Rebuilding add-ons database from installed extensions."); logger.warn("Rebuilding add-ons database from installed extensions.");
@ -660,6 +794,203 @@ this.XPIDatabase = {
} }
}, },
/**
* Gets the list of file descriptors of active extension directories or XPI
* files from the add-ons list. This must be loaded from disk since the
* directory service gives no easy way to get both directly. This list doesn't
* include themes as preferences already say which theme is currently active
*
* @return an array of persistent descriptors for the directories
*/
getActiveBundles() {
let bundles = [];
// non-bootstrapped extensions
let addonsList = FileUtils.getFile(KEY_PROFILEDIR, [FILE_XPI_ADDONS_LIST],
true);
if (!addonsList.exists())
// XXX Irving believes this is broken in the case where there is no
// extensions.ini but there are bootstrap extensions (e.g. Android)
return null;
try {
let iniFactory = Cc["@mozilla.org/xpcom/ini-parser-factory;1"]
.getService(Ci.nsIINIParserFactory);
let parser = iniFactory.createINIParser(addonsList);
let keys = parser.getKeys("ExtensionDirs");
while (keys.hasMore())
bundles.push(parser.getString("ExtensionDirs", keys.getNext()));
} catch (e) {
logger.warn("Failed to parse extensions.ini", e);
return null;
}
// Also include the list of active bootstrapped extensions
for (let id in XPIProvider.bootstrappedAddons)
bundles.push(XPIProvider.bootstrappedAddons[id].descriptor);
return bundles;
},
/**
* Retrieves migration data from the old extensions.rdf database.
*
* @return an object holding information about what add-ons were previously
* userDisabled and any updated compatibility information
*/
getMigrateDataFromRDF(aDbWasMissing) {
// Migrate data from extensions.rdf
let rdffile = FileUtils.getFile(KEY_PROFILEDIR, [FILE_OLD_DATABASE], true);
if (!rdffile.exists())
return null;
logger.debug("Migrating data from " + FILE_OLD_DATABASE);
let migrateData = {};
try {
let ds = gRDF.GetDataSourceBlocking(Services.io.newFileURI(rdffile).spec);
let root = Cc["@mozilla.org/rdf/container;1"].
createInstance(Ci.nsIRDFContainer);
root.Init(ds, gRDF.GetResource(RDFURI_ITEM_ROOT));
let elements = root.GetElements();
while (elements.hasMoreElements()) {
let source = elements.getNext().QueryInterface(Ci.nsIRDFResource);
let location = getRDFProperty(ds, source, "installLocation");
if (location) {
if (!(location in migrateData))
migrateData[location] = {};
let id = source.ValueUTF8.substring(PREFIX_ITEM_URI.length);
migrateData[location][id] = {
version: getRDFProperty(ds, source, "version"),
userDisabled: false,
targetApplications: []
}
let disabled = getRDFProperty(ds, source, "userDisabled");
if (disabled == "true" || disabled == "needs-disable")
migrateData[location][id].userDisabled = true;
let targetApps = ds.GetTargets(source, EM_R("targetApplication"),
true);
while (targetApps.hasMoreElements()) {
let targetApp = targetApps.getNext()
.QueryInterface(Ci.nsIRDFResource);
let appInfo = {
id: getRDFProperty(ds, targetApp, "id")
};
let minVersion = getRDFProperty(ds, targetApp, "updatedMinVersion");
if (minVersion) {
appInfo.minVersion = minVersion;
appInfo.maxVersion = getRDFProperty(ds, targetApp, "updatedMaxVersion");
} else {
appInfo.minVersion = getRDFProperty(ds, targetApp, "minVersion");
appInfo.maxVersion = getRDFProperty(ds, targetApp, "maxVersion");
}
migrateData[location][id].targetApplications.push(appInfo);
}
}
}
} catch (e) {
logger.warn("Error reading " + FILE_OLD_DATABASE, e);
migrateData = null;
}
return migrateData;
},
/**
* Retrieves migration data from a database that has an older or newer schema.
*
* @return an object holding information about what add-ons were previously
* userDisabled and any updated compatibility information
*/
getMigrateDataFromDatabase(aConnection) {
let migrateData = {};
// Attempt to migrate data from a different (even future!) version of the
// database
try {
var stmt = aConnection.createStatement("PRAGMA table_info(addon)");
const REQUIRED = ["internal_id", "id", "location", "userDisabled",
"installDate", "version"];
let reqCount = 0;
let props = [];
for (let row of resultRows(stmt)) {
if (REQUIRED.indexOf(row.name) != -1) {
reqCount++;
props.push(row.name);
} else if (DB_METADATA.indexOf(row.name) != -1) {
props.push(row.name);
} else if (DB_BOOL_METADATA.indexOf(row.name) != -1) {
props.push(row.name);
}
}
if (reqCount < REQUIRED.length) {
logger.error("Unable to read anything useful from the database");
return null;
}
stmt.finalize();
stmt = aConnection.createStatement("SELECT " + props.join(",") + " FROM addon");
for (let row of resultRows(stmt)) {
if (!(row.location in migrateData))
migrateData[row.location] = {};
let addonData = {
targetApplications: []
}
migrateData[row.location][row.id] = addonData;
props.forEach(function(aProp) {
if (aProp == "isForeignInstall")
addonData.foreignInstall = (row[aProp] == 1);
if (DB_BOOL_METADATA.indexOf(aProp) != -1)
addonData[aProp] = row[aProp] == 1;
else
addonData[aProp] = row[aProp];
})
}
var taStmt = aConnection.createStatement("SELECT id, minVersion, " +
"maxVersion FROM " +
"targetApplication WHERE " +
"addon_internal_id=:internal_id");
for (let location in migrateData) {
for (let id in migrateData[location]) {
taStmt.params.internal_id = migrateData[location][id].internal_id;
delete migrateData[location][id].internal_id;
for (let row of resultRows(taStmt)) {
migrateData[location][id].targetApplications.push({
id: row.id,
minVersion: row.minVersion,
maxVersion: row.maxVersion
});
}
}
}
} catch (e) {
// An error here means the schema is too different to read
logger.error("Error migrating data", e);
return null;
} finally {
if (taStmt)
taStmt.finalize();
if (stmt)
stmt.finalize();
}
return migrateData;
},
/** /**
* Shuts down the database connection and releases all cached objects. * Shuts down the database connection and releases all cached objects.
* Return: Promise{integer} resolves / rejects with the result of the DB * Return: Promise{integer} resolves / rejects with the result of the DB
@ -903,11 +1234,11 @@ this.XPIDatabase = {
* *
* @param aAddon * @param aAddon
* AddonInternal to add * AddonInternal to add
* @param aPath * @param aDescriptor
* The file path of the add-on * The file descriptor of the add-on
* @return The DBAddonInternal that was added to the database * @return The DBAddonInternal that was added to the database
*/ */
addAddonMetadata(aAddon, aPath) { addAddonMetadata(aAddon, aDescriptor) {
if (!this.addonDB) { if (!this.addonDB) {
AddonManagerPrivate.recordSimpleMeasure("XPIDB_lateOpen_addMetadata", AddonManagerPrivate.recordSimpleMeasure("XPIDB_lateOpen_addMetadata",
XPIProvider.runPhase); XPIProvider.runPhase);
@ -915,7 +1246,7 @@ this.XPIDatabase = {
} }
let newAddon = new DBAddonInternal(aAddon); let newAddon = new DBAddonInternal(aAddon);
newAddon.path = aPath; newAddon.descriptor = aDescriptor;
this.addonDB.set(newAddon._key, newAddon); this.addonDB.set(newAddon._key, newAddon);
if (newAddon.visible) { if (newAddon.visible) {
this.makeAddonVisible(newAddon); this.makeAddonVisible(newAddon);
@ -933,11 +1264,11 @@ this.XPIDatabase = {
* The DBAddonInternal to be replaced * The DBAddonInternal to be replaced
* @param aNewAddon * @param aNewAddon
* The new AddonInternal to add * The new AddonInternal to add
* @param aPath * @param aDescriptor
* The file path of the add-on * The file descriptor of the add-on
* @return The DBAddonInternal that was added to the database * @return The DBAddonInternal that was added to the database
*/ */
updateAddonMetadata(aOldAddon, aNewAddon, aPath) { updateAddonMetadata(aOldAddon, aNewAddon, aDescriptor) {
this.removeAddonMetadata(aOldAddon); this.removeAddonMetadata(aOldAddon);
aNewAddon.syncGUID = aOldAddon.syncGUID; aNewAddon.syncGUID = aOldAddon.syncGUID;
aNewAddon.installDate = aOldAddon.installDate; aNewAddon.installDate = aOldAddon.installDate;
@ -947,7 +1278,7 @@ this.XPIDatabase = {
aNewAddon.active = (aNewAddon.visible && !aNewAddon.disabled && !aNewAddon.pendingUninstall); aNewAddon.active = (aNewAddon.visible && !aNewAddon.disabled && !aNewAddon.pendingUninstall);
// addAddonMetadata does a saveChanges() // addAddonMetadata does a saveChanges()
return this.addAddonMetadata(aNewAddon, aPath); return this.addAddonMetadata(aNewAddon, aDescriptor);
}, },
/** /**
@ -961,14 +1292,6 @@ this.XPIDatabase = {
this.saveChanges(); this.saveChanges();
}, },
updateXPIStates(addon) {
let xpiState = XPIStates.getAddon(addon.location, addon.id);
if (xpiState) {
xpiState.syncWithDB(addon);
XPIStates.save();
}
},
/** /**
* Synchronously marks a DBAddonInternal as visible marking all other * Synchronously marks a DBAddonInternal as visible marking all other
* instances with the same ID as not visible. * instances with the same ID as not visible.
@ -983,12 +1306,9 @@ this.XPIDatabase = {
logger.debug("Hide addon " + otherAddon._key); logger.debug("Hide addon " + otherAddon._key);
otherAddon.visible = false; otherAddon.visible = false;
otherAddon.active = false; otherAddon.active = false;
this.updateXPIStates(otherAddon);
} }
} }
aAddon.visible = true; aAddon.visible = true;
this.updateXPIStates(aAddon);
this.saveChanges(); this.saveChanges();
}, },
@ -1010,13 +1330,11 @@ this.XPIDatabase = {
logger.debug("Reveal addon " + addon._key); logger.debug("Reveal addon " + addon._key);
addon.visible = true; addon.visible = true;
addon.active = true; addon.active = true;
this.updateXPIStates(addon);
result = addon; result = addon;
} else { } else {
logger.debug("Hide addon " + addon._key); logger.debug("Hide addon " + addon._key);
addon.visible = false; addon.visible = false;
addon.active = false; addon.active = false;
this.updateXPIStates(addon);
} }
} }
this.saveChanges(); this.saveChanges();
@ -1076,15 +1394,6 @@ this.XPIDatabase = {
}, },
updateAddonsBlockingE10s() { updateAddonsBlockingE10s() {
if (!this.addonDB) {
// jank-tastic! Must synchronously load DB if the theme switches from
// an XPI theme to a lightweight theme before the DB has loaded,
// because we're called from sync XPIProvider.addonChanged
logger.warn("Synchronous load of XPI database due to updateAddonsBlockingE10s()");
AddonManagerPrivate.recordSimpleMeasure("XPIDB_lateOpen_byType", XPIProvider.runPhase);
this.syncLoadDB(true);
}
let blockE10s = false; let blockE10s = false;
Preferences.set(PREF_E10S_HAS_NONEXEMPT_ADDON, false); Preferences.set(PREF_E10S_HAS_NONEXEMPT_ADDON, false);
@ -1133,6 +1442,94 @@ this.XPIDatabase = {
} }
} }
}, },
/**
* Writes out the XPI add-ons list for the platform to read.
* @return true if the file was successfully updated, false otherwise
*/
writeAddonsList() {
if (!this.addonDB) {
// force the DB to load
AddonManagerPrivate.recordSimpleMeasure("XPIDB_lateOpen_writeList",
XPIProvider.runPhase);
this.syncLoadDB(true);
}
Services.appinfo.invalidateCachesOnRestart();
let addonsList = FileUtils.getFile(KEY_PROFILEDIR, [FILE_XPI_ADDONS_LIST],
true);
let enabledAddons = [];
let text = "[ExtensionDirs]\r\n";
let count = 0;
let fullCount = 0;
let activeAddons = _filterDB(
this.addonDB,
aAddon => aAddon.active && !aAddon.bootstrap && (aAddon.type != "theme"));
for (let row of activeAddons) {
text += "Extension" + (count++) + "=" + row.descriptor + "\r\n";
enabledAddons.push(encodeURIComponent(row.id) + ":" +
encodeURIComponent(row.version));
}
fullCount += count;
// The selected skin may come from an inactive theme (the default theme
// when a lightweight theme is applied for example)
text += "\r\n[ThemeDirs]\r\n";
let activeTheme = _findAddon(
this.addonDB,
aAddon => (aAddon.type == "theme") &&
(aAddon.internalName == XPIProvider.selectedSkin));
count = 0;
if (activeTheme) {
text += "Extension" + (count++) + "=" + activeTheme.descriptor + "\r\n";
enabledAddons.push(encodeURIComponent(activeTheme.id) + ":" +
encodeURIComponent(activeTheme.version));
}
fullCount += count;
text += "\r\n[MultiprocessIncompatibleExtensions]\r\n";
count = 0;
for (let row of activeAddons) {
if (!row.multiprocessCompatible) {
text += "Extension" + (count++) + "=" + row.id + "\r\n";
}
}
if (fullCount > 0) {
logger.debug("Writing add-ons list");
try {
let addonsListTmp = FileUtils.getFile(KEY_PROFILEDIR, [FILE_XPI_ADDONS_LIST + ".tmp"],
true);
var fos = FileUtils.openFileOutputStream(addonsListTmp);
fos.write(text, text.length);
fos.close();
addonsListTmp.moveTo(addonsListTmp.parent, FILE_XPI_ADDONS_LIST);
Services.prefs.setCharPref(PREF_EM_ENABLED_ADDONS, enabledAddons.join(","));
} catch (e) {
logger.error("Failed to write add-ons list to profile directory", e);
return false;
}
} else {
if (addonsList.exists()) {
logger.debug("Deleting add-ons list");
try {
addonsList.remove(false);
} catch (e) {
logger.error("Failed to remove " + addonsList.path, e);
return false;
}
}
Services.prefs.clearUserPref(PREF_EM_ENABLED_ADDONS);
}
return true;
}
}; };
this.XPIDatabaseReconcile = { this.XPIDatabaseReconcile = {
@ -1205,17 +1602,20 @@ this.XPIDatabaseReconcile = {
* @param aOldPlatformVersion * @param aOldPlatformVersion
* The version of the platform last run with this profile or null * The version of the platform last run with this profile or null
* if it is a new profile or the version is unknown * if it is a new profile or the version is unknown
* @param aMigrateData
* If during startup the database had to be upgraded this will
* contain data that used to be held about this add-on
* @return a boolean indicating if flushing caches is required to complete * @return a boolean indicating if flushing caches is required to complete
* changing this add-on * changing this add-on
*/ */
addMetadata(aInstallLocation, aId, aAddonState, aNewAddon, aOldAppVersion, addMetadata(aInstallLocation, aId, aAddonState, aNewAddon, aOldAppVersion,
aOldPlatformVersion) { aOldPlatformVersion, aMigrateData) {
logger.debug("New add-on " + aId + " installed in " + aInstallLocation.name); logger.debug("New add-on " + aId + " installed in " + aInstallLocation.name);
// If we had staged data for this add-on or we aren't recovering from a // If we had staged data for this add-on or we aren't recovering from a
// corrupt database and we don't have migration data for this add-on then // corrupt database and we don't have migration data for this add-on then
// this must be a new install. // this must be a new install.
let isNewInstall = !!aNewAddon || !XPIDatabase.activeBundles; let isNewInstall = (!!aNewAddon) || (!XPIDatabase.activeBundles && !aMigrateData);
// If it's a new install and we haven't yet loaded the manifest then it // If it's a new install and we haven't yet loaded the manifest then it
// must be something dropped directly into the install location // must be something dropped directly into the install location
@ -1225,7 +1625,8 @@ this.XPIDatabaseReconcile = {
try { try {
if (!aNewAddon) { if (!aNewAddon) {
// Load the manifest from the add-on. // Load the manifest from the add-on.
let file = new nsIFile(aAddonState.path); let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
file.persistentDescriptor = aAddonState.descriptor;
aNewAddon = syncLoadManifestFromFile(file, aInstallLocation); aNewAddon = syncLoadManifestFromFile(file, aInstallLocation);
} }
// The add-on in the manifest should match the add-on ID. // The add-on in the manifest should match the add-on ID.
@ -1260,6 +1661,38 @@ this.XPIDatabaseReconcile = {
// appDisabled depends on whether the add-on is a foreignInstall so update // appDisabled depends on whether the add-on is a foreignInstall so update
aNewAddon.appDisabled = !isUsableAddon(aNewAddon); aNewAddon.appDisabled = !isUsableAddon(aNewAddon);
if (aMigrateData) {
// If there is migration data then apply it.
logger.debug("Migrating data from old database");
DB_MIGRATE_METADATA.forEach(function(aProp) {
// A theme's disabled state is determined by the selected theme
// preference which is read in loadManifestFromRDF
if (aProp == "userDisabled" && aNewAddon.type == "theme")
return;
if (aProp in aMigrateData)
aNewAddon[aProp] = aMigrateData[aProp];
});
// Force all non-profile add-ons to be foreignInstalls since they can't
// have been installed through the API
aNewAddon.foreignInstall |= aInstallLocation.name != KEY_APP_PROFILE;
// Some properties should only be migrated if the add-on hasn't changed.
// The version property isn't a perfect check for this but covers the
// vast majority of cases.
if (aMigrateData.version == aNewAddon.version) {
logger.debug("Migrating compatibility info");
if ("targetApplications" in aMigrateData)
aNewAddon.applyCompatibilityUpdate(aMigrateData, true);
}
// Since the DB schema has changed make sure softDisabled is correct
applyBlocklistChanges(aNewAddon, aNewAddon, aOldAppVersion,
aOldPlatformVersion);
}
// The default theme is never a foreign install // The default theme is never a foreign install
if (aNewAddon.type == "theme" && aNewAddon.internalName == XPIProvider.defaultSkin) if (aNewAddon.type == "theme" && aNewAddon.internalName == XPIProvider.defaultSkin)
aNewAddon.foreignInstall = false; aNewAddon.foreignInstall = false;
@ -1275,12 +1708,11 @@ this.XPIDatabaseReconcile = {
// If we don't have an old app version then this is a new profile in // If we don't have an old app version then this is a new profile in
// which case just mark any sideloaded add-ons as already seen. // which case just mark any sideloaded add-ons as already seen.
aNewAddon.seen = (aInstallLocation.name != KEY_APP_PROFILE && aNewAddon.seen = !aOldAppVersion;
!aOldAppVersion);
} }
} }
return XPIDatabase.addAddonMetadata(aNewAddon, aAddonState.path); return XPIDatabase.addAddonMetadata(aNewAddon, aAddonState.descriptor);
}, },
/** /**
@ -1321,7 +1753,8 @@ this.XPIDatabaseReconcile = {
try { try {
// If there isn't an updated install manifest for this add-on then load it. // If there isn't an updated install manifest for this add-on then load it.
if (!aNewAddon) { if (!aNewAddon) {
let file = new nsIFile(aAddonState.path); let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
file.persistentDescriptor = aAddonState.descriptor;
aNewAddon = syncLoadManifestFromFile(file, aInstallLocation); aNewAddon = syncLoadManifestFromFile(file, aInstallLocation);
applyBlocklistChanges(aOldAddon, aNewAddon); applyBlocklistChanges(aOldAddon, aNewAddon);
@ -1352,11 +1785,11 @@ this.XPIDatabaseReconcile = {
aNewAddon.updateDate = aAddonState.mtime; aNewAddon.updateDate = aAddonState.mtime;
// Update the database // Update the database
return XPIDatabase.updateAddonMetadata(aOldAddon, aNewAddon, aAddonState.path); return XPIDatabase.updateAddonMetadata(aOldAddon, aNewAddon, aAddonState.descriptor);
}, },
/** /**
* Updates an add-on's path for when the add-on has moved in the * Updates an add-on's descriptor for when the add-on has moved in the
* filesystem but hasn't changed in any other way. * filesystem but hasn't changed in any other way.
* *
* @param aInstallLocation * @param aInstallLocation
@ -1369,10 +1802,10 @@ this.XPIDatabaseReconcile = {
* @return a boolean indicating if flushing caches is required to complete * @return a boolean indicating if flushing caches is required to complete
* changing this add-on * changing this add-on
*/ */
updatePath(aInstallLocation, aOldAddon, aAddonState) { updateDescriptor(aInstallLocation, aOldAddon, aAddonState) {
logger.debug("Add-on " + aOldAddon.id + " moved to " + aAddonState.path); logger.debug("Add-on " + aOldAddon.id + " moved to " + aAddonState.descriptor);
aOldAddon.path = aAddonState.path; aOldAddon.descriptor = aAddonState.descriptor;
aOldAddon._sourceBundle = new nsIFile(aAddonState.path); aOldAddon._sourceBundle.persistentDescriptor = aAddonState.descriptor;
return aOldAddon; return aOldAddon;
}, },
@ -1407,7 +1840,8 @@ this.XPIDatabaseReconcile = {
// then fetch that property now // then fetch that property now
if (aOldAddon.signedState === undefined && ADDON_SIGNING && if (aOldAddon.signedState === undefined && ADDON_SIGNING &&
SIGNED_TYPES.has(aOldAddon.type)) { SIGNED_TYPES.has(aOldAddon.type)) {
let file = new nsIFile(aAddonState.path); let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
file.persistentDescriptor = aAddonState.descriptor;
let manifest = syncLoadManifestFromFile(file, aInstallLocation); let manifest = syncLoadManifestFromFile(file, aInstallLocation);
aOldAddon.signedState = manifest.signedState; aOldAddon.signedState = manifest.signedState;
} }
@ -1415,7 +1849,8 @@ this.XPIDatabaseReconcile = {
// May be updating from a version of the app that didn't support all the // May be updating from a version of the app that didn't support all the
// properties of the currently-installed add-ons. // properties of the currently-installed add-ons.
if (aReloadMetadata) { if (aReloadMetadata) {
let file = new nsIFile(aAddonState.path); let file = new nsIFile()
file.persistentDescriptor = aAddonState.descriptor;
let manifest = syncLoadManifestFromFile(file, aInstallLocation); let manifest = syncLoadManifestFromFile(file, aInstallLocation);
// Avoid re-reading these properties from manifest, // Avoid re-reading these properties from manifest,
@ -1472,7 +1907,7 @@ this.XPIDatabaseReconcile = {
}; };
// Add-ons loaded from the database can have an uninitialized _sourceBundle // Add-ons loaded from the database can have an uninitialized _sourceBundle
// if the path was invalid. Swallow that error and say they don't exist. // if the descriptor was invalid. Swallow that error and say they don't exist.
let exists = (aAddon) => { let exists = (aAddon) => {
try { try {
return aAddon._sourceBundle.exists(); return aAddon._sourceBundle.exists();
@ -1522,14 +1957,17 @@ this.XPIDatabaseReconcile = {
// Did time change in the wrong direction? // Did time change in the wrong direction?
if (xpiState.mtime < oldAddon.updateDate) { if (xpiState.mtime < oldAddon.updateDate) {
XPIProvider.setTelemetry(oldAddon.id, "olderFile", { XPIProvider.setTelemetry(oldAddon.id, "olderFile", {
name: XPIProvider._mostRecentlyModifiedFile[id],
mtime: xpiState.mtime, mtime: xpiState.mtime,
oldtime: oldAddon.updateDate oldtime: oldAddon.updateDate
}); });
} else {
XPIProvider.setTelemetry(oldAddon.id, "modifiedFile",
XPIProvider._mostRecentlyModifiedFile[id]);
} }
} }
let wasDisabled = oldAddon.appDisabled; let wasDisabled = oldAddon.appDisabled;
let oldPath = oldAddon.path || descriptorToPath(oldAddon.descriptor);
// The add-on has changed if the modification time has changed, if // The add-on has changed if the modification time has changed, if
// we have an updated manifest for it, or if the schema version has // we have an updated manifest for it, or if the schema version has
@ -1542,8 +1980,8 @@ this.XPIDatabaseReconcile = {
(aUpdateCompatibility && (installLocation.name == KEY_APP_GLOBAL || (aUpdateCompatibility && (installLocation.name == KEY_APP_GLOBAL ||
installLocation.name == KEY_APP_SYSTEM_DEFAULTS))) { installLocation.name == KEY_APP_SYSTEM_DEFAULTS))) {
newAddon = this.updateMetadata(installLocation, oldAddon, xpiState, newAddon); newAddon = this.updateMetadata(installLocation, oldAddon, xpiState, newAddon);
} else if (oldPath != xpiState.path) { } else if (oldAddon.descriptor != xpiState.descriptor) {
newAddon = this.updatePath(installLocation, oldAddon, xpiState); newAddon = this.updateDescriptor(installLocation, oldAddon, xpiState);
} else if (aUpdateCompatibility || aSchemaChange) { } else if (aUpdateCompatibility || aSchemaChange) {
// Check compatility when the application version and/or schema // Check compatility when the application version and/or schema
// version has changed. A schema change also reloads metadata from // version has changed. A schema change also reloads metadata from
@ -1624,6 +2062,7 @@ this.XPIDatabaseReconcile = {
let previousVisible = this.getVisibleAddons(previousAddons); let previousVisible = this.getVisibleAddons(previousAddons);
let currentVisible = this.flattenByID(currentAddons, hideLocation); let currentVisible = this.flattenByID(currentAddons, hideLocation);
let sawActiveTheme = false; let sawActiveTheme = false;
XPIProvider.bootstrappedAddons = {};
// Pass over the new set of visible add-ons, record any changes that occured // Pass over the new set of visible add-ons, record any changes that occured
// during startup and call bootstrap install/uninstall scripts as necessary // during startup and call bootstrap install/uninstall scripts as necessary
@ -1634,7 +2073,7 @@ this.XPIDatabaseReconcile = {
if (currentAddon._installLocation.name != KEY_APP_GLOBAL) if (currentAddon._installLocation.name != KEY_APP_GLOBAL)
XPIProvider.allAppGlobal = false; XPIProvider.allAppGlobal = false;
let isActive = !currentAddon.disabled && !currentAddon.pendingUninstall; let isActive = !currentAddon.disabled;
let wasActive = previousAddon ? previousAddon.active : currentAddon.active let wasActive = previousAddon ? previousAddon.active : currentAddon.active
if (!previousAddon) { if (!previousAddon) {
@ -1649,7 +2088,7 @@ this.XPIDatabaseReconcile = {
if (currentAddon.type == "theme") if (currentAddon.type == "theme")
isActive = currentAddon.internalName == XPIProvider.currentSkin; isActive = currentAddon.internalName == XPIProvider.currentSkin;
else else
isActive = XPIDatabase.activeBundles.includes(currentAddon.path); isActive = XPIDatabase.activeBundles.indexOf(currentAddon.descriptor) != -1;
// If the add-on wasn't active and it isn't already disabled in some way // If the add-on wasn't active and it isn't already disabled in some way
// then it was probably either softDisabled or userDisabled // then it was probably either softDisabled or userDisabled
@ -1701,7 +2140,8 @@ this.XPIDatabaseReconcile = {
if (currentAddon.bootstrap) { if (currentAddon.bootstrap) {
// Visible bootstrapped add-ons need to have their install method called // Visible bootstrapped add-ons need to have their install method called
let file = currentAddon._sourceBundle.clone(); let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
file.persistentDescriptor = currentAddon._sourceBundle.persistentDescriptor;
XPIProvider.callBootstrapMethod(currentAddon, file, XPIProvider.callBootstrapMethod(currentAddon, file,
"install", installReason, "install", installReason,
{ oldVersion: previousAddon.version }); { oldVersion: previousAddon.version });
@ -1720,6 +2160,19 @@ this.XPIDatabaseReconcile = {
XPIDatabase.makeAddonVisible(currentAddon); XPIDatabase.makeAddonVisible(currentAddon);
currentAddon.active = isActive; currentAddon.active = isActive;
// Make sure the bootstrap information is up to date for this ID
if (currentAddon.bootstrap && currentAddon.active) {
XPIProvider.bootstrappedAddons[id] = {
version: currentAddon.version,
type: currentAddon.type,
descriptor: currentAddon._sourceBundle.persistentDescriptor,
multiprocessCompatible: currentAddon.multiprocessCompatible,
runInSafeMode: canRunInSafeMode(currentAddon),
dependencies: currentAddon.dependencies,
hasEmbeddedWebExtension: currentAddon.hasEmbeddedWebExtension,
};
}
if (currentAddon.active && currentAddon.internalName == XPIProvider.selectedSkin) if (currentAddon.active && currentAddon.internalName == XPIProvider.selectedSkin)
sawActiveTheme = true; sawActiveTheme = true;
} }
@ -1740,7 +2193,6 @@ this.XPIDatabaseReconcile = {
XPIProvider.unloadBootstrapScope(previousAddon.id); XPIProvider.unloadBootstrapScope(previousAddon.id);
} }
AddonManagerPrivate.addStartupChange(AddonManager.STARTUP_CHANGE_UNINSTALLED, id); AddonManagerPrivate.addStartupChange(AddonManager.STARTUP_CHANGE_UNINSTALLED, id);
XPIStates.removeAddon(previousAddon.location, id);
// Make sure to flush the cache when an old add-on has gone away // Make sure to flush the cache when an old add-on has gone away
flushChromeCaches(); flushChromeCaches();
@ -1771,6 +2223,8 @@ this.XPIDatabaseReconcile = {
} }
XPIStates.save(); XPIStates.save();
XPIProvider.persistBootstrappedAddons();
// Clear out any cached migration data. // Clear out any cached migration data.
XPIDatabase.migrateData = null; XPIDatabase.migrateData = null;
XPIDatabase.saveChanges(); XPIDatabase.saveChanges();

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

@ -14,7 +14,6 @@ TEST_DIRS += ['test']
XPIDL_SOURCES += [ XPIDL_SOURCES += [
'amIAddonManager.idl', 'amIAddonManager.idl',
'amIAddonManagerStartup.idl',
'amIAddonPathService.idl', 'amIAddonPathService.idl',
'amIWebInstallPrompt.idl', 'amIWebInstallPrompt.idl',
] ]
@ -45,14 +44,12 @@ JAR_MANIFESTS += ['jar.mn']
EXPORTS.mozilla += [ EXPORTS.mozilla += [
'AddonContentPolicy.h', 'AddonContentPolicy.h',
'AddonManagerStartup.h',
'AddonManagerWebAPI.h', 'AddonManagerWebAPI.h',
'AddonPathService.h', 'AddonPathService.h',
] ]
UNIFIED_SOURCES += [ UNIFIED_SOURCES += [
'AddonContentPolicy.cpp', 'AddonContentPolicy.cpp',
'AddonManagerStartup.cpp',
'AddonManagerWebAPI.cpp', 'AddonManagerWebAPI.cpp',
'AddonPathService.cpp', 'AddonPathService.cpp',
] ]

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

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

@ -0,0 +1,21 @@
<?xml version="1.0"?>
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
<Description about="urn:mozilla:install-manifest">
<em:id>bug594058@tests.mozilla.org</em:id>
<em:version>1.0</em:version>
<em:targetApplication>
<Description>
<em:id>xpcshell@tests.mozilla.org</em:id>
<em:minVersion>1</em:minVersion>
<em:maxVersion>2</em:maxVersion>
</Description>
</em:targetApplication>
<em:name>bug 594058</em:name>
<em:description>stat-based invalidation</em:description>
<em:unpack>true</em:unpack>
</Description>
</RDF>

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

@ -0,0 +1,125 @@
<?xml version="1.0"?>
<!-- This is a copy of extensions.rdf from Firefox 3.5 including four
test extensions. Addon1 was user enabled, addon2 was user disabled, addon3
was pending user disable at the next restart and addon4 was pending user
enable at the next restart. Additionally addon1 and 2 have had
compatibility updates applies to make them compatible with the app and
toolkit respectively, addon3 and 4 have not. addon5 is disabled however
at the same time as the migration a new version should be detected. addon6
is pending install and needs a compatibility update to be compatible.
It also contains two themes in the profile -->
<RDF:RDF xmlns:NS1="http://www.mozilla.org/2004/em-rdf#"
xmlns:NC="http://home.netscape.com/NC-rdf#"
xmlns:RDF="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<RDF:Description RDF:about="rdf:#$w8dNC3"
NS1:id="xpcshell@tests.mozilla.org"
NS1:minVersion="1"
NS1:maxVersion="1" />
<RDF:Description RDF:about="rdf:#$w8dNC4"
NS1:id="xpcshell@tests.mozilla.org"
NS1:minVersion="1"
NS1:maxVersion="2" />
<RDF:Description RDF:about="rdf:#$w8dNC5"
NS1:id="xpcshell@tests.mozilla.org"
NS1:minVersion="1"
NS1:maxVersion="2" />
<RDF:Description RDF:about="rdf:#$w8dNC6"
NS1:id="xpcshell@tests.mozilla.org"
NS1:minVersion="1"
NS1:maxVersion="2" />
<RDF:Description RDF:about="rdf:#$w8dNC2"
NS1:id="toolkit@mozilla.org"
NS1:minVersion="1"
NS1:maxVersion="1" />
<RDF:Description RDF:about="rdf:#$w8dNC1"
NS1:id="toolkit@mozilla.org"
NS1:minVersion="1"
NS1:maxVersion="2" />
<RDF:Description RDF:about="rdf:#$w8dNC7"
NS1:id="toolkit@mozilla.org"
NS1:minVersion="1"
NS1:maxVersion="2" />
<RDF:Description RDF:about="rdf:#$oadNC1"
NS1:id="xpcshell@tests.mozilla.org"
NS1:minVersion="1"
NS1:maxVersion="2" />
<RDF:Description RDF:about="rdf:#$TpnM4"
NS1:id="xpcshell@tests.mozilla.org"
NS1:updatedMinVersion="1"
NS1:updatedMaxVersion="2" />
<RDF:Description RDF:about="urn:mozilla:item:addon1@tests.mozilla.org"
NS1:installLocation="app-profile"
NS1:version="1.0"
NS1:name="Test 1">
<NS1:type NC:parseType="Integer">2</NS1:type>
<NS1:targetApplication RDF:resource="rdf:#$oadNC1"/>
</RDF:Description>
<RDF:Description RDF:about="urn:mozilla:item:addon2@tests.mozilla.org"
NS1:installLocation="app-profile"
NS1:version="2.0"
NS1:name="Test 2"
NS1:userDisabled="true">
<NS1:type NC:parseType="Integer">2</NS1:type>
<NS1:targetApplication RDF:resource="rdf:#$w8dNC1"/>
</RDF:Description>
<RDF:Description RDF:about="urn:mozilla:item:addon3@tests.mozilla.org"
NS1:installLocation="app-profile"
NS1:version="2.0"
NS1:name="Test 3"
NS1:userDisabled="needs-disable">
<NS1:type NC:parseType="Integer">2</NS1:type>
<NS1:targetApplication RDF:resource="rdf:#$w8dNC3"/>
</RDF:Description>
<RDF:Description RDF:about="urn:mozilla:item:addon4@tests.mozilla.org"
NS1:installLocation="app-profile"
NS1:version="2.0"
NS1:name="Test 4"
NS1:userDisabled="needs-enable">
<NS1:type NC:parseType="Integer">2</NS1:type>
<NS1:targetApplication RDF:resource="rdf:#$w8dNC2"/>
</RDF:Description>
<RDF:Description RDF:about="urn:mozilla:item:addon5@tests.mozilla.org"
NS1:installLocation="app-profile"
NS1:version="1.0"
NS1:name="Test 5"
NS1:userDisabled="true">
<NS1:type NC:parseType="Integer">2</NS1:type>
<NS1:targetApplication RDF:resource="rdf:#$w8dNC7"/>
</RDF:Description>
<RDF:Description RDF:about="urn:mozilla:item:addon6@tests.mozilla.org"
NS1:name="Test 6"
NS1:version="1.0"
NS1:newVersion="1.0"
NS1:installLocation="app-profile">
<NS1:type NC:parseType="Integer">2</NS1:type>
<NS1:targetApplication RDF:resource="rdf:#$TpnM4"/>
</RDF:Description>
<RDF:Description RDF:about="urn:mozilla:item:theme1@tests.mozilla.org"
NS1:installLocation="app-profile"
NS1:version="1.0"
NS1:name="Theme 2"
NS1:internalName="theme1/1.0">
<NS1:type NC:parseType="Integer">4</NS1:type>
<NS1:targetApplication RDF:resource="rdf:#$w8dNC5"/>
</RDF:Description>
<RDF:Description RDF:about="urn:mozilla:item:theme2@tests.mozilla.org"
NS1:installLocation="app-profile"
NS1:version="2.0"
NS1:name="Theme 2"
NS1:internalName="theme2/1.0">
<NS1:type NC:parseType="Integer">4</NS1:type>
<NS1:targetApplication RDF:resource="rdf:#$w8dNC6"/>
</RDF:Description>
<RDF:Seq RDF:about="urn:mozilla:item:root">
<RDF:li RDF:resource="urn:mozilla:item:addon1@tests.mozilla.org"/>
<RDF:li RDF:resource="urn:mozilla:item:addon2@tests.mozilla.org"/>
<RDF:li RDF:resource="urn:mozilla:item:addon3@tests.mozilla.org"/>
<RDF:li RDF:resource="urn:mozilla:item:addon4@tests.mozilla.org"/>
<RDF:li RDF:resource="urn:mozilla:item:addon5@tests.mozilla.org"/>
<RDF:li RDF:resource="urn:mozilla:item:addon6@tests.mozilla.org"/>
<RDF:li RDF:resource="urn:mozilla:item:theme1@tests.mozilla.org"/>
<RDF:li RDF:resource="urn:mozilla:item:theme2@tests.mozilla.org"/>
</RDF:Seq>
</RDF:RDF>

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

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8"?>
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
<Description about="urn:mozilla:extension:addon5@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</em:minVersion>
<em:maxVersion>2</em:maxVersion>
</Description>
</em:targetApplication>
</Description>
</li>
</Seq>
</em:updates>
</Description>
<Description about="urn:mozilla:extension:addon6@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</em:minVersion>
<em:maxVersion>2</em:maxVersion>
<em:updateLink>http://localhost:%PORT%/addons/test_migrate4_6.xpi</em:updateLink>
<em:updateInfoURL>http://example.com/updateInfo.xhtml</em:updateInfoURL>
</Description>
</em:targetApplication>
</Description>
</li>
</Seq>
</em:updates>
</Description>
</RDF>

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

@ -64,10 +64,6 @@ XPCOMUtils.defineLazyModuleGetter(this, "MockRegistrar",
XPCOMUtils.defineLazyModuleGetter(this, "MockRegistry", XPCOMUtils.defineLazyModuleGetter(this, "MockRegistry",
"resource://testing-common/MockRegistry.jsm"); "resource://testing-common/MockRegistry.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "aomStartup",
"@mozilla.org/addons/addon-manager-startup;1",
"amIAddonManagerStartup");
const { const {
awaitPromise, awaitPromise,
createAppInfo, createAppInfo,
@ -75,6 +71,7 @@ const {
createTempWebExtensionFile, createTempWebExtensionFile,
createUpdateRDF, createUpdateRDF,
getFileForAddon, getFileForAddon,
manuallyInstall,
manuallyUninstall, manuallyUninstall,
promiseAddonEvent, promiseAddonEvent,
promiseCompleteAllInstalls, promiseCompleteAllInstalls,
@ -93,11 +90,6 @@ const {
writeFilesToZip writeFilesToZip
} = AddonTestUtils; } = AddonTestUtils;
function manuallyInstall(...args) {
return AddonTestUtils.awaitPromise(
AddonTestUtils.manuallyInstall(...args));
}
// WebExtension wrapper for ease of testing // WebExtension wrapper for ease of testing
ExtensionTestUtils.init(this); ExtensionTestUtils.init(this);
@ -110,9 +102,9 @@ Object.defineProperty(this, "gAppInfo", {
}, },
}); });
Object.defineProperty(this, "gAddonStartup", { Object.defineProperty(this, "gExtensionsINI", {
get() { get() {
return AddonTestUtils.addonStartup.clone(); return AddonTestUtils.extensionsINI.clone();
}, },
}); });
@ -208,8 +200,6 @@ this.BootstrapMonitor = {
startupPromises: [], startupPromises: [],
installPromises: [], installPromises: [],
restartfulIds: new Set(),
init() { init() {
this.inited = true; this.inited = true;
Services.obs.addObserver(this, "bootstrapmonitor-event"); Services.obs.addObserver(this, "bootstrapmonitor-event");
@ -326,13 +316,9 @@ this.BootstrapMonitor = {
} }
if (info.event == "uninstall") { if (info.event == "uninstall") {
// We currently support registering, but not unregistering, // Chrome should be unregistered at this point
// restartful add-on manifests during xpcshell AOM "restarts". let isRegistered = isManifestRegistered(installPath);
if (!this.restartfulIds.has(id)) { do_check_false(isRegistered);
// Chrome should be unregistered at this point
let isRegistered = isManifestRegistered(installPath);
do_check_false(isRegistered);
}
this.installed.delete(id); this.installed.delete(id);
this.uninstalled.set(id, info) this.uninstalled.set(id, info)
@ -377,7 +363,8 @@ function do_check_in_crash_annotation(aId, aVersion) {
} }
let addons = gAppInfo.annotations["Add-ons"].split(","); let addons = gAppInfo.annotations["Add-ons"].split(",");
do_check_true(addons.includes(`${encodeURIComponent(aId)}:${encodeURIComponent(aVersion)}`)); do_check_false(addons.indexOf(encodeURIComponent(aId) + ":" +
encodeURIComponent(aVersion)) < 0);
} }
/** /**
@ -399,7 +386,8 @@ function do_check_not_in_crash_annotation(aId, aVersion) {
} }
let addons = gAppInfo.annotations["Add-ons"].split(","); let addons = gAppInfo.annotations["Add-ons"].split(",");
do_check_false(addons.includes(`${encodeURIComponent(aId)}:${encodeURIComponent(aVersion)}`)); do_check_true(addons.indexOf(encodeURIComponent(aId) + ":" +
encodeURIComponent(aVersion)) < 0);
} }
/** /**

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

@ -104,12 +104,6 @@ function getXS() {
return XPI.XPIStates; return XPI.XPIStates;
} }
async function getXSJSON() {
await AddonTestUtils.loadAddonsList(true);
return aomStartup.readStartupData();
}
add_task(function* detect_touches() { add_task(function* detect_touches() {
startupManager(); startupManager();
let [/* pe */, pd, /* ue */, ud] = yield promiseAddonsByIDs([ let [/* pe */, pd, /* ue */, ud] = yield promiseAddonsByIDs([
@ -154,6 +148,10 @@ add_task(function* detect_touches() {
let manifest = ueDir.clone(); let manifest = ueDir.clone();
manifest.append("install.rdf"); manifest.append("install.rdf");
checkChange(XS, manifest, true); checkChange(XS, manifest, true);
// We also notice changing another file for enabled unpacked add-on.
let otherFile = ueDir.clone();
otherFile.append("extraFile.js");
checkChange(XS, otherFile, true);
// We notice changing install.rdf for a *disabled* unpacked add-on. // We notice changing install.rdf for a *disabled* unpacked add-on.
let udDir = profileDir.clone(); let udDir = profileDir.clone();
@ -163,7 +161,7 @@ add_task(function* detect_touches() {
checkChange(XS, manifest, true); checkChange(XS, manifest, true);
// Finally, the case we actually care about... // Finally, the case we actually care about...
// We *don't* notice changing another file for disabled unpacked add-on. // We *don't* notice changing another file for disabled unpacked add-on.
let otherFile = udDir.clone(); otherFile = udDir.clone();
otherFile.append("extraFile.js"); otherFile.append("extraFile.js");
checkChange(XS, otherFile, false); checkChange(XS, otherFile, false);
@ -175,7 +173,7 @@ add_task(function* detect_touches() {
ud.userDisabled = false; ud.userDisabled = false;
let xState = XS.getAddon("app-profile", ud.id); let xState = XS.getAddon("app-profile", ud.id);
do_check_true(xState.enabled); do_check_true(xState.enabled);
do_check_eq(xState.mtime, ud.updateDate.getTime()); do_check_eq(xState.scanTime, ud.updateDate.getTime());
}); });
/* /*
@ -190,9 +188,8 @@ add_task(function* uninstall_bootstrap() {
"unpacked-disabled@tests.mozilla.org" "unpacked-disabled@tests.mozilla.org"
]); ]);
pe.uninstall(); pe.uninstall();
let xpiState = Services.prefs.getCharPref("extensions.xpiState");
let xpiState = yield getXSJSON(); do_check_false(xpiState.includes("\"packed-enabled@tests.mozilla.org\""));
do_check_false("packed-enabled@tests.mozilla.org" in xpiState["app-profile"].addons);
}); });
/* /*
@ -208,7 +205,7 @@ add_task(function* install_bootstrap() {
let xState = XS.getAddon("app-profile", newAddon.id); let xState = XS.getAddon("app-profile", newAddon.id);
do_check_true(!!xState); do_check_true(!!xState);
do_check_true(xState.enabled); do_check_true(xState.enabled);
do_check_eq(xState.mtime, newAddon.updateDate.getTime()); do_check_eq(xState.scanTime, newAddon.updateDate.getTime());
newAddon.uninstall(); newAddon.uninstall();
}); });
@ -241,7 +238,7 @@ add_task(function* install_restart() {
xState = XS.getAddon("app-profile", newID); xState = XS.getAddon("app-profile", newID);
do_check_true(xState); do_check_true(xState);
do_check_true(xState.enabled); do_check_true(xState.enabled);
do_check_eq(xState.mtime, newAddon.updateDate.getTime()); do_check_eq(xState.scanTime, newAddon.updateDate.getTime());
// Check that XPIState enabled flag is updated immediately, // Check that XPIState enabled flag is updated immediately,
// and doesn't change over restart. // and doesn't change over restart.

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

@ -81,12 +81,8 @@ function getUninstallNewVersion() {
} }
function do_check_bootstrappedPref(aCallback) { function do_check_bootstrappedPref(aCallback) {
let XPIScope = AM_Cu.import("resource://gre/modules/addons/XPIProvider.jsm", {}); let data = Services.prefs.getCharPref("extensions.bootstrappedAddons");
data = JSON.parse(data);
let data = {};
for (let entry of XPIScope.XPIStates.bootstrappedAddons()) {
data[entry.id] = entry;
}
AddonManager.getAddonsByTypes(["extension"], function(aAddons) { AddonManager.getAddonsByTypes(["extension"], function(aAddons) {
for (let addon of aAddons) { for (let addon of aAddons) {
@ -104,7 +100,7 @@ function do_check_bootstrappedPref(aCallback) {
do_check_eq(addonData.version, addon.version); do_check_eq(addonData.version, addon.version);
do_check_eq(addonData.type, addon.type); do_check_eq(addonData.type, addon.type);
let file = addon.getResourceURI().QueryInterface(Components.interfaces.nsIFileURL).file; let file = addon.getResourceURI().QueryInterface(Components.interfaces.nsIFileURL).file;
do_check_eq(addonData.path, file.path); do_check_eq(addonData.descriptor, file.persistentDescriptor);
} }
do_check_eq(Object.keys(data).length, 0); do_check_eq(Object.keys(data).length, 0);
@ -120,7 +116,7 @@ function run_test() {
do_check_false(gExtensionsJSON.exists()); do_check_false(gExtensionsJSON.exists());
do_check_false(gAddonStartup.exists()); do_check_false(gExtensionsINI.exists());
run_test_1(); run_test_1();
} }
@ -174,6 +170,8 @@ function run_test_1() {
} }
function check_test_1(installSyncGUID) { function check_test_1(installSyncGUID) {
do_check_false(gExtensionsINI.exists());
AddonManager.getAllInstalls(function(installs) { AddonManager.getAllInstalls(function(installs) {
// There should be no active installs now since the install completed and // There should be no active installs now since the install completed and
// doesn't require a restart. // doesn't require a restart.
@ -261,7 +259,7 @@ function run_test_3() {
do_check_eq(getShutdownNewVersion(), undefined); do_check_eq(getShutdownNewVersion(), undefined);
do_check_not_in_crash_annotation(ID1, "1.0"); do_check_not_in_crash_annotation(ID1, "1.0");
do_check_true(gAddonStartup.exists()); do_check_false(gExtensionsINI.exists());
AddonManager.getAddonByID(ID1, function(b1) { AddonManager.getAddonByID(ID1, function(b1) {
do_check_neq(b1, null); do_check_neq(b1, null);
@ -1055,8 +1053,6 @@ function run_test_22() {
let file = manuallyInstall(do_get_addon("test_bootstrap1_1"), profileDir, let file = manuallyInstall(do_get_addon("test_bootstrap1_1"), profileDir,
ID1); ID1);
if (file.isDirectory())
file.append("install.rdf");
// Make it look old so changes are detected // Make it look old so changes are detected
setExtensionModifiedTime(file, file.lastModifiedTime - 5000); setExtensionModifiedTime(file, file.lastModifiedTime - 5000);
@ -1206,7 +1202,7 @@ function run_test_24() {
Promise.all([BootstrapMonitor.promiseAddonStartup(ID2), Promise.all([BootstrapMonitor.promiseAddonStartup(ID2),
promiseInstallAllFiles([do_get_addon("test_bootstrap1_1"), do_get_addon("test_bootstrap2_1")])]) promiseInstallAllFiles([do_get_addon("test_bootstrap1_1"), do_get_addon("test_bootstrap2_1")])])
.then(async function test_24_pref() { .then(function test_24_pref() {
do_print("test 24 got prefs"); do_print("test 24 got prefs");
BootstrapMonitor.checkAddonInstalled(ID1, "1.0"); BootstrapMonitor.checkAddonInstalled(ID1, "1.0");
BootstrapMonitor.checkAddonStarted(ID1, "1.0"); BootstrapMonitor.checkAddonStarted(ID1, "1.0");
@ -1227,13 +1223,10 @@ function run_test_24() {
BootstrapMonitor.checkAddonInstalled(ID2, "1.0"); BootstrapMonitor.checkAddonInstalled(ID2, "1.0");
BootstrapMonitor.checkAddonNotStarted(ID2); BootstrapMonitor.checkAddonNotStarted(ID2);
// Break the JSON. // Break the preference
let data = aomStartup.readStartupData(); let bootstrappedAddons = JSON.parse(Services.prefs.getCharPref("extensions.bootstrappedAddons"));
data["app-profile"].addons[ID1].path += "foo"; bootstrappedAddons[ID1].descriptor += "foo";
Services.prefs.setCharPref("extensions.bootstrappedAddons", JSON.stringify(bootstrappedAddons));
await OS.File.writeAtomic(gAddonStartup.path,
new TextEncoder().encode(JSON.stringify(data)),
{compression: "lz4"});
startupManager(false); startupManager(false);
@ -1337,8 +1330,6 @@ function run_test_27() {
BootstrapMonitor.checkAddonInstalled(ID1, "1.0"); BootstrapMonitor.checkAddonInstalled(ID1, "1.0");
BootstrapMonitor.checkAddonNotStarted(ID1); BootstrapMonitor.checkAddonNotStarted(ID1);
BootstrapMonitor.restartfulIds.add(ID1);
installAllFiles([do_get_addon("test_bootstrap1_4")], function() { installAllFiles([do_get_addon("test_bootstrap1_4")], function() {
// Updating disabled things happens immediately // Updating disabled things happens immediately
BootstrapMonitor.checkAddonNotInstalled(ID1); BootstrapMonitor.checkAddonNotInstalled(ID1);

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

@ -9,7 +9,7 @@ const PREF_GENERAL_SKINS_SELECTEDSKIN = "general.skins.selectedSkin";
const profileDir = gProfD.clone(); const profileDir = gProfD.clone();
profileDir.append("extensions"); profileDir.append("extensions");
async function run_test() { function run_test() {
do_test_pending(); do_test_pending();
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2"); createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2");
@ -38,7 +38,7 @@ async function run_test() {
}] }]
}, profileDir); }, profileDir);
await promiseStartupManager(); startupManager();
do_check_eq(Services.prefs.getCharPref(PREF_GENERAL_SKINS_SELECTEDSKIN), "classic/1.0"); do_check_eq(Services.prefs.getCharPref(PREF_GENERAL_SKINS_SELECTEDSKIN), "classic/1.0");

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

@ -8,7 +8,7 @@
const profileDir = gProfD.clone(); const profileDir = gProfD.clone();
profileDir.append("extensions"); profileDir.append("extensions");
async function run_test() { function run_test() {
do_test_pending(); do_test_pending();
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "2", "1.9.2"); createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "2", "1.9.2");
@ -26,9 +26,9 @@ async function run_test() {
// the update makes the last modified time change. // the update makes the last modified time change.
setExtensionModifiedTime(dest, dest.lastModifiedTime - 5000); setExtensionModifiedTime(dest, dest.lastModifiedTime - 5000);
await promiseStartupManager(); startupManager();
AddonManager.getAddonByID("addon1@tests.mozilla.org", callback_soon(async function(a) { AddonManager.getAddonByID("addon1@tests.mozilla.org", callback_soon(function(a) {
do_check_neq(a, null); do_check_neq(a, null);
do_check_eq(a.version, "1.0"); do_check_eq(a.version, "1.0");
do_check_false(a.userDisabled); do_check_false(a.userDisabled);
@ -47,7 +47,7 @@ async function run_test() {
}] }]
}, profileDir); }, profileDir);
await promiseRestartManager(); restartManager();
AddonManager.getAddonByID("addon1@tests.mozilla.org", function(a2) { AddonManager.getAddonByID("addon1@tests.mozilla.org", function(a2) {
do_check_neq(a2, null); do_check_neq(a2, null);

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

@ -123,10 +123,10 @@ function run_test_1() {
function run_test_2() { function run_test_2() {
restartManager(); restartManager();
installAllFiles([do_get_addon("test_bug587088_1")], async function() { installAllFiles([do_get_addon("test_bug587088_1")], function() {
await promiseRestartManager(); restartManager();
AddonManager.getAddonByID("addon1@tests.mozilla.org", callback_soon(async function(a1) { AddonManager.getAddonByID("addon1@tests.mozilla.org", callback_soon(function(a1) {
check_addon(a1, "1.0"); check_addon(a1, "1.0");
// Lock either install.rdf for unpacked add-ons or the xpi for packed add-ons. // Lock either install.rdf for unpacked add-ons or the xpi for packed add-ons.
@ -142,19 +142,19 @@ function run_test_2() {
check_addon_uninstalling(a1); check_addon_uninstalling(a1);
await promiseRestartManager(); restartManager();
AddonManager.getAddonByID("addon1@tests.mozilla.org", callback_soon(async function(a1_2) { AddonManager.getAddonByID("addon1@tests.mozilla.org", callback_soon(function(a1_2) {
check_addon_uninstalling(a1_2, true); check_addon_uninstalling(a1_2, true);
await promiseRestartManager(); restartManager();
AddonManager.getAddonByID("addon1@tests.mozilla.org", callback_soon(async function(a1_3) { AddonManager.getAddonByID("addon1@tests.mozilla.org", callback_soon(function(a1_3) {
check_addon_uninstalling(a1_3, true); check_addon_uninstalling(a1_3, true);
fstream.close(); fstream.close();
await promiseRestartManager(); restartManager();
AddonManager.getAddonByID("addon1@tests.mozilla.org", function(a1_4) { AddonManager.getAddonByID("addon1@tests.mozilla.org", function(a1_4) {
do_check_eq(a1_4, null); do_check_eq(a1_4, null);

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

@ -0,0 +1,88 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
// This tests is modifying a file in an unpacked extension
// causes cache invalidation.
// Disables security checking our updates which haven't been signed
Services.prefs.setBoolPref("extensions.checkUpdateSecurity", false);
// Allow the mismatch UI to show
Services.prefs.setBoolPref("extensions.showMismatchUI", true);
Components.utils.import("resource://testing-common/MockRegistrar.jsm");
var Ci = Components.interfaces;
const extDir = gProfD.clone();
extDir.append("extensions");
var gCachePurged = false;
// Override the window watcher
var WindowWatcher = {
openWindow(parent, url, name, features, args) {
do_check_false(gCachePurged);
},
QueryInterface(iid) {
if (iid.equals(Ci.nsIWindowWatcher)
|| iid.equals(Ci.nsISupports))
return this;
throw Components.results.NS_ERROR_NO_INTERFACE;
}
}
MockRegistrar.register("@mozilla.org/embedcomp/window-watcher;1", WindowWatcher);
/**
* Start the test by installing extensions.
*/
function run_test() {
do_test_pending();
gCachePurged = false;
let obs = AM_Cc["@mozilla.org/observer-service;1"].
getService(AM_Ci.nsIObserverService);
obs.addObserver({
observe(aSubject, aTopic, aData) {
gCachePurged = true;
}
}, "startupcache-invalidate");
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1");
startupManager();
// nsAppRunner takes care of clearing this when a new app is installed
do_check_false(gCachePurged);
installAllFiles([do_get_addon("test_bug594058")], function() {
restartManager();
do_check_true(gCachePurged);
gCachePurged = false;
// Now, make it look like we've updated the file. First, start the EM
// so it records the bogus old time, then update the file and restart.
let extFile = extDir.clone();
let pastTime = extFile.lastModifiedTime - 5000;
extFile.append("bug594058@tests.mozilla.org");
setExtensionModifiedTime(extFile, pastTime);
let otherFile = extFile.clone();
otherFile.append("directory");
otherFile.lastModifiedTime = pastTime;
otherFile.append("file1");
otherFile.lastModifiedTime = pastTime;
restartManager();
gCachePurged = false;
otherFile.lastModifiedTime = pastTime + 5000;
restartManager();
do_check_true(gCachePurged);
gCachePurged = false;
restartManager();
do_check_false(gCachePurged);
do_test_finished();
});
}

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

@ -16,8 +16,8 @@ function run_test() {
} }
function run_test_1() { function run_test_1() {
installAllFiles([do_get_addon("test_bug595573")], async function() { installAllFiles([do_get_addon("test_bug595573")], function() {
await promiseRestartManager(); restartManager();
AddonManager.getAddonByID("{2f69dacd-03df-4150-a9f1-e8a7b2748829}", function(a1) { AddonManager.getAddonByID("{2f69dacd-03df-4150-a9f1-e8a7b2748829}", function(a1) {
do_check_neq(a1, null); do_check_neq(a1, null);

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

@ -58,14 +58,14 @@ function end_test() {
testserver.stop(do_test_finished); testserver.stop(do_test_finished);
} }
async function run_test_1() { function run_test_1() {
var time = Date.now(); var time = Date.now();
var dir = writeInstallRDFForExtension(addon1, userDir); var dir = writeInstallRDFForExtension(addon1, userDir);
setExtensionModifiedTime(dir, time); setExtensionModifiedTime(dir, time);
manuallyInstall(do_get_addon("test_bug655254_2"), userDir, "addon2@tests.mozilla.org"); manuallyInstall(do_get_addon("test_bug655254_2"), userDir, "addon2@tests.mozilla.org");
await promiseStartupManager(); startupManager();
AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org", AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",
"addon2@tests.mozilla.org"], function([a1, a2]) { "addon2@tests.mozilla.org"], function([a1, a2]) {
@ -81,10 +81,10 @@ async function run_test_1() {
do_check_eq(Services.prefs.getIntPref("bootstraptest.active_version"), 1); do_check_eq(Services.prefs.getIntPref("bootstraptest.active_version"), 1);
a1.findUpdates({ a1.findUpdates({
async onUpdateFinished() { onUpdateFinished() {
await promiseRestartManager(); restartManager();
AddonManager.getAddonByID("addon1@tests.mozilla.org", callback_soon(async function(a1_2) { AddonManager.getAddonByID("addon1@tests.mozilla.org", callback_soon(function(a1_2) {
do_check_neq(a1_2, null); do_check_neq(a1_2, null);
do_check_false(a1_2.appDisabled); do_check_false(a1_2.appDisabled);
do_check_true(a1_2.isActive); do_check_true(a1_2.isActive);
@ -100,7 +100,7 @@ async function run_test_1() {
userDir.append(gAppInfo.ID); userDir.append(gAppInfo.ID);
do_check_true(userDir.exists()); do_check_true(userDir.exists());
await promiseStartupManager(false); startupManager(false);
AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org", AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",
"addon2@tests.mozilla.org"], function([a1_3, a2_3]) { "addon2@tests.mozilla.org"], function([a1_3, a2_3]) {
@ -125,7 +125,7 @@ async function run_test_1() {
// Set up the profile // Set up the profile
function run_test_2() { function run_test_2() {
AddonManager.getAddonByID("addon2@tests.mozilla.org", callback_soon(async function(a2) { AddonManager.getAddonByID("addon2@tests.mozilla.org", callback_soon(function(a2) {
do_check_neq(a2, null); do_check_neq(a2, null);
do_check_false(a2.appDisabled); do_check_false(a2.appDisabled);
do_check_true(a2.isActive); do_check_true(a2.isActive);
@ -143,7 +143,7 @@ function run_test_2() {
userDir.append(gAppInfo.ID); userDir.append(gAppInfo.ID);
do_check_true(userDir.exists()); do_check_true(userDir.exists());
await promiseStartupManager(false); startupManager(false);
AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org", AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",
"addon2@tests.mozilla.org"], function([a1_2, a2_2]) { "addon2@tests.mozilla.org"], function([a1_2, a2_2]) {

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

@ -59,13 +59,13 @@ function run_test() {
} }
// Tests whether a schema migration without app version change works // Tests whether a schema migration without app version change works
async function run_test_1() { function run_test_1() {
writeInstallRDFForExtension(addon1, profileDir); writeInstallRDFForExtension(addon1, profileDir);
writeInstallRDFForExtension(addon2, profileDir); writeInstallRDFForExtension(addon2, profileDir);
writeInstallRDFForExtension(addon3, profileDir); writeInstallRDFForExtension(addon3, profileDir);
writeInstallRDFForExtension(addon4, profileDir); writeInstallRDFForExtension(addon4, profileDir);
await promiseStartupManager(); startupManager();
AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org", AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",
"addon2@tests.mozilla.org", "addon2@tests.mozilla.org",
@ -104,7 +104,7 @@ async function run_test_1() {
installAllFiles([ installAllFiles([
do_get_addon("test_bug659772"), do_get_addon("test_bug659772"),
do_get_addon("test_bootstrap1_1") do_get_addon("test_bootstrap1_1")
], async function() { ], function() {
shutdownManager(); shutdownManager();
// Make it look like the next time the app is started it has a new DB schema // Make it look like the next time the app is started it has a new DB schema
@ -142,7 +142,7 @@ async function run_test_1() {
Services.prefs.clearUserPref("bootstraptest.install_reason"); Services.prefs.clearUserPref("bootstraptest.install_reason");
Services.prefs.clearUserPref("bootstraptest.uninstall_reason"); Services.prefs.clearUserPref("bootstraptest.uninstall_reason");
await promiseStartupManager(false); startupManager(false);
AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org", AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",
"addon2@tests.mozilla.org", "addon2@tests.mozilla.org",
@ -194,7 +194,7 @@ async function run_test_1() {
} }
// Tests whether a schema migration with app version change works // Tests whether a schema migration with app version change works
async function run_test_2() { function run_test_2() {
restartManager(); restartManager();
shutdownManager(); shutdownManager();
@ -204,7 +204,7 @@ async function run_test_2() {
writeInstallRDFForExtension(addon3, profileDir); writeInstallRDFForExtension(addon3, profileDir);
writeInstallRDFForExtension(addon4, profileDir); writeInstallRDFForExtension(addon4, profileDir);
await promiseStartupManager(); startupManager();
AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org", AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",
"addon2@tests.mozilla.org", "addon2@tests.mozilla.org",
@ -245,7 +245,7 @@ async function run_test_2() {
do_get_addon("test_bootstrap1_1") do_get_addon("test_bootstrap1_1")
], function() { do_execute_soon(prepare_schema_migrate); }); ], function() { do_execute_soon(prepare_schema_migrate); });
async function prepare_schema_migrate() { function prepare_schema_migrate() {
shutdownManager(); shutdownManager();
// Make it look like the next time the app is started it has a new DB schema // Make it look like the next time the app is started it has a new DB schema
@ -284,7 +284,7 @@ async function run_test_2() {
Services.prefs.clearUserPref("bootstraptest.uninstall_reason"); Services.prefs.clearUserPref("bootstraptest.uninstall_reason");
gAppInfo.version = "2"; gAppInfo.version = "2";
await promiseStartupManager(true); startupManager(true);
AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org", AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",
"addon2@tests.mozilla.org", "addon2@tests.mozilla.org",

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

@ -4,10 +4,10 @@
// Tests the extensions.defaultProviders.enabled pref which turns // Tests the extensions.defaultProviders.enabled pref which turns
// off the default XPIProvider and LightweightThemeManager. // off the default XPIProvider and LightweightThemeManager.
async function run_test() { function run_test() {
Services.prefs.setBoolPref("extensions.defaultProviders.enabled", false); Services.prefs.setBoolPref("extensions.defaultProviders.enabled", false);
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2"); createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2");
await promiseStartupManager(); startupManager();
do_check_false(AddonManager.isInstallEnabled("application/x-xpinstall")); do_check_false(AddonManager.isInstallEnabled("application/x-xpinstall"));
Services.prefs.clearUserPref("extensions.defaultProviders.enabled"); Services.prefs.clearUserPref("extensions.defaultProviders.enabled");
} }

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

@ -32,14 +32,14 @@ function run_test() {
startupManager(); startupManager();
AddonManager.getAddonByID("addon1@tests.mozilla.org", callback_soon(async function(a1) { AddonManager.getAddonByID("addon1@tests.mozilla.org", callback_soon(function(a1) {
do_check_eq(a1, null); do_check_eq(a1, null);
do_check_not_in_crash_annotation(addon1.id, addon1.version); do_check_not_in_crash_annotation(addon1.id, addon1.version);
writeInstallRDFForExtension(addon1, profileDir, addon1.id, "icon.png"); writeInstallRDFForExtension(addon1, profileDir, addon1.id, "icon.png");
gIconURL = do_get_addon_root_uri(profileDir.clone(), addon1.id) + "icon.png"; gIconURL = do_get_addon_root_uri(profileDir.clone(), addon1.id) + "icon.png";
await promiseRestartManager(); restartManager();
AddonManager.getAddonByID("addon1@tests.mozilla.org", function(newa1) { AddonManager.getAddonByID("addon1@tests.mozilla.org", function(newa1) {
do_check_neq(newa1, null); do_check_neq(newa1, null);

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

@ -1,23 +1,12 @@
/* Any copyright is dedicated to the Public Domain. /* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */ * http://creativecommons.org/publicdomain/zero/1.0/ */
var scope = Components.utils.import("resource://gre/modules/addons/XPIProvider.jsm", {});
const XPIProvider = scope.XPIProvider;
const ID = "experiment1@tests.mozilla.org"; const ID = "experiment1@tests.mozilla.org";
var gIsNightly = false; var gIsNightly = false;
function getXS() {
let XPI = Components.utils.import("resource://gre/modules/addons/XPIProvider.jsm", {});
return XPI.XPIStates;
}
function getBootstrappedAddons() {
let obj = {}
for (let addon of getXS().bootstrappedAddons()) {
obj[addon.id] = addon;
}
return obj;
}
function run_test() { function run_test() {
BootstrapMonitor.init(); BootstrapMonitor.init();
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2"); createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2");
@ -91,7 +80,7 @@ add_task(function* test_userDisabledNotPersisted() {
Assert.equal(addon2.userDisabled, false, "Add-on is no longer user disabled."); Assert.equal(addon2.userDisabled, false, "Add-on is no longer user disabled.");
Assert.ok(addon2.isActive, "Add-on is active."); Assert.ok(addon2.isActive, "Add-on is active.");
Assert.ok(ID in getBootstrappedAddons(), Assert.ok(ID in XPIProvider.bootstrappedAddons,
"Experiment add-on listed in XPIProvider bootstrapped list."); "Experiment add-on listed in XPIProvider bootstrapped list.");
addon = yield promiseAddonByID(ID); addon = yield promiseAddonByID(ID);
@ -105,8 +94,8 @@ add_task(function* test_userDisabledNotPersisted() {
// Now when we restart the manager the add-on should revert state. // Now when we restart the manager the add-on should revert state.
yield promiseRestartManager(); yield promiseRestartManager();
let persisted = JSON.parse(Services.prefs.getCharPref("extensions.bootstrappedAddons"));
Assert.ok(!(ID in getBootstrappedAddons()), Assert.ok(!(ID in persisted),
"Experiment add-on not persisted to bootstrappedAddons."); "Experiment add-on not persisted to bootstrappedAddons.");
BootstrapMonitor.checkAddonInstalled(ID, "1.0"); BootstrapMonitor.checkAddonInstalled(ID, "1.0");

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

@ -18,16 +18,16 @@ function run_test() {
do_get_addon("test_chromemanifest_3"), do_get_addon("test_chromemanifest_3"),
do_get_addon("test_chromemanifest_4"), do_get_addon("test_chromemanifest_4"),
do_get_addon("test_chromemanifest_5")], do_get_addon("test_chromemanifest_5")],
async function() { function() {
await promiseRestartManager(); restartManager();
AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org", AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",
"addon2@tests.mozilla.org", "addon2@tests.mozilla.org",
"addon3@tests.mozilla.org", "addon3@tests.mozilla.org",
"addon4@tests.mozilla.org", "addon4@tests.mozilla.org",
"addon5@tests.mozilla.org"], "addon5@tests.mozilla.org"],
async function([a1, a2, a3, a4, a5]) { function([a1, a2, a3, a4, a5]) {
// addon1 has no binary components // addon1 has no binary components
do_check_neq(a1, null); do_check_neq(a1, null);
do_check_false(a1.userDisabled); do_check_false(a1.userDisabled);

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

@ -117,7 +117,7 @@ function check_test_1(installSyncGUID) {
AddonManager.getAddonByID("addon1@tests.mozilla.org", function(olda1) { AddonManager.getAddonByID("addon1@tests.mozilla.org", function(olda1) {
do_check_eq(olda1, null); do_check_eq(olda1, null);
AddonManager.getAddonsWithOperationsByTypes(null, callback_soon(async function(pendingAddons) { AddonManager.getAddonsWithOperationsByTypes(null, callback_soon(function(pendingAddons) {
do_check_eq(pendingAddons.length, 1); do_check_eq(pendingAddons.length, 1);
do_check_eq(pendingAddons[0].id, "addon1@tests.mozilla.org"); do_check_eq(pendingAddons[0].id, "addon1@tests.mozilla.org");
let uri = NetUtil.newURI(pendingAddons[0].iconURL); let uri = NetUtil.newURI(pendingAddons[0].iconURL);
@ -150,7 +150,7 @@ function check_test_1(installSyncGUID) {
do_check_false(hasFlag(pendingAddons[0].permissions, AddonManager.PERM_CAN_ENABLE)); do_check_false(hasFlag(pendingAddons[0].permissions, AddonManager.PERM_CAN_ENABLE));
do_check_false(hasFlag(pendingAddons[0].permissions, AddonManager.PERM_CAN_DISABLE)); do_check_false(hasFlag(pendingAddons[0].permissions, AddonManager.PERM_CAN_DISABLE));
await promiseRestartManager(); restartManager();
AddonManager.getAllInstalls(function(activeInstalls) { AddonManager.getAllInstalls(function(activeInstalls) {
do_check_eq(activeInstalls, 0); do_check_eq(activeInstalls, 0);
@ -276,9 +276,9 @@ function check_test_3(aInstall) {
setExtensionModifiedTime(ext, updateDate); setExtensionModifiedTime(ext, updateDate);
ensure_test_completed(); ensure_test_completed();
AddonManager.getAddonByID("addon2@tests.mozilla.org", callback_soon(async function(olda2) { AddonManager.getAddonByID("addon2@tests.mozilla.org", callback_soon(function(olda2) {
do_check_eq(olda2, null); do_check_eq(olda2, null);
await promiseRestartManager(); restartManager();
AddonManager.getAllInstalls(function(installs) { AddonManager.getAllInstalls(function(installs) {
do_check_eq(installs, 0); do_check_eq(installs, 0);
@ -465,9 +465,9 @@ function run_test_7() {
function check_test_7() { function check_test_7() {
ensure_test_completed(); ensure_test_completed();
AddonManager.getAddonByID("addon3@tests.mozilla.org", callback_soon(async function(olda3) { AddonManager.getAddonByID("addon3@tests.mozilla.org", callback_soon(function(olda3) {
do_check_eq(olda3, null); do_check_eq(olda3, null);
await promiseRestartManager(); restartManager();
AddonManager.getAllInstalls(function(installs) { AddonManager.getAllInstalls(function(installs) {
do_check_eq(installs, 0); do_check_eq(installs, 0);
@ -514,8 +514,8 @@ function run_test_8() {
}); });
} }
async function check_test_8() { function check_test_8() {
await promiseRestartManager(); restartManager();
AddonManager.getAddonByID("addon3@tests.mozilla.org", function(a3) { AddonManager.getAddonByID("addon3@tests.mozilla.org", function(a3) {
do_check_neq(a3, null); do_check_neq(a3, null);

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

@ -114,7 +114,7 @@ function check_test_1() {
AddonManager.getAddonByID("addon1@tests.mozilla.org", function(olda1) { AddonManager.getAddonByID("addon1@tests.mozilla.org", function(olda1) {
do_check_eq(olda1, null); do_check_eq(olda1, null);
AddonManager.getAddonsWithOperationsByTypes(null, callback_soon(async function(pendingAddons) { AddonManager.getAddonsWithOperationsByTypes(null, callback_soon(function(pendingAddons) {
do_check_eq(pendingAddons.length, 1); do_check_eq(pendingAddons.length, 1);
do_check_eq(pendingAddons[0].id, "addon1@tests.mozilla.org"); do_check_eq(pendingAddons[0].id, "addon1@tests.mozilla.org");
let uri = NetUtil.newURI(pendingAddons[0].iconURL); let uri = NetUtil.newURI(pendingAddons[0].iconURL);
@ -145,7 +145,7 @@ function check_test_1() {
do_check_false(hasFlag(pendingAddons[0].permissions, AddonManager.PERM_CAN_ENABLE)); do_check_false(hasFlag(pendingAddons[0].permissions, AddonManager.PERM_CAN_ENABLE));
do_check_false(hasFlag(pendingAddons[0].permissions, AddonManager.PERM_CAN_DISABLE)); do_check_false(hasFlag(pendingAddons[0].permissions, AddonManager.PERM_CAN_DISABLE));
await promiseRestartManager(); restartManager();
AddonManager.getAllInstalls(function(activeInstalls) { AddonManager.getAllInstalls(function(activeInstalls) {
do_check_eq(activeInstalls, 0); do_check_eq(activeInstalls, 0);
@ -259,9 +259,9 @@ function check_test_3(aInstall) {
setExtensionModifiedTime(ext, updateDate); setExtensionModifiedTime(ext, updateDate);
ensure_test_completed(); ensure_test_completed();
AddonManager.getAddonByID("addon2@tests.mozilla.org", callback_soon(async function(olda2) { AddonManager.getAddonByID("addon2@tests.mozilla.org", callback_soon(function(olda2) {
do_check_eq(olda2, null); do_check_eq(olda2, null);
await promiseRestartManager(); restartManager();
AddonManager.getAllInstalls(function(installs) { AddonManager.getAllInstalls(function(installs) {
do_check_eq(installs, 0); do_check_eq(installs, 0);
@ -359,10 +359,10 @@ function check_test_5(install) {
do_check_neq(olda2, null); do_check_neq(olda2, null);
do_check_true(hasFlag(olda2.pendingOperations, AddonManager.PENDING_UPGRADE)); do_check_true(hasFlag(olda2.pendingOperations, AddonManager.PENDING_UPGRADE));
AddonManager.getInstallsByTypes(null, callback_soon(async function(installs) { AddonManager.getInstallsByTypes(null, callback_soon(function(installs) {
do_check_eq(installs.length, 1); do_check_eq(installs.length, 1);
do_check_eq(installs[0].addon, olda2.pendingUpgrade); do_check_eq(installs[0].addon, olda2.pendingUpgrade);
await promiseRestartManager(); restartManager();
AddonManager.getInstallsByTypes(null, function(installs2) { AddonManager.getInstallsByTypes(null, function(installs2) {
do_check_eq(installs2.length, 0); do_check_eq(installs2.length, 0);
@ -446,9 +446,9 @@ function run_test_7() {
function check_test_7() { function check_test_7() {
ensure_test_completed(); ensure_test_completed();
AddonManager.getAddonByID("addon3@tests.mozilla.org", callback_soon(async function(olda3) { AddonManager.getAddonByID("addon3@tests.mozilla.org", callback_soon(function(olda3) {
do_check_eq(olda3, null); do_check_eq(olda3, null);
await promiseRestartManager(); restartManager();
AddonManager.getAllInstalls(function(installs) { AddonManager.getAllInstalls(function(installs) {
do_check_eq(installs, 0); do_check_eq(installs, 0);
@ -494,8 +494,8 @@ function run_test_8() {
}); });
} }
async function check_test_8() { function check_test_8() {
await promiseRestartManager(); restartManager();
AddonManager.getAddonByID("addon3@tests.mozilla.org", function(a3) { AddonManager.getAddonByID("addon3@tests.mozilla.org", function(a3) {
do_check_neq(a3, null); do_check_neq(a3, null);

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

@ -182,7 +182,6 @@ add_task(function* init() {
add_task(function* run_test_1() { add_task(function* run_test_1() {
restartManager(); restartManager();
let [a1, a2, a3, a4, a5, a6, a7, t1, t2] = let [a1, a2, a3, a4, a5, a6, a7, t1, t2] =
yield promiseAddonsByIDs(["addon1@tests.mozilla.org", yield promiseAddonsByIDs(["addon1@tests.mozilla.org",
"addon2@tests.mozilla.org", "addon2@tests.mozilla.org",
@ -454,7 +453,8 @@ add_task(function* run_test_1() {
do_print("Unlocking " + gExtensionsJSON.path); do_print("Unlocking " + gExtensionsJSON.path);
yield file.close(); yield file.close();
gExtensionsJSON.permissions = filePermissions; gExtensionsJSON.permissions = filePermissions;
yield promiseStartupManager(); startupManager();
// Shouldn't have seen any startup changes // Shouldn't have seen any startup changes
check_startup_changes(AddonManager.STARTUP_CHANGE_INSTALLED, []); check_startup_changes(AddonManager.STARTUP_CHANGE_INSTALLED, []);

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

@ -164,7 +164,7 @@ add_task(function*() {
if (!OS.Constants.Win) { if (!OS.Constants.Win) {
gExtensionsJSON.permissions = 0; gExtensionsJSON.permissions = 0;
} }
yield promiseStartupManager(false); startupManager(false);
check_startup_changes(AddonManager.STARTUP_CHANGE_INSTALLED, []); check_startup_changes(AddonManager.STARTUP_CHANGE_INSTALLED, []);
check_startup_changes(AddonManager.STARTUP_CHANGE_UNINSTALLED, []); check_startup_changes(AddonManager.STARTUP_CHANGE_UNINSTALLED, []);
@ -225,7 +225,7 @@ add_task(function*() {
} }
yield file.close(); yield file.close();
gExtensionsJSON.permissions = filePermissions; gExtensionsJSON.permissions = filePermissions;
yield promiseStartupManager(); startupManager();
// On Unix, we can save the DB even when the original file wasn't // On Unix, we can save the DB even when the original file wasn't
// readable, so our changes were saved. On Windows, // readable, so our changes were saved. On Windows,

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

@ -148,7 +148,7 @@ add_task(function* init() {
writeInstallRDFForExtension(theme2, profileDir); writeInstallRDFForExtension(theme2, profileDir);
// Startup the profile and setup the initial state // Startup the profile and setup the initial state
yield promiseStartupManager(); startupManager();
// New profile so new add-ons are ignored // New profile so new add-ons are ignored
check_startup_changes(AddonManager.STARTUP_CHANGE_INSTALLED, []); check_startup_changes(AddonManager.STARTUP_CHANGE_INSTALLED, []);
@ -271,7 +271,7 @@ add_task(function* run_test_1() {
if (!OS.Constants.Win) { if (!OS.Constants.Win) {
gExtensionsJSON.permissions = 0; gExtensionsJSON.permissions = 0;
} }
yield promiseStartupManager(false); startupManager(false);
// Shouldn't have seen any startup changes // Shouldn't have seen any startup changes
check_startup_changes(AddonManager.STARTUP_CHANGE_INSTALLED, []); check_startup_changes(AddonManager.STARTUP_CHANGE_INSTALLED, []);
@ -365,7 +365,7 @@ add_task(function* run_test_1() {
} catch (e) { } catch (e) {
// We're expecting an error here. // We're expecting an error here.
} }
yield promiseStartupManager(false); startupManager(false);
// Shouldn't have seen any startup changes // Shouldn't have seen any startup changes
check_startup_changes(AddonManager.STARTUP_CHANGE_INSTALLED, []); check_startup_changes(AddonManager.STARTUP_CHANGE_INSTALLED, []);
@ -453,7 +453,7 @@ add_task(function* run_test_1() {
do_print("Unlocking " + gExtensionsJSON.path); do_print("Unlocking " + gExtensionsJSON.path);
yield file.close(); yield file.close();
gExtensionsJSON.permissions = filePermissions; gExtensionsJSON.permissions = filePermissions;
yield promiseStartupManager(false); startupManager(false);
// Shouldn't have seen any startup changes // Shouldn't have seen any startup changes
check_startup_changes(AddonManager.STARTUP_CHANGE_INSTALLED, []); check_startup_changes(AddonManager.STARTUP_CHANGE_INSTALLED, []);

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

@ -0,0 +1,231 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
// Checks that we migrate data from the old rdf style database
var addon1 = {
id: "addon1@tests.mozilla.org",
version: "1.0",
name: "Test 1",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "1"
}]
};
var addon2 = {
id: "addon2@tests.mozilla.org",
version: "2.0",
name: "Test 2",
targetApplications: [{
id: "toolkit@mozilla.org",
minVersion: "1",
maxVersion: "1"
}]
};
var addon3 = {
id: "addon3@tests.mozilla.org",
version: "2.0",
name: "Test 3",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "1"
}]
};
var addon4 = {
id: "addon4@tests.mozilla.org",
version: "2.0",
name: "Test 4",
targetApplications: [{
id: "toolkit@mozilla.org",
minVersion: "1",
maxVersion: "1"
}]
};
var addon5 = {
id: "addon5@tests.mozilla.org",
version: "2.0",
name: "Test 5",
targetApplications: [{
id: "toolkit@mozilla.org",
minVersion: "1",
maxVersion: "1"
}]
};
var theme1 = {
id: "theme1@tests.mozilla.org",
version: "1.0",
name: "Theme 1",
type: 4,
internalName: "theme1/1.0",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "2"
}]
};
var theme2 = {
id: "theme2@tests.mozilla.org",
version: "1.0",
name: "Theme 2",
type: 4,
internalName: "theme2/1.0",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "2"
}]
};
const profileDir = gProfD.clone();
profileDir.append("extensions");
function run_test() {
do_test_pending();
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "2", "2");
writeInstallRDFForExtension(addon1, profileDir);
writeInstallRDFForExtension(addon2, profileDir);
writeInstallRDFForExtension(addon3, profileDir);
writeInstallRDFForExtension(addon4, profileDir);
writeInstallRDFForExtension(addon5, profileDir);
writeInstallRDFForExtension(theme1, profileDir);
writeInstallRDFForExtension(theme2, profileDir);
let stagedXPIs = profileDir.clone();
stagedXPIs.append("staged-xpis");
stagedXPIs.append("addon6@tests.mozilla.org");
stagedXPIs.create(AM_Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY);
let addon6 = do_get_addon("test_migrate6");
addon6.copyTo(stagedXPIs, "tmp.xpi");
stagedXPIs = stagedXPIs.parent;
stagedXPIs.append("addon7@tests.mozilla.org");
stagedXPIs.create(AM_Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY);
let addon7 = do_get_addon("test_migrate7");
addon7.copyTo(stagedXPIs, "tmp.xpi");
stagedXPIs = stagedXPIs.parent;
stagedXPIs.append("addon8@tests.mozilla.org");
stagedXPIs.create(AM_Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY);
let addon8 = do_get_addon("test_migrate8");
addon8.copyTo(stagedXPIs, "tmp.xpi");
stagedXPIs = stagedXPIs.parent;
let old = do_get_file("data/test_migrate.rdf");
old.copyTo(gProfD, "extensions.rdf");
let oldCache = gProfD.clone();
oldCache.append("extensions.cache");
oldCache.create(AM_Ci.nsIFile.NORMAL_FILE_TYPE, FileUtils.PERMS_FILE);
// Theme state is determined by the selected theme pref
Services.prefs.setCharPref("general.skins.selectedSkin", "theme1/1.0");
Services.prefs.setCharPref("extensions.lastAppVersion", "1");
startupManager();
check_startup_changes("installed", []);
check_startup_changes("updated", []);
check_startup_changes("uninstalled", []);
check_startup_changes("disabled", []);
check_startup_changes("enabled", []);
do_check_false(oldCache.exists());
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",
"theme1@tests.mozilla.org",
"theme2@tests.mozilla.org"], function([a1, a2, a3,
a4, a5, a6,
a7, a8, t1,
t2]) {
// addon1 was user and app enabled in the old extensions.rdf
do_check_neq(a1, null);
do_check_false(a1.userDisabled);
do_check_false(a1.appDisabled);
do_check_true(a1.isActive);
do_check_true(isExtensionInAddonsList(profileDir, a1.id));
do_check_false(a1.hasBinaryComponents);
do_check_true(a1.seen);
// addon2 was user disabled and app enabled in the old extensions.rdf
do_check_neq(a2, null);
do_check_true(a2.userDisabled);
do_check_false(a2.appDisabled);
do_check_false(a2.isActive);
do_check_false(isExtensionInAddonsList(profileDir, a2.id));
do_check_false(a2.hasBinaryComponents);
do_check_true(a2.seen);
// addon3 was pending user disable and app disabled in the old extensions.rdf
do_check_neq(a3, null);
do_check_true(a3.userDisabled);
do_check_true(a3.appDisabled);
do_check_false(a3.isActive);
do_check_false(isExtensionInAddonsList(profileDir, a3.id));
do_check_false(a3.hasBinaryComponents);
do_check_true(a3.seen);
// addon4 was pending user enable and app disabled in the old extensions.rdf
do_check_neq(a4, null);
do_check_false(a4.userDisabled);
do_check_true(a4.appDisabled);
do_check_false(a4.isActive);
do_check_false(isExtensionInAddonsList(profileDir, a4.id));
do_check_false(a4.hasBinaryComponents);
do_check_true(a4.seen);
// addon5 was disabled and compatible but a new version has been installed
// since, it should still be disabled but should be incompatible
do_check_neq(a5, null);
do_check_true(a5.userDisabled);
do_check_true(a5.appDisabled);
do_check_false(a5.isActive);
do_check_false(isExtensionInAddonsList(profileDir, a5.id));
do_check_false(a5.hasBinaryComponents);
do_check_true(a5.seen);
// addon6, addon7 and addon8 will have been lost as they were staged in the
// pre-Firefox 4.0 directory
do_check_eq(a6, null);
do_check_eq(a7, null);
do_check_eq(a8, null);
// Theme 1 was previously enabled
do_check_neq(t1, null);
do_check_false(t1.userDisabled);
do_check_false(t1.appDisabled);
do_check_true(t1.isActive);
do_check_true(isThemeInAddonsList(profileDir, t1.id));
do_check_false(hasFlag(t1.permissions, AddonManager.PERM_CAN_ENABLE));
do_check_true(t1.seen);
// Theme 2 was previously disabled
do_check_neq(t2, null);
do_check_true(t2.userDisabled);
do_check_false(t2.appDisabled);
do_check_false(t2.isActive);
do_check_false(isThemeInAddonsList(profileDir, t2.id));
do_check_true(hasFlag(t2.permissions, AddonManager.PERM_CAN_ENABLE));
do_check_true(t2.seen);
do_execute_soon(do_test_finished);
});
}

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

@ -0,0 +1,267 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
// Checks that we migrate data from SQLITE databases
// Note that since the database doesn't contain the foreignInstall field we
// should just assume that no add-ons in the user profile were foreignInstalls
// Enable loading extensions from the user and system scopes
Services.prefs.setIntPref("extensions.enabledScopes",
AddonManager.SCOPE_PROFILE + AddonManager.SCOPE_USER +
AddonManager.SCOPE_SYSTEM);
var addon1 = {
id: "addon1@tests.mozilla.org",
version: "1.0",
name: "Test 1",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "1"
}]
};
var addon2 = {
id: "addon2@tests.mozilla.org",
version: "2.0",
name: "Test 2",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "1"
}]
};
var addon3 = {
id: "addon3@tests.mozilla.org",
version: "2.0",
name: "Test 3",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "1"
}]
};
var addon4 = {
id: "addon4@tests.mozilla.org",
version: "2.0",
name: "Test 4",
strictCompatibility: true,
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "1"
}]
};
var addon5 = {
id: "addon5@tests.mozilla.org",
version: "2.0",
name: "Test 5",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "0",
maxVersion: "0"
}]
};
var addon6 = {
id: "addon6@tests.mozilla.org",
version: "2.0",
name: "Test 6",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "0",
maxVersion: "0"
}]
};
var addon7 = {
id: "addon7@tests.mozilla.org",
version: "2.0",
name: "Test 7",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "1"
}]
};
var addon8 = {
id: "addon8@tests.mozilla.org",
version: "2.0",
name: "Test 8",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "1"
}]
};
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2");
const profileDir = gProfD.clone();
profileDir.append("extensions");
const globalDir = gProfD.clone();
globalDir.append("extensions2");
globalDir.append(gAppInfo.ID);
registerDirectory("XRESysSExtPD", globalDir.parent);
const userDir = gProfD.clone();
userDir.append("extensions3");
userDir.append(gAppInfo.ID);
registerDirectory("XREUSysExt", userDir.parent);
function run_test() {
do_test_pending();
writeInstallRDFForExtension(addon1, profileDir);
writeInstallRDFForExtension(addon2, profileDir);
writeInstallRDFForExtension(addon3, profileDir);
writeInstallRDFForExtension(addon4, profileDir);
writeInstallRDFForExtension(addon5, profileDir);
writeInstallRDFForExtension(addon6, profileDir);
writeInstallRDFForExtension(addon7, globalDir);
writeInstallRDFForExtension(addon8, userDir);
// Write out a minimal database
let dbfile = gProfD.clone();
dbfile.append("extensions.sqlite");
let db = AM_Cc["@mozilla.org/storage/service;1"].
getService(AM_Ci.mozIStorageService).
openDatabase(dbfile);
db.createTable("addon", "internal_id INTEGER PRIMARY KEY AUTOINCREMENT, " +
"id TEXT, location TEXT, version TEXT, active INTEGER, " +
"userDisabled INTEGER, installDate INTEGER");
db.createTable("targetApplication", "addon_internal_id INTEGER, " +
"id TEXT, minVersion TEXT, maxVersion TEXT");
let stmt = db.createStatement("INSERT INTO addon VALUES (NULL, :id, :location, " +
":version, :active, :userDisabled, :installDate)");
let internal_ids = {};
[["addon1@tests.mozilla.org", "app-profile", "1.0", "1", "0", "0"],
["addon2@tests.mozilla.org", "app-profile", "2.0", "0", "1", "0"],
["addon3@tests.mozilla.org", "app-profile", "2.0", "1", "1", "0"],
["addon4@tests.mozilla.org", "app-profile", "2.0", "0", "0", "0"],
["addon5@tests.mozilla.org", "app-profile", "2.0", "1", "0", "0"],
["addon6@tests.mozilla.org", "app-profile", "1.0", "0", "1", "0"],
["addon7@tests.mozilla.org", "app-system-share", "1.0", "1", "0", "0"],
["addon8@tests.mozilla.org", "app-system-user", "1.0", "1", "0", "0"]].forEach(function(a) {
stmt.params.id = a[0];
stmt.params.location = a[1];
stmt.params.version = a[2];
stmt.params.active = a[3];
stmt.params.userDisabled = a[4];
stmt.params.installDate = a[5];
stmt.execute();
internal_ids[a[0]] = db.lastInsertRowID;
});
stmt.finalize();
// Add updated target application into for addon5
stmt = db.createStatement("INSERT INTO targetApplication VALUES " +
"(:internal_id, :id, :minVersion, :maxVersion)");
stmt.params.internal_id = internal_ids["addon5@tests.mozilla.org"];
stmt.params.id = "xpcshell@tests.mozilla.org";
stmt.params.minVersion = "0";
stmt.params.maxVersion = "1";
stmt.execute();
// Add updated target application into for addon6
stmt.params.internal_id = internal_ids["addon6@tests.mozilla.org"];
stmt.params.id = "xpcshell@tests.mozilla.org";
stmt.params.minVersion = "0";
stmt.params.maxVersion = "1";
stmt.execute();
stmt.finalize();
db.schemaVersion = 10000;
Services.prefs.setIntPref("extensions.databaseSchema", 14);
db.close();
startupManager();
check_startup_changes("installed", []);
check_startup_changes("updated", []);
check_startup_changes("uninstalled", []);
check_startup_changes("disabled", []);
check_startup_changes("enabled", []);
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"],
function([a1, a2, a3, a4, a5, a6, a7, a8]) {
// addon1 was enabled in the database
do_check_neq(a1, null);
do_check_false(a1.userDisabled);
do_check_false(a1.appDisabled);
do_check_true(a1.isActive);
do_check_false(a1.strictCompatibility);
do_check_false(a1.foreignInstall);
do_check_true(a1.seen);
// addon2 was disabled in the database
do_check_neq(a2, null);
do_check_true(a2.userDisabled);
do_check_false(a2.appDisabled);
do_check_false(a2.isActive);
do_check_false(a2.strictCompatibility);
do_check_false(a2.foreignInstall);
do_check_true(a2.seen);
// addon3 was pending-disable in the database
do_check_neq(a3, null);
do_check_true(a3.userDisabled);
do_check_false(a3.appDisabled);
do_check_false(a3.isActive);
do_check_false(a3.strictCompatibility);
do_check_false(a3.foreignInstall);
do_check_true(a3.seen);
// addon4 was pending-enable in the database
do_check_neq(a4, null);
do_check_false(a4.userDisabled);
do_check_false(a4.appDisabled);
do_check_true(a4.isActive);
do_check_true(a4.strictCompatibility);
do_check_false(a4.foreignInstall);
do_check_true(a4.seen);
// addon5 was enabled in the database but needed a compatibility update
do_check_neq(a5, null);
do_check_false(a5.userDisabled);
do_check_false(a5.appDisabled);
do_check_true(a5.isActive);
do_check_false(a5.strictCompatibility);
do_check_false(a5.foreignInstall);
do_check_true(a5.seen);
// addon6 was disabled and compatible but a new version has been installed
// since, it should still be disabled but should be incompatible
do_check_neq(a6, null);
do_check_true(a6.userDisabled);
do_check_true(a6.appDisabled);
do_check_false(a6.isActive);
do_check_false(a6.strictCompatibility);
do_check_false(a6.foreignInstall);
do_check_true(a6.seen);
// addon7 is in the global install location so should be a foreignInstall
do_check_neq(a7, null);
do_check_false(a7.userDisabled);
do_check_false(a7.appDisabled);
do_check_true(a7.isActive);
do_check_false(a7.strictCompatibility);
do_check_true(a7.foreignInstall);
do_check_true(a7.seen);
// addon8 is in the user install location so should be a foreignInstall
do_check_neq(a8, null);
do_check_false(a8.userDisabled);
do_check_false(a8.appDisabled);
do_check_true(a8.isActive);
do_check_false(a8.strictCompatibility);
do_check_true(a8.foreignInstall);
do_check_true(a8.seen);
do_execute_soon(do_test_finished);
});
}

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

@ -0,0 +1,229 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
// Checks that we migrate data from the old extensions.rdf database. This
// matches test_migrate1.js however it runs with a lightweight theme selected
// so the themes should appear disabled.
Components.utils.import("resource://gre/modules/LightweightThemeManager.jsm");
var addon1 = {
id: "addon1@tests.mozilla.org",
version: "1.0",
name: "Test 1",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "1"
}]
};
var addon2 = {
id: "addon2@tests.mozilla.org",
version: "2.0",
name: "Test 2",
targetApplications: [{
id: "toolkit@mozilla.org",
minVersion: "1",
maxVersion: "1"
}]
};
var addon3 = {
id: "addon3@tests.mozilla.org",
version: "2.0",
name: "Test 3",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "1"
}]
};
var addon4 = {
id: "addon4@tests.mozilla.org",
version: "2.0",
name: "Test 4",
targetApplications: [{
id: "toolkit@mozilla.org",
minVersion: "1",
maxVersion: "1"
}]
};
var addon5 = {
id: "addon5@tests.mozilla.org",
version: "2.0",
name: "Test 5",
targetApplications: [{
id: "toolkit@mozilla.org",
minVersion: "1",
maxVersion: "1"
}]
};
var theme1 = {
id: "theme1@tests.mozilla.org",
version: "1.0",
name: "Theme 1",
type: 4,
internalName: "theme1/1.0",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "2"
}]
};
var theme2 = {
id: "theme2@tests.mozilla.org",
version: "1.0",
name: "Theme 2",
type: 4,
internalName: "theme2/1.0",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "2"
}]
};
const profileDir = gProfD.clone();
profileDir.append("extensions");
function run_test() {
do_test_pending();
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "2", "2");
writeInstallRDFForExtension(addon1, profileDir);
writeInstallRDFForExtension(addon2, profileDir);
writeInstallRDFForExtension(addon3, profileDir);
writeInstallRDFForExtension(addon4, profileDir);
writeInstallRDFForExtension(addon5, profileDir);
writeInstallRDFForExtension(theme1, profileDir);
writeInstallRDFForExtension(theme2, profileDir);
// Cannot use the LightweightThemeManager before AddonManager has been started
// so inject the correct prefs
Services.prefs.setCharPref("lightweightThemes.usedThemes", JSON.stringify([{
id: "1",
version: "1",
name: "Test LW Theme",
description: "A test theme",
author: "Mozilla",
homepageURL: "http://localhost/data/index.html",
headerURL: "http://localhost/data/header.png",
footerURL: "http://localhost/data/footer.png",
previewURL: "http://localhost/data/preview.png",
iconURL: "http://localhost/data/icon.png"
}]));
Services.prefs.setCharPref("lightweightThemes.selectedThemeID", "1");
let stagedXPIs = profileDir.clone();
stagedXPIs.append("staged-xpis");
stagedXPIs.append("addon6@tests.mozilla.org");
stagedXPIs.create(AM_Ci.nsIFile.DIRECTORY_TYPE, 0o755);
let addon6 = do_get_addon("test_migrate6");
addon6.copyTo(stagedXPIs, "tmp.xpi");
stagedXPIs = stagedXPIs.parent;
stagedXPIs.append("addon7@tests.mozilla.org");
stagedXPIs.create(AM_Ci.nsIFile.DIRECTORY_TYPE, 0o755);
let addon7 = do_get_addon("test_migrate7");
addon7.copyTo(stagedXPIs, "tmp.xpi");
stagedXPIs = stagedXPIs.parent;
let old = do_get_file("data/test_migrate.rdf");
old.copyTo(gProfD, "extensions.rdf");
// Theme state is determined by the selected theme pref
Services.prefs.setCharPref("general.skins.selectedSkin", "theme1/1.0");
startupManager();
check_startup_changes("installed", []);
check_startup_changes("updated", []);
check_startup_changes("uninstalled", []);
check_startup_changes("disabled", []);
check_startup_changes("enabled", []);
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",
"theme1@tests.mozilla.org",
"theme2@tests.mozilla.org"], function([a1, a2, a3,
a4, a5, a6,
a7, t1, t2]) {
// addon1 was user and app enabled in the old extensions.rdf
do_check_neq(a1, null);
do_check_false(a1.userDisabled);
do_check_false(a1.appDisabled);
do_check_true(a1.isActive);
do_check_true(isExtensionInAddonsList(profileDir, a1.id));
do_check_true(a1.seen);
// addon2 was user disabled and app enabled in the old extensions.rdf
do_check_neq(a2, null);
do_check_true(a2.userDisabled);
do_check_false(a2.appDisabled);
do_check_false(a2.isActive);
do_check_false(isExtensionInAddonsList(profileDir, a2.id));
do_check_true(a2.seen);
// addon3 was pending user disable and app disabled in the old extensions.rdf
do_check_neq(a3, null);
do_check_true(a3.userDisabled);
do_check_true(a3.appDisabled);
do_check_false(a3.isActive);
do_check_false(isExtensionInAddonsList(profileDir, a3.id));
do_check_true(a3.seen);
// addon4 was pending user enable and app disabled in the old extensions.rdf
do_check_neq(a4, null);
do_check_false(a4.userDisabled);
do_check_true(a4.appDisabled);
do_check_false(a4.isActive);
do_check_false(isExtensionInAddonsList(profileDir, a4.id));
do_check_true(a4.seen);
// addon5 was disabled and compatible but a new version has been installed
// since, it should still be disabled but should be incompatible
do_check_neq(a5, null);
do_check_true(a5.userDisabled);
do_check_true(a5.appDisabled);
do_check_false(a5.isActive);
do_check_false(isExtensionInAddonsList(profileDir, a5.id));
do_check_true(a5.seen);
// addon6 and addon7 will have been lost as they were staged in the
// pre-Firefox 4.0 directory
do_check_eq(a6, null);
do_check_eq(a7, null);
// Theme 1 was previously disabled
do_check_neq(t1, null);
do_check_true(t1.userDisabled);
do_check_false(t1.appDisabled);
do_check_false(t1.isActive);
do_check_true(isThemeInAddonsList(profileDir, t1.id));
do_check_true(hasFlag(t1.permissions, AddonManager.PERM_CAN_ENABLE));
do_check_true(t1.seen);
// Theme 2 was previously disabled
do_check_neq(t2, null);
do_check_true(t2.userDisabled);
do_check_false(t2.appDisabled);
do_check_false(t2.isActive);
do_check_false(isThemeInAddonsList(profileDir, t2.id));
do_check_true(hasFlag(t2.permissions, AddonManager.PERM_CAN_ENABLE));
do_check_true(t2.seen);
do_execute_soon(do_test_finished);
});
}

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

@ -0,0 +1,321 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
// Checks that we migrate data from a previous version of the JSON database
// The test extension uses an insecure update url.
Services.prefs.setBoolPref("extensions.checkUpdateSecurity", false);
Components.utils.import("resource://testing-common/httpd.js");
var testserver = new HttpServer();
testserver.start(-1);
gPort = testserver.identity.primaryPort;
mapFile("/data/test_migrate4.rdf", testserver);
testserver.registerDirectory("/addons/", do_get_file("addons"));
var addon1 = {
id: "addon1@tests.mozilla.org",
version: "1.0",
name: "Test 1",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "2"
}]
};
var addon2 = {
id: "addon2@tests.mozilla.org",
version: "2.0",
name: "Test 2",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "2"
}]
};
var addon3 = {
id: "addon3@tests.mozilla.org",
version: "2.0",
name: "Test 3",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "2"
}]
};
var addon4 = {
id: "addon4@tests.mozilla.org",
version: "2.0",
name: "Test 4",
strictCompatibility: true,
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "2"
}]
};
var addon5 = {
id: "addon5@tests.mozilla.org",
version: "2.0",
name: "Test 5",
updateURL: "http://localhost:" + gPort + "/data/test_migrate4.rdf",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "0",
maxVersion: "1"
}]
};
var addon6 = {
id: "addon6@tests.mozilla.org",
version: "1.0",
name: "Test 6",
updateURL: "http://localhost:" + gPort + "/data/test_migrate4.rdf",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "0",
maxVersion: "1"
}]
};
var defaultTheme = {
id: "default@tests.mozilla.org",
version: "1.0",
name: "Default",
internalName: "classic/1.0",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "2"
}]
};
const profileDir = gProfD.clone();
profileDir.append("extensions");
var oldSyncGUIDs = {};
function prepare_profile() {
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2");
writeInstallRDFForExtension(addon1, profileDir);
writeInstallRDFForExtension(addon2, profileDir);
writeInstallRDFForExtension(addon3, profileDir);
writeInstallRDFForExtension(addon4, profileDir);
writeInstallRDFForExtension(addon5, profileDir);
writeInstallRDFForExtension(addon6, profileDir);
writeInstallRDFForExtension(defaultTheme, profileDir);
startupManager();
installAllFiles([do_get_addon("test_migrate8"), do_get_addon("test_migrate9")],
function() {
restartManager();
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",
"addon9@tests.mozilla.org"],
function([a1, a2, a3, a4, a5, a6, a9]) {
a1.applyBackgroundUpdates = AddonManager.AUTOUPDATE_DEFAULT;
a2.userDisabled = true;
a2.applyBackgroundUpdates = AddonManager.AUTOUPDATE_DISABLE;
a3.applyBackgroundUpdates = AddonManager.AUTOUPDATE_ENABLE;
a4.userDisabled = true;
a6.userDisabled = true;
a9.userDisabled = false;
for (let addon of [a1, a2, a3, a4, a5, a6]) {
oldSyncGUIDs[addon.id] = addon.syncGUID;
}
a6.findUpdates({
onUpdateAvailable(aAddon, aInstall6) {
AddonManager.getInstallForURL("http://localhost:" + gPort + "/addons/test_migrate4_7.xpi", function(aInstall7) {
completeAllInstalls([aInstall6, aInstall7], function() {
restartManager();
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"],
function([a1_2, a2_2, a3_2, a4_2, a5_2, a6_2]) {
a3_2.userDisabled = true;
a4_2.userDisabled = false;
a5_2.findUpdates({
onUpdateFinished() {
do_execute_soon(perform_migration);
}
}, AddonManager.UPDATE_WHEN_USER_REQUESTED);
});
});
}, "application/x-xpinstall");
}
}, AddonManager.UPDATE_WHEN_USER_REQUESTED);
});
});
}
function perform_migration() {
shutdownManager();
// Turn on disabling for all scopes
Services.prefs.setIntPref("extensions.autoDisableScopes", 15);
changeXPIDBVersion(1, data => {
// Delete the seen property from all add-ons to make sure it defaults to true
for (let addon of data.addons) {
delete addon.seen;
}
});
Services.prefs.setIntPref("extensions.databaseSchema", 1);
gAppInfo.version = "2"
startupManager(true);
test_results();
}
function test_results() {
check_startup_changes("installed", []);
check_startup_changes("updated", []);
check_startup_changes("uninstalled", []);
check_startup_changes("disabled", []);
check_startup_changes("enabled", []);
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"],
function([a1, a2, a3, a4, a5, a6, a7, a8, a9]) {
// addon1 was enabled
do_check_neq(a1, null);
do_check_eq(a1.syncGUID, oldSyncGUIDs[a1.id]);
do_check_false(a1.userDisabled);
do_check_false(a1.appDisabled);
do_check_true(a1.isActive);
do_check_eq(a1.applyBackgroundUpdates, AddonManager.AUTOUPDATE_DEFAULT);
do_check_true(a1.foreignInstall);
do_check_true(a1.seen);
do_check_false(a1.hasBinaryComponents);
do_check_false(a1.strictCompatibility);
// addon2 was disabled
do_check_neq(a2, null);
do_check_eq(a2.syncGUID, oldSyncGUIDs[a2.id]);
do_check_true(a2.userDisabled);
do_check_false(a2.appDisabled);
do_check_false(a2.isActive);
do_check_eq(a2.applyBackgroundUpdates, AddonManager.AUTOUPDATE_DISABLE);
do_check_true(a2.foreignInstall);
do_check_true(a2.seen);
do_check_false(a2.hasBinaryComponents);
do_check_false(a2.strictCompatibility);
// addon3 was pending-disable in the database
do_check_neq(a3, null);
do_check_eq(a3.syncGUID, oldSyncGUIDs[a3.id]);
do_check_true(a3.userDisabled);
do_check_false(a3.appDisabled);
do_check_false(a3.isActive);
do_check_eq(a3.applyBackgroundUpdates, AddonManager.AUTOUPDATE_ENABLE);
do_check_true(a3.foreignInstall);
do_check_true(a3.seen);
do_check_false(a3.hasBinaryComponents);
do_check_false(a3.strictCompatibility);
// addon4 was pending-enable in the database
do_check_neq(a4, null);
do_check_eq(a4.syncGUID, oldSyncGUIDs[a4.id]);
do_check_false(a4.userDisabled);
do_check_false(a4.appDisabled);
do_check_true(a4.isActive);
do_check_eq(a4.applyBackgroundUpdates, AddonManager.AUTOUPDATE_DEFAULT);
do_check_true(a4.foreignInstall);
do_check_true(a4.seen);
do_check_false(a4.hasBinaryComponents);
do_check_true(a4.strictCompatibility);
// addon5 was enabled in the database but needed a compatibility update
do_check_neq(a5, null);
do_check_false(a5.userDisabled);
do_check_false(a5.appDisabled);
do_check_true(a5.isActive);
do_check_eq(a4.applyBackgroundUpdates, AddonManager.AUTOUPDATE_DEFAULT);
do_check_true(a5.foreignInstall);
do_check_true(a5.seen);
do_check_false(a5.hasBinaryComponents);
do_check_false(a5.strictCompatibility);
// addon6 was disabled and compatible but a new version has been installed
do_check_neq(a6, null);
do_check_eq(a6.syncGUID, oldSyncGUIDs[a6.id]);
do_check_eq(a6.version, "2.0");
do_check_true(a6.userDisabled);
do_check_false(a6.appDisabled);
do_check_false(a6.isActive);
do_check_eq(a6.applyBackgroundUpdates, AddonManager.AUTOUPDATE_DEFAULT);
do_check_true(a6.foreignInstall);
do_check_true(a6.seen);
do_check_eq(a6.sourceURI.spec, "http://localhost:" + gPort + "/addons/test_migrate4_6.xpi");
do_check_eq(a6.releaseNotesURI.spec, "http://example.com/updateInfo.xhtml");
do_check_false(a6.hasBinaryComponents);
do_check_false(a6.strictCompatibility);
// addon7 was installed manually
do_check_neq(a7, null);
do_check_eq(a7.version, "1.0");
do_check_false(a7.userDisabled);
do_check_false(a7.appDisabled);
do_check_true(a7.isActive);
do_check_eq(a7.applyBackgroundUpdates, AddonManager.AUTOUPDATE_DEFAULT);
do_check_false(a7.foreignInstall);
do_check_true(a7.seen);
do_check_eq(a7.sourceURI.spec, "http://localhost:" + gPort + "/addons/test_migrate4_7.xpi");
do_check_eq(a7.releaseNotesURI, null);
do_check_false(a7.hasBinaryComponents);
do_check_false(a7.strictCompatibility);
// addon8 was enabled and has binary components
do_check_neq(a8, null);
do_check_false(a8.userDisabled);
do_check_false(a8.appDisabled);
do_check_true(a8.isActive);
do_check_false(a8.foreignInstall);
do_check_true(a8.seen);
do_check_true(a8.hasBinaryComponents);
do_check_false(a8.strictCompatibility);
// addon9 is the active theme
do_check_neq(a9, null);
do_check_false(a9.userDisabled);
do_check_false(a9.appDisabled);
do_check_true(a9.isActive);
do_check_false(a9.foreignInstall);
do_check_true(a9.seen);
do_check_false(a9.hasBinaryComponents);
do_check_true(a9.strictCompatibility);
testserver.stop(do_test_finished);
});
}
function run_test() {
do_test_pending();
prepare_profile();
}

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

@ -0,0 +1,139 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
// Checks that we fail to migrate but still start up ok when there is a SQLITE database
// with no useful data in it.
const PREF_GENERAL_SKINS_SELECTEDSKIN = "general.skins.selectedSkin";
var addon1 = {
id: "addon1@tests.mozilla.org",
version: "1.0",
name: "Test 1",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "1"
}]
};
var addon2 = {
id: "addon2@tests.mozilla.org",
version: "2.0",
name: "Test 5",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "0",
maxVersion: "0"
}]
};
var defaultTheme = {
id: "default@tests.mozilla.org",
version: "2.0",
name: "Default theme",
internalName: "classic/1.0",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "1"
}]
};
var theme1 = {
id: "theme1@tests.mozilla.org",
version: "2.0",
name: "Test theme",
internalName: "theme1/1.0",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "1"
}]
};
const profileDir = gProfD.clone();
profileDir.append("extensions");
function run_test() {
do_test_pending();
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2");
writeInstallRDFForExtension(addon1, profileDir);
writeInstallRDFForExtension(addon2, profileDir);
writeInstallRDFForExtension(defaultTheme, profileDir);
writeInstallRDFForExtension(theme1, profileDir);
Services.prefs.setCharPref(PREF_GENERAL_SKINS_SELECTEDSKIN, "theme1/1.0");
// Write out a broken database (no userDisabled field)
let dbfile = gProfD.clone();
dbfile.append("extensions.sqlite");
let db = AM_Cc["@mozilla.org/storage/service;1"].
getService(AM_Ci.mozIStorageService).
openDatabase(dbfile);
db.createTable("addon", "internal_id INTEGER PRIMARY KEY AUTOINCREMENT, " +
"id TEXT, location TEXT, version TEXT, active INTEGER, " +
"installDate INTEGER");
db.createTable("targetApplication", "addon_internal_id INTEGER, " +
"id TEXT, minVersion TEXT, maxVersion TEXT");
let stmt = db.createStatement("INSERT INTO addon VALUES (NULL, :id, :location, " +
":version, :active, :installDate)");
let internal_ids = {};
[["addon1@tests.mozilla.org", "app-profile", "1.0", "1", "0"],
["addon2@tests.mozilla.org", "app-profile", "2.0", "0", "0"],
["default@tests.mozilla.org", "app-profile", "2.0", "1", "0"],
["theme1@tests.mozilla.org", "app-profile", "2.0", "0", "0"]].forEach(function(a) {
stmt.params.id = a[0];
stmt.params.location = a[1];
stmt.params.version = a[2];
stmt.params.active = a[3];
stmt.params.installDate = a[4];
stmt.execute();
internal_ids[a[0]] = db.lastInsertRowID;
});
stmt.finalize();
db.schemaVersion = 100;
Services.prefs.setIntPref("extensions.databaseSchema", 100);
db.close();
startupManager();
check_startup_changes("installed", []);
check_startup_changes("updated", []);
check_startup_changes("uninstalled", []);
check_startup_changes("disabled", []);
check_startup_changes("enabled", []);
AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",
"addon2@tests.mozilla.org",
"default@tests.mozilla.org",
"theme1@tests.mozilla.org"],
function([a1, a2, d, t1]) {
do_check_neq(a1, null);
do_check_false(a1.userDisabled);
do_check_false(a1.appDisabled);
do_check_true(a1.isActive);
do_check_neq(a2, null);
do_check_false(a2.userDisabled);
do_check_true(a2.appDisabled);
do_check_false(a2.isActive);
// Should have enabled the selected theme
do_check_neq(t1, null);
do_check_false(t1.userDisabled);
do_check_false(t1.appDisabled);
do_check_true(t1.isActive);
do_check_neq(d, null);
do_check_true(d.userDisabled);
do_check_false(d.appDisabled);
do_check_false(d.isActive);
do_execute_soon(do_test_finished);
});
}

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

@ -0,0 +1,127 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
const EXPECTED_SCHEMA_VERSION = 4;
var dbfile;
function run_test() {
do_test_pending();
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2");
// Write out a minimal database.
dbfile = gProfD.clone();
dbfile.append("addons.sqlite");
let db = AM_Cc["@mozilla.org/storage/service;1"].
getService(AM_Ci.mozIStorageService).
openDatabase(dbfile);
db.createTable("addon",
"internal_id INTEGER PRIMARY KEY AUTOINCREMENT, " +
"id TEXT UNIQUE, " +
"type TEXT, " +
"name TEXT, " +
"version TEXT, " +
"creator TEXT, " +
"creatorURL TEXT, " +
"description TEXT, " +
"fullDescription TEXT, " +
"developerComments TEXT, " +
"eula TEXT, " +
"iconURL TEXT, " +
"homepageURL TEXT, " +
"supportURL TEXT, " +
"contributionURL TEXT, " +
"contributionAmount TEXT, " +
"averageRating INTEGER, " +
"reviewCount INTEGER, " +
"reviewURL TEXT, " +
"totalDownloads INTEGER, " +
"weeklyDownloads INTEGER, " +
"dailyUsers INTEGER, " +
"sourceURI TEXT, " +
"repositoryStatus INTEGER, " +
"size INTEGER, " +
"updateDate INTEGER");
db.createTable("developer",
"addon_internal_id INTEGER, " +
"num INTEGER, " +
"name TEXT, " +
"url TEXT, " +
"PRIMARY KEY (addon_internal_id, num)");
db.createTable("screenshot",
"addon_internal_id INTEGER, " +
"num INTEGER, " +
"url TEXT, " +
"thumbnailURL TEXT, " +
"caption TEXT, " +
"PRIMARY KEY (addon_internal_id, num)");
let insertStmt = db.createStatement("INSERT INTO addon (id) VALUES (:id)");
insertStmt.params.id = "test1@tests.mozilla.org";
insertStmt.execute();
insertStmt.finalize();
insertStmt = db.createStatement("INSERT INTO screenshot VALUES " +
"(:addon_internal_id, :num, :url, :thumbnailURL, :caption)");
insertStmt.params.addon_internal_id = 1;
insertStmt.params.num = 0;
insertStmt.params.url = "http://localhost/full1-1.png";
insertStmt.params.thumbnailURL = "http://localhost/thumbnail1-1.png";
insertStmt.params.caption = "Caption 1 - 1";
insertStmt.execute();
insertStmt.finalize();
db.schemaVersion = 1;
db.close();
Services.prefs.setBoolPref("extensions.getAddons.cache.enabled", true);
AddonRepository.getCachedAddonByID("test1@tests.mozilla.org", function(aAddon) {
do_check_neq(aAddon, null);
do_check_eq(aAddon.screenshots.length, 1);
do_check_true(aAddon.screenshots[0].width === null);
do_check_true(aAddon.screenshots[0].height === null);
do_check_true(aAddon.screenshots[0].thumbnailWidth === null);
do_check_true(aAddon.screenshots[0].thumbnailHeight === null);
do_check_eq(aAddon.iconURL, undefined);
do_check_eq(JSON.stringify(aAddon.icons), "{}");
AddonRepository.shutdown().then(
function checkAfterRepoShutdown() {
// Check the DB schema has changed once AddonRepository has freed it.
db = AM_Cc["@mozilla.org/storage/service;1"].
getService(AM_Ci.mozIStorageService).
openDatabase(dbfile);
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"));
do_check_true(db.indexExists("icon_idx"));
do_check_true(db.tableExists("icon"));
// 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 selectStmt = db.createStatement("SELECT COUNT(*) AS count FROM compatibility_override");
selectStmt.executeStep();
do_check_eq(selectStmt.row.count, 1);
selectStmt.reset();
db.executeSimpleSQL("DELETE FROM addon");
selectStmt.executeStep();
do_check_eq(selectStmt.row.count, 0);
selectStmt.finalize();
db.close();
do_test_finished();
},
do_report_unexpected_exception
);
});
}

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

@ -0,0 +1,103 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
// Checks that we don't migrate data from SQLITE if
// the "extensions.databaseSchema" preference shows we've
// already upgraded to JSON
// Enable loading extensions from the user and system scopes
Services.prefs.setIntPref("extensions.enabledScopes",
AddonManager.SCOPE_PROFILE + AddonManager.SCOPE_USER +
AddonManager.SCOPE_SYSTEM);
var addon1 = {
id: "addon1@tests.mozilla.org",
version: "1.0",
name: "Test 1",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "1"
}]
};
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2");
const profileDir = gProfD.clone();
profileDir.append("extensions");
function run_test() {
writeInstallRDFForExtension(addon1, profileDir);
// Write out a minimal database
let dbfile = gProfD.clone();
dbfile.append("extensions.sqlite");
let db = AM_Cc["@mozilla.org/storage/service;1"].
getService(AM_Ci.mozIStorageService).
openDatabase(dbfile);
db.createTable("addon", "internal_id INTEGER PRIMARY KEY AUTOINCREMENT, " +
"id TEXT, location TEXT, version TEXT, active INTEGER, " +
"userDisabled INTEGER, installDate INTEGER");
db.createTable("targetApplication", "addon_internal_id INTEGER, " +
"id TEXT, minVersion TEXT, maxVersion TEXT");
let stmt = db.createStatement("INSERT INTO addon VALUES (NULL, :id, :location, " +
":version, :active, :userDisabled, :installDate)");
let internal_ids = {};
let a = ["addon1@tests.mozilla.org", "app-profile", "1.0", "0", "1", "0"];
stmt.params.id = a[0];
stmt.params.location = a[1];
stmt.params.version = a[2];
stmt.params.active = a[3];
stmt.params.userDisabled = a[4];
stmt.params.installDate = a[5];
stmt.execute();
internal_ids[a[0]] = db.lastInsertRowID;
stmt.finalize();
db.schemaVersion = 14;
Services.prefs.setIntPref("extensions.databaseSchema", 14);
db.close();
startupManager();
run_next_test();
}
add_test(function before_rebuild() {
AddonManager.getAddonByID("addon1@tests.mozilla.org",
function check_before_rebuild(a1) {
// First check that it migrated OK once
// addon1 was disabled in the database
do_check_neq(a1, null);
do_check_true(a1.userDisabled);
do_check_false(a1.appDisabled);
do_check_false(a1.isActive);
do_check_false(a1.strictCompatibility);
do_check_false(a1.foreignInstall);
run_next_test();
});
});
// now shut down, remove the JSON database,
// start up again, and make sure the data didn't migrate this time
add_test(function rebuild_again() {
shutdownManager();
gExtensionsJSON.remove(true);
startupManager();
AddonManager.getAddonByID("addon1@tests.mozilla.org",
function check_after_rebuild(a1) {
// addon1 was rebuilt from extensions directory,
// so it appears enabled as a foreign install
do_check_neq(a1, null);
do_check_false(a1.userDisabled);
do_check_false(a1.appDisabled);
do_check_true(a1.isActive);
do_check_false(a1.strictCompatibility);
do_check_true(a1.foreignInstall);
run_next_test();
});
});

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

@ -1,120 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
"use strict";
/* globals Preferences */
AM_Cu.import("resource://gre/modules/Preferences.jsm");
function getXS() {
let XPI = Components.utils.import("resource://gre/modules/addons/XPIProvider.jsm", {});
return XPI.XPIStates;
}
function installExtension(id, data) {
return AddonTestUtils.promiseWriteFilesToExtension(
AddonTestUtils.profileExtensions.path, id, data);
}
add_task(async function test_migrate_prefs() {
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "54");
ok(!AddonTestUtils.addonStartup.exists(),
"addonStartup.json.lz4 should not exist");
const ID1 = "bootstrapped-enabled@xpcshell.mozilla.org";
const ID2 = "bootstrapped-disabled@xpcshell.mozilla.org";
const ID3 = "restartful-enabled@xpcshell.mozilla.org";
const ID4 = "restartful-disabled@xpcshell.mozilla.org";
let targetApplications = [{ id: "toolkit@mozilla.org", "minVersion": "0", "maxVersion": "*" }];
let file1 = await installExtension(ID1, { "install.rdf": { id: ID1, name: ID1, bootstrapped: true, version: "0.1", targetApplications } });
let file2 = await installExtension(ID2, { "install.rdf": { id: ID2, name: ID2, bootstrapped: true, version: "0.2", targetApplications } });
let file3 = await installExtension(ID3, { "install.rdf": { id: ID3, name: ID1, bootstrapped: false, version: "0.3", targetApplications } });
let file4 = await installExtension(ID4, { "install.rdf": { id: ID4, name: ID2, bootstrapped: false, version: "0.4", targetApplications } });
function mt(file) {
let f = file.clone();
if (TEST_UNPACKED) {
f.append("install.rdf");
}
return f.lastModifiedTime;
}
// Startup and shut down the add-on manager so the add-ons are added
// to the DB.
await promiseStartupManager();
await promiseShutdownManager();
// Remove the startup state file and add legacy prefs to replace it.
AddonTestUtils.addonStartup.remove(false);
Preferences.set("extensions.xpiState", JSON.stringify({
"app-profile": {
[ID1]: {e: true, d: file1.persistentDescriptor, v: "0.1", mt: mt(file1)},
[ID2]: {e: false, d: file2.persistentDescriptor, v: "0.2", mt: mt(file2)},
[ID3]: {e: true, d: file3.persistentDescriptor, v: "0.3", mt: mt(file3)},
[ID4]: {e: false, d: file4.persistentDescriptor, v: "0.4", mt: mt(file4)},
}
}));
Preferences.set("extensions.bootstrappedAddons", JSON.stringify({
[ID1]: {
version: "0.1",
type: "extension",
multiprocessCompatible: false,
descriptor: file1.persistentDescriptor,
hasEmbeddedWebExtension: true,
}
}));
await promiseStartupManager();
// Check the the state data is updated correctly.
let states = getXS();
let addon1 = states.findAddon(ID1);
ok(addon1.enabled, "Addon 1 should be enabled");
ok(addon1.bootstrapped, "Addon 1 should be bootstrapped");
equal(addon1.version, "0.1", "Addon 1 has the correct version");
equal(addon1.mtime, mt(file1), "Addon 1 has the correct timestamp");
ok(addon1.enableShims, "Addon 1 has shims enabled");
ok(addon1.hasEmbeddedWebExtension, "Addon 1 has an embedded WebExtension");
let addon2 = states.findAddon(ID2);
ok(!addon2.enabled, "Addon 2 should not be enabled");
ok(!addon2.bootstrapped, "Addon 2 should be bootstrapped, because that information is not stored in xpiStates");
equal(addon2.version, "0.2", "Addon 2 has the correct version");
equal(addon2.mtime, mt(file2), "Addon 2 has the correct timestamp");
ok(!addon2.enableShims, "Addon 2 does not have shims enabled");
ok(!addon2.hasEmbeddedWebExtension, "Addon 2 no embedded WebExtension");
let addon3 = states.findAddon(ID3);
ok(addon3.enabled, "Addon 3 should be enabled");
ok(!addon3.bootstrapped, "Addon 3 should not be bootstrapped");
equal(addon3.version, "0.3", "Addon 3 has the correct version");
equal(addon3.mtime, mt(file3), "Addon 3 has the correct timestamp");
ok(!addon3.enableShims, "Addon 3 does not have shims enabled");
ok(!addon3.hasEmbeddedWebExtension, "Addon 3 no embedded WebExtension");
let addon4 = states.findAddon(ID4);
ok(!addon4.enabled, "Addon 4 should not be enabled");
ok(!addon4.bootstrapped, "Addon 4 should not be bootstrapped");
equal(addon4.version, "0.4", "Addon 4 has the correct version");
equal(addon4.mtime, mt(file4), "Addon 4 has the correct timestamp");
ok(!addon4.enableShims, "Addon 4 does not have shims enabled");
ok(!addon4.hasEmbeddedWebExtension, "Addon 4 no embedded WebExtension");
// Check that legacy prefs and files have been removed.
ok(!Preferences.has("extensions.xpiState"), "No xpiState pref left behind");
ok(!Preferences.has("extensions.bootstrappedAddons"), "No bootstrappedAddons pref left behind");
ok(!Preferences.has("extensions.enabledAddons"), "No enabledAddons pref left behind");
let file = AddonTestUtils.profileDir.clone();
file.append("extensions.ini");
ok(!file.exists(), "No extensions.ini file left behind");
await promiseShutdownManager();
});

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

@ -27,9 +27,23 @@ function checkPending() {
} }
} }
function checkString(aPref, aValue) {
try {
do_check_eq(Services.prefs.getCharPref(aPref), aValue)
} catch (e) {
// OK
}
}
// Make sure all our extension state is empty/nonexistent // Make sure all our extension state is empty/nonexistent
function check_empty_state() { function check_empty_state() {
do_check_false(gExtensionsJSON.exists());
do_check_false(gExtensionsINI.exists());
do_check_eq(Services.prefs.getIntPref("extensions.databaseSchema"), DB_SCHEMA); do_check_eq(Services.prefs.getIntPref("extensions.databaseSchema"), DB_SCHEMA);
checkString("extensions.bootstrappedAddons", "{}");
checkString("extensions.installCache", "[]");
checkPending(); checkPending();
} }

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

@ -33,14 +33,14 @@ function run_test() {
startupManager(); startupManager();
AddonManager.getAddonByID("addon1@tests.mozilla.org", callback_soon(async function(a1) { AddonManager.getAddonByID("addon1@tests.mozilla.org", callback_soon(function(a1) {
do_check_eq(a1, null); do_check_eq(a1, null);
do_check_not_in_crash_annotation(addon1.id, addon1.version); do_check_not_in_crash_annotation(addon1.id, addon1.version);
writeInstallRDFForExtension(addon1, profileDir, addon1.id, "icon.png"); writeInstallRDFForExtension(addon1, profileDir, addon1.id, "icon.png");
gIconURL = do_get_addon_root_uri(profileDir.clone(), addon1.id) + "icon.png"; gIconURL = do_get_addon_root_uri(profileDir.clone(), addon1.id) + "icon.png";
await promiseRestartManager(); restartManager();
AddonManager.getAddonByID("addon1@tests.mozilla.org", function(newa1) { AddonManager.getAddonByID("addon1@tests.mozilla.org", function(newa1) {
do_check_neq(newa1, null); do_check_neq(newa1, null);

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

@ -18,7 +18,6 @@ const IGNORE_PRIVATE = ["AddonAuthor", "AddonCompatibilityOverride",
"AddonScreenshot", "AddonType", "startup", "shutdown", "AddonScreenshot", "AddonType", "startup", "shutdown",
"addonIsActive", "registerProvider", "unregisterProvider", "addonIsActive", "registerProvider", "unregisterProvider",
"addStartupChange", "removeStartupChange", "addStartupChange", "removeStartupChange",
"getNewSideloads",
"recordTimestamp", "recordSimpleMeasure", "recordTimestamp", "recordSimpleMeasure",
"recordException", "getSimpleMeasures", "simpleTimer", "recordException", "getSimpleMeasures", "simpleTimer",
"setTelemetryDetails", "getTelemetryDetails", "setTelemetryDetails", "getTelemetryDetails",

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

@ -1,90 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "49");
async function createWebExtension(details) {
let options = {
manifest: {
applications: {gecko: {id: details.id}},
name: details.name,
permissions: details.permissions,
},
};
if (details.iconURL) {
options.manifest.icons = {"64": details.iconURL};
}
let xpi = AddonTestUtils.createTempWebExtensionFile(options);
await AddonTestUtils.manuallyInstall(xpi);
}
async function createXULExtension(details) {
let xpi = AddonTestUtils.createTempXPIFile({
"install.rdf": {
id: details.id,
name: details.name,
version: "0.1",
targetApplications: [{
id: "toolkit@mozilla.org",
minVersion: "0",
maxVersion: "*",
}],
},
});
await AddonTestUtils.manuallyInstall(xpi);
}
add_task(async function test_sideloading() {
Services.prefs.setIntPref("extensions.autoDisableScopes", 15);
Services.prefs.setIntPref("extensions.startupScanScopes", 0);
const ID1 = "addon1@tests.mozilla.org";
await createWebExtension({
id: ID1,
name: "Test 1",
userDisabled: true,
permissions: ["history", "https://*/*"],
iconURL: "foo-icon.png",
});
const ID2 = "addon2@tests.mozilla.org";
await createXULExtension({
id: ID2,
name: "Test 2",
});
const ID3 = "addon3@tests.mozilla.org";
await createWebExtension({
id: ID3,
name: "Test 3",
permissions: ["<all_urls>"],
});
const ID4 = "addon4@tests.mozilla.org";
await createWebExtension({
id: ID4,
name: "Test 4",
permissions: ["<all_urls>"],
});
await promiseStartupManager();
let sideloaded = await AddonManagerPrivate.getNewSideloads();
sideloaded.sort((a, b) => a.id.localeCompare(b.id));
deepEqual(sideloaded.map(a => a.id),
[ID1, ID2, ID3, ID4],
"Got the correct sideload add-ons");
deepEqual(sideloaded.map(a => a.userDisabled),
[true, true, true, true],
"All sideloaded add-ons are disabled");
});

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

@ -25,13 +25,8 @@ profileDir.append("extensions");
// Deletes a file from the test add-on in the profile // Deletes a file from the test add-on in the profile
function breakAddon(file) { function breakAddon(file) {
if (TEST_UNPACKED) { if (TEST_UNPACKED) {
let f = file.clone(); file.append("test.txt");
f.append("test.txt"); file.remove(true);
f.remove(true);
f = file.clone();
f.append("install.rdf");
f.lastModifiedTime = Date.now();
} else { } else {
var zipW = AM_Cc["@mozilla.org/zipwriter;1"]. var zipW = AM_Cc["@mozilla.org/zipwriter;1"].
createInstance(AM_Ci.nsIZipWriter); createInstance(AM_Ci.nsIZipWriter);
@ -261,7 +256,7 @@ add_task(function*() {
// detection but the periodic scan will catch that // detection but the periodic scan will catch that
yield promiseSetExtensionModifiedTime(file.path, Date.now() - 60000); yield promiseSetExtensionModifiedTime(file.path, Date.now() - 60000);
yield promiseStartupManager(); startupManager();
let addon = yield promiseAddonByID(ID); let addon = yield promiseAddonByID(ID);
do_check_neq(addon, null); do_check_neq(addon, null);
do_check_false(addon.appDisabled); do_check_false(addon.appDisabled);
@ -274,7 +269,7 @@ add_task(function*() {
clearCache(file); clearCache(file);
breakAddon(file); breakAddon(file);
yield promiseStartupManager(); startupManager();
addon = yield promiseAddonByID(ID); addon = yield promiseAddonByID(ID);
do_check_neq(addon, null); do_check_neq(addon, null);

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

@ -104,7 +104,7 @@ function* test_breaking_migrate(addons, test, expectedSignedState) {
// Update the application // Update the application
gAppInfo.version = "5"; gAppInfo.version = "5";
yield promiseStartupManager(true); startupManager(true);
let addon = yield promiseAddonByID(ID); let addon = yield promiseAddonByID(ID);
do_check_neq(addon, null); do_check_neq(addon, null);
@ -154,7 +154,7 @@ function* test_working_migrate(addons, test, expectedSignedState) {
// Update the application // Update the application
gAppInfo.version = "5"; gAppInfo.version = "5";
yield promiseStartupManager(true); startupManager(true);
let addon = yield promiseAddonByID(ID); let addon = yield promiseAddonByID(ID);
do_check_neq(addon, null); do_check_neq(addon, null);

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

@ -134,7 +134,7 @@ function run_test() {
do_check_false(gExtensionsJSON.exists()); do_check_false(gExtensionsJSON.exists());
do_check_false(gAddonStartup.exists()); do_check_false(gExtensionsINI.exists());
AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org", AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",
"addon2@tests.mozilla.org", "addon2@tests.mozilla.org",
@ -163,7 +163,7 @@ function end_test() {
} }
// Try to install all the items into the profile // Try to install all the items into the profile
async function run_test_1() { function run_test_1() {
writeInstallRDFForExtension(addon1, profileDir); writeInstallRDFForExtension(addon1, profileDir);
var dest = writeInstallRDFForExtension(addon2, profileDir); var dest = writeInstallRDFForExtension(addon2, profileDir);
// Attempt to make this look like it was added some time in the past so // Attempt to make this look like it was added some time in the past so
@ -177,7 +177,7 @@ async function run_test_1() {
writeInstallRDFForExtension(addon7, profileDir); writeInstallRDFForExtension(addon7, profileDir);
gCachePurged = false; gCachePurged = false;
await promiseRestartManager(); restartManager();
check_startup_changes(AddonManager.STARTUP_CHANGE_INSTALLED, ["addon1@tests.mozilla.org", check_startup_changes(AddonManager.STARTUP_CHANGE_INSTALLED, ["addon1@tests.mozilla.org",
"addon2@tests.mozilla.org", "addon2@tests.mozilla.org",
"addon3@tests.mozilla.org"]); "addon3@tests.mozilla.org"]);
@ -187,8 +187,8 @@ async function run_test_1() {
check_startup_changes(AddonManager.STARTUP_CHANGE_ENABLED, []); check_startup_changes(AddonManager.STARTUP_CHANGE_ENABLED, []);
do_check_true(gCachePurged); do_check_true(gCachePurged);
do_print("Checking for " + gAddonStartup.path); do_print("Checking for " + gExtensionsINI.path);
do_check_true(gAddonStartup.exists()); do_check_true(gExtensionsINI.exists());
AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org", AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",
"addon2@tests.mozilla.org", "addon2@tests.mozilla.org",
@ -281,7 +281,7 @@ async function run_test_1() {
// Test that modified items are detected and items in other install locations // Test that modified items are detected and items in other install locations
// are ignored // are ignored
async function run_test_2() { function run_test_2() {
addon1.version = "1.1"; addon1.version = "1.1";
writeInstallRDFForExtension(addon1, userDir); writeInstallRDFForExtension(addon1, userDir);
addon2.version = "2.1"; addon2.version = "2.1";
@ -295,8 +295,7 @@ async function run_test_2() {
dest.remove(true); dest.remove(true);
gCachePurged = false; gCachePurged = false;
await promiseRestartManager(); restartManager();
check_startup_changes(AddonManager.STARTUP_CHANGE_INSTALLED, []); check_startup_changes(AddonManager.STARTUP_CHANGE_INSTALLED, []);
check_startup_changes(AddonManager.STARTUP_CHANGE_CHANGED, ["addon2@tests.mozilla.org"]); check_startup_changes(AddonManager.STARTUP_CHANGE_CHANGED, ["addon2@tests.mozilla.org"]);
check_startup_changes(AddonManager.STARTUP_CHANGE_UNINSTALLED, ["addon3@tests.mozilla.org"]); check_startup_changes(AddonManager.STARTUP_CHANGE_UNINSTALLED, ["addon3@tests.mozilla.org"]);
@ -304,7 +303,7 @@ async function run_test_2() {
check_startup_changes(AddonManager.STARTUP_CHANGE_ENABLED, []); check_startup_changes(AddonManager.STARTUP_CHANGE_ENABLED, []);
do_check_true(gCachePurged); do_check_true(gCachePurged);
do_check_true(gAddonStartup.exists()); do_check_true(gExtensionsINI.exists());
AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org", AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",
"addon2@tests.mozilla.org", "addon2@tests.mozilla.org",
@ -351,7 +350,7 @@ async function run_test_2() {
} }
// Check that removing items from the profile reveals their hidden versions. // Check that removing items from the profile reveals their hidden versions.
async function run_test_3() { function run_test_3() {
var dest = profileDir.clone(); var dest = profileDir.clone();
dest.append(do_get_expected_addon_name("addon1@tests.mozilla.org")); dest.append(do_get_expected_addon_name("addon1@tests.mozilla.org"));
dest.remove(true); dest.remove(true);
@ -361,8 +360,7 @@ async function run_test_3() {
writeInstallRDFForExtension(addon3, profileDir, "addon4@tests.mozilla.org"); writeInstallRDFForExtension(addon3, profileDir, "addon4@tests.mozilla.org");
gCachePurged = false; gCachePurged = false;
await promiseRestartManager(); restartManager();
check_startup_changes(AddonManager.STARTUP_CHANGE_INSTALLED, []); check_startup_changes(AddonManager.STARTUP_CHANGE_INSTALLED, []);
check_startup_changes(AddonManager.STARTUP_CHANGE_CHANGED, ["addon1@tests.mozilla.org", check_startup_changes(AddonManager.STARTUP_CHANGE_CHANGED, ["addon1@tests.mozilla.org",
"addon2@tests.mozilla.org"]); "addon2@tests.mozilla.org"]);
@ -417,12 +415,11 @@ async function run_test_3() {
} }
// Test that disabling an install location works // Test that disabling an install location works
async function run_test_4() { function run_test_4() {
Services.prefs.setIntPref("extensions.enabledScopes", AddonManager.SCOPE_SYSTEM); Services.prefs.setIntPref("extensions.enabledScopes", AddonManager.SCOPE_SYSTEM);
gCachePurged = false; gCachePurged = false;
await promiseRestartManager(); restartManager();
check_startup_changes(AddonManager.STARTUP_CHANGE_INSTALLED, []); check_startup_changes(AddonManager.STARTUP_CHANGE_INSTALLED, []);
check_startup_changes(AddonManager.STARTUP_CHANGE_CHANGED, ["addon2@tests.mozilla.org"]); check_startup_changes(AddonManager.STARTUP_CHANGE_CHANGED, ["addon2@tests.mozilla.org"]);
check_startup_changes(AddonManager.STARTUP_CHANGE_UNINSTALLED, ["addon1@tests.mozilla.org"]); check_startup_changes(AddonManager.STARTUP_CHANGE_UNINSTALLED, ["addon1@tests.mozilla.org"]);
@ -457,12 +454,11 @@ async function run_test_4() {
} }
// Switching disabled locations works // Switching disabled locations works
async function run_test_5() { function run_test_5() {
Services.prefs.setIntPref("extensions.enabledScopes", AddonManager.SCOPE_USER); Services.prefs.setIntPref("extensions.enabledScopes", AddonManager.SCOPE_USER);
gCachePurged = false; gCachePurged = false;
await promiseRestartManager(); restartManager();
check_startup_changes(AddonManager.STARTUP_CHANGE_INSTALLED, ["addon1@tests.mozilla.org"]); check_startup_changes(AddonManager.STARTUP_CHANGE_INSTALLED, ["addon1@tests.mozilla.org"]);
check_startup_changes(AddonManager.STARTUP_CHANGE_CHANGED, ["addon2@tests.mozilla.org"]); check_startup_changes(AddonManager.STARTUP_CHANGE_CHANGED, ["addon2@tests.mozilla.org"]);
check_startup_changes(AddonManager.STARTUP_CHANGE_UNINSTALLED, []); check_startup_changes(AddonManager.STARTUP_CHANGE_UNINSTALLED, []);
@ -503,12 +499,11 @@ async function run_test_5() {
} }
// Resetting the pref makes everything visible again // Resetting the pref makes everything visible again
async function run_test_6() { function run_test_6() {
Services.prefs.clearUserPref("extensions.enabledScopes"); Services.prefs.clearUserPref("extensions.enabledScopes");
gCachePurged = false; gCachePurged = false;
await promiseRestartManager(); restartManager();
check_startup_changes(AddonManager.STARTUP_CHANGE_INSTALLED, []); check_startup_changes(AddonManager.STARTUP_CHANGE_INSTALLED, []);
check_startup_changes(AddonManager.STARTUP_CHANGE_CHANGED, []); check_startup_changes(AddonManager.STARTUP_CHANGE_CHANGED, []);
check_startup_changes(AddonManager.STARTUP_CHANGE_UNINSTALLED, []); check_startup_changes(AddonManager.STARTUP_CHANGE_UNINSTALLED, []);
@ -549,7 +544,7 @@ async function run_test_6() {
} }
// Check that items in the profile hide the others again. // Check that items in the profile hide the others again.
async function run_test_7() { function run_test_7() {
addon1.version = "1.2"; addon1.version = "1.2";
writeInstallRDFForExtension(addon1, profileDir); writeInstallRDFForExtension(addon1, profileDir);
var dest = userDir.clone(); var dest = userDir.clone();
@ -557,8 +552,7 @@ async function run_test_7() {
dest.remove(true); dest.remove(true);
gCachePurged = false; gCachePurged = false;
await promiseRestartManager(); restartManager();
check_startup_changes(AddonManager.STARTUP_CHANGE_INSTALLED, []); check_startup_changes(AddonManager.STARTUP_CHANGE_INSTALLED, []);
check_startup_changes(AddonManager.STARTUP_CHANGE_CHANGED, ["addon1@tests.mozilla.org", check_startup_changes(AddonManager.STARTUP_CHANGE_CHANGED, ["addon1@tests.mozilla.org",
"addon2@tests.mozilla.org"]); "addon2@tests.mozilla.org"]);
@ -609,12 +603,11 @@ async function run_test_7() {
} }
// Disabling all locations still leaves the profile working // Disabling all locations still leaves the profile working
async function run_test_8() { function run_test_8() {
Services.prefs.setIntPref("extensions.enabledScopes", 0); Services.prefs.setIntPref("extensions.enabledScopes", 0);
gCachePurged = false; gCachePurged = false;
await promiseRestartManager(); restartManager();
check_startup_changes(AddonManager.STARTUP_CHANGE_INSTALLED, []); check_startup_changes(AddonManager.STARTUP_CHANGE_INSTALLED, []);
check_startup_changes(AddonManager.STARTUP_CHANGE_CHANGED, []); check_startup_changes(AddonManager.STARTUP_CHANGE_CHANGED, []);
check_startup_changes(AddonManager.STARTUP_CHANGE_UNINSTALLED, ["addon2@tests.mozilla.org"]); check_startup_changes(AddonManager.STARTUP_CHANGE_UNINSTALLED, ["addon2@tests.mozilla.org"]);
@ -649,7 +642,7 @@ async function run_test_8() {
} }
// More hiding and revealing // More hiding and revealing
async function run_test_9() { function run_test_9() {
Services.prefs.clearUserPref("extensions.enabledScopes"); Services.prefs.clearUserPref("extensions.enabledScopes");
var dest = userDir.clone(); var dest = userDir.clone();
@ -662,8 +655,7 @@ async function run_test_9() {
writeInstallRDFForExtension(addon2, profileDir); writeInstallRDFForExtension(addon2, profileDir);
gCachePurged = false; gCachePurged = false;
await promiseRestartManager(); restartManager();
check_startup_changes(AddonManager.STARTUP_CHANGE_INSTALLED, ["addon2@tests.mozilla.org"]); check_startup_changes(AddonManager.STARTUP_CHANGE_INSTALLED, ["addon2@tests.mozilla.org"]);
check_startup_changes(AddonManager.STARTUP_CHANGE_CHANGED, []); check_startup_changes(AddonManager.STARTUP_CHANGE_CHANGED, []);
check_startup_changes(AddonManager.STARTUP_CHANGE_UNINSTALLED, []); check_startup_changes(AddonManager.STARTUP_CHANGE_UNINSTALLED, []);
@ -712,7 +704,7 @@ async function run_test_9() {
// Checks that a removal from one location and an addition in another location // Checks that a removal from one location and an addition in another location
// for the same item is handled // for the same item is handled
async function run_test_10() { function run_test_10() {
var dest = profileDir.clone(); var dest = profileDir.clone();
dest.append(do_get_expected_addon_name("addon1@tests.mozilla.org")); dest.append(do_get_expected_addon_name("addon1@tests.mozilla.org"));
dest.remove(true); dest.remove(true);
@ -720,8 +712,7 @@ async function run_test_10() {
writeInstallRDFForExtension(addon1, userDir); writeInstallRDFForExtension(addon1, userDir);
gCachePurged = false; gCachePurged = false;
await promiseRestartManager(); restartManager();
check_startup_changes(AddonManager.STARTUP_CHANGE_INSTALLED, []); check_startup_changes(AddonManager.STARTUP_CHANGE_INSTALLED, []);
check_startup_changes(AddonManager.STARTUP_CHANGE_CHANGED, ["addon1@tests.mozilla.org"]); check_startup_changes(AddonManager.STARTUP_CHANGE_CHANGED, ["addon1@tests.mozilla.org"]);
check_startup_changes(AddonManager.STARTUP_CHANGE_UNINSTALLED, []); check_startup_changes(AddonManager.STARTUP_CHANGE_UNINSTALLED, []);
@ -769,7 +760,7 @@ async function run_test_10() {
} }
// This should remove any remaining items // This should remove any remaining items
async function run_test_11() { function run_test_11() {
var dest = userDir.clone(); var dest = userDir.clone();
dest.append(do_get_expected_addon_name("addon1@tests.mozilla.org")); dest.append(do_get_expected_addon_name("addon1@tests.mozilla.org"));
dest.remove(true); dest.remove(true);
@ -778,8 +769,7 @@ async function run_test_11() {
dest.remove(true); dest.remove(true);
gCachePurged = false; gCachePurged = false;
await promiseRestartManager(); restartManager();
check_startup_changes(AddonManager.STARTUP_CHANGE_INSTALLED, []); check_startup_changes(AddonManager.STARTUP_CHANGE_INSTALLED, []);
check_startup_changes(AddonManager.STARTUP_CHANGE_CHANGED, []); check_startup_changes(AddonManager.STARTUP_CHANGE_CHANGED, []);
check_startup_changes(AddonManager.STARTUP_CHANGE_UNINSTALLED, ["addon1@tests.mozilla.org", check_startup_changes(AddonManager.STARTUP_CHANGE_UNINSTALLED, ["addon1@tests.mozilla.org",

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

@ -89,7 +89,7 @@ const profileDir = gProfD.clone();
profileDir.append("extensions"); profileDir.append("extensions");
// Set up the profile // Set up the profile
async function run_test() { function run_test() {
do_test_pending(); do_test_pending();
writeInstallRDFForExtension(addon1, profileDir); writeInstallRDFForExtension(addon1, profileDir);
@ -98,8 +98,7 @@ async function run_test() {
writeInstallRDFForExtension(addon4, profileDir); writeInstallRDFForExtension(addon4, profileDir);
writeInstallRDFForExtension(addon5, profileDir); writeInstallRDFForExtension(addon5, profileDir);
await promiseRestartManager(); restartManager();
AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org", AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",
"addon2@tests.mozilla.org", "addon2@tests.mozilla.org",
"addon3@tests.mozilla.org", "addon3@tests.mozilla.org",

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

@ -34,7 +34,7 @@ AM_Cc["@mozilla.org/observer-service;1"]
.addObserver(LightweightThemeObserver, "lightweight-theme-styling-update"); .addObserver(LightweightThemeObserver, "lightweight-theme-styling-update");
async function run_test() { function run_test() {
do_test_pending(); do_test_pending();
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2"); createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2");
@ -80,7 +80,7 @@ async function run_test() {
}] }]
}, profileDir); }, profileDir);
await promiseStartupManager(); startupManager();
// Make sure we only register once despite multiple calls // Make sure we only register once despite multiple calls
AddonManager.addInstallListener(InstallListener); AddonManager.addInstallListener(InstallListener);
AddonManager.addAddonListener(AddonListener); AddonManager.addAddonListener(AddonListener);
@ -158,9 +158,8 @@ function run_test_1() {
}); });
} }
async function check_test_1() { function check_test_1() {
await promiseRestartManager(); restartManager();
do_check_eq(Services.prefs.getCharPref(PREF_GENERAL_SKINS_SELECTEDSKIN), "theme2/1.0"); do_check_eq(Services.prefs.getCharPref(PREF_GENERAL_SKINS_SELECTEDSKIN), "theme2/1.0");
AddonManager.getAddonsByIDs(["theme1@tests.mozilla.org", AddonManager.getAddonsByIDs(["theme1@tests.mozilla.org",
@ -191,13 +190,12 @@ async function check_test_1() {
// Removing the active theme should fall back to the default (not ideal in this // Removing the active theme should fall back to the default (not ideal in this
// case since we don't have the default theme installed) // case since we don't have the default theme installed)
async function run_test_2() { function run_test_2() {
var dest = profileDir.clone(); var dest = profileDir.clone();
dest.append(do_get_expected_addon_name("theme2@tests.mozilla.org")); dest.append(do_get_expected_addon_name("theme2@tests.mozilla.org"));
dest.remove(true); dest.remove(true);
await promiseRestartManager(); restartManager();
do_check_eq(Services.prefs.getCharPref(PREF_GENERAL_SKINS_SELECTEDSKIN), "classic/1.0"); do_check_eq(Services.prefs.getCharPref(PREF_GENERAL_SKINS_SELECTEDSKIN), "classic/1.0");
AddonManager.getAddonsByIDs(["theme1@tests.mozilla.org", AddonManager.getAddonsByIDs(["theme1@tests.mozilla.org",

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

@ -25,12 +25,12 @@ function run_test() {
do_test_pending(); do_test_pending();
startupManager(); startupManager();
AddonManager.getAddonByID("addon1@tests.mozilla.org", callback_soon(async function(olda1) { AddonManager.getAddonByID("addon1@tests.mozilla.org", callback_soon(function(olda1) {
do_check_eq(olda1, null); do_check_eq(olda1, null);
writeInstallRDFForExtension(addon1, profileDir); writeInstallRDFForExtension(addon1, profileDir);
await promiseRestartManager(); restartManager();
AddonManager.getAddonByID("addon1@tests.mozilla.org", function(a1) { AddonManager.getAddonByID("addon1@tests.mozilla.org", function(a1) {
do_check_neq(a1, null); do_check_neq(a1, null);
@ -92,8 +92,8 @@ function check_test_1() {
} }
// Cancelling the uninstall should send onOperationCancelled // Cancelling the uninstall should send onOperationCancelled
async function run_test_2() { function run_test_2() {
await promiseRestartManager(); restartManager();
prepare_test({ prepare_test({
"addon1@tests.mozilla.org": [ "addon1@tests.mozilla.org": [
@ -126,8 +126,8 @@ async function run_test_2() {
}); });
} }
async function check_test_2() { function check_test_2() {
await promiseRestartManager(); restartManager();
AddonManager.getAddonByID("addon1@tests.mozilla.org", function(a1) { AddonManager.getAddonByID("addon1@tests.mozilla.org", function(a1) {
do_check_neq(a1, null); do_check_neq(a1, null);

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

@ -221,16 +221,14 @@ for (let test of testParams) {
check_test_2 = () => { check_test_2 = () => {
ensure_test_completed(); ensure_test_completed();
AddonManager.getAddonByID("addon1@tests.mozilla.org", callback_soon(async function(olda1) { AddonManager.getAddonByID("addon1@tests.mozilla.org", callback_soon(function(olda1) {
await AddonTestUtils.loadAddonsList(true);
do_check_neq(olda1, null); do_check_neq(olda1, null);
do_check_eq(olda1.version, "1.0"); do_check_eq(olda1.version, "1.0");
do_check_true(isExtensionInAddonsList(profileDir, olda1.id)); do_check_true(isExtensionInAddonsList(profileDir, olda1.id));
shutdownManager(); shutdownManager();
await promiseStartupManager(); startupManager();
do_check_true(isExtensionInAddonsList(profileDir, "addon1@tests.mozilla.org")); do_check_true(isExtensionInAddonsList(profileDir, "addon1@tests.mozilla.org"));

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

@ -216,16 +216,14 @@ for (let test of testParams) {
check_test_2 = () => { check_test_2 = () => {
ensure_test_completed(); ensure_test_completed();
AddonManager.getAddonByID("addon1@tests.mozilla.org", callback_soon(async function(olda1) { AddonManager.getAddonByID("addon1@tests.mozilla.org", callback_soon(function(olda1) {
await AddonTestUtils.loadAddonsList(true);
do_check_neq(olda1, null); do_check_neq(olda1, null);
do_check_eq(olda1.version, "1.0"); do_check_eq(olda1.version, "1.0");
do_check_true(isExtensionInAddonsList(profileDir, olda1.id)); do_check_true(isExtensionInAddonsList(profileDir, olda1.id));
shutdownManager(); shutdownManager();
await promiseStartupManager(); startupManager();
do_check_true(isExtensionInAddonsList(profileDir, "addon1@tests.mozilla.org")); do_check_true(isExtensionInAddonsList(profileDir, "addon1@tests.mozilla.org"));

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

@ -96,8 +96,8 @@ function end_test() {
} }
// Test that the test extensions are all installed // Test that the test extensions are all installed
async function run_test_1() { function run_test_1() {
await promiseStartupManager(); startupManager();
AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org", AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",
"addon2@tests.mozilla.org", "addon2@tests.mozilla.org",
@ -123,7 +123,7 @@ async function run_test_1() {
} }
// Test that upgrading the application doesn't disable now incompatible add-ons // Test that upgrading the application doesn't disable now incompatible add-ons
async function run_test_2() { function run_test_2() {
// Upgrade the extension // Upgrade the extension
var dest = writeInstallRDFForExtension({ var dest = writeInstallRDFForExtension({
id: "addon4@tests.mozilla.org", id: "addon4@tests.mozilla.org",
@ -137,7 +137,7 @@ async function run_test_2() {
}, globalDir); }, globalDir);
setExtensionModifiedTime(dest, gInstallTime); setExtensionModifiedTime(dest, gInstallTime);
await promiseRestartManager("2"); restartManager("2");
AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org", AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",
"addon2@tests.mozilla.org", "addon2@tests.mozilla.org",
"addon3@tests.mozilla.org", "addon3@tests.mozilla.org",
@ -178,7 +178,7 @@ function run_test_3() {
// Simulates a simple Build ID change, the platform deletes extensions.ini // Simulates a simple Build ID change, the platform deletes extensions.ini
// whenever the application is changed. // whenever the application is changed.
gAddonStartup.remove(true); gExtensionsINI.remove(true);
restartManager(); restartManager();
AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org", AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",

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

@ -99,8 +99,8 @@ function end_test() {
} }
// Test that the test extensions are all installed // Test that the test extensions are all installed
async function run_test_1() { function run_test_1() {
await promiseStartupManager(); startupManager();
AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org", AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",
"addon2@tests.mozilla.org", "addon2@tests.mozilla.org",
@ -126,7 +126,7 @@ async function run_test_1() {
} }
// Test that upgrading the application disables now incompatible add-ons // Test that upgrading the application disables now incompatible add-ons
async function run_test_2() { function run_test_2() {
// Upgrade the extension // Upgrade the extension
var dest = writeInstallRDFForExtension({ var dest = writeInstallRDFForExtension({
id: "addon4@tests.mozilla.org", id: "addon4@tests.mozilla.org",
@ -140,8 +140,7 @@ async function run_test_2() {
}, globalDir); }, globalDir);
setExtensionModifiedTime(dest, gInstallTime); setExtensionModifiedTime(dest, gInstallTime);
await promiseRestartManager("2"); restartManager("2");
AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org", AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",
"addon2@tests.mozilla.org", "addon2@tests.mozilla.org",
"addon3@tests.mozilla.org", "addon3@tests.mozilla.org",
@ -182,7 +181,7 @@ function run_test_3() {
// Simulates a simple Build ID change, the platform deletes extensions.ini // Simulates a simple Build ID change, the platform deletes extensions.ini
// whenever the application is changed. // whenever the application is changed.
gAddonStartup.remove(true); gExtensionsINI.remove(true);
restartManager(); restartManager();
AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org", AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",

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

@ -105,8 +105,7 @@ add_task(function* has_embedded_webextension_persisted() {
// hasEmbeddedWebExtension property as expected. // hasEmbeddedWebExtension property as expected.
yield promiseRestartManager(); yield promiseRestartManager();
let persisted = aomStartup.readStartupData()["app-profile"].addons; let persisted = JSON.parse(Services.prefs.getCharPref("extensions.bootstrappedAddons"));
ok(ID in persisted, "Hybrid add-on persisted to bootstrappedAddons."); ok(ID in persisted, "Hybrid add-on persisted to bootstrappedAddons.");
equal(persisted[ID].hasEmbeddedWebExtension, true, equal(persisted[ID].hasEmbeddedWebExtension, true,
"hasEmbeddedWebExtension flag persisted to bootstrappedAddons."); "hasEmbeddedWebExtension flag persisted to bootstrappedAddons.");

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

@ -27,10 +27,9 @@ function promiseAddonStartup() {
function* testSimpleIconsetParsing(manifest) { function* testSimpleIconsetParsing(manifest) {
yield promiseWriteWebManifestForExtension(manifest, profileDir); yield promiseWriteWebManifestForExtension(manifest, profileDir);
yield Promise.all([ yield promiseRestartManager();
promiseRestartManager(), if (!manifest.theme)
manifest.theme || promiseAddonStartup(), yield promiseAddonStartup();
]);
let uri = do_get_addon_root_uri(profileDir, ID); let uri = do_get_addon_root_uri(profileDir, ID);
@ -61,10 +60,9 @@ function* testSimpleIconsetParsing(manifest) {
check_icons(addon); check_icons(addon);
// check if icons are persisted through a restart // check if icons are persisted through a restart
yield Promise.all([ yield promiseRestartManager();
promiseRestartManager(), if (!manifest.theme)
manifest.theme || promiseAddonStartup(), yield promiseAddonStartup();
]);
addon = yield promiseAddonByID(ID); addon = yield promiseAddonByID(ID);
do_check_neq(addon, null); do_check_neq(addon, null);
@ -72,15 +70,16 @@ function* testSimpleIconsetParsing(manifest) {
check_icons(addon); check_icons(addon);
addon.uninstall(); addon.uninstall();
yield promiseRestartManager();
} }
function* testRetinaIconsetParsing(manifest) { function* testRetinaIconsetParsing(manifest) {
yield promiseWriteWebManifestForExtension(manifest, profileDir); yield promiseWriteWebManifestForExtension(manifest, profileDir);
yield Promise.all([ yield promiseRestartManager();
promiseRestartManager(), if (!manifest.theme)
manifest.theme || promiseAddonStartup(), yield promiseAddonStartup();
]);
let addon = yield promiseAddonByID(ID); let addon = yield promiseAddonByID(ID);
do_check_neq(addon, null); do_check_neq(addon, null);
@ -101,15 +100,16 @@ function* testRetinaIconsetParsing(manifest) {
}), uri + "icon128.png"); }), uri + "icon128.png");
addon.uninstall(); addon.uninstall();
yield promiseRestartManager();
} }
function* testNoIconsParsing(manifest) { function* testNoIconsParsing(manifest) {
yield promiseWriteWebManifestForExtension(manifest, profileDir); yield promiseWriteWebManifestForExtension(manifest, profileDir);
yield Promise.all([ yield promiseRestartManager();
promiseRestartManager(), if (!manifest.theme)
manifest.theme || promiseAddonStartup(), yield promiseAddonStartup();
]);
let addon = yield promiseAddonByID(ID); let addon = yield promiseAddonByID(ID);
do_check_neq(addon, null); do_check_neq(addon, null);
@ -122,6 +122,8 @@ function* testNoIconsParsing(manifest) {
equal(AddonManager.getPreferredIconURL(addon, 128), null); equal(AddonManager.getPreferredIconURL(addon, 128), null);
addon.uninstall(); addon.uninstall();
yield promiseRestartManager();
} }
// Test simple icon set parsing // Test simple icon set parsing

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

@ -36,7 +36,7 @@ skip-if = os == "android"
tags = blocklist tags = blocklist
[test_bootstrap.js] [test_bootstrap.js]
# Bug 676992: test consistently hangs on Android # Bug 676992: test consistently hangs on Android
skip-if = os == "android" || os == "win" # Bug 1358846 skip-if = os == "android"
[test_bootstrap_const.js] [test_bootstrap_const.js]
[test_bootstrap_resource.js] [test_bootstrap_resource.js]
[test_bug299716.js] [test_bug299716.js]
@ -151,7 +151,7 @@ fail-if = os == "android"
[test_bug570173.js] [test_bug570173.js]
[test_bug576735.js] [test_bug576735.js]
[test_bug587088.js] [test_bug587088.js]
skip-if = os == "win" # Bug 1358846 [test_bug594058.js]
[test_bug595081.js] [test_bug595081.js]
[test_bug595573.js] [test_bug595573.js]
[test_bug596607.js] [test_bug596607.js]
@ -247,6 +247,15 @@ run-sequentially = Uses hardcoded ports in xpi files.
[test_mapURIToAddonID.js] [test_mapURIToAddonID.js]
# Same as test_bootstrap.js # Same as test_bootstrap.js
skip-if = os == "android" skip-if = os == "android"
[test_migrate1.js]
[test_migrate2.js]
[test_migrate3.js]
[test_migrate4.js]
# Times out during parallel runs on desktop
requesttimeoutfactor = 2
[test_migrate5.js]
[test_migrateAddonRepository.js]
[test_migrate_max_version.js]
[test_multiprocessCompatible.js] [test_multiprocessCompatible.js]
[test_no_addons.js] [test_no_addons.js]
[test_onPropertyChanged_appDisabled.js] [test_onPropertyChanged_appDisabled.js]
@ -290,7 +299,6 @@ fail-if = os == "android"
[test_undothemeuninstall.js] [test_undothemeuninstall.js]
skip-if = appname == "thunderbird" skip-if = appname == "thunderbird"
[test_undouninstall.js] [test_undouninstall.js]
skip-if = os == "win" # Bug 1358846
[test_uninstall.js] [test_uninstall.js]
[test_update.js] [test_update.js]
# Bug 676992: test consistently hangs on Android # Bug 676992: test consistently hangs on Android
@ -309,7 +317,6 @@ skip-if = os == "android"
skip-if = os == "android" skip-if = os == "android"
run-sequentially = Uses hardcoded ports in xpi files. run-sequentially = Uses hardcoded ports in xpi files.
[test_json_updatecheck.js] [test_json_updatecheck.js]
[test_migrate_state_prefs.js]
[test_seen.js] [test_seen.js]
[test_seen_newprofile.js] [test_seen_newprofile.js]
[test_updateid.js] [test_updateid.js]
@ -328,7 +335,6 @@ run-sequentially = Uses global XCurProcD dir.
[test_overrideblocklist.js] [test_overrideblocklist.js]
run-sequentially = Uses global XCurProcD dir. run-sequentially = Uses global XCurProcD dir.
tags = blocklist tags = blocklist
[test_sideloads.js]
[test_sourceURI.js] [test_sourceURI.js]
[test_webextension_icons.js] [test_webextension_icons.js]
skip-if = appname == "thunderbird" skip-if = appname == "thunderbird"

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

@ -6,7 +6,6 @@
#include "nsAppRunner.h" #include "nsAppRunner.h"
#include "nsToolkitCompsCID.h" #include "nsToolkitCompsCID.h"
#include "nsXREDirProvider.h" #include "nsXREDirProvider.h"
#include "mozilla/AddonManagerStartup.h"
#include "jsapi.h" #include "jsapi.h"
#include "xpcpublic.h" #include "xpcpublic.h"
@ -28,6 +27,7 @@
#include "nsXULAppAPI.h" #include "nsXULAppAPI.h"
#include "nsCategoryManagerUtils.h" #include "nsCategoryManagerUtils.h"
#include "nsINIParser.h"
#include "nsDependentString.h" #include "nsDependentString.h"
#include "nsCOMArray.h" #include "nsCOMArray.h"
#include "nsArrayEnumerator.h" #include "nsArrayEnumerator.h"
@ -86,6 +86,15 @@ static const char* GetContentProcessTempBaseDirKey();
static already_AddRefed<nsIFile> CreateContentProcessSandboxTempDir(); static already_AddRefed<nsIFile> CreateContentProcessSandboxTempDir();
#endif #endif
static already_AddRefed<nsIFile>
CloneAndAppend(nsIFile* aFile, const char* name)
{
nsCOMPtr<nsIFile> file;
aFile->Clone(getter_AddRefs(file));
file->AppendNative(nsDependentCString(name));
return file.forget();
}
nsXREDirProvider* gDirServiceProvider = nullptr; nsXREDirProvider* gDirServiceProvider = nullptr;
nsXREDirProvider::nsXREDirProvider() : nsXREDirProvider::nsXREDirProvider() :
@ -589,7 +598,7 @@ LoadDirIntoArray(nsIFile* dir,
} }
static void static void
LoadDirsIntoArray(const nsCOMArray<nsIFile>& aSourceDirs, LoadDirsIntoArray(nsCOMArray<nsIFile>& aSourceDirs,
const char *const* aAppendList, const char *const* aAppendList,
nsCOMArray<nsIFile>& aDirectories) nsCOMArray<nsIFile>& aDirectories)
{ {
@ -650,6 +659,73 @@ nsXREDirProvider::GetFiles(const char* aProperty, nsISimpleEnumerator** aResult)
return NS_SUCCESS_AGGREGATE_RESULT; return NS_SUCCESS_AGGREGATE_RESULT;
} }
static void
RegisterExtensionInterpositions(nsINIParser &parser)
{
if (!mozilla::Preferences::GetBool("extensions.interposition.enabled", false))
return;
nsCOMPtr<nsIAddonInterposition> interposition =
do_GetService("@mozilla.org/addons/multiprocess-shims;1");
nsresult rv;
int32_t i = 0;
do {
nsAutoCString buf("Extension");
buf.AppendInt(i++);
nsAutoCString addonId;
rv = parser.GetString("MultiprocessIncompatibleExtensions", buf.get(), addonId);
if (NS_FAILED(rv))
return;
if (!xpc::SetAddonInterposition(addonId, interposition))
continue;
if (!xpc::AllowCPOWsInAddon(addonId, true))
continue;
}
while (true);
}
static void
LoadExtensionDirectories(nsINIParser &parser,
const char *aSection,
nsCOMArray<nsIFile> &aDirectories,
NSLocationType aType)
{
nsresult rv;
int32_t i = 0;
do {
nsAutoCString buf("Extension");
buf.AppendInt(i++);
nsAutoCString path;
rv = parser.GetString(aSection, buf.get(), path);
if (NS_FAILED(rv))
return;
nsCOMPtr<nsIFile> dir = do_CreateInstance("@mozilla.org/file/local;1", &rv);
if (NS_FAILED(rv))
continue;
rv = dir->SetPersistentDescriptor(path);
if (NS_FAILED(rv))
continue;
aDirectories.AppendObject(dir);
if (Substring(path, path.Length() - 4).EqualsLiteral(".xpi")) {
XRE_AddJarManifestLocation(aType, dir);
}
else {
nsCOMPtr<nsIFile> manifest =
CloneAndAppend(dir, "chrome.manifest");
XRE_AddManifestLocation(aType, manifest);
}
}
while (true);
}
#if (defined(XP_WIN) || defined(XP_MACOSX)) && defined(MOZ_CONTENT_SANDBOX) #if (defined(XP_WIN) || defined(XP_MACOSX)) && defined(MOZ_CONTENT_SANDBOX)
static const char* static const char*
@ -827,6 +903,59 @@ DeleteDirIfExists(nsIFile* dir)
#endif // (defined(XP_WIN) || defined(XP_MACOSX)) && #endif // (defined(XP_WIN) || defined(XP_MACOSX)) &&
// defined(MOZ_CONTENT_SANDBOX) // defined(MOZ_CONTENT_SANDBOX)
void
nsXREDirProvider::LoadExtensionBundleDirectories()
{
if (!mozilla::Preferences::GetBool("extensions.defaultProviders.enabled", true))
return;
if (mProfileDir) {
if (!gSafeMode) {
nsCOMPtr<nsIFile> extensionsINI;
mProfileDir->Clone(getter_AddRefs(extensionsINI));
if (!extensionsINI)
return;
extensionsINI->AppendNative(NS_LITERAL_CSTRING("extensions.ini"));
nsCOMPtr<nsIFile> extensionsINILF =
do_QueryInterface(extensionsINI);
if (!extensionsINILF)
return;
nsINIParser parser;
nsresult rv = parser.Init(extensionsINILF);
if (NS_FAILED(rv))
return;
RegisterExtensionInterpositions(parser);
LoadExtensionDirectories(parser, "ExtensionDirs", mExtensionDirectories,
NS_EXTENSION_LOCATION);
LoadExtensionDirectories(parser, "ThemeDirs", mThemeDirectories,
NS_SKIN_LOCATION);
/* non-Firefox applications that use overrides in their default theme should
* define AC_DEFINE(MOZ_SEPARATE_MANIFEST_FOR_THEME_OVERRIDES) in their
* configure.in */
#if defined(MOZ_BUILD_APP_IS_BROWSER) || defined(MOZ_SEPARATE_MANIFEST_FOR_THEME_OVERRIDES)
} else {
// In safe mode, still load the default theme directory:
nsCOMPtr<nsIFile> themeManifest;
mXULAppDir->Clone(getter_AddRefs(themeManifest));
themeManifest->AppendNative(NS_LITERAL_CSTRING("extensions"));
themeManifest->AppendNative(NS_LITERAL_CSTRING("{972ce4c6-7e08-4474-a285-3208198ce6fd}.xpi"));
bool exists = false;
if (NS_SUCCEEDED(themeManifest->Exists(&exists)) && exists) {
XRE_AddJarManifestLocation(NS_SKIN_LOCATION, themeManifest);
} else {
themeManifest->SetNativeLeafName(NS_LITERAL_CSTRING("{972ce4c6-7e08-4474-a285-3208198ce6fd}"));
themeManifest->AppendNative(NS_LITERAL_CSTRING("chrome.manifest"));
XRE_AddManifestLocation(NS_SKIN_LOCATION, themeManifest);
}
#endif
}
}
}
#ifdef MOZ_B2G #ifdef MOZ_B2G
void void
nsXREDirProvider::LoadAppBundleDirs() nsXREDirProvider::LoadAppBundleDirs()
@ -890,7 +1019,7 @@ nsXREDirProvider::GetFilesInternal(const char* aProperty,
LoadDirsIntoArray(mAppBundleDirectories, LoadDirsIntoArray(mAppBundleDirectories,
kAppendNothing, directories); kAppendNothing, directories);
LoadDirsIntoArray(AddonManagerStartup::GetSingleton().ExtensionPaths(), LoadDirsIntoArray(mExtensionDirectories,
kAppendNothing, directories); kAppendNothing, directories);
rv = NS_NewArrayEnumerator(aResult, directories); rv = NS_NewArrayEnumerator(aResult, directories);
@ -907,7 +1036,7 @@ nsXREDirProvider::GetFilesInternal(const char* aProperty,
else if (!strcmp(aProperty, NS_EXT_PREFS_DEFAULTS_DIR_LIST)) { else if (!strcmp(aProperty, NS_EXT_PREFS_DEFAULTS_DIR_LIST)) {
nsCOMArray<nsIFile> directories; nsCOMArray<nsIFile> directories;
LoadDirsIntoArray(AddonManagerStartup::GetSingleton().ExtensionPaths(), LoadDirsIntoArray(mExtensionDirectories,
kAppendPrefDir, directories); kAppendPrefDir, directories);
if (mProfileDir) { if (mProfileDir) {
@ -934,7 +1063,7 @@ nsXREDirProvider::GetFilesInternal(const char* aProperty,
LoadDirsIntoArray(mAppBundleDirectories, LoadDirsIntoArray(mAppBundleDirectories,
kAppendChromeDir, kAppendChromeDir,
directories); directories);
LoadDirsIntoArray(AddonManagerStartup::GetSingleton().ExtensionPaths(), LoadDirsIntoArray(mExtensionDirectories,
kAppendChromeDir, kAppendChromeDir,
directories); directories);
@ -959,7 +1088,7 @@ nsXREDirProvider::GetFilesInternal(const char* aProperty,
LoadDirsIntoArray(mAppBundleDirectories, LoadDirsIntoArray(mAppBundleDirectories,
kAppendPlugins, kAppendPlugins,
directories); directories);
LoadDirsIntoArray(AddonManagerStartup::GetSingleton().ExtensionPaths(), LoadDirsIntoArray(mExtensionDirectories,
kAppendPlugins, kAppendPlugins,
directories); directories);
@ -1032,6 +1161,8 @@ nsXREDirProvider::DoStartup()
NS_WARNING("Failed to create Addons Manager."); NS_WARNING("Failed to create Addons Manager.");
} }
LoadExtensionBundleDirectories();
obsSvc->NotifyObservers(nullptr, "load-extension-defaults", nullptr); obsSvc->NotifyObservers(nullptr, "load-extension-defaults", nullptr);
obsSvc->NotifyObservers(nullptr, "profile-after-change", kStartup); obsSvc->NotifyObservers(nullptr, "profile-after-change", kStartup);

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

@ -126,6 +126,9 @@ protected:
nsresult LoadContentProcessTempDir(); nsresult LoadContentProcessTempDir();
#endif #endif
// Calculate and register extension and theme bundle directories.
void LoadExtensionBundleDirectories();
#ifdef MOZ_B2G #ifdef MOZ_B2G
// Calculate and register app-bundled extension directories. // Calculate and register app-bundled extension directories.
void LoadAppBundleDirs(); void LoadAppBundleDirs();
@ -148,6 +151,8 @@ protected:
nsCOMPtr<nsIFile> mContentProcessSandboxTempDir; nsCOMPtr<nsIFile> mContentProcessSandboxTempDir;
#endif #endif
nsCOMArray<nsIFile> mAppBundleDirectories; nsCOMArray<nsIFile> mAppBundleDirectories;
nsCOMArray<nsIFile> mExtensionDirectories;
nsCOMArray<nsIFile> mThemeDirectories;
}; };
#endif #endif