mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-28 07:13:20 +00:00
Bug 594058 - invalidate cache by statting contents of extensions directory r=dtownsend r=bz a=bsmedberg
This commit is contained in:
parent
b07a02bb8b
commit
fb0a2b2373
@ -183,6 +183,9 @@ nsXULPrototypeCache::Observe(nsISupports* aSubject,
|
||||
else if (!strcmp(aTopic, "chrome-flush-caches")) {
|
||||
Flush();
|
||||
}
|
||||
else if (!strcmp(aTopic, "startupcache-invalidate")) {
|
||||
AbortFastLoads();
|
||||
}
|
||||
else {
|
||||
NS_WARNING("Unexpected observer topic.");
|
||||
}
|
||||
|
@ -175,6 +175,9 @@ StartupCache::Init()
|
||||
rv = mObserverService->AddObserver(mListener, NS_XPCOM_SHUTDOWN_OBSERVER_ID,
|
||||
PR_FALSE);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = mObserverService->AddObserver(mListener, "startupcache-invalidate",
|
||||
PR_FALSE);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = LoadArchive();
|
||||
|
||||
@ -420,6 +423,10 @@ StartupCacheListener::Observe(nsISupports *subject, const char* topic, const PRU
|
||||
nsresult rv = NS_OK;
|
||||
if (strcmp(topic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) {
|
||||
StartupCache::gShutdownInitiated = PR_TRUE;
|
||||
} else if (strcmp(topic, "startupcache-invalidate") == 0) {
|
||||
StartupCache* sc = StartupCache::GetSingleton();
|
||||
if (sc)
|
||||
sc->InvalidateCache();
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
@ -888,6 +888,34 @@ function resultRows(aStatement) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the timestamp of the most recently modified file in a directory,
|
||||
* or simply the file's own timestamp if it is not a directory.
|
||||
*
|
||||
* @param aFile
|
||||
* A non-null nsIFile object
|
||||
* @return Epoch time, as described above. 0 for an empty directory.
|
||||
*/
|
||||
function recursiveLastModifiedTime(aFile) {
|
||||
if (aFile.isFile())
|
||||
return aFile.lastModifiedTime;
|
||||
|
||||
if (aFile.isDirectory()) {
|
||||
let entries = aFile.directoryEntries.QueryInterface(Ci.nsIDirectoryEnumerator);
|
||||
let entry, time;
|
||||
let maxTime = aFile.lastModifiedTime;
|
||||
while (entry = entries.nextFile) {
|
||||
time = recursiveLastModifiedTime(entry);
|
||||
maxTime = Math.max(time, maxTime);
|
||||
}
|
||||
entries.close();
|
||||
return maxTime;
|
||||
}
|
||||
|
||||
// If the file is something else, just ignore it.
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* A helpful wrapper around the prefs service that allows for default values
|
||||
* when requested values aren't set.
|
||||
@ -1296,9 +1324,10 @@ var XPIProvider = {
|
||||
}
|
||||
catch (e) { }
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Gets the add-on states for an install location.
|
||||
* Gets the add-on states for an install location.
|
||||
* This function may be expensive because of the recursiveLastModifiedTime call.
|
||||
*
|
||||
* @param location
|
||||
* The install location to retrieve the add-on states for
|
||||
@ -1313,7 +1342,7 @@ var XPIProvider = {
|
||||
let id = aLocation.getIDForLocation(file);
|
||||
addonStates[id] = {
|
||||
descriptor: file.persistentDescriptor,
|
||||
mtime: file.lastModifiedTime
|
||||
mtime: recursiveLastModifiedTime(file)
|
||||
};
|
||||
});
|
||||
|
||||
@ -1323,7 +1352,7 @@ var XPIProvider = {
|
||||
/**
|
||||
* Gets an array of install location states which uniquely describes all
|
||||
* installed add-ons with the add-on's InstallLocation name and last modified
|
||||
* time.
|
||||
* time. This function may be expensive because of the getAddonStates() call.
|
||||
*
|
||||
* @return an array of add-on states for each install location. Each state
|
||||
* is an object with a name property holding the location's name and
|
||||
@ -1461,7 +1490,8 @@ var XPIProvider = {
|
||||
/**
|
||||
* Compares the add-ons that are currently installed to those that were
|
||||
* known to be installed when the application last ran and applies any
|
||||
* changes found to the database.
|
||||
* changes found to the database. Also sends "startupcache-invalidate" signal to
|
||||
* observerservice if it detects that data may have changed.
|
||||
*
|
||||
* @param aState
|
||||
* The array of current install location states
|
||||
@ -1869,6 +1899,12 @@ var XPIProvider = {
|
||||
// Cache the new install location states
|
||||
cache = JSON.stringify(this.getInstallLocationStates());
|
||||
Services.prefs.setCharPref(PREF_INSTALL_CACHE, cache);
|
||||
|
||||
if (changed) {
|
||||
// Init this, so it will get the notification.
|
||||
let xulPrototypeCache = Cc["@mozilla.org/xul/xul-prototype-cache;1"].getService(Ci.nsISupports);
|
||||
Services.obs.notifyObservers(null, "startupcache-invalidate", null);
|
||||
}
|
||||
return changed;
|
||||
},
|
||||
|
||||
@ -4975,7 +5011,7 @@ AddonInstall.prototype = {
|
||||
|
||||
// Update the metadata in the database
|
||||
this.addon._installLocation = this.installLocation;
|
||||
this.addon.updateDate = file.lastModifiedTime;
|
||||
this.addon.updateDate = recursiveLastModifiedTime(file);
|
||||
this.addon.visible = true;
|
||||
if (isUpgrade) {
|
||||
XPIDatabase.updateAddonMetadata(this.existingAddon, this.addon,
|
||||
|
@ -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>1</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>
|
@ -572,6 +572,23 @@ function writeInstallRDFForExtension(aData, aDir, aId, aExtraFile) {
|
||||
return dir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the last modified time of the extension, usually to trigger an update
|
||||
* of its metadata. If the extension is unpacked, this function assumes that
|
||||
* the extension contains only the install.rdf file.
|
||||
*
|
||||
* @param aExt a file pointing to either the packed extension or its unpacked directory.
|
||||
* @param aTime the time to which we set the lastModifiedTime of the extension
|
||||
*/
|
||||
function setExtensionModifiedTime(aExt, aTime) {
|
||||
aExt.lastModifiedTime = aTime;
|
||||
if (aExt.isDirectory()) {
|
||||
aExt = aExt.clone();
|
||||
aExt.append("install.rdf");
|
||||
aExt.lastModifiedTime = aTime;
|
||||
}
|
||||
}
|
||||
|
||||
function registerDirectory(aKey, aDir) {
|
||||
var dirProvider = {
|
||||
getFile: function(aProp, aPersistent) {
|
||||
|
@ -24,7 +24,7 @@ function run_test() {
|
||||
}, profileDir);
|
||||
// Attempt to make this look like it was added some time in the past so
|
||||
// the update makes the last modified time change.
|
||||
dest.lastModifiedTime -= 5000;
|
||||
setExtensionModifiedTime(dest, dest.lastModifiedTime - 5000);
|
||||
|
||||
startupManager();
|
||||
|
||||
|
62
toolkit/mozapps/extensions/test/xpcshell/test_bug594058.js
Normal file
62
toolkit/mozapps/extensions/test/xpcshell/test_bug594058.js
Normal file
@ -0,0 +1,62 @@
|
||||
/* 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);
|
||||
|
||||
const Ci = Components.interfaces;
|
||||
const extDir = gProfD.clone();
|
||||
extDir.append("extensions");
|
||||
|
||||
/**
|
||||
* Start the test by installing extensions.
|
||||
*/
|
||||
function run_test() {
|
||||
do_test_pending();
|
||||
let cachePurged = false;
|
||||
|
||||
let obs = AM_Cc["@mozilla.org/observer-service;1"].
|
||||
getService(AM_Ci.nsIObserverService);
|
||||
obs.addObserver({
|
||||
observe: function(aSubject, aTopic, aData) {
|
||||
cachePurged = true;
|
||||
}
|
||||
}, "startupcache-invalidate", false);
|
||||
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1");
|
||||
startupManager();
|
||||
|
||||
installAllFiles([do_get_addon("test_bug594058")], function() {
|
||||
restartManager();
|
||||
do_check_true(cachePurged);
|
||||
cachePurged = 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();
|
||||
cachePurged = false;
|
||||
|
||||
otherFile.lastModifiedTime = pastTime + 5000;
|
||||
restartManager();
|
||||
do_check_true(cachePurged);
|
||||
cachePurged = false;
|
||||
|
||||
restartManager();
|
||||
do_check_true(!cachePurged);
|
||||
|
||||
do_test_finished();
|
||||
});
|
||||
}
|
@ -220,7 +220,7 @@ function run_test_5() {
|
||||
|
||||
var dest = writeInstallRDFForExtension(addon2, sourceDir, addon1.id);
|
||||
// Make sure the modification time changes enough to be detected.
|
||||
dest.lastModifiedTime -= 5000;
|
||||
setExtensionModifiedTime(dest, dest.lastModifiedTime - 5000);
|
||||
|
||||
restartManager();
|
||||
|
||||
@ -310,7 +310,7 @@ function run_test_8() {
|
||||
|
||||
var dest = writeInstallRDFForExtension(addon1_2, sourceDir);
|
||||
// Make sure the modification time changes enough to be detected.
|
||||
dest.lastModifiedTime -= 5000;
|
||||
setExtensionModifiedTime(dest, dest.lastModifiedTime - 5000);
|
||||
|
||||
restartManager();
|
||||
|
||||
|
@ -120,7 +120,8 @@ function run_test_1() {
|
||||
var dest = writeInstallRDFForExtension(addon2, profileDir);
|
||||
// Attempt to make this look like it was added some time in the past so
|
||||
// the change in run_test_2 makes the last modified time change.
|
||||
dest.lastModifiedTime -= 5000;
|
||||
setExtensionModifiedTime(dest, dest.lastModifiedTime - 5000);
|
||||
|
||||
writeInstallRDFForExtension(addon3, profileDir);
|
||||
writeInstallRDFForExtension(addon4, profileDir);
|
||||
writeInstallRDFForExtension(addon5, profileDir);
|
||||
|
@ -75,7 +75,7 @@ function run_test() {
|
||||
}],
|
||||
name: "Test Addon 4",
|
||||
}, globalDir);
|
||||
dest.lastModifiedTime = gInstallTime;
|
||||
setExtensionModifiedTime(dest, gInstallTime);
|
||||
|
||||
do_test_pending();
|
||||
|
||||
@ -133,7 +133,7 @@ function run_test_2() {
|
||||
}],
|
||||
name: "Test Addon 4",
|
||||
}, globalDir);
|
||||
dest.lastModifiedTime = gInstallTime;
|
||||
setExtensionModifiedTime(dest, gInstallTime);
|
||||
|
||||
restartManager("2");
|
||||
AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",
|
||||
@ -172,7 +172,7 @@ function run_test_3() {
|
||||
}],
|
||||
name: "Test Addon 4",
|
||||
}, globalDir);
|
||||
dest.lastModifiedTime = gInstallTime;
|
||||
setExtensionModifiedTime(dest, gInstallTime);
|
||||
|
||||
// Simulates a simple Build ID change, the platform deletes extensions.ini
|
||||
// whenever the application is changed.
|
||||
|
Loading…
Reference in New Issue
Block a user