Bug 1258496 - Fire message-manager-flush-caches to update message manager cached scripts. r=mossop
authorAlexandre Poirot <poirot.alex@gmail.com>
Wed, 13 Apr 2016 11:04:11 -0700
changeset 330925 6f51002d4589638e0120681f8de5512c48bb5155
parent 330924 4653c5c78f68b6a437444815de7ed04048f23745
child 330926 a01d14eb9caf57b73ede38fcfe3620e42f9b32db
push id6048
push userkmoir@mozilla.com
push dateMon, 06 Jun 2016 19:02:08 +0000
treeherdermozilla-beta@46d72a56c57d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmossop
bugs1258496
milestone48.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1258496 - Fire message-manager-flush-caches to update message manager cached scripts. r=mossop
toolkit/mozapps/extensions/internal/Content.js
toolkit/mozapps/extensions/internal/XPIProvider.jsm
toolkit/mozapps/extensions/internal/XPIProviderUtils.js
toolkit/mozapps/extensions/test/browser/addons/browser_update1_1.xpi
toolkit/mozapps/extensions/test/browser/addons/browser_update1_1/bootstrap.js
toolkit/mozapps/extensions/test/browser/addons/browser_update1_1/chrome.manifest
toolkit/mozapps/extensions/test/browser/addons/browser_update1_1/frame-script.js
toolkit/mozapps/extensions/test/browser/addons/browser_update1_1/install.rdf
toolkit/mozapps/extensions/test/browser/addons/browser_update1_2.xpi
toolkit/mozapps/extensions/test/browser/addons/browser_update1_2/bootstrap.js
toolkit/mozapps/extensions/test/browser/addons/browser_update1_2/chrome.manifest
toolkit/mozapps/extensions/test/browser/addons/browser_update1_2/frame-script.js
toolkit/mozapps/extensions/test/browser/addons/browser_update1_2/install.rdf
toolkit/mozapps/extensions/test/browser/browser.ini
toolkit/mozapps/extensions/test/browser/browser_update.js
--- a/toolkit/mozapps/extensions/internal/Content.js
+++ b/toolkit/mozapps/extensions/internal/Content.js
@@ -11,23 +11,28 @@
 var {classes: Cc, interfaces: Ci, utils: Cu} = Components;
 
 var {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
 
 var nsIFile = Components.Constructor("@mozilla.org/file/local;1", "nsIFile",
                                      "initWithPath");
 
 const MSG_JAR_FLUSH = "AddonJarFlush";
+const MSG_MESSAGE_MANAGER_CACHES_FLUSH = "AddonMessageManagerCachesFlush";
 
 
 try {
   if (Services.appinfo.processType !== Services.appinfo.PROCESS_TYPE_DEFAULT) {
-  // Propagate JAR cache flush notifications across process boundaries.
+    // Propagate JAR cache flush notifications across process boundaries.
     addMessageListener(MSG_JAR_FLUSH, function(message) {
       let file = new nsIFile(message.data);
       Services.obs.notifyObservers(file, "flush-cache-entry", null);
     });
+    // Propagate message manager caches flush notifications across processes.
+    addMessageListener(MSG_MESSAGE_MANAGER_CACHES_FLUSH, function() {
+      Services.obs.notifyObservers(null, "message-manager-flush-caches", null);
+    });
   }
 } catch(e) {
   Cu.reportError(e);
 }
 
 })();
--- a/toolkit/mozapps/extensions/internal/XPIProvider.jsm
+++ b/toolkit/mozapps/extensions/internal/XPIProvider.jsm
@@ -256,16 +256,17 @@ const XPI_BEFORE_UI_STARTUP = "BeforeFin
 const XPI_AFTER_UI_STARTUP = "AfterFinalUIStartup";
 
 const COMPATIBLE_BY_DEFAULT_TYPES = {
   extension: true,
   dictionary: true
 };
 
 const MSG_JAR_FLUSH = "AddonJarFlush";
+const MSG_MESSAGE_MANAGER_CACHES_FLUSH = "AddonMessageManagerCachesFlush";
 
 var gGlobalScope = this;
 
 /**
  * Valid IDs fit this pattern.
  */
 var gIDTest = /^(\{[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\}|[a-z0-9-\._]*\@[a-z0-9-\._]+)$/i;
 
@@ -295,17 +296,17 @@ function loadLazyObjects() {
     DB_SCHEMA,
     AddonInternal,
     XPIProvider,
     XPIStates,
     syncLoadManifestFromFile,
     isUsableAddon,
     recordAddonTelemetry,
     applyBlocklistChanges,
-    flushStartupCache,
+    flushChromeCaches,
     canRunInSafeMode,
   }
 
   for (let key of Object.keys(shared))
     scope[key] = shared[key];
 
   Services.scriptloader.loadSubScript(uri, scope);
 
@@ -1500,23 +1501,26 @@ function buildJarURI(aJarfile, aPath) {
 /**
  * Sends local and remote notifications to flush a JAR file cache entry
  *
  * @param aJarFile
  *        The ZIP/XPI/JAR file as a nsIFile
  */
 function flushJarCache(aJarFile) {
   Services.obs.notifyObservers(aJarFile, "flush-cache-entry", null);
-  Cc["@mozilla.org/globalmessagemanager;1"].getService(Ci.nsIMessageBroadcaster)
-    .broadcastAsyncMessage(MSG_JAR_FLUSH, aJarFile.path);
+  Services.mm.broadcastAsyncMessage(MSG_JAR_FLUSH, aJarFile.path);
 }
 
-function flushStartupCache() {
+function flushChromeCaches() {
   // Init this, so it will get the notification.
   Services.obs.notifyObservers(null, "startupcache-invalidate", null);
+  // Flush message manager cached scripts
+  Services.obs.notifyObservers(null, "message-manager-flush-caches", null);
+  // Also dispatch this event to child processes
+  Services.mm.broadcastAsyncMessage(MSG_MESSAGE_MANAGER_CACHES_FLUSH, null);
 }
 
 /**
  * Creates and returns a new unique temporary file. The caller should delete
  * the file when it is no longer needed.
  *
  * @return an nsIFile that points to a randomly named, initially empty file in
  *         the OS temporary files directory
@@ -2645,17 +2649,17 @@ this.XPIProvider = {
         let addonsToUpdate = this.shouldForceUpdateCheck(aAppChanged);
         if (addonsToUpdate) {
           this.showUpgradeUI(addonsToUpdate);
           flushCaches = true;
         }
       }
 
       if (flushCaches) {
-        flushStartupCache();
+        Services.obs.notifyObservers(null, "startupcache-invalidate", null);
         // UI displayed early in startup (like the compatibility UI) may have
         // caused us to cache parts of the skin or locale in memory. These must
         // be flushed to allow extension provided skins and locales to take full
         // effect
         Services.obs.notifyObservers(null, "chrome-flush-skin-caches", null);
         Services.obs.notifyObservers(null, "chrome-flush-caches", null);
       }
 
@@ -3330,17 +3334,17 @@ this.XPIProvider = {
               let uninstallReason = Services.vc.compare(oldVersion, newVersion) < 0 ?
                                     BOOTSTRAP_REASONS.ADDON_UPGRADE :
                                     BOOTSTRAP_REASONS.ADDON_DOWNGRADE;
 
               this.callBootstrapMethod(createAddonDetails(existingAddonID, oldBootstrap),
                                        existingAddon, "uninstall", uninstallReason,
                                        { newVersion: newVersion });
               this.unloadBootstrapScope(existingAddonID);
-              flushStartupCache();
+              flushChromeCaches();
             }
           }
           catch (e) {
           }
         }
 
         try {
           addon._sourceBundle = location.installAddon(id, stageDirEntry,
@@ -3873,17 +3877,17 @@ this.XPIProvider = {
         if (oldAddon.active) {
           XPIProvider.callBootstrapMethod(oldAddon, existingAddon,
                                           "shutdown", uninstallReason,
                                           { newVersion });
         }
         this.callBootstrapMethod(oldAddon, existingAddon,
                                  "uninstall", uninstallReason, { newVersion });
         this.unloadBootstrapScope(existingAddonID);
-        flushStartupCache();
+        flushChromeCaches();
       }
     }
 
     let file = addon._sourceBundle;
 
     XPIProvider._addURIMapping(addon.id, file);
     XPIProvider.callBootstrapMethod(addon, file, "install",
                                     BOOTSTRAP_REASONS.ADDON_INSTALL);
@@ -4988,17 +4992,17 @@ this.XPIProvider = {
         if (aAddon.active) {
           this.callBootstrapMethod(aAddon, aAddon._sourceBundle, "shutdown",
                                    BOOTSTRAP_REASONS.ADDON_UNINSTALL);
         }
 
         this.callBootstrapMethod(aAddon, aAddon._sourceBundle, "uninstall",
                                  BOOTSTRAP_REASONS.ADDON_UNINSTALL);
         this.unloadBootstrapScope(aAddon.id);
-        flushStartupCache();
+        flushChromeCaches();
       }
       aAddon._installLocation.uninstallAddon(aAddon.id);
       XPIDatabase.removeAddonMetadata(aAddon);
       XPIStates.removeAddon(aAddon.location, aAddon.id);
       AddonManagerPrivate.callAddonListeners("onUninstalled", wrapper);
 
       findAddonAndReveal(aAddon.id);
     }
@@ -6095,17 +6099,17 @@ AddonInstall.prototype = {
                                               "shutdown", reason,
                                               { newVersion: this.addon.version });
             }
 
             XPIProvider.callBootstrapMethod(this.existingAddon, file,
                                             "uninstall", reason,
                                             { newVersion: this.addon.version });
             XPIProvider.unloadBootstrapScope(this.existingAddon.id);
-            flushStartupCache();
+            flushChromeCaches();
           }
 
           if (!isUpgrade && this.existingAddon.active) {
             XPIDatabase.updateAddonActive(this.existingAddon, false);
           }
         }
 
         // Install the new add-on into its final location
@@ -7304,17 +7308,17 @@ AddonWrapper.prototype = {
       const isReloadable = (!XPIProvider.enableRequiresRestart(addon) &&
                             !XPIProvider.disableRequiresRestart(addon));
       if (!isReloadable) {
         throw new Error(
           "cannot reload add-on because it requires a browser restart");
       }
 
       this.userDisabled = true;
-      flushStartupCache();
+      flushChromeCaches();
       this.userDisabled = false;
       resolve();
     });
   },
 
   /**
    * Returns a URI to the selected resource or to the add-on bundle if aPath
    * is null. URIs to the bundle will always be file: URIs. URIs to resources
--- a/toolkit/mozapps/extensions/internal/XPIProviderUtils.js
+++ b/toolkit/mozapps/extensions/internal/XPIProviderUtils.js
@@ -3,17 +3,17 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 // These are injected from XPIProvider.jsm
 /*globals ADDON_SIGNING, SIGNED_TYPES, BOOTSTRAP_REASONS, DB_SCHEMA,
           AddonInternal, XPIProvider, XPIStates, syncLoadManifestFromFile,
           isUsableAddon, recordAddonTelemetry, applyBlocklistChanges,
-          flushStartupCache, canRunInSafeMode*/
+          flushChromeCaches, canRunInSafeMode*/
 
 var Cc = Components.classes;
 var Ci = Components.interfaces;
 var Cr = Components.results;
 var Cu = Components.utils;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
@@ -2115,17 +2115,17 @@ this.XPIDatabaseReconcile = {
 
             XPIProvider.callBootstrapMethod(previousAddon, previousAddon._sourceBundle,
                                             "uninstall", installReason,
                                             { newVersion: currentAddon.version });
             XPIProvider.unloadBootstrapScope(previousAddon.id);
           }
 
           // Make sure to flush the cache when an old add-on has gone away
-          flushStartupCache();
+          flushChromeCaches();
 
           if (currentAddon.bootstrap) {
             // Visible bootstrapped add-ons need to have their install method called
             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 });
@@ -2172,17 +2172,17 @@ this.XPIDatabaseReconcile = {
       if (previousAddon.bootstrap && exists(previousAddon)) {
         XPIProvider.callBootstrapMethod(previousAddon, previousAddon._sourceBundle,
                                         "uninstall", BOOTSTRAP_REASONS.ADDON_UNINSTALL);
         XPIProvider.unloadBootstrapScope(previousAddon.id);
       }
       AddonManagerPrivate.addStartupChange(AddonManager.STARTUP_CHANGE_UNINSTALLED, id);
 
       // Make sure to flush the cache when an old add-on has gone away
-      flushStartupCache();
+      flushChromeCaches();
     }
 
     // Make sure add-ons from hidden locations are marked invisible and inactive
     let locationAddonMap = currentAddons.get(hideLocation);
     if (locationAddonMap) {
       for (let addon of locationAddonMap.values()) {
         addon.visible = false;
         addon.active = false;
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..aba80181d2d1e028d002737172d4ee8a6c729db4
GIT binary patch
literal 1416
zc$^FHW@Zs#U|`^2U@&a=*ytsBHI|WqA&!}Wftx{wAv3SIBrzvPuP7xgG=!6Zd3`in
zI0%<ka5FHnya1{K6MKU%`W-S5sl6Y5<zrgVtz4HIMr>*)X6w7v?sqtNY;Ei<YscRI
z?=*5Yboi@%Tl;)o@q5dcxmGttEh~kOd96KGcj5UzmCt*=B$}z0y58LQzbQhkCwKep
ze`c?;HzzvE9Peq@;aM5Ec4ciihxMwQ^WRVWvq)6x>f3ff-st>6Qw~dcgTOaeZTHK$
zdsqpVWu|m)<z?cIeRyMik5}I+7p?9I&$lqBUO$wy_Ljew>%<eGVN<mo1bsHHyYbmm
z(^??vlVN5Ud+F9^_k_fv7P~U1wk;FtD{k5|tu4WfDgU(5bngS(oXtI&x7yhsEjpsS
zPwrCciAKIWwrnZ=9Sa;;1dk}mxh*~ze!OI{-jXW2s;7TX1fE-<CtAi^SF13u;h5_0
z#LI^IM}8%zT(PR3YVr4Npx)Ep-%G-$Oxk&o>*U<1iPen;%q&hXGxbG8l&XuW-Q>P!
zKeMvB@;1Lb<<u+wDV6sF;4w7Upxq<s$pWj@K;9i7<_E@5T2W$ds%~*|QD#AjURE(U
zmVQOCg-c_`lI<DCtiujGtq=G5EAH`PmNdOxCORv3;RInH(?j!;df7brES9gI?K<7Q
z=KVuKy<Fx?`y%H)Yj_o~BjnUURwu=@w)J1DSF(gpjfs|ez)|c{@2v7z=Igm7O1ErQ
z`reqo!$#NchRFGsqTdDi4!3(<Kc;K5Hc;HZG{5_B#+zMIAOBfOF3yM)FWa;6uJ*>|
z^3y*)t^JYzO6lazsonX#b~kPPYa~*wp9XE2d#?VMILOaj3?KmVv-6>u7N8Iif%-W)
zqbNT&RWCO&FEcH*xCEb{i&Bg8ON)|I6>=+e6H`+1^Az;BPy<w@*lqP2Aa4>d+4BGm
zPs-0PDK05WEFch?wG$lum<@SczZY|5hvi;X+t4bi#lGT-aLbXooL-Mkly$Kkx!ak>
zC@Q40|L>oa+wUH%)OoN{PiA?fA{PtKMeCysUJHy5t=zlh#lxAKx{vZ~XpY=!7x7wh
z?lJAEQ!~3H9-X`<%BP)uf8xn|v#oEpzcGl3`Y5&1L1&TPQs07C-!AAnrE<&9w|9BJ
zdE2kq5)6G)v_*BamSy@RC7oY0dt%^<jmP)hIFe!9IxXOh<WDKvuF9!4dGfm-?heX6
zr#6vWec8OHZ!E*^masesn?AjnyRmEUhSL=jL|^YK<QJdLviob<*PWRQwtqTby7te{
zM*RS9MkYCCT*ZV0IHG`DhAoXC7D}PP3Mn+u0uR|h%v6nR;36P}k;Yjev4Yi5T*(I6
o&}mEzn289Vp}3L@vZ0@WhN31OTqd%zfpoC|p)XLYDhr4Q0JOLNTL1t6
new file mode 100644
--- /dev/null
+++ b/toolkit/mozapps/extensions/test/browser/addons/browser_update1_1/bootstrap.js
@@ -0,0 +1,12 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+function install(data, reason) {}
+function startup(data, reason) {
+  Components.utils.import("resource://gre/modules/Services.jsm");
+  Services.ppmm.loadProcessScript(
+    "resource://my-addon/frame-script.js", false);
+}
+function shutdown(data, reason) {}
+function uninstall(data, reason) {}
new file mode 100644
--- /dev/null
+++ b/toolkit/mozapps/extensions/test/browser/addons/browser_update1_1/chrome.manifest
@@ -0,0 +1,1 @@
+resource my-addon .
new file mode 100644
--- /dev/null
+++ b/toolkit/mozapps/extensions/test/browser/addons/browser_update1_1/frame-script.js
@@ -0,0 +1,6 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+Components.utils.import("resource://gre/modules/Services.jsm");
+Services.cpmm.sendAsyncMessage("my-addon-1");
new file mode 100644
--- /dev/null
+++ b/toolkit/mozapps/extensions/test/browser/addons/browser_update1_1/install.rdf
@@ -0,0 +1,31 @@
+<?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>update1@tests.mozilla.org</em:id>
+    <em:version>1.0</em:version>
+    <em:bootstrap>true</em:bootstrap>
+
+    <em:targetApplication>
+      <Description>
+        <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
+        <em:minVersion>0.3</em:minVersion>
+        <em:maxVersion>*</em:maxVersion>
+      </Description>
+    </em:targetApplication>
+
+    <em:targetApplication>
+      <Description>
+        <em:id>toolkit@mozilla.org</em:id>
+        <em:minVersion>0</em:minVersion>
+        <em:maxVersion>*</em:maxVersion>
+      </Description>
+    </em:targetApplication>
+
+    <!-- Front End MetaData -->
+    <em:name>Update Tests</em:name>
+
+  </Description>
+</RDF>
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..8d7fd01e824611b91915bf00a0ec0c40387645dd
GIT binary patch
literal 1418
zc$^FHW@Zs#U|`^2U^8s@Sida9E{>6bA&!}Wftx{wAv3SIBrzvPuP7xgG=!6Zc~3N3
zI0%<ka5FHnya1{K6MKU%`W-S5sl6Y5<zw2VtvN0?jM&sp%+`0S-M^u!H+uILamU{O
z?=*5Yboi@%Tl;)o@q5dcxmGu)vQ`Qo^IChX&i=tamCt*=B$}z0y58LQzbQhsCwKep
z1Zmb=Ya;FYl8-rywOx6lopoRIP@mTA&$gTF{bqD*TCDrEU5BfH*XbO)&y?!Y^Xrcb
zPCC~TD;1fT+kC(&zu--Nk5}I+7p?99ku5B$;fIpe-tzZyoq59Mc8KMI7ycX9-T3UO
zX)O@-$uLul?atL%)!q>qy<)r}lCydX<_JI8YQnNvtRgzJHHK-M>@G*CHD7;fPE(fq
zcy)rFGha!8am2-ngRF1e1sruAC7MXpl=_&z3R?Aiak!jIUlCjB$_?2cUNe7WG10rp
zKfA9|@tVBy;%i4&A9<PIU!-|||MK07rkv>w^LQ8H_m1@tj{wKg<$D7Hy55|8D_MDG
z{mj=d0=DnJJ5h7BeZaF?<^XsUEjDQP*ffu!b`6ks2Z;HBQIuAcn479woLrPyP@<Pr
z42~uyU=&GXMw9Is$E?E+JgpD+`YZ17VwT(*yKVJ^JnqJM39AIRb)}nl6dkavy{oh9
z&%<i|{(?N|3E$49%wj&Wut4zCK~^Wlw6@p3_HrC-zow(hThL;;Xusm5LcX1bnQL#^
ztn|Ghzr#l7-c6DCOUCb%W!k#0t?P}hh;kP5-?aT`qDfh7Z^i#PJsYzk#moLA?dIIL
zTz>uI%fCO|zmn~HZta}f>@O$ZRX#c#u{~JN_4doJ{{NXkp5|fz0g$Ji56!dy1%U|E
z)5#e{`MIfjxruq1X{p5}_&i;dTAW{6l$@%NTdA9vl9HdNpvQ$8qAJC1tKR^5lYj}I
z2WWUwett=DNl{_}f#9s2;ONI}$m9CGm@7Lh_o~{4R#7eX6<35?j?CrsdUT?!i|xqW
z&NN0*A)Wny|D@c0_h6;YgOz$R%Oe%JSa>d4A7$`bV0>uh-X$*{&fL^}lxIV8<W{?g
z*OGIOX;+<^*(LGl<TX(~?d<y#Pu`nteY^dQK}^&~sg({oi}aTI7QFg)LDwmjTYkR1
z%lpmSe$AF(=$oP~s-v|m(<dqE{F>Pl16OQ3zVF774CB^m0dFLKO4)W*PPNIC-~DiR
zQ1&^siQMYT<~@C58FsgX<w4l=>CN1YU3)j2u9zVDdS4;G_;i-tU(3Gk%v`Yj)A`c1
ze||RV2Y53w$uZ+9C?voU1>`bpX#}xQiVapsv4IwN$Od92Yh(i#11XF|&I*YYtcK!B
qHpqs~U}C^bMEDHFm0XYw{R%V`HSypwk(CXkiv<XMfm+pBKs*3bXaKzc
new file mode 100644
--- /dev/null
+++ b/toolkit/mozapps/extensions/test/browser/addons/browser_update1_2/bootstrap.js
@@ -0,0 +1,12 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+function install(data, reason) {}
+function startup(data, reason) {
+  Components.utils.import("resource://gre/modules/Services.jsm");
+  Services.ppmm.loadProcessScript(
+    "resource://my-addon/frame-script.js", false);
+}
+function shutdown(data, reason) {}
+function uninstall(data, reason) {}
new file mode 100644
--- /dev/null
+++ b/toolkit/mozapps/extensions/test/browser/addons/browser_update1_2/chrome.manifest
@@ -0,0 +1,1 @@
+resource my-addon .
new file mode 100644
--- /dev/null
+++ b/toolkit/mozapps/extensions/test/browser/addons/browser_update1_2/frame-script.js
@@ -0,0 +1,6 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+Components.utils.import("resource://gre/modules/Services.jsm");
+Services.cpmm.sendAsyncMessage("my-addon-2");
new file mode 100644
--- /dev/null
+++ b/toolkit/mozapps/extensions/test/browser/addons/browser_update1_2/install.rdf
@@ -0,0 +1,31 @@
+<?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>update1@tests.mozilla.org</em:id>
+    <em:version>2.0</em:version>
+    <em:bootstrap>true</em:bootstrap>
+
+    <em:targetApplication>
+      <Description>
+        <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
+        <em:minVersion>0.3</em:minVersion>
+        <em:maxVersion>*</em:maxVersion>
+      </Description>
+    </em:targetApplication>
+
+    <em:targetApplication>
+      <Description>
+        <em:id>toolkit@mozilla.org</em:id>
+        <em:minVersion>0</em:minVersion>
+        <em:maxVersion>*</em:maxVersion>
+      </Description>
+    </em:targetApplication>
+
+    <!-- Front End MetaData -->
+    <em:name>Update Tests</em:name>
+
+  </Description>
+</RDF>
--- a/toolkit/mozapps/extensions/test/browser/browser.ini
+++ b/toolkit/mozapps/extensions/test/browser/browser.ini
@@ -54,10 +54,11 @@ support-files =
 [browser_hotfix.js]
 # Verifies the old style of signing hotfixes
 skip-if = require_signing
 [browser_installssl.js]
 [browser_newaddon.js]
 [browser_updatessl.js]
 [browser_task_next_test.js]
 [browser_discovery_install.js]
+[browser_update.js]
 
 [include:browser-common.ini]
new file mode 100644
--- /dev/null
+++ b/toolkit/mozapps/extensions/test/browser/browser_update.js
@@ -0,0 +1,55 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Tests that updates correctly flush caches and that new files gets updated.
+
+function test() {
+  requestLongerTimeout(2);
+  waitForExplicitFinish();
+
+  Services.prefs.setBoolPref("extensions.checkUpdateSecurity", false);
+  Services.prefs.setBoolPref("xpinstall.signatures.required", false);
+
+  run_next_test();
+}
+
+// Install a first version
+add_test(function() {
+  AddonManager.getInstallForURL(TESTROOT + "addons/browser_update1_1.xpi",
+                                function(aInstall) {
+    aInstall.install();
+  }, "application/x-xpinstall");
+
+  Services.ppmm.addMessageListener("my-addon-1", function messageListener() {
+    Services.ppmm.removeMessageListener("my-addon-1", messageListener);
+    ok(true, "first version sent frame script message");
+    run_next_test();
+  });
+});
+
+// Update to a second version and verify that content gets updated
+add_test(function() {
+  AddonManager.getInstallForURL(TESTROOT + "addons/browser_update1_2.xpi",
+                                function(aInstall) {
+    aInstall.install();
+  }, "application/x-xpinstall");
+
+  Services.ppmm.addMessageListener("my-addon-2", function messageListener() {
+    Services.ppmm.removeMessageListener("my-addon-2", messageListener);
+    ok(true, "second version sent frame script message");
+    run_next_test();
+  });
+});
+
+// Finally, cleanup things
+add_test(function() {
+  Services.prefs.setBoolPref("xpinstall.signatures.required", true);
+  Services.prefs.setBoolPref("extensions.checkUpdateSecurity", true);
+
+  AddonManager.getAddonByID("update1@tests.mozilla.org", function(aAddon) {
+    aAddon.uninstall();
+
+    finish();
+  });
+});