Bug 944006: Don't load XPIProviderUtils if no addons and no schemaVersion; r=unfocused

This commit is contained in:
Irving Reid 2013-12-02 19:46:41 -05:00
Родитель 3fb89e506b
Коммит 37aaad48b9
10 изменённых файлов: 169 добавлений и 61 удалений

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

@ -1727,7 +1727,8 @@ var XPIProvider = {
bootstrapScopes: {},
// True if the platform could have activated extensions
extensionsActive: false,
// File / directory state of installed add-ons
installStates: [],
// True if all of the add-ons found during startup were installed in the
// application install location
allAppGlobal: true,
@ -3371,7 +3372,8 @@ var XPIProvider = {
}
// Cache the new install location states
let cache = JSON.stringify(this.getInstallLocationStates());
this.installStates = this.getInstallLocationStates();
let cache = JSON.stringify(this.installStates);
Services.prefs.setCharPref(PREF_INSTALL_CACHE, cache);
this.persistBootstrappedAddons();
@ -3445,11 +3447,6 @@ var XPIProvider = {
updateReasons.push("hasPendingChanges");
}
// If the schema appears to have changed then we should update the database
if (DB_SCHEMA != Prefs.getIntPref(PREF_DB_SCHEMA, 0)) {
updateReasons.push("schemaChanged");
}
// If the application has changed then check for new distribution add-ons
if (aAppChanged !== false &&
Prefs.getBoolPref(PREF_INSTALL_DISTRO_ADDONS, true))
@ -3462,16 +3459,18 @@ var XPIProvider = {
// Telemetry probe added around getInstallLocationStates() to check perf
let telemetryCaptureTime = Date.now();
let state = this.getInstallLocationStates();
this.installStates = this.getInstallLocationStates();
let telemetry = Services.telemetry;
telemetry.getHistogramById("CHECK_ADDONS_MODIFIED_MS").add(Date.now() - telemetryCaptureTime);
// If the install directory state has changed then we must update the database
let cache = Prefs.getCharPref(PREF_INSTALL_CACHE, null);
let cache = Prefs.getCharPref(PREF_INSTALL_CACHE, "[]");
// For a little while, gather telemetry on whether the deep comparison
// makes a difference
if (cache != JSON.stringify(state)) {
if (directoryStateDiffers(state, cache)) {
let newState = JSON.stringify(this.installStates);
if (cache != newState) {
LOG("Directory state JSON differs: cache " + cache + " state " + newState);
if (directoryStateDiffers(this.installStates, cache)) {
updateReasons.push("directoryState");
}
else {
@ -3479,11 +3478,24 @@ var XPIProvider = {
}
}
// If the schema appears to have changed then we should update the database
if (DB_SCHEMA != Prefs.getIntPref(PREF_DB_SCHEMA, 0)) {
// If we don't have any add-ons, just update the pref, since we don't need to
// write the database
if (this.installStates.length == 0) {
LOG("Empty XPI database, setting schema version preference to " + DB_SCHEMA);
Services.prefs.setIntPref(PREF_DB_SCHEMA, DB_SCHEMA);
}
else {
updateReasons.push("schemaChanged");
}
}
// If the database doesn't exist and there are add-ons installed then we
// must update the database however if there are no add-ons then there is
// no need to update the database.
let dbFile = FileUtils.getFile(KEY_PROFILEDIR, [FILE_DATABASE], true);
if (!dbFile.exists() && state.length > 0) {
if (!dbFile.exists() && this.installStates.length > 0) {
updateReasons.push("needNewDatabase");
}
@ -3491,7 +3503,7 @@ var XPIProvider = {
let bootstrapDescriptors = [this.bootstrappedAddons[b].descriptor
for (b in this.bootstrappedAddons)];
state.forEach(function(aInstallLocationState) {
this.installStates.forEach(function(aInstallLocationState) {
for (let id in aInstallLocationState.addons) {
let pos = bootstrapDescriptors.indexOf(aInstallLocationState.addons[id].descriptor);
if (pos != -1)
@ -3514,7 +3526,7 @@ var XPIProvider = {
AddonManagerPrivate.recordSimpleMeasure("XPIDB_startup_load_reasons", updateReasons);
XPIDatabase.syncLoadDB(false);
try {
extensionListChanged = this.processFileChanges(state, manifests,
extensionListChanged = this.processFileChanges(this.installStates, manifests,
aAppChanged,
aOldAppVersion,
aOldPlatformVersion);
@ -3566,7 +3578,7 @@ var XPIProvider = {
// Check that the add-ons list still exists
let addonsList = FileUtils.getFile(KEY_PROFILEDIR, [FILE_XPI_ADDONS_LIST],
true);
if (addonsList.exists() == (state.length == 0)) {
if (addonsList.exists() == (this.installStates.length == 0)) {
LOG("Add-ons list is invalid, rebuilding");
XPIDatabase.writeAddonsList();
}

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

@ -616,6 +616,9 @@ this.XPIDatabase = {
"schemaMismatch-" + inputAddons.schemaVersion);
LOG("JSON schema mismatch: expected " + DB_SCHEMA +
", actual " + inputAddons.schemaVersion);
// When we rev the schema of the JSON database, we need to make sure we
// force the DB to save so that the DB_SCHEMA value in the JSON file and
// the preference are updated.
}
// If we got here, we probably have good data
// Make AddonInternal instances from the loaded data and save them
@ -656,6 +659,7 @@ this.XPIDatabase = {
let schemaVersion = Services.prefs.getIntPref(PREF_DB_SCHEMA);
if (schemaVersion <= LAST_SQLITE_DB_SCHEMA) {
// we should have an older SQLITE database
LOG("Attempting to upgrade from SQLITE database");
this.migrateData = this.getMigrateDataFromSQLITE();
}
else {
@ -756,6 +760,12 @@ this.XPIDatabase = {
this.addonDB = new Map();
this.initialized = true;
if (XPIProvider.installStates && XPIProvider.installStates.length == 0) {
// No extensions installed, so we're done
LOG("Rebuilding XPI database with no extensions");
return;
}
// If there is no migration data then load the list of add-on directories
// that were active during the last run
if (!this.migrateData)
@ -764,13 +774,12 @@ this.XPIDatabase = {
if (aRebuildOnError) {
WARN("Rebuilding add-ons database from installed extensions.");
try {
let state = XPIProvider.getInstallLocationStates();
XPIProvider.processFileChanges(state, {}, false);
XPIProvider.processFileChanges(XPIProvider.installStates, {}, false);
}
catch (e) {
ERROR("Failed to rebuild XPI database from installed extensions", e);
}
// Make to update the active add-ons and add-ons list on shutdown
// Make sure to update the active add-ons and add-ons list on shutdown
Services.prefs.setBoolPref(PREF_PENDING_OPERATIONS, true);
}
},
@ -786,10 +795,13 @@ this.XPIDatabase = {
getActiveBundles: function XPIDB_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 {

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

@ -377,10 +377,8 @@ function startupManager(aAppChanged) {
do_throw("Test attempt to startup manager that was already started.");
if (aAppChanged || aAppChanged === undefined) {
var file = gProfD.clone();
file.append("extensions.ini");
if (file.exists())
file.remove(true);
if (gExtensionsINI.exists())
gExtensionsINI.remove(true);
}
gInternalManager = AM_Cc["@mozilla.org/addons/integration;1"].
@ -473,14 +471,12 @@ function loadAddonsList() {
themes: []
};
var file = gProfD.clone();
file.append("extensions.ini");
if (!file.exists())
if (!gExtensionsINI.exists())
return;
var factory = AM_Cc["@mozilla.org/xpcom/ini-parser-factory;1"].
getService(AM_Ci.nsIINIParserFactory);
var parser = factory.createINIParser(file);
var parser = factory.createINIParser(gExtensionsINI);
gAddonsList.extensions = readDirectories("ExtensionDirs");
gAddonsList.themes = readDirectories("ThemeDirs");
}
@ -1214,6 +1210,14 @@ if ("nsIWindowsRegKey" in AM_Ci) {
// Get the profile directory for tests to use.
const gProfD = do_get_profile();
const EXTENSIONS_DB = "extensions.json";
let gExtensionsJSON = gProfD.clone();
gExtensionsJSON.append(EXTENSIONS_DB);
const EXTENSIONS_INI = "extensions.ini";
let gExtensionsINI = gProfD.clone();
gExtensionsINI.append(EXTENSIONS_INI);
// Enable more extensive EM logging
Services.prefs.setBoolPref("extensions.logging.enabled", true);
@ -1399,10 +1403,6 @@ function do_exception_wrap(func) {
};
}
const EXTENSIONS_DB = "extensions.json";
let gExtensionsJSON = gProfD.clone();
gExtensionsJSON.append(EXTENSIONS_DB);
/**
* Change the schema version of the JSON extensions database
*/

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

@ -167,9 +167,7 @@ function run_test() {
do_check_false(gExtensionsJSON.exists());
let file = gProfD.clone();
file.leafName = "extensions.ini";
do_check_false(file.exists());
do_check_false(gExtensionsINI.exists());
do_check_bootstrappedPref(run_test_1);
}
@ -223,9 +221,7 @@ function run_test_1() {
}
function check_test_1(installSyncGUID) {
let file = gProfD.clone();
file.leafName = "extensions.ini";
do_check_false(file.exists());
do_check_false(gExtensionsINI.exists());
AddonManager.getAllInstalls(function(installs) {
// There should be no active installs now since the install completed and
@ -313,9 +309,7 @@ function run_test_3() {
do_check_eq(getShutdownNewVersion(), 0);
do_check_not_in_crash_annotation("bootstrap1@tests.mozilla.org", "1.0");
let file = gProfD.clone();
file.append("extensions.ini");
do_check_false(file.exists());
do_check_false(gExtensionsINI.exists());
AddonManager.getAddonByID("bootstrap1@tests.mozilla.org", function(b1) {
do_check_neq(b1, null);

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

@ -143,12 +143,12 @@ var PluginHostFactory = {
// Don't need the full interface, attempts to call other methods will just
// throw which is just fine
var WindowWatcher = {
openWindow: function(parent, url, name, features, arguments) {
openWindow: function(parent, url, name, features, windowArguments) {
// Should be called to list the newly blocklisted items
do_check_eq(url, URI_EXTENSION_BLOCKLIST_DIALOG);
if (gNotificationCheck) {
var args = arguments.wrappedJSObject;
var args = windowArguments.wrappedJSObject;
gNotificationCheck(args);
}
@ -205,10 +205,12 @@ function create_addon(addon) {
target.append("extensions");
target.append(addon.id);
target.append("install.rdf");
target.create(target.NORMAL_FILE_TYPE, 0644);
target.create(target.NORMAL_FILE_TYPE, FileUtils.PERMS_FILE);
var stream = Cc["@mozilla.org/network/file-output-stream;1"].
createInstance(Ci.nsIFileOutputStream);
stream.init(target, 0x04 | 0x08 | 0x20, 0664, 0); // write, create, truncate
stream.init(target,
FileUtils.MODE_WRONLY | FileUtils.MODE_CREATE | FileUtils.MODE_TRUNCATE,
FileUtils.PERMS_FILE, 0);
stream.write(installrdf, installrdf.length);
stream.close();
}

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

@ -0,0 +1,98 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
// Test startup and restart when no add-ons are installed
// bug 944006
Components.utils.import("resource://gre/modules/Promise.jsm");
// Load XPI Provider to get schema version ID
let XPIScope = Components.utils.import("resource://gre/modules/XPIProvider.jsm");
const DB_SCHEMA = XPIScope.DB_SCHEMA;
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2");
function run_test() {
// Kick off the task-based tests...
run_next_test();
}
// Test for a preference to either exist with a specified value, or not exist at all
function checkPending() {
try {
do_check_false(Services.prefs.getBoolPref("extensions.pendingOperations"));
}
catch (e) {
// OK
}
}
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();
}
// After first run with no add-ons, we expect:
// no extensions.json is created
// no extensions.ini
// database schema version preference is set
// bootstrap add-ons preference is not found
// add-on directory state preference is an empty array
// no pending operations
add_task(function first_run() {
startupManager();
check_empty_state();
yield true;
});
// Now do something that causes a DB load, and re-check
function trigger_db_load() {
let addonDefer = Promise.defer();
AddonManager.getAddonsByTypes(['extension'], addonDefer.resolve);
let addonList = yield addonDefer.promise;
do_check_eq(addonList.length, 0);
check_empty_state();
yield true;
};
add_task(trigger_db_load);
// Now restart the manager and check again
add_task(function restart_and_recheck() {
restartManager();
check_empty_state();
yield true;
});
// and reload the DB again
add_task(trigger_db_load);
// When we start up with no DB and an old database schema, we should update the
// schema number but not create a database
add_task(function upgrade_schema_version() {
shutdownManager();
Services.prefs.setIntPref("extensions.databaseSchema", 1);
startupManager();
do_check_eq(Services.prefs.getIntPref("extensions.databaseSchema"), DB_SCHEMA);
check_empty_state();
});

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

@ -132,12 +132,9 @@ function run_test() {
check_startup_changes(AddonManager.STARTUP_CHANGE_DISABLED, []);
check_startup_changes(AddonManager.STARTUP_CHANGE_ENABLED, []);
let file = gProfD.clone();
file.append("extensions.json");
do_check_false(file.exists());
do_check_false(gExtensionsJSON.exists());
file.leafName = "extensions.ini";
do_check_false(file.exists());
do_check_false(gExtensionsINI.exists());
AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",
"addon2@tests.mozilla.org",
@ -190,10 +187,8 @@ function run_test_1() {
check_startup_changes(AddonManager.STARTUP_CHANGE_ENABLED, []);
do_check_true(gCachePurged);
let file = gProfD.clone();
file.append = "extensions.ini";
do_print("Checking for " + file.path);
do_check_true(file.exists());
do_print("Checking for " + gExtensionsINI.path);
do_check_true(gExtensionsINI.exists());
AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",
"addon2@tests.mozilla.org",
@ -302,9 +297,7 @@ function run_test_2() {
check_startup_changes(AddonManager.STARTUP_CHANGE_ENABLED, []);
do_check_true(gCachePurged);
var file = gProfD.clone();
file.append("extensions.ini");
do_check_true(file.exists());
do_check_true(gExtensionsINI.exists());
AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",
"addon2@tests.mozilla.org",

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

@ -179,9 +179,7 @@ function run_test_3() {
// Simulates a simple Build ID change, the platform deletes extensions.ini
// whenever the application is changed.
var file = gProfD.clone();
file.append("extensions.ini");
file.remove(true);
gExtensionsINI.remove(true);
restartManager();
AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",

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

@ -182,9 +182,7 @@ function run_test_3() {
// Simulates a simple Build ID change, the platform deletes extensions.ini
// whenever the application is changed.
var file = gProfD.clone();
file.append("extensions.ini");
file.remove(true);
gExtensionsINI.remove(true);
restartManager();
AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",

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

@ -205,6 +205,7 @@ skip-if = os == "android"
[test_migrate5.js]
[test_migrateAddonRepository.js]
[test_migrate_max_version.js]
[test_no_addons.js]
[test_onPropertyChanged_appDisabled.js]
[test_permissions.js]
[test_permissions_prefs.js]