зеркало из https://github.com/mozilla/gecko-dev.git
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 (bug1356826
) Backed out changeset c861e23ec8ef (bug1356826
) Backed out changeset d47998fa24cd (bug1356826
) Backed out changeset b02e89c67132 (bug1356826
) Backed out changeset c46fed6e4f6a (bug1356826
) Backed out changeset 237268e3d9d2 (bug1356826
) Backed out changeset 527435fc20db (bug1356826
)
This commit is contained in:
Родитель
fcd9a5550a
Коммит
6559420d58
|
@ -1,7 +1,6 @@
|
|||
[addon-manager.xpi]
|
||||
[author-email.xpi]
|
||||
[child_process.xpi]
|
||||
skip-if = true
|
||||
[chrome.xpi]
|
||||
[content-permissions.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.
|
||||
// See the SCOPE constants in AddonManager.jsm for values to use here.
|
||||
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.
|
||||
// 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);
|
||||
});
|
||||
|
||||
let _resolveDelayedStartup;
|
||||
var delayedStartupPromise = new Promise(resolve => {
|
||||
_resolveDelayedStartup = resolve;
|
||||
});
|
||||
|
||||
var gBrowserInit = {
|
||||
delayedStartupFinished: false,
|
||||
|
||||
|
@ -1624,7 +1619,6 @@ var gBrowserInit = {
|
|||
|
||||
this.delayedStartupFinished = true;
|
||||
|
||||
_resolveDelayedStartup();
|
||||
Services.obs.notifyObservers(window, "browser-delayed-startup-finished");
|
||||
TelemetryTimestamps.add("delayedStartupFinished");
|
||||
},
|
||||
|
|
|
@ -1,89 +1,155 @@
|
|||
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) {
|
||||
let options = {
|
||||
manifest: {
|
||||
applications: {gecko: {id: details.id}},
|
||||
class MockAddon {
|
||||
constructor(props) {
|
||||
this._userDisabled = false;
|
||||
this.pendingOperations = 0;
|
||||
this.type = "extension";
|
||||
|
||||
name: details.name,
|
||||
|
||||
permissions: details.permissions,
|
||||
},
|
||||
};
|
||||
|
||||
if (details.iconURL) {
|
||||
options.manifest.icons = {"64": details.iconURL};
|
||||
for (let name in props) {
|
||||
if (name == "userDisabled") {
|
||||
this._userDisabled = props[name];
|
||||
}
|
||||
this[name] = props[name];
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
let xpi = AddonTestUtils.createTempXPIFile({
|
||||
"install.rdf": {
|
||||
id: details.id,
|
||||
name: details.name,
|
||||
version: "0.1",
|
||||
targetApplications: [{
|
||||
id: "toolkit@mozilla.org",
|
||||
minVersion: "0",
|
||||
maxVersion: "*",
|
||||
}],
|
||||
},
|
||||
});
|
||||
class MockProvider {
|
||||
constructor(...addons) {
|
||||
this.addons = new Set(addons);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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";
|
||||
|
||||
yield SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
["xpinstall.signatures.required", false],
|
||||
["extensions.autoDisableScopes", 15],
|
||||
["extensions.ui.ignoreUnsigned", true],
|
||||
],
|
||||
});
|
||||
|
||||
const ID1 = "addon1@tests.mozilla.org";
|
||||
yield createWebExtension({
|
||||
let mock1 = new MockAddon({
|
||||
id: ID1,
|
||||
name: "Test 1",
|
||||
userDisabled: true,
|
||||
permissions: ["history", "https://*/*"],
|
||||
iconURL: "foo-icon.png",
|
||||
seen: false,
|
||||
userPermissions: {
|
||||
permissions: ["history"],
|
||||
origins: ["https://*/*"],
|
||||
},
|
||||
iconURL: ICON_URL,
|
||||
});
|
||||
|
||||
const ID2 = "addon2@tests.mozilla.org";
|
||||
yield createXULExtension({
|
||||
let mock2 = new MockAddon({
|
||||
id: ID2,
|
||||
name: "Test 2",
|
||||
userDisabled: true,
|
||||
seen: false,
|
||||
userPermissions: {
|
||||
permissions: [],
|
||||
origins: [],
|
||||
},
|
||||
});
|
||||
|
||||
const ID3 = "addon3@tests.mozilla.org";
|
||||
yield createWebExtension({
|
||||
let mock3 = new MockAddon({
|
||||
id: ID3,
|
||||
name: "Test 3",
|
||||
permissions: ["<all_urls>"],
|
||||
isWebExtension: true,
|
||||
userDisabled: true,
|
||||
seen: false,
|
||||
userPermissions: {
|
||||
permissions: [],
|
||||
origins: ["<all_urls>"],
|
||||
}
|
||||
});
|
||||
|
||||
const ID4 = "addon4@tests.mozilla.org";
|
||||
yield createWebExtension({
|
||||
let mock4 = new MockAddon({
|
||||
id: ID4,
|
||||
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() {
|
||||
AddonManagerPrivate.unregisterProvider(provider);
|
||||
|
||||
// clear out ExtensionsUI state about sideloaded extensions so
|
||||
// subsequent tests don't get confused.
|
||||
ExtensionsUI.sideloaded.clear();
|
||||
|
@ -137,13 +203,17 @@ add_task(function* test_sideloading() {
|
|||
is(win.gViewController.currentViewId, VIEW, "about:addons is at extensions list");
|
||||
|
||||
// Check the contents of the notification, then choose "Cancel"
|
||||
checkNotification(panel, /\/foo-icon\.png$/, [
|
||||
checkNotification(panel, ICON_URL, [
|
||||
["webextPerms.hostDescription.allUrls"],
|
||||
["webextPerms.description.history"],
|
||||
]);
|
||||
|
||||
let disablePromise = promiseSetDisabled(mock1);
|
||||
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]);
|
||||
ok(addon1.seen, "Addon should be marked as seen");
|
||||
is(addon1.userDisabled, true, "Addon 1 should still be disabled");
|
||||
|
@ -175,8 +245,12 @@ add_task(function* test_sideloading() {
|
|||
checkNotification(panel, DEFAULT_ICON_URL, []);
|
||||
|
||||
// This time accept the install.
|
||||
disablePromise = promiseSetDisabled(mock2);
|
||||
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]);
|
||||
is(addon1.userDisabled, true, "Addon 1 should still be disabled");
|
||||
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"]]);
|
||||
|
||||
// Accept the permissions
|
||||
disablePromise = promiseSetDisabled(mock3);
|
||||
panel.button.click();
|
||||
value = yield disablePromise;
|
||||
is(value, false, "userDisabled should be set on addon 3");
|
||||
|
||||
addon3 = yield AddonManager.getAddonByID(ID3);
|
||||
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"]]);
|
||||
|
||||
// Accept the permissions
|
||||
disablePromise = promiseSetDisabled(mock4);
|
||||
panel.button.click();
|
||||
value = yield disablePromise;
|
||||
is(value, false, "userDisabled should be set on addon 4");
|
||||
|
||||
addon4 = yield AddonManager.getAddonByID(ID4);
|
||||
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");
|
||||
|
||||
yield new Promise(resolve => setTimeout(resolve, 100));
|
||||
|
||||
for (let addon of [addon1, addon2, addon3, addon4]) {
|
||||
addon.uninstall();
|
||||
}
|
||||
|
||||
yield BrowserTestUtils.removeTab(gBrowser.selectedTab);
|
||||
});
|
||||
|
|
|
@ -218,7 +218,7 @@ function checkNotification(panel, checkIcon, permissions) {
|
|||
let header = document.getElementById("addon-webext-perm-intro");
|
||||
|
||||
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") {
|
||||
ok(checkIcon(icon), "Notification icon is correct");
|
||||
} else {
|
||||
|
|
|
@ -12,8 +12,6 @@ Cu.import("resource://gre/modules/EventEmitter.jsm");
|
|||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "AddonManager",
|
||||
"resource://gre/modules/AddonManager.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "AddonManagerPrivate",
|
||||
"resource://gre/modules/AddonManager.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "PluralForm",
|
||||
"resource://gre/modules/PluralForm.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "RecentWindow",
|
||||
|
@ -37,7 +35,7 @@ this.ExtensionsUI = {
|
|||
sideloadListener: null,
|
||||
histogram: null,
|
||||
|
||||
async init() {
|
||||
init() {
|
||||
this.histogram = Services.telemetry.getHistogramById("EXTENSION_INSTALL_PROMPT_RESULT");
|
||||
|
||||
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-optional-permission-prompt");
|
||||
|
||||
await RecentWindow.getMostRecentBrowserWindow().delayedStartupPromise;
|
||||
|
||||
this._checkForSideloaded();
|
||||
},
|
||||
|
||||
async _checkForSideloaded() {
|
||||
let sideloaded = await AddonManagerPrivate.getNewSideloads();
|
||||
_checkForSideloaded() {
|
||||
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) {
|
||||
// No new side-loads. We're done.
|
||||
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);
|
||||
if (!sideloaded.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (let addon of sideloaded) {
|
||||
this.sideloaded.add(addon);
|
||||
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) {
|
||||
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) {
|
||||
|
@ -150,11 +146,6 @@ this.ExtensionsUI = {
|
|||
}
|
||||
|
||||
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);
|
||||
|
||||
// If this is an update with no promptable permissions, just apply it
|
||||
|
|
|
@ -529,12 +529,6 @@ interface nsIXPCComponents_Utils : nsISupports
|
|||
[implicit_jscontext]
|
||||
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]
|
||||
void setGCZeal(in long zeal);
|
||||
|
||||
|
|
|
@ -2916,7 +2916,7 @@ nsXPCComponents_Utils::SetWantXrays(HandleValue vscope, JSContext* cx)
|
|||
NS_IMETHODIMP
|
||||
nsXPCComponents_Utils::ForcePermissiveCOWs(JSContext* cx)
|
||||
{
|
||||
xpc::CrashIfNotInAutomation();
|
||||
CrashIfNotInAutomation();
|
||||
CompartmentPrivate::Get(CurrentGlobalOrNull(cx))->forcePermissiveCOWs = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -2927,7 +2927,7 @@ nsXPCComponents_Utils::ForcePrivilegedComponentsForScope(HandleValue vscope,
|
|||
{
|
||||
if (!vscope.isObject())
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
xpc::CrashIfNotInAutomation();
|
||||
CrashIfNotInAutomation();
|
||||
JSObject* scopeObj = js::UncheckedUnwrap(&vscope.toObject());
|
||||
XPCWrappedNativeScope* scope = ObjectScope(scopeObj);
|
||||
scope->ForcePrivilegedComponents();
|
||||
|
@ -3012,22 +3012,6 @@ nsXPCComponents_Utils::SetGCZeal(int32_t aValue, JSContext* cx)
|
|||
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
|
||||
nsXPCComponents_Utils::NukeSandbox(HandleValue obj, JSContext* cx)
|
||||
{
|
||||
|
|
|
@ -612,8 +612,8 @@ SpecialPowersObserverAPI.prototype = {
|
|||
let id = aMessage.data.id;
|
||||
let extension = this._extensions.get(id);
|
||||
this._extensions.delete(id);
|
||||
let done = () => this._sendReply(aMessage, "SPExtensionMessage", {id, type: "extensionUnloaded", args: []});
|
||||
extension.shutdown().then(done, done);
|
||||
extension.shutdown();
|
||||
this._sendReply(aMessage, "SPExtensionMessage", {id, type: "extensionUnloaded", args: []});
|
||||
return undefined;
|
||||
}
|
||||
|
||||
|
|
|
@ -36,7 +36,6 @@
|
|||
#include "mozilla/FinalizationWitnessService.h"
|
||||
#include "mozilla/NativeOSFileInternals.h"
|
||||
#include "mozilla/AddonContentPolicy.h"
|
||||
#include "mozilla/AddonManagerStartup.h"
|
||||
#include "mozilla/AddonPathService.h"
|
||||
|
||||
#if defined(XP_WIN)
|
||||
|
@ -127,7 +126,6 @@ NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(NativeFileWatcherService, Init)
|
|||
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(AddonContentPolicy)
|
||||
NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(AddonPathService, AddonPathService::GetInstance)
|
||||
NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(AddonManagerStartup, AddonManagerStartup::GetInstance)
|
||||
|
||||
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(NS_ADDONCONTENTPOLICY_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(NS_WEBREQUESTLISTENER_CID);
|
||||
|
||||
|
@ -199,7 +196,6 @@ static const Module::CIDEntry kToolkitCIDs[] = {
|
|||
{ &kNATIVE_OSFILE_INTERNALS_SERVICE_CID, false, nullptr, NativeOSFileInternalsServiceConstructor },
|
||||
{ &kNS_ADDONCONTENTPOLICY_CID, false, nullptr, AddonContentPolicyConstructor },
|
||||
{ &kNS_ADDON_PATH_SERVICE_CID, false, nullptr, AddonPathServiceConstructor },
|
||||
{ &kNS_ADDON_MANAGER_STARTUP_CID, false, nullptr, AddonManagerStartupConstructor },
|
||||
{ &kNATIVE_FILEWATCHER_SERVICE_CID, false, nullptr, NativeFileWatcherServiceConstructor },
|
||||
{ &kNS_WEBREQUESTLISTENER_CID, false, nullptr, nsWebRequestListenerConstructor },
|
||||
{ nullptr }
|
||||
|
@ -237,7 +233,6 @@ static const Module::ContractIDEntry kToolkitContracts[] = {
|
|||
{ NATIVE_OSFILE_INTERNALS_SERVICE_CONTRACTID, &kNATIVE_OSFILE_INTERNALS_SERVICE_CID },
|
||||
{ NS_ADDONCONTENTPOLICY_CONTRACTID, &kNS_ADDONCONTENTPOLICY_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 },
|
||||
{ NS_WEBREQUESTLISTENER_CONTRACTID, &kNS_WEBREQUESTLISTENER_CID },
|
||||
{ nullptr }
|
||||
|
|
|
@ -958,19 +958,14 @@ this.Extension = class extends ExtensionData {
|
|||
return super.initLocale(locale);
|
||||
}
|
||||
|
||||
startup() {
|
||||
this.startupPromise = this._startup();
|
||||
return this.startupPromise;
|
||||
}
|
||||
|
||||
async _startup() {
|
||||
this.started = false;
|
||||
async startup() {
|
||||
let started = false;
|
||||
|
||||
try {
|
||||
let [, perms] = await Promise.all([this.loadManifest(), ExtensionPermissions.get(this)]);
|
||||
|
||||
ExtensionManagement.startupExtension(this.uuid, this.addonData.resourceURI, this);
|
||||
this.started = true;
|
||||
started = true;
|
||||
|
||||
if (!this.hasShutdown) {
|
||||
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`);
|
||||
Cu.reportError(e);
|
||||
|
||||
if (this.started) {
|
||||
this.started = false;
|
||||
if (started) {
|
||||
ExtensionManagement.shutdownExtension(this.uuid);
|
||||
}
|
||||
|
||||
|
@ -1018,8 +1012,6 @@ this.Extension = class extends ExtensionData {
|
|||
|
||||
throw e;
|
||||
}
|
||||
|
||||
this.startupPromise = null;
|
||||
}
|
||||
|
||||
cleanupGeneratedFile() {
|
||||
|
@ -1041,22 +1033,10 @@ this.Extension = class extends ExtensionData {
|
|||
}).catch(Cu.reportError);
|
||||
}
|
||||
|
||||
async shutdown(reason) {
|
||||
try {
|
||||
if (this.startupPromise) {
|
||||
await this.startupPromise;
|
||||
}
|
||||
} catch (e) {
|
||||
Cu.reportError(e);
|
||||
}
|
||||
|
||||
shutdown(reason) {
|
||||
this.shutdownReason = reason;
|
||||
this.hasShutdown = true;
|
||||
|
||||
if (!this.started) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.cleanupFile ||
|
||||
["ADDON_INSTALL", "ADDON_UNINSTALL", "ADDON_UPGRADE", "ADDON_DOWNGRADE"].includes(reason)) {
|
||||
StartupCache.clearAddonData(this.id);
|
||||
|
|
|
@ -112,9 +112,6 @@ var Service = {
|
|||
// Called when an extension is unloaded.
|
||||
shutdownExtension(uuid) {
|
||||
let extension = this.uuidMap.get(uuid);
|
||||
if (!extension) {
|
||||
return;
|
||||
}
|
||||
this.uuidMap.delete(uuid);
|
||||
this.aps.setAddonHasPermissionCallback(extension.id, null);
|
||||
this.aps.setAddonLoadURICallback(extension.id, null);
|
||||
|
|
|
@ -50,7 +50,7 @@ class BackgroundPage extends HiddenExtensionPage {
|
|||
// console.
|
||||
if (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() {
|
||||
if (this.extension.addonData.instanceID) {
|
||||
AddonManager.getAddonByInstanceID(this.extension.addonData.instanceID)
|
||||
.then(addon => addon && addon.setDebugGlobal(null));
|
||||
.then(addon => addon.setDebugGlobal(null));
|
||||
}
|
||||
|
||||
super.shutdown();
|
||||
|
|
|
@ -64,9 +64,7 @@ this.runtime = class extends ExtensionAPI {
|
|||
fire.sync(details);
|
||||
});
|
||||
return () => {
|
||||
AddonManager.removeUpgradeListener(instanceID).catch(e => {
|
||||
// This can happen if we try this after shutdown is complete.
|
||||
});
|
||||
AddonManager.removeUpgradeListener(instanceID);
|
||||
};
|
||||
}).api(),
|
||||
|
||||
|
|
|
@ -638,11 +638,9 @@ ExtensionManager = {
|
|||
let extension = this.extensions.get(data.id);
|
||||
this.extensions.delete(data.id);
|
||||
|
||||
if (extension) {
|
||||
extension.shutdown();
|
||||
extension.shutdown();
|
||||
|
||||
DocumentManager.uninitExtension(extension);
|
||||
}
|
||||
DocumentManager.uninitExtension(extension);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -129,7 +129,5 @@ add_task(async function test_management_themes() {
|
|||
theme.unload(),
|
||||
extension.awaitMessage("onUninstalled"),
|
||||
]);
|
||||
|
||||
is(await extension.awaitMessage("onEnabled"), "Default", "default enabled");
|
||||
await extension.unload();
|
||||
});
|
||||
|
|
|
@ -90,8 +90,6 @@ const kSaveDelayMs = 1500;
|
|||
* automatically finalize the file when triggered. Defaults
|
||||
* to `profileBeforeChange`; exposed as an option for
|
||||
* testing.
|
||||
* - compression: A compression algorithm to use when reading and
|
||||
* writing the data.
|
||||
*/
|
||||
function JSONFile(config) {
|
||||
this.path = config.path;
|
||||
|
@ -108,11 +106,6 @@ function JSONFile(config) {
|
|||
}
|
||||
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._finalizeInternalBound = this._finalizeInternal.bind(this);
|
||||
this._finalizeAt.addBlocker("JSON store: writing data",
|
||||
|
@ -183,7 +176,7 @@ JSONFile.prototype = {
|
|||
let data = {};
|
||||
|
||||
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 (this.dataReady) {
|
||||
|
@ -293,9 +286,7 @@ JSONFile.prototype = {
|
|||
yield Promise.resolve(this._beforeSave());
|
||||
}
|
||||
yield OS.File.writeAtomic(this.path, bytes,
|
||||
Object.assign(
|
||||
{ tmpPath: this.path + ".tmp" },
|
||||
this._options));
|
||||
{ tmpPath: this.path + ".tmp" });
|
||||
}),
|
||||
|
||||
/**
|
||||
|
|
|
@ -2250,7 +2250,7 @@ var AddonManagerInternal = {
|
|||
throw Components.Exception("aInstanceID must be a symbol",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
|
||||
return this.getAddonByInstanceID(aInstanceID).then(addon => {
|
||||
this.getAddonByInstanceID(aInstanceID).then(addon => {
|
||||
if (!addon) {
|
||||
throw Error("No addon for instanceID:", aInstanceID.toString());
|
||||
}
|
||||
|
@ -3086,17 +3086,6 @@ this.AddonManagerPrivate = {
|
|||
.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() {
|
||||
return gBrowserUpdated;
|
||||
},
|
||||
|
@ -3665,7 +3654,7 @@ this.AddonManager = {
|
|||
},
|
||||
|
||||
removeUpgradeListener(aInstanceID) {
|
||||
return AddonManagerInternal.removeUpgradeListener(aInstanceID);
|
||||
AddonManagerInternal.removeUpgradeListener(aInstanceID);
|
||||
},
|
||||
|
||||
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",
|
||||
"resource://gre/modules/Extension.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "aomStartup",
|
||||
"@mozilla.org/addons/addon-manager-startup;1",
|
||||
"amIAddonManagerStartup");
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "rdfService",
|
||||
"@mozilla.org/rdf/rdf-service;1", "nsIRDFService");
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "uuidGen",
|
||||
|
@ -45,8 +42,6 @@ XPCOMUtils.defineLazyGetter(this, "AppInfo", () => {
|
|||
return AppInfo;
|
||||
});
|
||||
|
||||
const PREF_DISABLE_SECURITY = ("security.turn_off_all_security_so_that_" +
|
||||
"viruses_can_take_over_this_computer");
|
||||
|
||||
const ArrayBufferInputStream = Components.Constructor(
|
||||
"@mozilla.org/io/arraybuffer-input-stream;1",
|
||||
|
@ -134,46 +129,46 @@ function escaped(strings, ...values) {
|
|||
|
||||
|
||||
class AddonsList {
|
||||
constructor(file) {
|
||||
constructor(extensionsINI) {
|
||||
this.multiprocessIncompatibleIDs = new Set();
|
||||
this.extensions = [];
|
||||
this.themes = [];
|
||||
|
||||
if (!file.exists()) {
|
||||
if (!extensionsINI.exists()) {
|
||||
this.extensions = [];
|
||||
this.themes = [];
|
||||
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 dir = loc.path && new nsFile(loc.path);
|
||||
let parser = factory.createINIParser(extensionsINI);
|
||||
|
||||
for (let [id, addon] of Object.entries(loc.addons)) {
|
||||
if (addon.enabled && !addon.bootstrapped) {
|
||||
let file;
|
||||
if (dir) {
|
||||
file = dir.clone();
|
||||
try {
|
||||
file.appendRelativePath(addon.path);
|
||||
} catch (e) {
|
||||
file = new nsFile(addon.path);
|
||||
}
|
||||
} else {
|
||||
file = new nsFile(addon.path);
|
||||
}
|
||||
function readDirectories(section) {
|
||||
var dirs = [];
|
||||
var keys = parser.getKeys(section);
|
||||
for (let key of XPCOMUtils.IterStringEnumerator(keys)) {
|
||||
let descriptor = parser.getString(section, key);
|
||||
|
||||
addon.type = addon.type || "extension";
|
||||
|
||||
if (addon.type == "theme") {
|
||||
this.themes.push(file);
|
||||
} else {
|
||||
this.extensions.push(file);
|
||||
if (addon.enableShims) {
|
||||
this.multiprocessIncompatibleIDs.add(id);
|
||||
}
|
||||
}
|
||||
let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
|
||||
try {
|
||||
file.persistentDescriptor = descriptor;
|
||||
} catch (e) {
|
||||
// Throws if the directory doesn't exist, we can ignore this since the
|
||||
// platform will too.
|
||||
continue;
|
||||
}
|
||||
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 => {
|
||||
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())
|
||||
return file.equals(path);
|
||||
|
@ -213,7 +208,7 @@ var AddonTestUtils = {
|
|||
addonIntegrationService: null,
|
||||
addonsList: null,
|
||||
appInfo: null,
|
||||
addonStartup: null,
|
||||
extensionsINI: null,
|
||||
testUnpacked: false,
|
||||
useRealCertChecks: false,
|
||||
|
||||
|
@ -223,11 +218,8 @@ var AddonTestUtils = {
|
|||
// Get the profile directory for tests to use.
|
||||
this.profileDir = testScope.do_get_profile();
|
||||
|
||||
this.profileExtensions = this.profileDir.clone();
|
||||
this.profileExtensions.append("extensions");
|
||||
|
||||
this.addonStartup = this.profileDir.clone();
|
||||
this.addonStartup.append("addonStartup.json.lz4");
|
||||
this.extensionsINI = this.profileDir.clone();
|
||||
this.extensionsINI.append("extensions.ini");
|
||||
|
||||
// Register a temporary directory for the tests.
|
||||
this.tempDir = this.profileDir.clone();
|
||||
|
@ -251,9 +243,6 @@ var AddonTestUtils = {
|
|||
// By default don't disable add-ons from any scope
|
||||
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
|
||||
Services.prefs.setBoolPref("extensions.getAddons.cache.enabled", false);
|
||||
|
||||
|
@ -295,7 +284,10 @@ var AddonTestUtils = {
|
|||
}
|
||||
|
||||
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
|
||||
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
|
||||
*
|
||||
|
@ -448,10 +409,6 @@ var AddonTestUtils = {
|
|||
}
|
||||
},
|
||||
|
||||
getIDFromExtension(file) {
|
||||
return this.getIDFromManifest(this.getManifestURI(file));
|
||||
},
|
||||
|
||||
getIDFromManifest: Task.async(function*(manifestURI) {
|
||||
let body = yield fetch(manifestURI.spec);
|
||||
|
||||
|
@ -560,13 +517,15 @@ var AddonTestUtils = {
|
|||
* An optional boolean parameter to simulate the case where the
|
||||
* application has changed version since the last run. If not passed it
|
||||
* 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)
|
||||
throw new Error("Attempting to startup manager that was already started.");
|
||||
|
||||
if (appChanged && this.addonStartup.exists())
|
||||
this.addonStartup.remove(true);
|
||||
if (appChanged && this.extensionsINI.exists())
|
||||
this.extensionsINI.remove(true);
|
||||
|
||||
this.addonIntegrationService = Cc["@mozilla.org/addons/integration;1"]
|
||||
.getService(Ci.nsIObserver);
|
||||
|
@ -576,7 +535,9 @@ var AddonTestUtils = {
|
|||
this.emit("addon-manager-started");
|
||||
|
||||
// Load the add-ons list as it was after extension registration
|
||||
await this.loadAddonsList(true);
|
||||
this.loadAddonsList();
|
||||
|
||||
return Promise.resolve();
|
||||
},
|
||||
|
||||
promiseShutdownManager() {
|
||||
|
@ -606,12 +567,6 @@ var AddonTestUtils = {
|
|||
AddonManagerPrivate.unregisterProvider(XPIscope.XPIProvider);
|
||||
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)
|
||||
throw shutdownError;
|
||||
|
||||
|
@ -629,14 +584,8 @@ var AddonTestUtils = {
|
|||
});
|
||||
},
|
||||
|
||||
async loadAddonsList(flush = false) {
|
||||
if (flush) {
|
||||
let XPIScope = Cu.import("resource://gre/modules/addons/XPIProvider.jsm", {});
|
||||
XPIScope.XPIStates.save();
|
||||
await XPIScope.XPIStates._jsonFile._save();
|
||||
}
|
||||
|
||||
this.addonsList = new AddonsList(this.addonStartup);
|
||||
loadAddonsList() {
|
||||
this.addonsList = new AddonsList(this.extensionsINI);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -900,9 +849,9 @@ var AddonTestUtils = {
|
|||
*
|
||||
* @param {nsIFile} xpiFile
|
||||
* The XPI file to install.
|
||||
* @param {nsIFile} [installLocation = this.profileExtensions]
|
||||
* @param {nsIFile} installLocation
|
||||
* The install location (an nsIFile) to install into.
|
||||
* @param {string} [id]
|
||||
* @param {string} id
|
||||
* The ID to install as.
|
||||
* @param {boolean} [unpacked = this.testUnpacked]
|
||||
* 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
|
||||
* unpacked directory.
|
||||
*/
|
||||
async manuallyInstall(xpiFile, installLocation = this.profileExtensions, id = null, unpacked = this.testUnpacked) {
|
||||
if (id == null) {
|
||||
id = await this.getIDFromExtension(xpiFile);
|
||||
}
|
||||
|
||||
manuallyInstall(xpiFile, installLocation, id, unpacked = this.testUnpacked) {
|
||||
if (unpacked) {
|
||||
let dir = installLocation.clone();
|
||||
dir.append(id);
|
||||
|
|
|
@ -31,7 +31,6 @@ function startup(data, reason) {
|
|||
|
||||
function shutdown(data, reason) {
|
||||
extension.shutdown(BOOTSTRAP_REASON_TO_STRING_MAP[reason]);
|
||||
extension = null;
|
||||
}
|
||||
|
||||
function uninstall(data, reason) {
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -8,7 +8,7 @@
|
|||
/* globals ADDON_SIGNING, SIGNED_TYPES, BOOTSTRAP_REASONS, DB_SCHEMA,
|
||||
AddonInternal, XPIProvider, XPIStates, syncLoadManifestFromFile,
|
||||
isUsableAddon, recordAddonTelemetry, applyBlocklistChanges,
|
||||
flushChromeCaches, descriptorToPath */
|
||||
flushChromeCaches, canRunInSafeMode*/
|
||||
|
||||
var Cc = Components.classes;
|
||||
var Ci = Components.interfaces;
|
||||
|
@ -41,20 +41,23 @@ XPCOMUtils.defineLazyPreferenceGetter(this, "ALLOW_NON_MPC",
|
|||
Cu.import("resource://gre/modules/Log.jsm");
|
||||
const LOGGER_ID = "addons.xpi-utils";
|
||||
|
||||
const nsIFile = Components.Constructor("@mozilla.org/file/local;1", "nsIFile",
|
||||
"initWithPath");
|
||||
const nsIFile = Components.Constructor("@mozilla.org/file/local;1", "nsIFile");
|
||||
|
||||
// Create a new logger for use by the Addons XPI Provider Utils
|
||||
// (Requires AddonManager.jsm)
|
||||
var logger = Log.repository.getLogger(LOGGER_ID);
|
||||
|
||||
const KEY_PROFILEDIR = "ProfD";
|
||||
const FILE_DATABASE = "extensions.sqlite";
|
||||
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
|
||||
const LAST_SQLITE_DB_SCHEMA = 14;
|
||||
const PREF_DB_SCHEMA = "extensions.databaseSchema";
|
||||
const PREF_PENDING_OPERATIONS = "extensions.pendingOperations";
|
||||
const PREF_EM_ENABLED_ADDONS = "extensions.enabledAddons";
|
||||
const PREF_EM_AUTO_DISABLED_SCOPES = "extensions.autoDisableScopes";
|
||||
const PREF_E10S_BLOCKED_BY_ADDONS = "extensions.e10sBlockedByAddons";
|
||||
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_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
|
||||
const PROP_JSON_FIELDS = ["id", "syncGUID", "location", "version", "type",
|
||||
"internalName", "updateURL", "updateKey", "optionsURL",
|
||||
"optionsType", "optionsBrowserStyle", "aboutURL",
|
||||
"defaultLocale", "visible", "active", "userDisabled",
|
||||
"appDisabled", "pendingUninstall", "installDate",
|
||||
"updateDate", "applyBackgroundUpdates", "bootstrap", "path",
|
||||
"appDisabled", "pendingUninstall", "descriptor", "installDate",
|
||||
"updateDate", "applyBackgroundUpdates", "bootstrap",
|
||||
"skinnable", "size", "sourceURI", "releaseNotesURI",
|
||||
"softDisabled", "foreignInstall", "hasBinaryComponents",
|
||||
"strictCompatibility", "locales", "targetApplications",
|
||||
|
@ -80,9 +96,59 @@ const PROP_JSON_FIELDS = ["id", "syncGUID", "location", "version", "type",
|
|||
"seen", "dependencies", "hasEmbeddedWebExtension", "mpcOptedOut",
|
||||
"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
|
||||
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
|
||||
*/
|
||||
|
@ -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
|
||||
* a new object will be created and returned.
|
||||
|
@ -191,13 +301,6 @@ function copyProperties(aObject, aProperties, aTarget) {
|
|||
function DBAddonInternal(aLoaded) {
|
||||
AddonInternal.call(this);
|
||||
|
||||
if (aLoaded.descriptor) {
|
||||
if (!aLoaded.path) {
|
||||
aLoaded.path = descriptorToPath(aLoaded.descriptor);
|
||||
}
|
||||
delete aLoaded.descriptor;
|
||||
}
|
||||
|
||||
copyProperties(aLoaded, PROP_JSON_FIELDS, this);
|
||||
|
||||
if (!this.dependencies)
|
||||
|
@ -214,7 +317,7 @@ function DBAddonInternal(aLoaded) {
|
|||
this._key = this.location + ":" + this.id;
|
||||
|
||||
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;
|
||||
|
@ -395,6 +498,32 @@ this.XPIDatabase = {
|
|||
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
|
||||
* databases or making a new DB if needed.
|
||||
|
@ -501,10 +630,11 @@ this.XPIDatabase = {
|
|||
// Make AddonInternal instances from the loaded data and save them
|
||||
let addonDB = new Map();
|
||||
for (let loadedAddon of inputAddons.addons) {
|
||||
loadedAddon._sourceBundle = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
|
||||
try {
|
||||
loadedAddon._sourceBundle = new nsIFile(loadedAddon.path);
|
||||
loadedAddon._sourceBundle.persistentDescriptor = loadedAddon.descriptor;
|
||||
} 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
|
||||
logger.warn("Could not find source bundle for add-on " + loadedAddon.id, e);
|
||||
}
|
||||
|
@ -538,12 +668,21 @@ this.XPIDatabase = {
|
|||
*/
|
||||
upgradeDB(aRebuildOnError) {
|
||||
let upgradeTimer = AddonManagerPrivate.simpleTimer("XPIDB_upgradeDB_MS");
|
||||
|
||||
let schemaVersion = Services.prefs.getIntPref(PREF_DB_SCHEMA, 0);
|
||||
if (schemaVersion > LAST_SQLITE_DB_SCHEMA) {
|
||||
// we've upgraded before but the JSON file is gone, fall through
|
||||
// and rebuild from scratch
|
||||
AddonManagerPrivate.recordSimpleMeasure("XPIDB_startupError", "dbMissing");
|
||||
try {
|
||||
let schemaVersion = Services.prefs.getIntPref(PREF_DB_SCHEMA);
|
||||
if (schemaVersion <= LAST_SQLITE_DB_SCHEMA) {
|
||||
// we should have an older SQLITE database
|
||||
logger.debug("Attempting to upgrade from SQLITE database");
|
||||
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);
|
||||
|
@ -640,13 +779,8 @@ this.XPIDatabase = {
|
|||
|
||||
// If there is no migration data then load the list of add-on directories
|
||||
// that were active during the last run
|
||||
if (!this.migrateData) {
|
||||
this.activeBundles = Array.from(XPIStates.initialEnabledAddons(),
|
||||
addon => addon.path);
|
||||
if (!this.activeBundles.length)
|
||||
this.activeBundles = null;
|
||||
}
|
||||
|
||||
if (!this.migrateData)
|
||||
this.activeBundles = this.getActiveBundles();
|
||||
|
||||
if (aRebuildOnError) {
|
||||
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.
|
||||
* Return: Promise{integer} resolves / rejects with the result of the DB
|
||||
|
@ -903,11 +1234,11 @@ this.XPIDatabase = {
|
|||
*
|
||||
* @param aAddon
|
||||
* AddonInternal to add
|
||||
* @param aPath
|
||||
* The file path of the add-on
|
||||
* @param aDescriptor
|
||||
* The file descriptor of the add-on
|
||||
* @return The DBAddonInternal that was added to the database
|
||||
*/
|
||||
addAddonMetadata(aAddon, aPath) {
|
||||
addAddonMetadata(aAddon, aDescriptor) {
|
||||
if (!this.addonDB) {
|
||||
AddonManagerPrivate.recordSimpleMeasure("XPIDB_lateOpen_addMetadata",
|
||||
XPIProvider.runPhase);
|
||||
|
@ -915,7 +1246,7 @@ this.XPIDatabase = {
|
|||
}
|
||||
|
||||
let newAddon = new DBAddonInternal(aAddon);
|
||||
newAddon.path = aPath;
|
||||
newAddon.descriptor = aDescriptor;
|
||||
this.addonDB.set(newAddon._key, newAddon);
|
||||
if (newAddon.visible) {
|
||||
this.makeAddonVisible(newAddon);
|
||||
|
@ -933,11 +1264,11 @@ this.XPIDatabase = {
|
|||
* The DBAddonInternal to be replaced
|
||||
* @param aNewAddon
|
||||
* The new AddonInternal to add
|
||||
* @param aPath
|
||||
* The file path of the add-on
|
||||
* @param aDescriptor
|
||||
* The file descriptor of the add-on
|
||||
* @return The DBAddonInternal that was added to the database
|
||||
*/
|
||||
updateAddonMetadata(aOldAddon, aNewAddon, aPath) {
|
||||
updateAddonMetadata(aOldAddon, aNewAddon, aDescriptor) {
|
||||
this.removeAddonMetadata(aOldAddon);
|
||||
aNewAddon.syncGUID = aOldAddon.syncGUID;
|
||||
aNewAddon.installDate = aOldAddon.installDate;
|
||||
|
@ -947,7 +1278,7 @@ this.XPIDatabase = {
|
|||
aNewAddon.active = (aNewAddon.visible && !aNewAddon.disabled && !aNewAddon.pendingUninstall);
|
||||
|
||||
// addAddonMetadata does a saveChanges()
|
||||
return this.addAddonMetadata(aNewAddon, aPath);
|
||||
return this.addAddonMetadata(aNewAddon, aDescriptor);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -961,14 +1292,6 @@ this.XPIDatabase = {
|
|||
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
|
||||
* instances with the same ID as not visible.
|
||||
|
@ -983,12 +1306,9 @@ this.XPIDatabase = {
|
|||
logger.debug("Hide addon " + otherAddon._key);
|
||||
otherAddon.visible = false;
|
||||
otherAddon.active = false;
|
||||
|
||||
this.updateXPIStates(otherAddon);
|
||||
}
|
||||
}
|
||||
aAddon.visible = true;
|
||||
this.updateXPIStates(aAddon);
|
||||
this.saveChanges();
|
||||
},
|
||||
|
||||
|
@ -1010,13 +1330,11 @@ this.XPIDatabase = {
|
|||
logger.debug("Reveal addon " + addon._key);
|
||||
addon.visible = true;
|
||||
addon.active = true;
|
||||
this.updateXPIStates(addon);
|
||||
result = addon;
|
||||
} else {
|
||||
logger.debug("Hide addon " + addon._key);
|
||||
addon.visible = false;
|
||||
addon.active = false;
|
||||
this.updateXPIStates(addon);
|
||||
}
|
||||
}
|
||||
this.saveChanges();
|
||||
|
@ -1076,15 +1394,6 @@ this.XPIDatabase = {
|
|||
},
|
||||
|
||||
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;
|
||||
|
||||
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 = {
|
||||
|
@ -1205,17 +1602,20 @@ this.XPIDatabaseReconcile = {
|
|||
* @param aOldPlatformVersion
|
||||
* The version of the platform last run with this profile or null
|
||||
* if it is a new profile or the version is unknown
|
||||
* @param aMigrateData
|
||||
* If during startup the database had to be upgraded this will
|
||||
* contain data that used to be held about this add-on
|
||||
* @return a boolean indicating if flushing caches is required to complete
|
||||
* changing this add-on
|
||||
*/
|
||||
addMetadata(aInstallLocation, aId, aAddonState, aNewAddon, aOldAppVersion,
|
||||
aOldPlatformVersion) {
|
||||
aOldPlatformVersion, aMigrateData) {
|
||||
logger.debug("New add-on " + aId + " installed in " + aInstallLocation.name);
|
||||
|
||||
// If we had staged data for this add-on or we aren't recovering from a
|
||||
// corrupt database and we don't have migration data for this add-on then
|
||||
// this must be a new install.
|
||||
let isNewInstall = !!aNewAddon || !XPIDatabase.activeBundles;
|
||||
let isNewInstall = (!!aNewAddon) || (!XPIDatabase.activeBundles && !aMigrateData);
|
||||
|
||||
// If it's a new install and we haven't yet loaded the manifest then it
|
||||
// must be something dropped directly into the install location
|
||||
|
@ -1225,7 +1625,8 @@ this.XPIDatabaseReconcile = {
|
|||
try {
|
||||
if (!aNewAddon) {
|
||||
// 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);
|
||||
}
|
||||
// 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
|
||||
aNewAddon.appDisabled = !isUsableAddon(aNewAddon);
|
||||
|
||||
if (aMigrateData) {
|
||||
// If there is migration data then apply it.
|
||||
logger.debug("Migrating data from old database");
|
||||
|
||||
DB_MIGRATE_METADATA.forEach(function(aProp) {
|
||||
// A theme's disabled state is determined by the selected theme
|
||||
// preference which is read in loadManifestFromRDF
|
||||
if (aProp == "userDisabled" && aNewAddon.type == "theme")
|
||||
return;
|
||||
|
||||
if (aProp in aMigrateData)
|
||||
aNewAddon[aProp] = aMigrateData[aProp];
|
||||
});
|
||||
|
||||
// Force all non-profile add-ons to be foreignInstalls since they can't
|
||||
// have been installed through the API
|
||||
aNewAddon.foreignInstall |= aInstallLocation.name != KEY_APP_PROFILE;
|
||||
|
||||
// Some properties should only be migrated if the add-on hasn't changed.
|
||||
// The version property isn't a perfect check for this but covers the
|
||||
// vast majority of cases.
|
||||
if (aMigrateData.version == aNewAddon.version) {
|
||||
logger.debug("Migrating compatibility info");
|
||||
if ("targetApplications" in aMigrateData)
|
||||
aNewAddon.applyCompatibilityUpdate(aMigrateData, true);
|
||||
}
|
||||
|
||||
// Since the DB schema has changed make sure softDisabled is correct
|
||||
applyBlocklistChanges(aNewAddon, aNewAddon, aOldAppVersion,
|
||||
aOldPlatformVersion);
|
||||
}
|
||||
|
||||
// The default theme is never a foreign install
|
||||
if (aNewAddon.type == "theme" && aNewAddon.internalName == XPIProvider.defaultSkin)
|
||||
aNewAddon.foreignInstall = false;
|
||||
|
@ -1275,12 +1708,11 @@ this.XPIDatabaseReconcile = {
|
|||
|
||||
// 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.
|
||||
aNewAddon.seen = (aInstallLocation.name != KEY_APP_PROFILE &&
|
||||
!aOldAppVersion);
|
||||
aNewAddon.seen = !aOldAppVersion;
|
||||
}
|
||||
}
|
||||
|
||||
return XPIDatabase.addAddonMetadata(aNewAddon, aAddonState.path);
|
||||
return XPIDatabase.addAddonMetadata(aNewAddon, aAddonState.descriptor);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -1321,7 +1753,8 @@ this.XPIDatabaseReconcile = {
|
|||
try {
|
||||
// If there isn't an updated install manifest for this add-on then load it.
|
||||
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);
|
||||
applyBlocklistChanges(aOldAddon, aNewAddon);
|
||||
|
||||
|
@ -1352,11 +1785,11 @@ this.XPIDatabaseReconcile = {
|
|||
aNewAddon.updateDate = aAddonState.mtime;
|
||||
|
||||
// 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.
|
||||
*
|
||||
* @param aInstallLocation
|
||||
|
@ -1369,10 +1802,10 @@ this.XPIDatabaseReconcile = {
|
|||
* @return a boolean indicating if flushing caches is required to complete
|
||||
* changing this add-on
|
||||
*/
|
||||
updatePath(aInstallLocation, aOldAddon, aAddonState) {
|
||||
logger.debug("Add-on " + aOldAddon.id + " moved to " + aAddonState.path);
|
||||
aOldAddon.path = aAddonState.path;
|
||||
aOldAddon._sourceBundle = new nsIFile(aAddonState.path);
|
||||
updateDescriptor(aInstallLocation, aOldAddon, aAddonState) {
|
||||
logger.debug("Add-on " + aOldAddon.id + " moved to " + aAddonState.descriptor);
|
||||
aOldAddon.descriptor = aAddonState.descriptor;
|
||||
aOldAddon._sourceBundle.persistentDescriptor = aAddonState.descriptor;
|
||||
|
||||
return aOldAddon;
|
||||
},
|
||||
|
@ -1407,7 +1840,8 @@ this.XPIDatabaseReconcile = {
|
|||
// then fetch that property now
|
||||
if (aOldAddon.signedState === undefined && ADDON_SIGNING &&
|
||||
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);
|
||||
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
|
||||
// properties of the currently-installed add-ons.
|
||||
if (aReloadMetadata) {
|
||||
let file = new nsIFile(aAddonState.path);
|
||||
let file = new nsIFile()
|
||||
file.persistentDescriptor = aAddonState.descriptor;
|
||||
let manifest = syncLoadManifestFromFile(file, aInstallLocation);
|
||||
|
||||
// Avoid re-reading these properties from manifest,
|
||||
|
@ -1472,7 +1907,7 @@ this.XPIDatabaseReconcile = {
|
|||
};
|
||||
|
||||
// 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) => {
|
||||
try {
|
||||
return aAddon._sourceBundle.exists();
|
||||
|
@ -1522,14 +1957,17 @@ this.XPIDatabaseReconcile = {
|
|||
// Did time change in the wrong direction?
|
||||
if (xpiState.mtime < oldAddon.updateDate) {
|
||||
XPIProvider.setTelemetry(oldAddon.id, "olderFile", {
|
||||
name: XPIProvider._mostRecentlyModifiedFile[id],
|
||||
mtime: xpiState.mtime,
|
||||
oldtime: oldAddon.updateDate
|
||||
});
|
||||
} else {
|
||||
XPIProvider.setTelemetry(oldAddon.id, "modifiedFile",
|
||||
XPIProvider._mostRecentlyModifiedFile[id]);
|
||||
}
|
||||
}
|
||||
|
||||
let wasDisabled = oldAddon.appDisabled;
|
||||
let oldPath = oldAddon.path || descriptorToPath(oldAddon.descriptor);
|
||||
|
||||
// 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
|
||||
|
@ -1542,8 +1980,8 @@ this.XPIDatabaseReconcile = {
|
|||
(aUpdateCompatibility && (installLocation.name == KEY_APP_GLOBAL ||
|
||||
installLocation.name == KEY_APP_SYSTEM_DEFAULTS))) {
|
||||
newAddon = this.updateMetadata(installLocation, oldAddon, xpiState, newAddon);
|
||||
} else if (oldPath != xpiState.path) {
|
||||
newAddon = this.updatePath(installLocation, oldAddon, xpiState);
|
||||
} else if (oldAddon.descriptor != xpiState.descriptor) {
|
||||
newAddon = this.updateDescriptor(installLocation, oldAddon, xpiState);
|
||||
} else if (aUpdateCompatibility || aSchemaChange) {
|
||||
// Check compatility when the application version and/or schema
|
||||
// version has changed. A schema change also reloads metadata from
|
||||
|
@ -1624,6 +2062,7 @@ this.XPIDatabaseReconcile = {
|
|||
let previousVisible = this.getVisibleAddons(previousAddons);
|
||||
let currentVisible = this.flattenByID(currentAddons, hideLocation);
|
||||
let sawActiveTheme = false;
|
||||
XPIProvider.bootstrappedAddons = {};
|
||||
|
||||
// Pass over the new set of visible add-ons, record any changes that occured
|
||||
// during startup and call bootstrap install/uninstall scripts as necessary
|
||||
|
@ -1634,7 +2073,7 @@ this.XPIDatabaseReconcile = {
|
|||
if (currentAddon._installLocation.name != KEY_APP_GLOBAL)
|
||||
XPIProvider.allAppGlobal = false;
|
||||
|
||||
let isActive = !currentAddon.disabled && !currentAddon.pendingUninstall;
|
||||
let isActive = !currentAddon.disabled;
|
||||
let wasActive = previousAddon ? previousAddon.active : currentAddon.active
|
||||
|
||||
if (!previousAddon) {
|
||||
|
@ -1649,7 +2088,7 @@ this.XPIDatabaseReconcile = {
|
|||
if (currentAddon.type == "theme")
|
||||
isActive = currentAddon.internalName == XPIProvider.currentSkin;
|
||||
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
|
||||
// then it was probably either softDisabled or userDisabled
|
||||
|
@ -1701,7 +2140,8 @@ this.XPIDatabaseReconcile = {
|
|||
|
||||
if (currentAddon.bootstrap) {
|
||||
// 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,
|
||||
"install", installReason,
|
||||
{ oldVersion: previousAddon.version });
|
||||
|
@ -1720,6 +2160,19 @@ this.XPIDatabaseReconcile = {
|
|||
XPIDatabase.makeAddonVisible(currentAddon);
|
||||
currentAddon.active = isActive;
|
||||
|
||||
// Make sure the bootstrap information is up to date for this ID
|
||||
if (currentAddon.bootstrap && currentAddon.active) {
|
||||
XPIProvider.bootstrappedAddons[id] = {
|
||||
version: currentAddon.version,
|
||||
type: currentAddon.type,
|
||||
descriptor: currentAddon._sourceBundle.persistentDescriptor,
|
||||
multiprocessCompatible: currentAddon.multiprocessCompatible,
|
||||
runInSafeMode: canRunInSafeMode(currentAddon),
|
||||
dependencies: currentAddon.dependencies,
|
||||
hasEmbeddedWebExtension: currentAddon.hasEmbeddedWebExtension,
|
||||
};
|
||||
}
|
||||
|
||||
if (currentAddon.active && currentAddon.internalName == XPIProvider.selectedSkin)
|
||||
sawActiveTheme = true;
|
||||
}
|
||||
|
@ -1740,7 +2193,6 @@ this.XPIDatabaseReconcile = {
|
|||
XPIProvider.unloadBootstrapScope(previousAddon.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
|
||||
flushChromeCaches();
|
||||
|
@ -1771,6 +2223,8 @@ this.XPIDatabaseReconcile = {
|
|||
}
|
||||
XPIStates.save();
|
||||
|
||||
XPIProvider.persistBootstrappedAddons();
|
||||
|
||||
// Clear out any cached migration data.
|
||||
XPIDatabase.migrateData = null;
|
||||
XPIDatabase.saveChanges();
|
||||
|
|
|
@ -14,7 +14,6 @@ TEST_DIRS += ['test']
|
|||
|
||||
XPIDL_SOURCES += [
|
||||
'amIAddonManager.idl',
|
||||
'amIAddonManagerStartup.idl',
|
||||
'amIAddonPathService.idl',
|
||||
'amIWebInstallPrompt.idl',
|
||||
]
|
||||
|
@ -45,14 +44,12 @@ JAR_MANIFESTS += ['jar.mn']
|
|||
|
||||
EXPORTS.mozilla += [
|
||||
'AddonContentPolicy.h',
|
||||
'AddonManagerStartup.h',
|
||||
'AddonManagerWebAPI.h',
|
||||
'AddonPathService.h',
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'AddonContentPolicy.cpp',
|
||||
'AddonManagerStartup.cpp',
|
||||
'AddonManagerWebAPI.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",
|
||||
"resource://testing-common/MockRegistry.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "aomStartup",
|
||||
"@mozilla.org/addons/addon-manager-startup;1",
|
||||
"amIAddonManagerStartup");
|
||||
|
||||
const {
|
||||
awaitPromise,
|
||||
createAppInfo,
|
||||
|
@ -75,6 +71,7 @@ const {
|
|||
createTempWebExtensionFile,
|
||||
createUpdateRDF,
|
||||
getFileForAddon,
|
||||
manuallyInstall,
|
||||
manuallyUninstall,
|
||||
promiseAddonEvent,
|
||||
promiseCompleteAllInstalls,
|
||||
|
@ -93,11 +90,6 @@ const {
|
|||
writeFilesToZip
|
||||
} = AddonTestUtils;
|
||||
|
||||
function manuallyInstall(...args) {
|
||||
return AddonTestUtils.awaitPromise(
|
||||
AddonTestUtils.manuallyInstall(...args));
|
||||
}
|
||||
|
||||
// WebExtension wrapper for ease of testing
|
||||
ExtensionTestUtils.init(this);
|
||||
|
||||
|
@ -110,9 +102,9 @@ Object.defineProperty(this, "gAppInfo", {
|
|||
},
|
||||
});
|
||||
|
||||
Object.defineProperty(this, "gAddonStartup", {
|
||||
Object.defineProperty(this, "gExtensionsINI", {
|
||||
get() {
|
||||
return AddonTestUtils.addonStartup.clone();
|
||||
return AddonTestUtils.extensionsINI.clone();
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -208,8 +200,6 @@ this.BootstrapMonitor = {
|
|||
startupPromises: [],
|
||||
installPromises: [],
|
||||
|
||||
restartfulIds: new Set(),
|
||||
|
||||
init() {
|
||||
this.inited = true;
|
||||
Services.obs.addObserver(this, "bootstrapmonitor-event");
|
||||
|
@ -326,13 +316,9 @@ this.BootstrapMonitor = {
|
|||
}
|
||||
|
||||
if (info.event == "uninstall") {
|
||||
// We currently support registering, but not unregistering,
|
||||
// restartful add-on manifests during xpcshell AOM "restarts".
|
||||
if (!this.restartfulIds.has(id)) {
|
||||
// Chrome should be unregistered at this point
|
||||
let isRegistered = isManifestRegistered(installPath);
|
||||
do_check_false(isRegistered);
|
||||
}
|
||||
// Chrome should be unregistered at this point
|
||||
let isRegistered = isManifestRegistered(installPath);
|
||||
do_check_false(isRegistered);
|
||||
|
||||
this.installed.delete(id);
|
||||
this.uninstalled.set(id, info)
|
||||
|
@ -377,7 +363,8 @@ function do_check_in_crash_annotation(aId, aVersion) {
|
|||
}
|
||||
|
||||
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(",");
|
||||
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;
|
||||
}
|
||||
|
||||
async function getXSJSON() {
|
||||
await AddonTestUtils.loadAddonsList(true);
|
||||
|
||||
return aomStartup.readStartupData();
|
||||
}
|
||||
|
||||
add_task(function* detect_touches() {
|
||||
startupManager();
|
||||
let [/* pe */, pd, /* ue */, ud] = yield promiseAddonsByIDs([
|
||||
|
@ -154,6 +148,10 @@ add_task(function* detect_touches() {
|
|||
let manifest = ueDir.clone();
|
||||
manifest.append("install.rdf");
|
||||
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.
|
||||
let udDir = profileDir.clone();
|
||||
|
@ -163,7 +161,7 @@ add_task(function* detect_touches() {
|
|||
checkChange(XS, manifest, true);
|
||||
// Finally, the case we actually care about...
|
||||
// We *don't* notice changing another file for disabled unpacked add-on.
|
||||
let otherFile = udDir.clone();
|
||||
otherFile = udDir.clone();
|
||||
otherFile.append("extraFile.js");
|
||||
checkChange(XS, otherFile, false);
|
||||
|
||||
|
@ -175,7 +173,7 @@ add_task(function* detect_touches() {
|
|||
ud.userDisabled = false;
|
||||
let xState = XS.getAddon("app-profile", ud.id);
|
||||
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"
|
||||
]);
|
||||
pe.uninstall();
|
||||
|
||||
let xpiState = yield getXSJSON();
|
||||
do_check_false("packed-enabled@tests.mozilla.org" in xpiState["app-profile"].addons);
|
||||
let xpiState = Services.prefs.getCharPref("extensions.xpiState");
|
||||
do_check_false(xpiState.includes("\"packed-enabled@tests.mozilla.org\""));
|
||||
});
|
||||
|
||||
/*
|
||||
|
@ -208,7 +205,7 @@ add_task(function* install_bootstrap() {
|
|||
let xState = XS.getAddon("app-profile", newAddon.id);
|
||||
do_check_true(!!xState);
|
||||
do_check_true(xState.enabled);
|
||||
do_check_eq(xState.mtime, newAddon.updateDate.getTime());
|
||||
do_check_eq(xState.scanTime, newAddon.updateDate.getTime());
|
||||
newAddon.uninstall();
|
||||
});
|
||||
|
||||
|
@ -241,7 +238,7 @@ add_task(function* install_restart() {
|
|||
xState = XS.getAddon("app-profile", newID);
|
||||
do_check_true(xState);
|
||||
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,
|
||||
// and doesn't change over restart.
|
||||
|
|
|
@ -81,12 +81,8 @@ function getUninstallNewVersion() {
|
|||
}
|
||||
|
||||
function do_check_bootstrappedPref(aCallback) {
|
||||
let XPIScope = AM_Cu.import("resource://gre/modules/addons/XPIProvider.jsm", {});
|
||||
|
||||
let data = {};
|
||||
for (let entry of XPIScope.XPIStates.bootstrappedAddons()) {
|
||||
data[entry.id] = entry;
|
||||
}
|
||||
let data = Services.prefs.getCharPref("extensions.bootstrappedAddons");
|
||||
data = JSON.parse(data);
|
||||
|
||||
AddonManager.getAddonsByTypes(["extension"], function(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.type, addon.type);
|
||||
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);
|
||||
|
||||
|
@ -120,7 +116,7 @@ function run_test() {
|
|||
|
||||
do_check_false(gExtensionsJSON.exists());
|
||||
|
||||
do_check_false(gAddonStartup.exists());
|
||||
do_check_false(gExtensionsINI.exists());
|
||||
|
||||
run_test_1();
|
||||
}
|
||||
|
@ -174,6 +170,8 @@ function run_test_1() {
|
|||
}
|
||||
|
||||
function check_test_1(installSyncGUID) {
|
||||
do_check_false(gExtensionsINI.exists());
|
||||
|
||||
AddonManager.getAllInstalls(function(installs) {
|
||||
// There should be no active installs now since the install completed and
|
||||
// doesn't require a restart.
|
||||
|
@ -261,7 +259,7 @@ function run_test_3() {
|
|||
do_check_eq(getShutdownNewVersion(), undefined);
|
||||
do_check_not_in_crash_annotation(ID1, "1.0");
|
||||
|
||||
do_check_true(gAddonStartup.exists());
|
||||
do_check_false(gExtensionsINI.exists());
|
||||
|
||||
AddonManager.getAddonByID(ID1, function(b1) {
|
||||
do_check_neq(b1, null);
|
||||
|
@ -1055,8 +1053,6 @@ function run_test_22() {
|
|||
|
||||
let file = manuallyInstall(do_get_addon("test_bootstrap1_1"), profileDir,
|
||||
ID1);
|
||||
if (file.isDirectory())
|
||||
file.append("install.rdf");
|
||||
|
||||
// Make it look old so changes are detected
|
||||
setExtensionModifiedTime(file, file.lastModifiedTime - 5000);
|
||||
|
@ -1206,7 +1202,7 @@ function run_test_24() {
|
|||
|
||||
Promise.all([BootstrapMonitor.promiseAddonStartup(ID2),
|
||||
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");
|
||||
BootstrapMonitor.checkAddonInstalled(ID1, "1.0");
|
||||
BootstrapMonitor.checkAddonStarted(ID1, "1.0");
|
||||
|
@ -1227,13 +1223,10 @@ function run_test_24() {
|
|||
BootstrapMonitor.checkAddonInstalled(ID2, "1.0");
|
||||
BootstrapMonitor.checkAddonNotStarted(ID2);
|
||||
|
||||
// Break the JSON.
|
||||
let data = aomStartup.readStartupData();
|
||||
data["app-profile"].addons[ID1].path += "foo";
|
||||
|
||||
await OS.File.writeAtomic(gAddonStartup.path,
|
||||
new TextEncoder().encode(JSON.stringify(data)),
|
||||
{compression: "lz4"});
|
||||
// Break the preference
|
||||
let bootstrappedAddons = JSON.parse(Services.prefs.getCharPref("extensions.bootstrappedAddons"));
|
||||
bootstrappedAddons[ID1].descriptor += "foo";
|
||||
Services.prefs.setCharPref("extensions.bootstrappedAddons", JSON.stringify(bootstrappedAddons));
|
||||
|
||||
startupManager(false);
|
||||
|
||||
|
@ -1337,8 +1330,6 @@ function run_test_27() {
|
|||
BootstrapMonitor.checkAddonInstalled(ID1, "1.0");
|
||||
BootstrapMonitor.checkAddonNotStarted(ID1);
|
||||
|
||||
BootstrapMonitor.restartfulIds.add(ID1);
|
||||
|
||||
installAllFiles([do_get_addon("test_bootstrap1_4")], function() {
|
||||
// Updating disabled things happens immediately
|
||||
BootstrapMonitor.checkAddonNotInstalled(ID1);
|
||||
|
|
|
@ -9,7 +9,7 @@ const PREF_GENERAL_SKINS_SELECTEDSKIN = "general.skins.selectedSkin";
|
|||
const profileDir = gProfD.clone();
|
||||
profileDir.append("extensions");
|
||||
|
||||
async function run_test() {
|
||||
function run_test() {
|
||||
do_test_pending();
|
||||
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2");
|
||||
|
||||
|
@ -38,7 +38,7 @@ async function run_test() {
|
|||
}]
|
||||
}, profileDir);
|
||||
|
||||
await promiseStartupManager();
|
||||
startupManager();
|
||||
|
||||
do_check_eq(Services.prefs.getCharPref(PREF_GENERAL_SKINS_SELECTEDSKIN), "classic/1.0");
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
const profileDir = gProfD.clone();
|
||||
profileDir.append("extensions");
|
||||
|
||||
async function run_test() {
|
||||
function run_test() {
|
||||
do_test_pending();
|
||||
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.
|
||||
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_eq(a.version, "1.0");
|
||||
do_check_false(a.userDisabled);
|
||||
|
@ -47,7 +47,7 @@ async function run_test() {
|
|||
}]
|
||||
}, profileDir);
|
||||
|
||||
await promiseRestartManager();
|
||||
restartManager();
|
||||
|
||||
AddonManager.getAddonByID("addon1@tests.mozilla.org", function(a2) {
|
||||
do_check_neq(a2, null);
|
||||
|
|
|
@ -123,10 +123,10 @@ function run_test_1() {
|
|||
function run_test_2() {
|
||||
restartManager();
|
||||
|
||||
installAllFiles([do_get_addon("test_bug587088_1")], async function() {
|
||||
await promiseRestartManager();
|
||||
installAllFiles([do_get_addon("test_bug587088_1")], function() {
|
||||
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");
|
||||
|
||||
// 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);
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
fstream.close();
|
||||
|
||||
await promiseRestartManager();
|
||||
restartManager();
|
||||
|
||||
AddonManager.getAddonByID("addon1@tests.mozilla.org", function(a1_4) {
|
||||
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() {
|
||||
installAllFiles([do_get_addon("test_bug595573")], async function() {
|
||||
await promiseRestartManager();
|
||||
installAllFiles([do_get_addon("test_bug595573")], function() {
|
||||
restartManager();
|
||||
|
||||
AddonManager.getAddonByID("{2f69dacd-03df-4150-a9f1-e8a7b2748829}", function(a1) {
|
||||
do_check_neq(a1, null);
|
||||
|
|
|
@ -58,14 +58,14 @@ function end_test() {
|
|||
testserver.stop(do_test_finished);
|
||||
}
|
||||
|
||||
async function run_test_1() {
|
||||
function run_test_1() {
|
||||
var time = Date.now();
|
||||
var dir = writeInstallRDFForExtension(addon1, userDir);
|
||||
setExtensionModifiedTime(dir, time);
|
||||
|
||||
manuallyInstall(do_get_addon("test_bug655254_2"), userDir, "addon2@tests.mozilla.org");
|
||||
|
||||
await promiseStartupManager();
|
||||
startupManager();
|
||||
|
||||
AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",
|
||||
"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);
|
||||
|
||||
a1.findUpdates({
|
||||
async onUpdateFinished() {
|
||||
await promiseRestartManager();
|
||||
onUpdateFinished() {
|
||||
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_false(a1_2.appDisabled);
|
||||
do_check_true(a1_2.isActive);
|
||||
|
@ -100,7 +100,7 @@ async function run_test_1() {
|
|||
userDir.append(gAppInfo.ID);
|
||||
do_check_true(userDir.exists());
|
||||
|
||||
await promiseStartupManager(false);
|
||||
startupManager(false);
|
||||
|
||||
AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",
|
||||
"addon2@tests.mozilla.org"], function([a1_3, a2_3]) {
|
||||
|
@ -125,7 +125,7 @@ async function run_test_1() {
|
|||
|
||||
// Set up the profile
|
||||
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_false(a2.appDisabled);
|
||||
do_check_true(a2.isActive);
|
||||
|
@ -143,7 +143,7 @@ function run_test_2() {
|
|||
userDir.append(gAppInfo.ID);
|
||||
do_check_true(userDir.exists());
|
||||
|
||||
await promiseStartupManager(false);
|
||||
startupManager(false);
|
||||
|
||||
AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",
|
||||
"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
|
||||
async function run_test_1() {
|
||||
function run_test_1() {
|
||||
writeInstallRDFForExtension(addon1, profileDir);
|
||||
writeInstallRDFForExtension(addon2, profileDir);
|
||||
writeInstallRDFForExtension(addon3, profileDir);
|
||||
writeInstallRDFForExtension(addon4, profileDir);
|
||||
|
||||
await promiseStartupManager();
|
||||
startupManager();
|
||||
|
||||
AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",
|
||||
"addon2@tests.mozilla.org",
|
||||
|
@ -104,7 +104,7 @@ async function run_test_1() {
|
|||
installAllFiles([
|
||||
do_get_addon("test_bug659772"),
|
||||
do_get_addon("test_bootstrap1_1")
|
||||
], async function() {
|
||||
], function() {
|
||||
shutdownManager();
|
||||
|
||||
// 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.uninstall_reason");
|
||||
|
||||
await promiseStartupManager(false);
|
||||
startupManager(false);
|
||||
|
||||
AddonManager.getAddonsByIDs(["addon1@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
|
||||
async function run_test_2() {
|
||||
function run_test_2() {
|
||||
restartManager();
|
||||
|
||||
shutdownManager();
|
||||
|
@ -204,7 +204,7 @@ async function run_test_2() {
|
|||
writeInstallRDFForExtension(addon3, profileDir);
|
||||
writeInstallRDFForExtension(addon4, profileDir);
|
||||
|
||||
await promiseStartupManager();
|
||||
startupManager();
|
||||
|
||||
AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",
|
||||
"addon2@tests.mozilla.org",
|
||||
|
@ -245,7 +245,7 @@ async function run_test_2() {
|
|||
do_get_addon("test_bootstrap1_1")
|
||||
], function() { do_execute_soon(prepare_schema_migrate); });
|
||||
|
||||
async function prepare_schema_migrate() {
|
||||
function prepare_schema_migrate() {
|
||||
shutdownManager();
|
||||
|
||||
// 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");
|
||||
|
||||
gAppInfo.version = "2";
|
||||
await promiseStartupManager(true);
|
||||
startupManager(true);
|
||||
|
||||
AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",
|
||||
"addon2@tests.mozilla.org",
|
||||
|
|
|
@ -4,10 +4,10 @@
|
|||
// Tests the extensions.defaultProviders.enabled pref which turns
|
||||
// off the default XPIProvider and LightweightThemeManager.
|
||||
|
||||
async function run_test() {
|
||||
function run_test() {
|
||||
Services.prefs.setBoolPref("extensions.defaultProviders.enabled", false);
|
||||
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2");
|
||||
await promiseStartupManager();
|
||||
startupManager();
|
||||
do_check_false(AddonManager.isInstallEnabled("application/x-xpinstall"));
|
||||
Services.prefs.clearUserPref("extensions.defaultProviders.enabled");
|
||||
}
|
||||
|
|
|
@ -32,14 +32,14 @@ function run_test() {
|
|||
|
||||
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_not_in_crash_annotation(addon1.id, addon1.version);
|
||||
|
||||
writeInstallRDFForExtension(addon1, profileDir, 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) {
|
||||
do_check_neq(newa1, null);
|
||||
|
|
|
@ -1,23 +1,12 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* 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";
|
||||
|
||||
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() {
|
||||
BootstrapMonitor.init();
|
||||
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.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.");
|
||||
|
||||
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.
|
||||
yield promiseRestartManager();
|
||||
|
||||
Assert.ok(!(ID in getBootstrappedAddons()),
|
||||
let persisted = JSON.parse(Services.prefs.getCharPref("extensions.bootstrappedAddons"));
|
||||
Assert.ok(!(ID in persisted),
|
||||
"Experiment add-on not persisted to bootstrappedAddons.");
|
||||
|
||||
BootstrapMonitor.checkAddonInstalled(ID, "1.0");
|
||||
|
|
|
@ -18,16 +18,16 @@ function run_test() {
|
|||
do_get_addon("test_chromemanifest_3"),
|
||||
do_get_addon("test_chromemanifest_4"),
|
||||
do_get_addon("test_chromemanifest_5")],
|
||||
async function() {
|
||||
function() {
|
||||
|
||||
await promiseRestartManager();
|
||||
restartManager();
|
||||
|
||||
AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",
|
||||
"addon2@tests.mozilla.org",
|
||||
"addon3@tests.mozilla.org",
|
||||
"addon4@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
|
||||
do_check_neq(a1, null);
|
||||
do_check_false(a1.userDisabled);
|
||||
|
|
|
@ -117,7 +117,7 @@ function check_test_1(installSyncGUID) {
|
|||
AddonManager.getAddonByID("addon1@tests.mozilla.org", function(olda1) {
|
||||
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[0].id, "addon1@tests.mozilla.org");
|
||||
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_DISABLE));
|
||||
|
||||
await promiseRestartManager();
|
||||
restartManager();
|
||||
|
||||
AddonManager.getAllInstalls(function(activeInstalls) {
|
||||
do_check_eq(activeInstalls, 0);
|
||||
|
@ -276,9 +276,9 @@ function check_test_3(aInstall) {
|
|||
setExtensionModifiedTime(ext, updateDate);
|
||||
|
||||
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);
|
||||
await promiseRestartManager();
|
||||
restartManager();
|
||||
|
||||
AddonManager.getAllInstalls(function(installs) {
|
||||
do_check_eq(installs, 0);
|
||||
|
@ -465,9 +465,9 @@ function run_test_7() {
|
|||
|
||||
function check_test_7() {
|
||||
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);
|
||||
await promiseRestartManager();
|
||||
restartManager();
|
||||
|
||||
AddonManager.getAllInstalls(function(installs) {
|
||||
do_check_eq(installs, 0);
|
||||
|
@ -514,8 +514,8 @@ function run_test_8() {
|
|||
});
|
||||
}
|
||||
|
||||
async function check_test_8() {
|
||||
await promiseRestartManager();
|
||||
function check_test_8() {
|
||||
restartManager();
|
||||
|
||||
AddonManager.getAddonByID("addon3@tests.mozilla.org", function(a3) {
|
||||
do_check_neq(a3, null);
|
||||
|
|
|
@ -114,7 +114,7 @@ function check_test_1() {
|
|||
AddonManager.getAddonByID("addon1@tests.mozilla.org", function(olda1) {
|
||||
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[0].id, "addon1@tests.mozilla.org");
|
||||
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_DISABLE));
|
||||
|
||||
await promiseRestartManager();
|
||||
restartManager();
|
||||
|
||||
AddonManager.getAllInstalls(function(activeInstalls) {
|
||||
do_check_eq(activeInstalls, 0);
|
||||
|
@ -259,9 +259,9 @@ function check_test_3(aInstall) {
|
|||
setExtensionModifiedTime(ext, updateDate);
|
||||
|
||||
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);
|
||||
await promiseRestartManager();
|
||||
restartManager();
|
||||
|
||||
AddonManager.getAllInstalls(function(installs) {
|
||||
do_check_eq(installs, 0);
|
||||
|
@ -359,10 +359,10 @@ function check_test_5(install) {
|
|||
do_check_neq(olda2, null);
|
||||
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[0].addon, olda2.pendingUpgrade);
|
||||
await promiseRestartManager();
|
||||
restartManager();
|
||||
|
||||
AddonManager.getInstallsByTypes(null, function(installs2) {
|
||||
do_check_eq(installs2.length, 0);
|
||||
|
@ -446,9 +446,9 @@ function run_test_7() {
|
|||
|
||||
function check_test_7() {
|
||||
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);
|
||||
await promiseRestartManager();
|
||||
restartManager();
|
||||
|
||||
AddonManager.getAllInstalls(function(installs) {
|
||||
do_check_eq(installs, 0);
|
||||
|
@ -494,8 +494,8 @@ function run_test_8() {
|
|||
});
|
||||
}
|
||||
|
||||
async function check_test_8() {
|
||||
await promiseRestartManager();
|
||||
function check_test_8() {
|
||||
restartManager();
|
||||
|
||||
AddonManager.getAddonByID("addon3@tests.mozilla.org", function(a3) {
|
||||
do_check_neq(a3, null);
|
||||
|
|
|
@ -182,7 +182,6 @@ add_task(function* init() {
|
|||
|
||||
add_task(function* run_test_1() {
|
||||
restartManager();
|
||||
|
||||
let [a1, a2, a3, a4, a5, a6, a7, t1, t2] =
|
||||
yield promiseAddonsByIDs(["addon1@tests.mozilla.org",
|
||||
"addon2@tests.mozilla.org",
|
||||
|
@ -454,7 +453,8 @@ add_task(function* run_test_1() {
|
|||
do_print("Unlocking " + gExtensionsJSON.path);
|
||||
yield file.close();
|
||||
gExtensionsJSON.permissions = filePermissions;
|
||||
yield promiseStartupManager();
|
||||
startupManager();
|
||||
|
||||
|
||||
// Shouldn't have seen any startup changes
|
||||
check_startup_changes(AddonManager.STARTUP_CHANGE_INSTALLED, []);
|
||||
|
|
|
@ -164,7 +164,7 @@ add_task(function*() {
|
|||
if (!OS.Constants.Win) {
|
||||
gExtensionsJSON.permissions = 0;
|
||||
}
|
||||
yield promiseStartupManager(false);
|
||||
startupManager(false);
|
||||
|
||||
check_startup_changes(AddonManager.STARTUP_CHANGE_INSTALLED, []);
|
||||
check_startup_changes(AddonManager.STARTUP_CHANGE_UNINSTALLED, []);
|
||||
|
@ -225,7 +225,7 @@ add_task(function*() {
|
|||
}
|
||||
yield file.close();
|
||||
gExtensionsJSON.permissions = filePermissions;
|
||||
yield promiseStartupManager();
|
||||
startupManager();
|
||||
|
||||
// On Unix, we can save the DB even when the original file wasn't
|
||||
// readable, so our changes were saved. On Windows,
|
||||
|
|
|
@ -148,7 +148,7 @@ add_task(function* init() {
|
|||
writeInstallRDFForExtension(theme2, profileDir);
|
||||
|
||||
// Startup the profile and setup the initial state
|
||||
yield promiseStartupManager();
|
||||
startupManager();
|
||||
|
||||
// New profile so new add-ons are ignored
|
||||
check_startup_changes(AddonManager.STARTUP_CHANGE_INSTALLED, []);
|
||||
|
@ -271,7 +271,7 @@ add_task(function* run_test_1() {
|
|||
if (!OS.Constants.Win) {
|
||||
gExtensionsJSON.permissions = 0;
|
||||
}
|
||||
yield promiseStartupManager(false);
|
||||
startupManager(false);
|
||||
|
||||
// Shouldn't have seen any startup changes
|
||||
check_startup_changes(AddonManager.STARTUP_CHANGE_INSTALLED, []);
|
||||
|
@ -365,7 +365,7 @@ add_task(function* run_test_1() {
|
|||
} catch (e) {
|
||||
// We're expecting an error here.
|
||||
}
|
||||
yield promiseStartupManager(false);
|
||||
startupManager(false);
|
||||
|
||||
// Shouldn't have seen any startup changes
|
||||
check_startup_changes(AddonManager.STARTUP_CHANGE_INSTALLED, []);
|
||||
|
@ -453,7 +453,7 @@ add_task(function* run_test_1() {
|
|||
do_print("Unlocking " + gExtensionsJSON.path);
|
||||
yield file.close();
|
||||
gExtensionsJSON.permissions = filePermissions;
|
||||
yield promiseStartupManager(false);
|
||||
startupManager(false);
|
||||
|
||||
// Shouldn't have seen any startup changes
|
||||
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
|
||||
function check_empty_state() {
|
||||
do_check_false(gExtensionsJSON.exists());
|
||||
do_check_false(gExtensionsINI.exists());
|
||||
|
||||
do_check_eq(Services.prefs.getIntPref("extensions.databaseSchema"), DB_SCHEMA);
|
||||
|
||||
checkString("extensions.bootstrappedAddons", "{}");
|
||||
checkString("extensions.installCache", "[]");
|
||||
checkPending();
|
||||
}
|
||||
|
||||
|
|
|
@ -33,14 +33,14 @@ function run_test() {
|
|||
|
||||
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_not_in_crash_annotation(addon1.id, addon1.version);
|
||||
|
||||
writeInstallRDFForExtension(addon1, profileDir, 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) {
|
||||
do_check_neq(newa1, null);
|
||||
|
|
|
@ -18,7 +18,6 @@ const IGNORE_PRIVATE = ["AddonAuthor", "AddonCompatibilityOverride",
|
|||
"AddonScreenshot", "AddonType", "startup", "shutdown",
|
||||
"addonIsActive", "registerProvider", "unregisterProvider",
|
||||
"addStartupChange", "removeStartupChange",
|
||||
"getNewSideloads",
|
||||
"recordTimestamp", "recordSimpleMeasure",
|
||||
"recordException", "getSimpleMeasures", "simpleTimer",
|
||||
"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
|
||||
function breakAddon(file) {
|
||||
if (TEST_UNPACKED) {
|
||||
let f = file.clone();
|
||||
f.append("test.txt");
|
||||
f.remove(true);
|
||||
|
||||
f = file.clone();
|
||||
f.append("install.rdf");
|
||||
f.lastModifiedTime = Date.now();
|
||||
file.append("test.txt");
|
||||
file.remove(true);
|
||||
} else {
|
||||
var zipW = AM_Cc["@mozilla.org/zipwriter;1"].
|
||||
createInstance(AM_Ci.nsIZipWriter);
|
||||
|
@ -261,7 +256,7 @@ add_task(function*() {
|
|||
// detection but the periodic scan will catch that
|
||||
yield promiseSetExtensionModifiedTime(file.path, Date.now() - 60000);
|
||||
|
||||
yield promiseStartupManager();
|
||||
startupManager();
|
||||
let addon = yield promiseAddonByID(ID);
|
||||
do_check_neq(addon, null);
|
||||
do_check_false(addon.appDisabled);
|
||||
|
@ -274,7 +269,7 @@ add_task(function*() {
|
|||
clearCache(file);
|
||||
breakAddon(file);
|
||||
|
||||
yield promiseStartupManager();
|
||||
startupManager();
|
||||
|
||||
addon = yield promiseAddonByID(ID);
|
||||
do_check_neq(addon, null);
|
||||
|
|
|
@ -104,7 +104,7 @@ function* test_breaking_migrate(addons, test, expectedSignedState) {
|
|||
|
||||
// Update the application
|
||||
gAppInfo.version = "5";
|
||||
yield promiseStartupManager(true);
|
||||
startupManager(true);
|
||||
|
||||
let addon = yield promiseAddonByID(ID);
|
||||
do_check_neq(addon, null);
|
||||
|
@ -154,7 +154,7 @@ function* test_working_migrate(addons, test, expectedSignedState) {
|
|||
|
||||
// Update the application
|
||||
gAppInfo.version = "5";
|
||||
yield promiseStartupManager(true);
|
||||
startupManager(true);
|
||||
|
||||
let addon = yield promiseAddonByID(ID);
|
||||
do_check_neq(addon, null);
|
||||
|
|
|
@ -134,7 +134,7 @@ function run_test() {
|
|||
|
||||
do_check_false(gExtensionsJSON.exists());
|
||||
|
||||
do_check_false(gAddonStartup.exists());
|
||||
do_check_false(gExtensionsINI.exists());
|
||||
|
||||
AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",
|
||||
"addon2@tests.mozilla.org",
|
||||
|
@ -163,7 +163,7 @@ function end_test() {
|
|||
}
|
||||
|
||||
// Try to install all the items into the profile
|
||||
async function run_test_1() {
|
||||
function run_test_1() {
|
||||
writeInstallRDFForExtension(addon1, profileDir);
|
||||
var dest = writeInstallRDFForExtension(addon2, profileDir);
|
||||
// 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);
|
||||
|
||||
gCachePurged = false;
|
||||
await promiseRestartManager();
|
||||
restartManager();
|
||||
check_startup_changes(AddonManager.STARTUP_CHANGE_INSTALLED, ["addon1@tests.mozilla.org",
|
||||
"addon2@tests.mozilla.org",
|
||||
"addon3@tests.mozilla.org"]);
|
||||
|
@ -187,8 +187,8 @@ async function run_test_1() {
|
|||
check_startup_changes(AddonManager.STARTUP_CHANGE_ENABLED, []);
|
||||
do_check_true(gCachePurged);
|
||||
|
||||
do_print("Checking for " + gAddonStartup.path);
|
||||
do_check_true(gAddonStartup.exists());
|
||||
do_print("Checking for " + gExtensionsINI.path);
|
||||
do_check_true(gExtensionsINI.exists());
|
||||
|
||||
AddonManager.getAddonsByIDs(["addon1@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
|
||||
// are ignored
|
||||
async function run_test_2() {
|
||||
function run_test_2() {
|
||||
addon1.version = "1.1";
|
||||
writeInstallRDFForExtension(addon1, userDir);
|
||||
addon2.version = "2.1";
|
||||
|
@ -295,8 +295,7 @@ async function run_test_2() {
|
|||
dest.remove(true);
|
||||
|
||||
gCachePurged = false;
|
||||
await promiseRestartManager();
|
||||
|
||||
restartManager();
|
||||
check_startup_changes(AddonManager.STARTUP_CHANGE_INSTALLED, []);
|
||||
check_startup_changes(AddonManager.STARTUP_CHANGE_CHANGED, ["addon2@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, []);
|
||||
do_check_true(gCachePurged);
|
||||
|
||||
do_check_true(gAddonStartup.exists());
|
||||
do_check_true(gExtensionsINI.exists());
|
||||
|
||||
AddonManager.getAddonsByIDs(["addon1@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.
|
||||
async function run_test_3() {
|
||||
function run_test_3() {
|
||||
var dest = profileDir.clone();
|
||||
dest.append(do_get_expected_addon_name("addon1@tests.mozilla.org"));
|
||||
dest.remove(true);
|
||||
|
@ -361,8 +360,7 @@ async function run_test_3() {
|
|||
writeInstallRDFForExtension(addon3, profileDir, "addon4@tests.mozilla.org");
|
||||
|
||||
gCachePurged = false;
|
||||
await promiseRestartManager();
|
||||
|
||||
restartManager();
|
||||
check_startup_changes(AddonManager.STARTUP_CHANGE_INSTALLED, []);
|
||||
check_startup_changes(AddonManager.STARTUP_CHANGE_CHANGED, ["addon1@tests.mozilla.org",
|
||||
"addon2@tests.mozilla.org"]);
|
||||
|
@ -417,12 +415,11 @@ async function run_test_3() {
|
|||
}
|
||||
|
||||
// Test that disabling an install location works
|
||||
async function run_test_4() {
|
||||
function run_test_4() {
|
||||
Services.prefs.setIntPref("extensions.enabledScopes", AddonManager.SCOPE_SYSTEM);
|
||||
|
||||
gCachePurged = false;
|
||||
await promiseRestartManager();
|
||||
|
||||
restartManager();
|
||||
check_startup_changes(AddonManager.STARTUP_CHANGE_INSTALLED, []);
|
||||
check_startup_changes(AddonManager.STARTUP_CHANGE_CHANGED, ["addon2@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
|
||||
async function run_test_5() {
|
||||
function run_test_5() {
|
||||
Services.prefs.setIntPref("extensions.enabledScopes", AddonManager.SCOPE_USER);
|
||||
|
||||
gCachePurged = false;
|
||||
await promiseRestartManager();
|
||||
|
||||
restartManager();
|
||||
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_UNINSTALLED, []);
|
||||
|
@ -503,12 +499,11 @@ async function run_test_5() {
|
|||
}
|
||||
|
||||
// Resetting the pref makes everything visible again
|
||||
async function run_test_6() {
|
||||
function run_test_6() {
|
||||
Services.prefs.clearUserPref("extensions.enabledScopes");
|
||||
|
||||
gCachePurged = false;
|
||||
await promiseRestartManager();
|
||||
|
||||
restartManager();
|
||||
check_startup_changes(AddonManager.STARTUP_CHANGE_INSTALLED, []);
|
||||
check_startup_changes(AddonManager.STARTUP_CHANGE_CHANGED, []);
|
||||
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.
|
||||
async function run_test_7() {
|
||||
function run_test_7() {
|
||||
addon1.version = "1.2";
|
||||
writeInstallRDFForExtension(addon1, profileDir);
|
||||
var dest = userDir.clone();
|
||||
|
@ -557,8 +552,7 @@ async function run_test_7() {
|
|||
dest.remove(true);
|
||||
|
||||
gCachePurged = false;
|
||||
await promiseRestartManager();
|
||||
|
||||
restartManager();
|
||||
check_startup_changes(AddonManager.STARTUP_CHANGE_INSTALLED, []);
|
||||
check_startup_changes(AddonManager.STARTUP_CHANGE_CHANGED, ["addon1@tests.mozilla.org",
|
||||
"addon2@tests.mozilla.org"]);
|
||||
|
@ -609,12 +603,11 @@ async function run_test_7() {
|
|||
}
|
||||
|
||||
// Disabling all locations still leaves the profile working
|
||||
async function run_test_8() {
|
||||
function run_test_8() {
|
||||
Services.prefs.setIntPref("extensions.enabledScopes", 0);
|
||||
|
||||
gCachePurged = false;
|
||||
await promiseRestartManager();
|
||||
|
||||
restartManager();
|
||||
check_startup_changes(AddonManager.STARTUP_CHANGE_INSTALLED, []);
|
||||
check_startup_changes(AddonManager.STARTUP_CHANGE_CHANGED, []);
|
||||
check_startup_changes(AddonManager.STARTUP_CHANGE_UNINSTALLED, ["addon2@tests.mozilla.org"]);
|
||||
|
@ -649,7 +642,7 @@ async function run_test_8() {
|
|||
}
|
||||
|
||||
// More hiding and revealing
|
||||
async function run_test_9() {
|
||||
function run_test_9() {
|
||||
Services.prefs.clearUserPref("extensions.enabledScopes");
|
||||
|
||||
var dest = userDir.clone();
|
||||
|
@ -662,8 +655,7 @@ async function run_test_9() {
|
|||
writeInstallRDFForExtension(addon2, profileDir);
|
||||
|
||||
gCachePurged = false;
|
||||
await promiseRestartManager();
|
||||
|
||||
restartManager();
|
||||
check_startup_changes(AddonManager.STARTUP_CHANGE_INSTALLED, ["addon2@tests.mozilla.org"]);
|
||||
check_startup_changes(AddonManager.STARTUP_CHANGE_CHANGED, []);
|
||||
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
|
||||
// for the same item is handled
|
||||
async function run_test_10() {
|
||||
function run_test_10() {
|
||||
var dest = profileDir.clone();
|
||||
dest.append(do_get_expected_addon_name("addon1@tests.mozilla.org"));
|
||||
dest.remove(true);
|
||||
|
@ -720,8 +712,7 @@ async function run_test_10() {
|
|||
writeInstallRDFForExtension(addon1, userDir);
|
||||
|
||||
gCachePurged = false;
|
||||
await promiseRestartManager();
|
||||
|
||||
restartManager();
|
||||
check_startup_changes(AddonManager.STARTUP_CHANGE_INSTALLED, []);
|
||||
check_startup_changes(AddonManager.STARTUP_CHANGE_CHANGED, ["addon1@tests.mozilla.org"]);
|
||||
check_startup_changes(AddonManager.STARTUP_CHANGE_UNINSTALLED, []);
|
||||
|
@ -769,7 +760,7 @@ async function run_test_10() {
|
|||
}
|
||||
|
||||
// This should remove any remaining items
|
||||
async function run_test_11() {
|
||||
function run_test_11() {
|
||||
var dest = userDir.clone();
|
||||
dest.append(do_get_expected_addon_name("addon1@tests.mozilla.org"));
|
||||
dest.remove(true);
|
||||
|
@ -778,8 +769,7 @@ async function run_test_11() {
|
|||
dest.remove(true);
|
||||
|
||||
gCachePurged = false;
|
||||
await promiseRestartManager();
|
||||
|
||||
restartManager();
|
||||
check_startup_changes(AddonManager.STARTUP_CHANGE_INSTALLED, []);
|
||||
check_startup_changes(AddonManager.STARTUP_CHANGE_CHANGED, []);
|
||||
check_startup_changes(AddonManager.STARTUP_CHANGE_UNINSTALLED, ["addon1@tests.mozilla.org",
|
||||
|
|
|
@ -89,7 +89,7 @@ const profileDir = gProfD.clone();
|
|||
profileDir.append("extensions");
|
||||
|
||||
// Set up the profile
|
||||
async function run_test() {
|
||||
function run_test() {
|
||||
do_test_pending();
|
||||
|
||||
writeInstallRDFForExtension(addon1, profileDir);
|
||||
|
@ -98,8 +98,7 @@ async function run_test() {
|
|||
writeInstallRDFForExtension(addon4, profileDir);
|
||||
writeInstallRDFForExtension(addon5, profileDir);
|
||||
|
||||
await promiseRestartManager();
|
||||
|
||||
restartManager();
|
||||
AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",
|
||||
"addon2@tests.mozilla.org",
|
||||
"addon3@tests.mozilla.org",
|
||||
|
|
|
@ -34,7 +34,7 @@ AM_Cc["@mozilla.org/observer-service;1"]
|
|||
.addObserver(LightweightThemeObserver, "lightweight-theme-styling-update");
|
||||
|
||||
|
||||
async function run_test() {
|
||||
function run_test() {
|
||||
do_test_pending();
|
||||
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2");
|
||||
|
||||
|
@ -80,7 +80,7 @@ async function run_test() {
|
|||
}]
|
||||
}, profileDir);
|
||||
|
||||
await promiseStartupManager();
|
||||
startupManager();
|
||||
// Make sure we only register once despite multiple calls
|
||||
AddonManager.addInstallListener(InstallListener);
|
||||
AddonManager.addAddonListener(AddonListener);
|
||||
|
@ -158,9 +158,8 @@ function run_test_1() {
|
|||
});
|
||||
}
|
||||
|
||||
async function check_test_1() {
|
||||
await promiseRestartManager();
|
||||
|
||||
function check_test_1() {
|
||||
restartManager();
|
||||
do_check_eq(Services.prefs.getCharPref(PREF_GENERAL_SKINS_SELECTEDSKIN), "theme2/1.0");
|
||||
|
||||
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
|
||||
// case since we don't have the default theme installed)
|
||||
async function run_test_2() {
|
||||
function run_test_2() {
|
||||
var dest = profileDir.clone();
|
||||
dest.append(do_get_expected_addon_name("theme2@tests.mozilla.org"));
|
||||
dest.remove(true);
|
||||
|
||||
await promiseRestartManager();
|
||||
|
||||
restartManager();
|
||||
do_check_eq(Services.prefs.getCharPref(PREF_GENERAL_SKINS_SELECTEDSKIN), "classic/1.0");
|
||||
|
||||
AddonManager.getAddonsByIDs(["theme1@tests.mozilla.org",
|
||||
|
|
|
@ -25,12 +25,12 @@ function run_test() {
|
|||
do_test_pending();
|
||||
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);
|
||||
|
||||
writeInstallRDFForExtension(addon1, profileDir);
|
||||
|
||||
await promiseRestartManager();
|
||||
restartManager();
|
||||
|
||||
AddonManager.getAddonByID("addon1@tests.mozilla.org", function(a1) {
|
||||
do_check_neq(a1, null);
|
||||
|
@ -92,8 +92,8 @@ function check_test_1() {
|
|||
}
|
||||
|
||||
// Cancelling the uninstall should send onOperationCancelled
|
||||
async function run_test_2() {
|
||||
await promiseRestartManager();
|
||||
function run_test_2() {
|
||||
restartManager();
|
||||
|
||||
prepare_test({
|
||||
"addon1@tests.mozilla.org": [
|
||||
|
@ -126,8 +126,8 @@ async function run_test_2() {
|
|||
});
|
||||
}
|
||||
|
||||
async function check_test_2() {
|
||||
await promiseRestartManager();
|
||||
function check_test_2() {
|
||||
restartManager();
|
||||
|
||||
AddonManager.getAddonByID("addon1@tests.mozilla.org", function(a1) {
|
||||
do_check_neq(a1, null);
|
||||
|
|
|
@ -221,16 +221,14 @@ for (let test of testParams) {
|
|||
check_test_2 = () => {
|
||||
ensure_test_completed();
|
||||
|
||||
AddonManager.getAddonByID("addon1@tests.mozilla.org", callback_soon(async function(olda1) {
|
||||
await AddonTestUtils.loadAddonsList(true);
|
||||
|
||||
AddonManager.getAddonByID("addon1@tests.mozilla.org", callback_soon(function(olda1) {
|
||||
do_check_neq(olda1, null);
|
||||
do_check_eq(olda1.version, "1.0");
|
||||
do_check_true(isExtensionInAddonsList(profileDir, olda1.id));
|
||||
|
||||
shutdownManager();
|
||||
|
||||
await promiseStartupManager();
|
||||
startupManager();
|
||||
|
||||
do_check_true(isExtensionInAddonsList(profileDir, "addon1@tests.mozilla.org"));
|
||||
|
||||
|
|
|
@ -216,16 +216,14 @@ for (let test of testParams) {
|
|||
check_test_2 = () => {
|
||||
ensure_test_completed();
|
||||
|
||||
AddonManager.getAddonByID("addon1@tests.mozilla.org", callback_soon(async function(olda1) {
|
||||
await AddonTestUtils.loadAddonsList(true);
|
||||
|
||||
AddonManager.getAddonByID("addon1@tests.mozilla.org", callback_soon(function(olda1) {
|
||||
do_check_neq(olda1, null);
|
||||
do_check_eq(olda1.version, "1.0");
|
||||
do_check_true(isExtensionInAddonsList(profileDir, olda1.id));
|
||||
|
||||
shutdownManager();
|
||||
|
||||
await promiseStartupManager();
|
||||
startupManager();
|
||||
|
||||
do_check_true(isExtensionInAddonsList(profileDir, "addon1@tests.mozilla.org"));
|
||||
|
||||
|
|
|
@ -96,8 +96,8 @@ function end_test() {
|
|||
}
|
||||
|
||||
// Test that the test extensions are all installed
|
||||
async function run_test_1() {
|
||||
await promiseStartupManager();
|
||||
function run_test_1() {
|
||||
startupManager();
|
||||
|
||||
AddonManager.getAddonsByIDs(["addon1@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
|
||||
async function run_test_2() {
|
||||
function run_test_2() {
|
||||
// Upgrade the extension
|
||||
var dest = writeInstallRDFForExtension({
|
||||
id: "addon4@tests.mozilla.org",
|
||||
|
@ -137,7 +137,7 @@ async function run_test_2() {
|
|||
}, globalDir);
|
||||
setExtensionModifiedTime(dest, gInstallTime);
|
||||
|
||||
await promiseRestartManager("2");
|
||||
restartManager("2");
|
||||
AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",
|
||||
"addon2@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
|
||||
// whenever the application is changed.
|
||||
gAddonStartup.remove(true);
|
||||
gExtensionsINI.remove(true);
|
||||
restartManager();
|
||||
|
||||
AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",
|
||||
|
|
|
@ -99,8 +99,8 @@ function end_test() {
|
|||
}
|
||||
|
||||
// Test that the test extensions are all installed
|
||||
async function run_test_1() {
|
||||
await promiseStartupManager();
|
||||
function run_test_1() {
|
||||
startupManager();
|
||||
|
||||
AddonManager.getAddonsByIDs(["addon1@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
|
||||
async function run_test_2() {
|
||||
function run_test_2() {
|
||||
// Upgrade the extension
|
||||
var dest = writeInstallRDFForExtension({
|
||||
id: "addon4@tests.mozilla.org",
|
||||
|
@ -140,8 +140,7 @@ async function run_test_2() {
|
|||
}, globalDir);
|
||||
setExtensionModifiedTime(dest, gInstallTime);
|
||||
|
||||
await promiseRestartManager("2");
|
||||
|
||||
restartManager("2");
|
||||
AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",
|
||||
"addon2@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
|
||||
// whenever the application is changed.
|
||||
gAddonStartup.remove(true);
|
||||
gExtensionsINI.remove(true);
|
||||
restartManager();
|
||||
|
||||
AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",
|
||||
|
|
|
@ -105,8 +105,7 @@ add_task(function* has_embedded_webextension_persisted() {
|
|||
// hasEmbeddedWebExtension property as expected.
|
||||
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.");
|
||||
equal(persisted[ID].hasEmbeddedWebExtension, true,
|
||||
"hasEmbeddedWebExtension flag persisted to bootstrappedAddons.");
|
||||
|
|
|
@ -27,10 +27,9 @@ function promiseAddonStartup() {
|
|||
function* testSimpleIconsetParsing(manifest) {
|
||||
yield promiseWriteWebManifestForExtension(manifest, profileDir);
|
||||
|
||||
yield Promise.all([
|
||||
promiseRestartManager(),
|
||||
manifest.theme || promiseAddonStartup(),
|
||||
]);
|
||||
yield promiseRestartManager();
|
||||
if (!manifest.theme)
|
||||
yield promiseAddonStartup();
|
||||
|
||||
let uri = do_get_addon_root_uri(profileDir, ID);
|
||||
|
||||
|
@ -61,10 +60,9 @@ function* testSimpleIconsetParsing(manifest) {
|
|||
check_icons(addon);
|
||||
|
||||
// check if icons are persisted through a restart
|
||||
yield Promise.all([
|
||||
promiseRestartManager(),
|
||||
manifest.theme || promiseAddonStartup(),
|
||||
]);
|
||||
yield promiseRestartManager();
|
||||
if (!manifest.theme)
|
||||
yield promiseAddonStartup();
|
||||
|
||||
addon = yield promiseAddonByID(ID);
|
||||
do_check_neq(addon, null);
|
||||
|
@ -72,15 +70,16 @@ function* testSimpleIconsetParsing(manifest) {
|
|||
check_icons(addon);
|
||||
|
||||
addon.uninstall();
|
||||
|
||||
yield promiseRestartManager();
|
||||
}
|
||||
|
||||
function* testRetinaIconsetParsing(manifest) {
|
||||
yield promiseWriteWebManifestForExtension(manifest, profileDir);
|
||||
|
||||
yield Promise.all([
|
||||
promiseRestartManager(),
|
||||
manifest.theme || promiseAddonStartup(),
|
||||
]);
|
||||
yield promiseRestartManager();
|
||||
if (!manifest.theme)
|
||||
yield promiseAddonStartup();
|
||||
|
||||
let addon = yield promiseAddonByID(ID);
|
||||
do_check_neq(addon, null);
|
||||
|
@ -101,15 +100,16 @@ function* testRetinaIconsetParsing(manifest) {
|
|||
}), uri + "icon128.png");
|
||||
|
||||
addon.uninstall();
|
||||
|
||||
yield promiseRestartManager();
|
||||
}
|
||||
|
||||
function* testNoIconsParsing(manifest) {
|
||||
yield promiseWriteWebManifestForExtension(manifest, profileDir);
|
||||
|
||||
yield Promise.all([
|
||||
promiseRestartManager(),
|
||||
manifest.theme || promiseAddonStartup(),
|
||||
]);
|
||||
yield promiseRestartManager();
|
||||
if (!manifest.theme)
|
||||
yield promiseAddonStartup();
|
||||
|
||||
let addon = yield promiseAddonByID(ID);
|
||||
do_check_neq(addon, null);
|
||||
|
@ -122,6 +122,8 @@ function* testNoIconsParsing(manifest) {
|
|||
equal(AddonManager.getPreferredIconURL(addon, 128), null);
|
||||
|
||||
addon.uninstall();
|
||||
|
||||
yield promiseRestartManager();
|
||||
}
|
||||
|
||||
// Test simple icon set parsing
|
||||
|
|
|
@ -36,7 +36,7 @@ skip-if = os == "android"
|
|||
tags = blocklist
|
||||
[test_bootstrap.js]
|
||||
# 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_resource.js]
|
||||
[test_bug299716.js]
|
||||
|
@ -151,7 +151,7 @@ fail-if = os == "android"
|
|||
[test_bug570173.js]
|
||||
[test_bug576735.js]
|
||||
[test_bug587088.js]
|
||||
skip-if = os == "win" # Bug 1358846
|
||||
[test_bug594058.js]
|
||||
[test_bug595081.js]
|
||||
[test_bug595573.js]
|
||||
[test_bug596607.js]
|
||||
|
@ -247,6 +247,15 @@ run-sequentially = Uses hardcoded ports in xpi files.
|
|||
[test_mapURIToAddonID.js]
|
||||
# Same as test_bootstrap.js
|
||||
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_no_addons.js]
|
||||
[test_onPropertyChanged_appDisabled.js]
|
||||
|
@ -290,7 +299,6 @@ fail-if = os == "android"
|
|||
[test_undothemeuninstall.js]
|
||||
skip-if = appname == "thunderbird"
|
||||
[test_undouninstall.js]
|
||||
skip-if = os == "win" # Bug 1358846
|
||||
[test_uninstall.js]
|
||||
[test_update.js]
|
||||
# Bug 676992: test consistently hangs on Android
|
||||
|
@ -309,7 +317,6 @@ skip-if = os == "android"
|
|||
skip-if = os == "android"
|
||||
run-sequentially = Uses hardcoded ports in xpi files.
|
||||
[test_json_updatecheck.js]
|
||||
[test_migrate_state_prefs.js]
|
||||
[test_seen.js]
|
||||
[test_seen_newprofile.js]
|
||||
[test_updateid.js]
|
||||
|
@ -328,7 +335,6 @@ run-sequentially = Uses global XCurProcD dir.
|
|||
[test_overrideblocklist.js]
|
||||
run-sequentially = Uses global XCurProcD dir.
|
||||
tags = blocklist
|
||||
[test_sideloads.js]
|
||||
[test_sourceURI.js]
|
||||
[test_webextension_icons.js]
|
||||
skip-if = appname == "thunderbird"
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
#include "nsAppRunner.h"
|
||||
#include "nsToolkitCompsCID.h"
|
||||
#include "nsXREDirProvider.h"
|
||||
#include "mozilla/AddonManagerStartup.h"
|
||||
|
||||
#include "jsapi.h"
|
||||
#include "xpcpublic.h"
|
||||
|
@ -28,6 +27,7 @@
|
|||
#include "nsXULAppAPI.h"
|
||||
#include "nsCategoryManagerUtils.h"
|
||||
|
||||
#include "nsINIParser.h"
|
||||
#include "nsDependentString.h"
|
||||
#include "nsCOMArray.h"
|
||||
#include "nsArrayEnumerator.h"
|
||||
|
@ -86,6 +86,15 @@ static const char* GetContentProcessTempBaseDirKey();
|
|||
static already_AddRefed<nsIFile> CreateContentProcessSandboxTempDir();
|
||||
#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::nsXREDirProvider() :
|
||||
|
@ -589,7 +598,7 @@ LoadDirIntoArray(nsIFile* dir,
|
|||
}
|
||||
|
||||
static void
|
||||
LoadDirsIntoArray(const nsCOMArray<nsIFile>& aSourceDirs,
|
||||
LoadDirsIntoArray(nsCOMArray<nsIFile>& aSourceDirs,
|
||||
const char *const* aAppendList,
|
||||
nsCOMArray<nsIFile>& aDirectories)
|
||||
{
|
||||
|
@ -650,6 +659,73 @@ nsXREDirProvider::GetFiles(const char* aProperty, nsISimpleEnumerator** aResult)
|
|||
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)
|
||||
|
||||
static const char*
|
||||
|
@ -827,6 +903,59 @@ DeleteDirIfExists(nsIFile* dir)
|
|||
#endif // (defined(XP_WIN) || defined(XP_MACOSX)) &&
|
||||
// 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
|
||||
void
|
||||
nsXREDirProvider::LoadAppBundleDirs()
|
||||
|
@ -890,7 +1019,7 @@ nsXREDirProvider::GetFilesInternal(const char* aProperty,
|
|||
|
||||
LoadDirsIntoArray(mAppBundleDirectories,
|
||||
kAppendNothing, directories);
|
||||
LoadDirsIntoArray(AddonManagerStartup::GetSingleton().ExtensionPaths(),
|
||||
LoadDirsIntoArray(mExtensionDirectories,
|
||||
kAppendNothing, 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)) {
|
||||
nsCOMArray<nsIFile> directories;
|
||||
|
||||
LoadDirsIntoArray(AddonManagerStartup::GetSingleton().ExtensionPaths(),
|
||||
LoadDirsIntoArray(mExtensionDirectories,
|
||||
kAppendPrefDir, directories);
|
||||
|
||||
if (mProfileDir) {
|
||||
|
@ -934,7 +1063,7 @@ nsXREDirProvider::GetFilesInternal(const char* aProperty,
|
|||
LoadDirsIntoArray(mAppBundleDirectories,
|
||||
kAppendChromeDir,
|
||||
directories);
|
||||
LoadDirsIntoArray(AddonManagerStartup::GetSingleton().ExtensionPaths(),
|
||||
LoadDirsIntoArray(mExtensionDirectories,
|
||||
kAppendChromeDir,
|
||||
directories);
|
||||
|
||||
|
@ -959,7 +1088,7 @@ nsXREDirProvider::GetFilesInternal(const char* aProperty,
|
|||
LoadDirsIntoArray(mAppBundleDirectories,
|
||||
kAppendPlugins,
|
||||
directories);
|
||||
LoadDirsIntoArray(AddonManagerStartup::GetSingleton().ExtensionPaths(),
|
||||
LoadDirsIntoArray(mExtensionDirectories,
|
||||
kAppendPlugins,
|
||||
directories);
|
||||
|
||||
|
@ -1032,6 +1161,8 @@ nsXREDirProvider::DoStartup()
|
|||
NS_WARNING("Failed to create Addons Manager.");
|
||||
}
|
||||
|
||||
LoadExtensionBundleDirectories();
|
||||
|
||||
obsSvc->NotifyObservers(nullptr, "load-extension-defaults", nullptr);
|
||||
obsSvc->NotifyObservers(nullptr, "profile-after-change", kStartup);
|
||||
|
||||
|
|
|
@ -126,6 +126,9 @@ protected:
|
|||
nsresult LoadContentProcessTempDir();
|
||||
#endif
|
||||
|
||||
// Calculate and register extension and theme bundle directories.
|
||||
void LoadExtensionBundleDirectories();
|
||||
|
||||
#ifdef MOZ_B2G
|
||||
// Calculate and register app-bundled extension directories.
|
||||
void LoadAppBundleDirs();
|
||||
|
@ -148,6 +151,8 @@ protected:
|
|||
nsCOMPtr<nsIFile> mContentProcessSandboxTempDir;
|
||||
#endif
|
||||
nsCOMArray<nsIFile> mAppBundleDirectories;
|
||||
nsCOMArray<nsIFile> mExtensionDirectories;
|
||||
nsCOMArray<nsIFile> mThemeDirectories;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
Загрузка…
Ссылка в новой задаче