diff --git a/b2g/config/emulator-ics/sources.xml b/b2g/config/emulator-ics/sources.xml
index c92156a382ac..7e6b2a0a5a01 100644
--- a/b2g/config/emulator-ics/sources.xml
+++ b/b2g/config/emulator-ics/sources.xml
@@ -19,7 +19,7 @@
-
+
diff --git a/b2g/config/emulator-jb/sources.xml b/b2g/config/emulator-jb/sources.xml
index 5bedf541a9a4..bb2805d6eba5 100644
--- a/b2g/config/emulator-jb/sources.xml
+++ b/b2g/config/emulator-jb/sources.xml
@@ -17,7 +17,7 @@
-
+
diff --git a/b2g/config/emulator-kk/sources.xml b/b2g/config/emulator-kk/sources.xml
index 5e8a59e6817a..50a1b5af94d3 100644
--- a/b2g/config/emulator-kk/sources.xml
+++ b/b2g/config/emulator-kk/sources.xml
@@ -15,7 +15,7 @@
-
+
diff --git a/b2g/config/emulator/sources.xml b/b2g/config/emulator/sources.xml
index c92156a382ac..7e6b2a0a5a01 100644
--- a/b2g/config/emulator/sources.xml
+++ b/b2g/config/emulator/sources.xml
@@ -19,7 +19,7 @@
-
+
diff --git a/b2g/config/flame/sources.xml b/b2g/config/flame/sources.xml
index eb3d067b59d1..ab8b138220f4 100644
--- a/b2g/config/flame/sources.xml
+++ b/b2g/config/flame/sources.xml
@@ -17,7 +17,7 @@
-
+
diff --git a/b2g/config/gaia.json b/b2g/config/gaia.json
index a7307d0a9e1b..3f005878d5d4 100644
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -4,6 +4,6 @@
"remote": "",
"branch": ""
},
- "revision": "333f877ae4029d7cb1a0893f89da484d8e3cc14f",
+ "revision": "278dd1b102a39cf2c48f11fe3038eaf8f0779d7d",
"repo_path": "/integration/gaia-central"
}
diff --git a/b2g/config/hamachi/sources.xml b/b2g/config/hamachi/sources.xml
index 2049f347b1e9..f203dc5e4db4 100644
--- a/b2g/config/hamachi/sources.xml
+++ b/b2g/config/hamachi/sources.xml
@@ -17,7 +17,7 @@
-
+
diff --git a/b2g/config/helix/sources.xml b/b2g/config/helix/sources.xml
index 5f9fb059b432..907cdcb506bf 100644
--- a/b2g/config/helix/sources.xml
+++ b/b2g/config/helix/sources.xml
@@ -15,7 +15,7 @@
-
+
diff --git a/b2g/config/nexus-4/sources.xml b/b2g/config/nexus-4/sources.xml
index 38f931fe7077..53f55c662d49 100644
--- a/b2g/config/nexus-4/sources.xml
+++ b/b2g/config/nexus-4/sources.xml
@@ -17,7 +17,7 @@
-
+
diff --git a/b2g/config/wasabi/sources.xml b/b2g/config/wasabi/sources.xml
index 6854c739fabb..29acd40091f9 100644
--- a/b2g/config/wasabi/sources.xml
+++ b/b2g/config/wasabi/sources.xml
@@ -17,7 +17,7 @@
-
+
diff --git a/b2g/installer/package-manifest.in b/b2g/installer/package-manifest.in
index 7cf0b3ff2407..139078e538a1 100644
--- a/b2g/installer/package-manifest.in
+++ b/b2g/installer/package-manifest.in
@@ -405,6 +405,8 @@
@BINPATH@/components/DOMWifiManager.manifest
@BINPATH@/components/DOMWifiP2pManager.js
@BINPATH@/components/DOMWifiP2pManager.manifest
+@BINPATH@/components/EthernetManager.js
+@BINPATH@/components/EthernetManager.manifest
@BINPATH@/components/NetworkInterfaceListService.js
@BINPATH@/components/NetworkInterfaceListService.manifest
@BINPATH@/components/NetworkManager.js
diff --git a/dom/apps/src/AppsServiceChild.jsm b/dom/apps/src/AppsServiceChild.jsm
index c7cb9890f768..5bf6a5aad746 100644
--- a/dom/apps/src/AppsServiceChild.jsm
+++ b/dom/apps/src/AppsServiceChild.jsm
@@ -8,10 +8,10 @@ const Cu = Components.utils;
const Cc = Components.classes;
const Ci = Components.interfaces;
-// This module exposes a subset of the functionnalities of the parent DOM
-// Registry to content processes, to be be used from the AppsService component.
+// This module exposes a subset of the functionalities of the parent DOM
+// Registry to content processes, to be used from the AppsService component.
-this.EXPORTED_SYMBOLS = ["DOMApplicationRegistry"];
+this.EXPORTED_SYMBOLS = ["DOMApplicationRegistry", "WrappedManifestCache"];
Cu.import("resource://gre/modules/AppsUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
@@ -20,54 +20,323 @@ function debug(s) {
//dump("-*- AppsServiceChild.jsm: " + s + "\n");
}
+const APPS_IPC_MSG_NAMES = [
+ "Webapps:AddApp",
+ "Webapps:RemoveApp",
+ "Webapps:UpdateApp",
+ "Webapps:CheckForUpdate:Return:KO",
+ "Webapps:FireEvent",
+ "Webapps:UpdateState"
+];
+
+// A simple cache for the wrapped manifests.
+this.WrappedManifestCache = {
+ _cache: { },
+
+ // Gets an entry from the cache, and populates the cache if needed.
+ get: function mcache_get(aManifestURL, aManifest, aWindow, aInnerWindowID) {
+ if (!aManifest) {
+ return;
+ }
+
+ if (!(aManifestURL in this._cache)) {
+ this._cache[aManifestURL] = { };
+ }
+
+ let winObjs = this._cache[aManifestURL];
+ if (!(aInnerWindowID in winObjs)) {
+ winObjs[aInnerWindowID] = Cu.cloneInto(aManifest, aWindow);
+ }
+
+ return winObjs[aInnerWindowID];
+ },
+
+ // Invalidates an entry in the cache.
+ evict: function mcache_evict(aManifestURL, aInnerWindowID) {
+ debug("Evicting manifest " + aManifestURL + " window ID " +
+ aInnerWindowID);
+ if (aManifestURL in this._cache) {
+ let winObjs = this._cache[aManifestURL];
+ if (aInnerWindowID in winObjs) {
+ delete winObjs[aInnerWindowID];
+ }
+
+ if (Object.keys(winObjs).length == 0) {
+ delete this._cache[aManifestURL];
+ }
+ }
+ },
+
+ observe: function(aSubject, aTopic, aData) {
+ // Clear the cache on memory pressure.
+ this._cache = { };
+ Cu.forceGC();
+ },
+
+ init: function() {
+ Services.obs.addObserver(this, "memory-pressure", false);
+ }
+};
+
+this.WrappedManifestCache.init();
+
+
+// DOMApplicationRegistry keeps a cache containing a list of apps in the device.
+// This information is updated with the data received from the main process and
+// it is queried by the DOM objects to set their state.
+// This module handle all the messages broadcasted from the parent process,
+// including DOM events, which are dispatched to the corresponding DOM objects.
+
this.DOMApplicationRegistry = {
+ // DOMApps will hold a list of arrays of weak references to
+ // mozIDOMApplication objects indexed by manifest URL.
+ DOMApps: {},
+
+ ready: false,
+ webapps: null,
+
init: function init() {
- debug("init");
this.cpmm = Cc["@mozilla.org/childprocessmessagemanager;1"]
.getService(Ci.nsISyncMessageSender);
- ["Webapps:AddApp", "Webapps:RemoveApp"].forEach((function(aMsgName) {
+ APPS_IPC_MSG_NAMES.forEach((function(aMsgName) {
this.cpmm.addMessageListener(aMsgName, this);
}).bind(this));
- // We need to prime the cache with the list of apps.
- // XXX shoud we do this async and block callers if it's not yet there?
- this.webapps = this.cpmm.sendSyncMessage("Webapps:GetList", { })[0];
+ this.cpmm.sendAsyncMessage("Webapps:RegisterForMessages", {
+ messages: APPS_IPC_MSG_NAMES
+ });
+ // We need to prime the cache with the list of apps.
+ let list = this.cpmm.sendSyncMessage("Webapps:GetList", { })[0];
+ this.webapps = list.webapps;
// We need a fast mapping from localId -> app, so we add an index.
+ // We also add the manifest to the app object.
this.localIdIndex = { };
for (let id in this.webapps) {
let app = this.webapps[id];
this.localIdIndex[app.localId] = app;
+ app.manifest = list.manifests[id];
}
Services.obs.addObserver(this, "xpcom-shutdown", false);
},
observe: function(aSubject, aTopic, aData) {
- // cpmm.addMessageListener causes the DOMApplicationRegistry object to live
- // forever if we don't clean up properly.
+ // cpmm.addMessageListener causes the DOMApplicationRegistry object to
+ // live forever if we don't clean up properly.
this.webapps = null;
- ["Webapps:AddApp", "Webapps:RemoveApp"].forEach((function(aMsgName) {
+ this.DOMApps = null;
+
+ APPS_IPC_MSG_NAMES.forEach((aMsgName) => {
this.cpmm.removeMessageListener(aMsgName, this);
- }).bind(this));
+ });
+
+ this.cpmm.sendAsyncMessage("Webapps:UnregisterForMessages",
+ APPS_IPC_MSG_NAMES)
},
receiveMessage: function receiveMessage(aMessage) {
debug("Received " + aMessage.name + " message.");
- let msg = aMessage.json;
+ let msg = aMessage.data;
switch (aMessage.name) {
case "Webapps:AddApp":
this.webapps[msg.id] = msg.app;
this.localIdIndex[msg.app.localId] = msg.app;
+ if (msg.manifest) {
+ this.webapps[msg.id].manifest = msg.manifest;
+ }
break;
case "Webapps:RemoveApp":
+ delete this.DOMApps[this.webapps[msg.id].manifestURL];
delete this.localIdIndex[this.webapps[msg.id].localId];
delete this.webapps[msg.id];
break;
+ case "Webapps:UpdateApp":
+ let app = this.webapps[msg.oldId];
+ if (!app) {
+ return;
+ }
+
+ if (msg.app) {
+ for (let prop in msg.app) {
+ app[prop] = msg.app[prop];
+ }
+ }
+
+ this.webapps[msg.newId] = app;
+ this.localIdIndex[app.localId] = app;
+ delete this.webapps[msg.oldId];
+
+ let apps = this.DOMApps[msg.app.manifestURL];
+ if (!apps) {
+ return;
+ }
+ for (let i = 0; i < apps.length; i++) {
+ let domApp = apps[i].get();
+ if (!domApp) {
+ apps.splice(i);
+ continue;
+ }
+ domApp._proxy = new Proxy(domApp, {
+ get: function(target, prop) {
+ if (!DOMApplicationRegistry.webapps[msg.newId]) {
+ return;
+ }
+ return DOMApplicationRegistry.webapps[msg.newId][prop];
+ },
+ set: function(target, prop, val) {
+ if (!DOMApplicationRegistry.webapps[msg.newId]) {
+ return;
+ }
+ DOMApplicationRegistry.webapps[msg.newId][prop] = val;
+ return;
+ },
+ });
+ }
+ break;
+ case "Webapps:FireEvent":
+ this._fireEvent(aMessage);
+ break;
+ case "Webapps:UpdateState":
+ this._updateState(msg);
+ break;
+ case "Webapps:CheckForUpdate:Return:KO":
+ let DOMApps = this.DOMApps[msg.manifestURL];
+ if (!DOMApps || !msg.requestID) {
+ return;
+ }
+ DOMApps.forEach((DOMApp) => {
+ let domApp = DOMApp.get();
+ if (domApp && msg.requestID) {
+ domApp._fireRequestResult(aMessage, true /* aIsError */);
+ }
+ });
+ break;
}
},
+ /**
+ * mozIDOMApplication management
+ */
+
+ // Every time a DOM app is created, we save a weak reference to it that will
+ // be used to dispatch events and fire request results.
+ addDOMApp: function(aApp, aManifestURL, aId) {
+ let weakRef = Cu.getWeakReference(aApp);
+
+ if (!this.DOMApps[aManifestURL]) {
+ this.DOMApps[aManifestURL] = [];
+ }
+
+ let apps = this.DOMApps[aManifestURL];
+
+ // Get rid of dead weak references.
+ for (let i = 0; i < apps.length; i++) {
+ if (!apps[i].get()) {
+ apps.splice(i);
+ }
+ }
+
+ apps.push(weakRef);
+
+ // Each DOM app contains a proxy object used to build their state. We
+ // return the handler for this proxy object with traps to get and set
+ // app properties kept in the DOMApplicationRegistry app cache.
+ return {
+ get: function(target, prop) {
+ if (!DOMApplicationRegistry.webapps[aId]) {
+ return;
+ }
+ return DOMApplicationRegistry.webapps[aId][prop];
+ },
+ set: function(target, prop, val) {
+ if (!DOMApplicationRegistry.webapps[aId]) {
+ return;
+ }
+ DOMApplicationRegistry.webapps[aId][prop] = val;
+ return;
+ },
+ };
+ },
+
+ _fireEvent: function(aMessage) {
+ let msg = aMessage.data;
+ debug("_fireEvent " + JSON.stringify(msg));
+ if (!this.DOMApps || !msg.manifestURL || !msg.eventType) {
+ return;
+ }
+
+ let DOMApps = this.DOMApps[msg.manifestURL];
+ if (!DOMApps) {
+ return;
+ }
+
+ // The parent might ask childs to trigger more than one event in one
+ // shot, so in order to avoid needless IPC we allow an array for the
+ // 'eventType' IPC message field.
+ if (!Array.isArray(msg.eventType)) {
+ msg.eventType = [msg.eventType];
+ }
+
+ DOMApps.forEach((DOMApp) => {
+ let domApp = DOMApp.get();
+ if (!domApp) {
+ return;
+ }
+ msg.eventType.forEach((aEventType) => {
+ if ('on' + aEventType in domApp) {
+ domApp._fireEvent(aEventType);
+ }
+ });
+
+ if (msg.requestID) {
+ aMessage.data.result = msg.manifestURL;
+ domApp._fireRequestResult(aMessage);
+ }
+ });
+ },
+
+ _updateState: function(aMessage) {
+ if (!this.DOMApps || !aMessage.id) {
+ return;
+ }
+
+ let app = this.webapps[aMessage.id];
+ if (!app) {
+ return;
+ }
+
+ if (aMessage.app) {
+ for (let prop in aMessage.app) {
+ app[prop] = aMessage.app[prop];
+ }
+ }
+
+ if ("error" in aMessage) {
+ app.downloadError = aMessage.error;
+ }
+
+ if (aMessage.manifest) {
+ app.manifest = aMessage.manifest;
+ // Evict the wrapped manifest cache for all the affected DOM objects.
+ let DOMApps = this.DOMApps[app.manifestURL];
+ if (!DOMApps) {
+ return;
+ }
+ DOMApps.forEach((DOMApp) => {
+ let domApp = DOMApp.get();
+ if (!domApp) {
+ return;
+ }
+ WrappedManifestCache.evict(app.manifestURL, domApp.innerWindowID);
+ });
+ }
+ },
+
+ /**
+ * nsIAppsService API
+ */
getAppByManifestURL: function getAppByManifestURL(aManifestURL) {
debug("getAppByManifestURL " + aManifestURL);
return AppsUtils.getAppByManifestURL(this.webapps, aManifestURL);
@@ -89,7 +358,7 @@ this.DOMApplicationRegistry = {
},
getAppByLocalId: function getAppByLocalId(aLocalId) {
- debug("getAppByLocalId " + aLocalId);
+ debug("getAppByLocalId " + aLocalId + " - ready: " + this.ready);
let app = this.localIdIndex[aLocalId];
if (!app) {
debug("Ouch, No app!");
diff --git a/dom/apps/src/Webapps.js b/dom/apps/src/Webapps.js
index 939a0db982d8..35a393907a7d 100644
--- a/dom/apps/src/Webapps.js
+++ b/dom/apps/src/Webapps.js
@@ -12,6 +12,7 @@ Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/DOMRequestHelper.jsm");
Cu.import("resource://gre/modules/AppsUtils.jsm");
Cu.import("resource://gre/modules/BrowserElementPromptService.jsm");
+Cu.import("resource://gre/modules/AppsServiceChild.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
"@mozilla.org/childprocessmessagemanager;1",
@@ -278,50 +279,9 @@ WebappsRegistry.prototype = {
* mozIDOMApplication object
*/
-// A simple cache for the wrapped manifests.
-let manifestCache = {
- _cache: { },
-
- // Gets an entry from the cache, and populates the cache if needed.
- get: function mcache_get(aManifestURL, aManifest, aWindow, aInnerWindowID) {
- if (!(aManifestURL in this._cache)) {
- this._cache[aManifestURL] = { };
- }
-
- let winObjs = this._cache[aManifestURL];
- if (!(aInnerWindowID in winObjs)) {
- winObjs[aInnerWindowID] = Cu.cloneInto(aManifest, aWindow);
- }
-
- return winObjs[aInnerWindowID];
- },
-
- // Invalidates an entry in the cache.
- evict: function mcache_evict(aManifestURL, aInnerWindowID) {
- if (aManifestURL in this._cache) {
- let winObjs = this._cache[aManifestURL];
- if (aInnerWindowID in winObjs) {
- delete winObjs[aInnerWindowID];
- }
-
- if (Object.keys(winObjs).length == 0) {
- delete this._cache[aManifestURL];
- }
- }
- },
-
- observe: function(aSubject, aTopic, aData) {
- // Clear the cache on memory pressure.
- this._cache = { };
- },
-
- init: function() {
- Services.obs.addObserver(this, "memory-pressure", false);
- }
-};
-
function createApplicationObject(aWindow, aApp) {
- let app = Cc["@mozilla.org/webapps/application;1"].createInstance(Ci.mozIDOMApplication);
+ let app = Cc["@mozilla.org/webapps/application;1"]
+ .createInstance(Ci.mozIDOMApplication);
app.wrappedJSObject.init(aWindow, aApp);
return app;
}
@@ -334,27 +294,12 @@ WebappsApplication.prototype = {
__proto__: DOMRequestIpcHelper.prototype,
init: function(aWindow, aApp) {
+ let proxyHandler = DOMApplicationRegistry.addDOMApp(this,
+ aApp.manifestURL,
+ aApp.id);
+ this._proxy = new Proxy(this, proxyHandler);
+
this._window = aWindow;
- let principal = this._window.document.nodePrincipal;
- this._appStatus = principal.appStatus;
- this.origin = aApp.origin;
- this._manifest = aApp.manifest;
- this._updateManifest = aApp.updateManifest;
- this.manifestURL = aApp.manifestURL;
- this.receipts = aApp.receipts;
- this.installOrigin = aApp.installOrigin;
- this.installTime = aApp.installTime;
- this.installState = aApp.installState || "installed";
- this.removable = aApp.removable;
- this.lastUpdateCheck = aApp.lastUpdateCheck ? aApp.lastUpdateCheck
- : Date.now();
- this.updateTime = aApp.updateTime ? aApp.updateTime
- : aApp.installTime;
- this.progress = NaN;
- this.downloadAvailable = aApp.downloadAvailable;
- this.downloading = aApp.downloading;
- this.readyToApplyDownload = aApp.readyToApplyDownload;
- this.downloadSize = aApp.downloadSize || 0;
this._onprogress = null;
this._ondownloadsuccess = null;
@@ -362,40 +307,83 @@ WebappsApplication.prototype = {
this._ondownloadavailable = null;
this._ondownloadapplied = null;
- this._downloadError = null;
+ this.initDOMRequestHelper(aWindow);
+ },
- this.initDOMRequestHelper(aWindow, [
- { name: "Webapps:CheckForUpdate:Return:KO", weakRef: true },
- { name: "Webapps:Connect:Return:OK", weakRef: true },
- { name: "Webapps:Connect:Return:KO", weakRef: true },
- { name: "Webapps:FireEvent", weakRef: true },
- { name: "Webapps:GetConnections:Return:OK", weakRef: true },
- { name: "Webapps:UpdateState", weakRef: true }
- ]);
+ get _appStatus() {
+ return this._proxy.appStatus;
+ },
- cpmm.sendAsyncMessage("Webapps:RegisterForMessages", {
- messages: ["Webapps:FireEvent",
- "Webapps:UpdateState"],
- app: {
- id: this.id,
- manifestURL: this.manifestURL,
- installState: this.installState,
- downloading: this.downloading
- }
- });
+ get downloadAvailable() {
+ return this._proxy.downloadAvailable;
+ },
+
+ get downloading() {
+ return this._proxy.downloading;
+ },
+
+ get downloadSize() {
+ return this._proxy.downloadSize;
+ },
+
+ get installOrigin() {
+ return this._proxy.installOrigin;
+ },
+
+ get installState() {
+ return this._proxy.installState;
+ },
+
+ get installTime() {
+ return this._proxy.installTime;
+ },
+
+ get lastUpdateCheck() {
+ return this._proxy.lastUpdateCheck;
+ },
+
+ get manifestURL() {
+ return this._proxy.manifestURL;
+ },
+
+ get origin() {
+ return this._proxy.origin;
+ },
+
+ get progress() {
+ return this._proxy.progress;
+ },
+
+ get readyToApplyDownload() {
+ return this._proxy.readyToApplyDownload;
+ },
+
+ get receipts() {
+ return this._proxy.receipts;
+ },
+
+ set receipts(aReceipts) {
+ this._proxy.receipts = aReceipts;
+ },
+
+ get removable() {
+ return this._proxy.removable;
+ },
+
+ get updateTime() {
+ return this._proxy.updateTime;
},
get manifest() {
- return manifestCache.get(this.manifestURL,
- this._manifest,
- this._window,
- this.innerWindowID);
+ return WrappedManifestCache.get(this.manifestURL,
+ this._proxy.manifest,
+ this._window,
+ this.innerWindowID);
},
get updateManifest() {
- return this.updateManifest =
- this._updateManifest ? Cu.cloneInto(this._updateManifest, this._window)
- : null;
+ return this._proxy.updateManifest ?
+ Cu.cloneInto(this._proxy.updateManifest, this._window) : null;
},
set onprogress(aCallback) {
@@ -440,10 +428,10 @@ WebappsApplication.prototype = {
get downloadError() {
// Only return DOMError when we have an error.
- if (!this._downloadError) {
+ if (!this._proxy.downloadError) {
return null;
}
- return new this._window.DOMError(this._downloadError);
+ return new this._window.DOMError(this._proxy.downloadError);
},
download: function() {
@@ -485,12 +473,11 @@ WebappsApplication.prototype = {
BrowserElementPromptService.getBrowserElementChildForWindow(this._window);
if (browserChild) {
this.addMessageListeners("Webapps:ClearBrowserData:Return");
- browserChild.messageManager.sendAsyncMessage(
- "Webapps:ClearBrowserData",
- { manifestURL: this.manifestURL,
- oid: this._id,
- requestID: this.getRequestId(request) }
- );
+ browserChild.messageManager.sendAsyncMessage("Webapps:ClearBrowserData", {
+ manifestURL: this.manifestURL,
+ oid: this._id,
+ requestID: this.getRequestId(request)
+ });
} else {
Services.DOMRequest.fireErrorAsync(request, "NO_CLEARABLE_BROWSER");
}
@@ -498,28 +485,33 @@ WebappsApplication.prototype = {
},
connect: function(aKeyword, aRules) {
+ this.addMessageListeners(["Webapps:Connect:Return:OK",
+ "Webapps:Connect:Return:KO"]);
return this.createPromise(function (aResolve, aReject) {
- cpmm.sendAsyncMessage("Webapps:Connect",
- { keyword: aKeyword,
- rules: aRules,
- manifestURL: this.manifestURL,
- outerWindowID: this._id,
- requestID: this.getPromiseResolverId({
- resolve: aResolve,
- reject: aReject
- })});
+ cpmm.sendAsyncMessage("Webapps:Connect", {
+ keyword: aKeyword,
+ rules: aRules,
+ manifestURL: this.manifestURL,
+ outerWindowID: this._id,
+ requestID: this.getPromiseResolverId({
+ resolve: aResolve,
+ reject: aReject
+ })
+ });
}.bind(this));
},
getConnections: function() {
+ this.addMessageListeners("Webapps:GetConnections:Return:OK");
return this.createPromise(function (aResolve, aReject) {
- cpmm.sendAsyncMessage("Webapps:GetConnections",
- { manifestURL: this.manifestURL,
- outerWindowID: this._id,
- requestID: this.getPromiseResolverId({
- resolve: aResolve,
- reject: aReject
- })});
+ cpmm.sendAsyncMessage("Webapps:GetConnections", {
+ manifestURL: this.manifestURL,
+ outerWindowID: this._id,
+ requestID: this.getPromiseResolverId({
+ resolve: aResolve,
+ reject: aReject
+ })
+ });
}.bind(this));
},
@@ -568,12 +560,7 @@ WebappsApplication.prototype = {
uninit: function() {
this._onprogress = null;
- cpmm.sendAsyncMessage("Webapps:UnregisterForMessages", [
- "Webapps:FireEvent",
- "Webapps:UpdateState"
- ]);
-
- manifestCache.evict(this.manifestURL, this.innerWindowID);
+ WrappedManifestCache.evict(this.manifestURL, this.innerWindowID);
},
_fireEvent: function(aName) {
@@ -590,22 +577,16 @@ WebappsApplication.prototype = {
}
},
- _updateState: function(aMsg) {
- if (aMsg.app) {
- for (let prop in aMsg.app) {
- this[prop] = aMsg.app[prop];
- }
+ _fireRequestResult: function(aMessage, aIsError) {
+ let req;
+ let msg = aMessage.data;
+ req = this.takeRequest(msg.requestID);
+ if (!req) {
+ return;
}
- // Intentional use of 'in' so we unset the error if this is explicitly null.
- if ('error' in aMsg) {
- this._downloadError = aMsg.error;
- }
-
- if (aMsg.manifest) {
- this._manifest = aMsg.manifest;
- manifestCache.evict(this.manifestURL, this.innerWindowID);
- }
+ aIsError ? Services.DOMRequest.fireError(req, msg.error)
+ : Services.DOMRequest.fireSuccess(req, msg.result);
},
receiveMessage: function(aMessage) {
@@ -619,10 +600,7 @@ WebappsApplication.prototype = {
req = this.takeRequest(msg.requestID);
}
- // ondownload* callbacks should be triggered on all app instances
- if ((msg.oid != this._id || !req) &&
- aMessage.name !== "Webapps:FireEvent" &&
- aMessage.name !== "Webapps:UpdateState") {
+ if (msg.oid !== this._id || !req) {
return;
}
@@ -637,51 +615,13 @@ WebappsApplication.prototype = {
"Webapps:Launch:Return:KO"]);
Services.DOMRequest.fireSuccess(req, null);
break;
- case "Webapps:CheckForUpdate:Return:KO":
- Services.DOMRequest.fireError(req, msg.error);
- break;
- case "Webapps:FireEvent":
- if (msg.manifestURL != this.manifestURL) {
- return;
- }
-
- // The parent might ask childs to trigger more than one event in one
- // shot, so in order to avoid needless IPC we allow an array for the
- // 'eventType' IPC message field.
- if (!Array.isArray(msg.eventType)) {
- msg.eventType = [msg.eventType];
- }
-
- msg.eventType.forEach((aEventType) => {
- // If we are in a successful state clear any past errors.
- if (aEventType === 'downloadapplied' ||
- aEventType === 'downloadsuccess') {
- this._downloadError = null;
- }
-
- if ("_on" + aEventType in this) {
- this._fireEvent(aEventType);
- } else {
- dump("Unsupported event type " + aEventType + "\n");
- }
- });
-
- if (req) {
- Services.DOMRequest.fireSuccess(req, this.manifestURL);
- }
- break;
- case "Webapps:UpdateState":
- if (msg.manifestURL != this.manifestURL) {
- return;
- }
-
- this._updateState(msg);
- break;
case "Webapps:ClearBrowserData:Return":
this.removeMessageListeners(aMessage.name);
Services.DOMRequest.fireSuccess(req, null);
break;
case "Webapps:Connect:Return:OK":
+ this.removeMessageListeners(["Webapps:Connect:Return:OK",
+ "Webapps:Connect:Return:KO"]);
let messagePorts = [];
msg.messagePortIDs.forEach((aPortID) => {
let port = new this._window.MozInterAppMessagePort(aPortID);
@@ -690,9 +630,12 @@ WebappsApplication.prototype = {
req.resolve(messagePorts);
break;
case "Webapps:Connect:Return:KO":
+ this.removeMessageListeners(["Webapps:Connect:Return:OK",
+ "Webapps:Connect:Return:KO"]);
req.reject("No connections registered");
break;
case "Webapps:GetConnections:Return:OK":
+ this.removeMessageListeners(aMessage.name);
let connections = [];
msg.connections.forEach((aConnection) => {
let connection =
@@ -874,12 +817,8 @@ WebappsApplicationMgmt.prototype = {
break;
case "Webapps:Uninstall:Broadcast:Return:OK":
if (this._onuninstall) {
- let detail = {
- manifestURL: msg.manifestURL,
- origin: msg.origin
- };
let event = new this._window.MozApplicationEvent("applicationuninstall",
- { application : createApplicationObject(this._window, detail) });
+ { application : createApplicationObject(this._window, msg) });
this._onuninstall.handleEvent(event);
}
break;
@@ -908,7 +847,5 @@ WebappsApplicationMgmt.prototype = {
classDescription: "Webapps Application Mgmt"})
}
-manifestCache.init();
-
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([WebappsRegistry,
WebappsApplication]);
diff --git a/dom/apps/src/Webapps.jsm b/dom/apps/src/Webapps.jsm
index 216fef131e59..37c86bf4cddc 100755
--- a/dom/apps/src/Webapps.jsm
+++ b/dom/apps/src/Webapps.jsm
@@ -1141,8 +1141,8 @@ this.DOMApplicationRegistry = {
this.removeMessageListener(["Webapps:Internal:AllMessages"], mm);
break;
case "Webapps:GetList":
- this.addMessageListener(["Webapps:AddApp", "Webapps:RemoveApp"], null, mm);
- return this.webapps;
+ return this.doGetList();
+ break;
case "Webapps:Download":
this.startDownload(msg.manifestURL);
break;
@@ -1245,6 +1245,38 @@ this.DOMApplicationRegistry = {
return deferred.promise;
},
+ /**
+ * Returns the full list of apps and manifests.
+ */
+ doGetList: function() {
+ let tmp = [];
+
+ for (let id in this.webapps) {
+ tmp.push({ id: id });
+ }
+
+ let res = {};
+ let done = false;
+
+ this._readManifests(tmp).then(
+ function(manifests) {
+ manifests.forEach((item) => {
+ res[item.id] = item.manifest;
+ });
+ done = true;
+ }
+ );
+
+ let thread = Services.tm.currentThread;
+ while (!done) {
+ //debug("before processNextEvent");
+ thread.processNextEvent(/* mayWait */ true);
+ //after("before processNextEvent");
+ }
+ return { webapps: this.webapps, manifests: res };
+ },
+
+
doLaunch: function (aData, aMm) {
this.launch(
aData.manifestURL,
@@ -1330,7 +1362,7 @@ this.DOMApplicationRegistry = {
downloading: false
},
error: error,
- manifestURL: app.manifestURL,
+ id: app.id
})
this.broadcastMessage("Webapps:FireEvent", {
eventType: "downloaderror",
@@ -1361,7 +1393,7 @@ this.DOMApplicationRegistry = {
if (!app.downloadAvailable) {
this.broadcastMessage("Webapps:UpdateState", {
error: "NO_DOWNLOAD_AVAILABLE",
- manifestURL: app.manifestURL
+ id: app.id
});
this.broadcastMessage("Webapps:FireEvent", {
eventType: "downloaderror",
@@ -1409,7 +1441,7 @@ this.DOMApplicationRegistry = {
this.broadcastMessage("Webapps:UpdateState", {
app: app,
manifest: jsonManifest,
- manifestURL: aManifestURL
+ id: app.id
});
this.broadcastMessage("Webapps:FireEvent", {
eventType: "downloadsuccess",
@@ -1453,7 +1485,7 @@ this.DOMApplicationRegistry = {
this.broadcastMessage("Webapps:UpdateState", {
app: app,
- manifestURL: aManifestURL
+ id: app.id
});
this.broadcastMessage("Webapps:FireEvent", {
eventType: "downloadsuccess",
@@ -1555,7 +1587,7 @@ this.DOMApplicationRegistry = {
this.broadcastMessage("Webapps:UpdateState", {
app: app,
manifest: newManifest,
- manifestURL: app.manifestURL
+ id: app.id
});
this.broadcastMessage("Webapps:FireEvent", {
eventType: "downloadapplied",
@@ -1594,7 +1626,7 @@ this.DOMApplicationRegistry = {
installState: aApp.installState,
progress: 0
},
- manifestURL: aApp.manifestURL
+ id: aApp.id
});
let cacheUpdate = updateSvc.scheduleAppUpdate(
appcacheURI, docURI, aApp.localId, false, aProfileDir);
@@ -1644,6 +1676,7 @@ this.DOMApplicationRegistry = {
debug("checkForUpdate for " + aData.manifestURL);
function sendError(aError) {
+ debug("checkForUpdate error " + aError);
aData.error = aError;
aMm.sendAsyncMessage("Webapps:CheckForUpdate:Return:KO", aData);
}
@@ -1673,8 +1706,7 @@ this.DOMApplicationRegistry = {
// then we can't have an update.
if (app.origin.startsWith("app://") &&
app.manifestURL.startsWith("app://")) {
- aData.error = "NOT_UPDATABLE";
- aMm.sendAsyncMessage("Webapps:CheckForUpdate:Return:KO", aData);
+ sendError("NOT_UPDATABLE");
return;
}
@@ -1691,8 +1723,7 @@ this.DOMApplicationRegistry = {
if (onlyCheckAppCache) {
// Bail out for packaged apps.
if (app.origin.startsWith("app://")) {
- aData.error = "NOT_UPDATABLE";
- aMm.sendAsyncMessage("Webapps:CheckForUpdate:Return:KO", aData);
+ sendError("NOT_UPDATABLE");
return;
}
@@ -1700,8 +1731,7 @@ this.DOMApplicationRegistry = {
this._readManifests([{ id: id }]).then((aResult) => {
let manifest = aResult[0].manifest;
if (!manifest.appcache_path) {
- aData.error = "NOT_UPDATABLE";
- aMm.sendAsyncMessage("Webapps:CheckForUpdate:Return:KO", aData);
+ sendError("NOT_UPDATABLE");
return;
}
@@ -1717,7 +1747,7 @@ this.DOMApplicationRegistry = {
this._saveApps().then(() => {
this.broadcastMessage("Webapps:UpdateState", {
app: app,
- manifestURL: app.manifestURL
+ id: app.id
});
this.broadcastMessage("Webapps:FireEvent", {
eventType: "downloadavailable",
@@ -1726,8 +1756,7 @@ this.DOMApplicationRegistry = {
});
});
} else {
- aData.error = "NOT_UPDATABLE";
- aMm.sendAsyncMessage("Webapps:CheckForUpdate:Return:KO", aData);
+ sendError("NOT_UPDATABLE");
}
}
};
@@ -1787,7 +1816,7 @@ this.DOMApplicationRegistry = {
: "downloadapplied";
aMm.sendAsyncMessage("Webapps:UpdateState", {
app: app,
- manifestURL: app.manifestURL
+ id: app.id
});
aMm.sendAsyncMessage("Webapps:FireEvent", {
eventType: eventType,
@@ -1814,7 +1843,7 @@ this.DOMApplicationRegistry = {
: "downloadapplied";
aMm.sendAsyncMessage("Webapps:UpdateState", {
app: app,
- manifestURL: app.manifestURL
+ id: app.id
});
aMm.sendAsyncMessage("Webapps:FireEvent", {
eventType: eventType,
@@ -1923,7 +1952,7 @@ this.DOMApplicationRegistry = {
this.broadcastMessage("Webapps:UpdateState", {
app: aApp,
- manifestURL: aApp.manifestURL
+ id: aApp.id
});
this.broadcastMessage("Webapps:FireEvent", {
eventType: "downloadavailable",
@@ -1989,7 +2018,7 @@ this.DOMApplicationRegistry = {
this.broadcastMessage("Webapps:UpdateState", {
app: aApp,
manifest: aApp.manifest,
- manifestURL: aApp.manifestURL
+ id: aApp.id
});
this.broadcastMessage("Webapps:FireEvent", {
eventType: "downloadapplied",
@@ -2023,7 +2052,7 @@ this.DOMApplicationRegistry = {
this.broadcastMessage("Webapps:UpdateState", {
app: aApp,
manifest: aApp.manifest,
- manifestURL: aApp.manifestURL
+ id: aApp.id
});
this.broadcastMessage("Webapps:FireEvent", {
eventType: eventType,
@@ -2450,7 +2479,8 @@ this.DOMApplicationRegistry = {
}
this._saveApps().then(() => {
- this.broadcastMessage("Webapps:AddApp", { id: app.id, app: app });
+ this.broadcastMessage("Webapps:AddApp",
+ { id: app.id, app: app, manifest: aManifest });
});
}),
@@ -2550,6 +2580,8 @@ this.DOMApplicationRegistry = {
// saved in the registry.
yield this._saveApps();
+ aData.isPackage ? appObject.updateManifest = jsonManifest :
+ appObject.manifest = jsonManifest;
this.broadcastMessage("Webapps:AddApp", { id: id, app: appObject });
// The presence of a requestID means that we have a page to update.
@@ -2626,7 +2658,8 @@ this.DOMApplicationRegistry = {
delete this._manifestCache[aId];
}
- this.broadcastMessage("Webapps:AddApp", { id: aId, app: aNewApp });
+ this.broadcastMessage("Webapps:AddApp",
+ { id: aId, app: aNewApp, manifest: aManifest });
Services.obs.notifyObservers(null, "webapps-installed",
JSON.stringify({ manifestURL: aNewApp.manifestURL }));
@@ -2760,14 +2793,11 @@ this.DOMApplicationRegistry = {
oldApp,
aNewApp);
- AppDownloadManager.add(
- aNewApp.manifestURL,
- {
- channel: requestChannel,
- appId: id,
- previousState: aIsUpdate ? "installed" : "pending"
- }
- );
+ AppDownloadManager.add(aNewApp.manifestURL, {
+ channel: requestChannel,
+ appId: id,
+ previousState: aIsUpdate ? "installed" : "pending"
+ });
// We set the 'downloading' flag to true right before starting the fetch.
oldApp.downloading = true;
@@ -2787,7 +2817,7 @@ this.DOMApplicationRegistry = {
// Clear any previous download errors.
error: null,
app: oldApp,
- manifestURL: aNewApp.manifestURL
+ id: id
});
let zipFile = yield this._getPackage(requestChannel, id, oldApp, aNewApp);
@@ -2802,7 +2832,7 @@ this.DOMApplicationRegistry = {
// We send an "applied" event right away so code awaiting that event
// can proceed to access the app. We also throw an error to alert
// the caller that the package wasn't downloaded.
- this._sendAppliedEvent(aNewApp, oldApp, id);
+ this._sendAppliedEvent(oldApp);
throw new Error("PACKAGE_UNCHANGED");
}
@@ -2942,7 +2972,7 @@ this.DOMApplicationRegistry = {
app: {
progress: aProgress
},
- manifestURL: aNewApp.manifestURL
+ id: aNewApp.id
});
this.broadcastMessage("Webapps:FireEvent", {
eventType: "progress",
@@ -3059,27 +3089,24 @@ this.DOMApplicationRegistry = {
* something similar after updating the app, and we could refactor both cases
* to use the same code to send the "applied" event.
*
- * @param aNewApp {Object} the new app data
- * @param aOldApp {Object} the currently stored app data
- * @param aId {String} the unique id of the app
+ * @param aApp {Object} app data
*/
- _sendAppliedEvent: function(aNewApp, aOldApp, aId) {
- aOldApp.downloading = false;
- aOldApp.downloadAvailable = false;
- aOldApp.downloadSize = 0;
- aOldApp.installState = "installed";
- aOldApp.readyToApplyDownload = false;
- if (aOldApp.staged && aOldApp.staged.manifestHash) {
+ _sendAppliedEvent: function(aApp) {
+ aApp.downloading = false;
+ aApp.downloadAvailable = false;
+ aApp.downloadSize = 0;
+ aApp.installState = "installed";
+ aApp.readyToApplyDownload = false;
+ if (aApp.staged && aApp.staged.manifestHash) {
// If we're here then the manifest has changed but the package
// hasn't. Let's clear this, so we don't keep offering
// a bogus update to the user
- aOldApp.manifestHash = aOldApp.staged.manifestHash;
- aOldApp.etag = aOldApp.staged.etag || aOldApp.etag;
- aOldApp.staged = {};
-
- // Move the staged update manifest to a non staged one.
+ aApp.manifestHash = aApp.staged.manifestHash;
+ aApp.etag = aApp.staged.etag || aApp.etag;
+ aApp.staged = {};
+ // Move the staged update manifest to a non staged one.
try {
- let staged = this._getAppDir(aId);
+ let staged = this._getAppDir(aApp.id);
staged.append("staged-update.webapp");
staged.moveTo(staged.parent, "update.webapp");
} catch (ex) {
@@ -3090,15 +3117,15 @@ this.DOMApplicationRegistry = {
// Save the updated registry, and cleanup the tmp directory.
this._saveApps().then(() => {
this.broadcastMessage("Webapps:UpdateState", {
- app: aOldApp,
- manifestURL: aNewApp.manifestURL
+ app: aApp,
+ id: aApp.id
});
this.broadcastMessage("Webapps:FireEvent", {
- manifestURL: aNewApp.manifestURL,
+ manifestURL: aApp.manifestURL,
eventType: ["downloadsuccess", "downloadapplied"]
});
});
- let file = FileUtils.getFile("TmpD", ["webapps", aId], false);
+ let file = FileUtils.getFile("TmpD", ["webapps", aApp.id], false);
if (file && file.exists()) {
file.remove(true);
}
@@ -3403,9 +3430,10 @@ this.DOMApplicationRegistry = {
dir.moveTo(parent, newId);
});
// Signals that we need to swap the old id with the new app.
- this.broadcastMessage("Webapps:RemoveApp", { id: oldId });
- this.broadcastMessage("Webapps:AddApp", { id: newId,
- app: aOldApp });
+ this.broadcastMessage("Webapps:UpdateApp", { oldId: oldId,
+ newId: newId,
+ app: aOldApp });
+
}
}
},
@@ -3508,7 +3536,7 @@ this.DOMApplicationRegistry = {
this.broadcastMessage("Webapps:UpdateState", {
app: aOldApp,
error: aError,
- manifestURL: aNewApp.manifestURL
+ id: aNewApp.id
});
this.broadcastMessage("Webapps:FireEvent", {
eventType: "downloaderror",
@@ -4060,7 +4088,7 @@ AppcacheObserver.prototype = {
let app = this.app;
DOMApplicationRegistry.broadcastMessage("Webapps:UpdateState", {
app: app,
- manifestURL: app.manifestURL
+ id: app.id
});
DOMApplicationRegistry.broadcastMessage("Webapps:FireEvent", {
eventType: "progress",
@@ -4092,7 +4120,7 @@ AppcacheObserver.prototype = {
app.downloadAvailable = false;
DOMApplicationRegistry.broadcastMessage("Webapps:UpdateState", {
app: app,
- manifestURL: app.manifestURL
+ id: app.id
});
DOMApplicationRegistry.broadcastMessage("Webapps:FireEvent", {
eventType: ["downloadsuccess", "downloadapplied"],
@@ -4115,7 +4143,7 @@ AppcacheObserver.prototype = {
DOMApplicationRegistry.broadcastMessage("Webapps:UpdateState", {
app: app,
error: aError,
- manifestURL: app.manifestURL
+ id: app.id
});
DOMApplicationRegistry.broadcastMessage("Webapps:FireEvent", {
eventType: "downloaderror",
diff --git a/dom/apps/tests/test_packaged_app_common.js b/dom/apps/tests/test_packaged_app_common.js
index 9a0bddbff4c3..7c91021f1f64 100644
--- a/dom/apps/tests/test_packaged_app_common.js
+++ b/dom/apps/tests/test_packaged_app_common.js
@@ -98,6 +98,7 @@ var PackagedTestHelper = (function PackagedTestHelper() {
var aApp = evt.application;
aApp.ondownloaderror = function(evt) {
var error = aApp.downloadError.name;
+ ok(true, "Got downloaderror " + error);
if (error == aExpectedError) {
ok(true, "Got expected " + aExpectedError);
var expected = {
diff --git a/dom/apps/tests/test_packaged_app_update.html b/dom/apps/tests/test_packaged_app_update.html
index 63be714db281..c26c2208ae24 100644
--- a/dom/apps/tests/test_packaged_app_update.html
+++ b/dom/apps/tests/test_packaged_app_update.html
@@ -79,15 +79,15 @@ function updateApp(aExpectedReady, aPreviousVersion, aNextVersion) {
checkLastAppState.bind(PackagedTestHelper, miniManifestURL, false, false,
aNextVersion, PackagedTestHelper.next);
- var ondownloadsuccesshandler =
- checkLastAppState.bind(undefined, miniManifestURL,
- aExpectedReady, false, aPreviousVersion,
- function() {
- navigator.mozApps.mgmt.applyDownload(lApp);
- });
+ var ondownloadsuccesshandler =
+ checkLastAppState.bind(undefined, miniManifestURL,
+ aExpectedReady, false, aPreviousVersion,
+ function() {
+ navigator.mozApps.mgmt.applyDownload(lApp);
+ });
- checkForUpdate(true, ondownloadsuccesshandler, ondownloadappliedhandler, null,
- true);
+ checkForUpdate(true, ondownloadsuccesshandler, ondownloadappliedhandler,
+ null, true);
}
@@ -251,7 +251,7 @@ var steps = [
"&appName=arandomname" +
"&appToFail1";
PackagedTestHelper.checkAppDownloadError(miniManifestURL,
- "MANIFEST_MISMATCH", 2, false, true,
+ "MANIFEST_MISMATCH", 1, false, true,
"arandomname",
function () {
checkForUpdate(false, null, null, null, false,
diff --git a/dom/apps/tests/test_receipt_operations.html b/dom/apps/tests/test_receipt_operations.html
index 0907e8d964c4..7ebe84ccfae0 100644
--- a/dom/apps/tests/test_receipt_operations.html
+++ b/dom/apps/tests/test_receipt_operations.html
@@ -243,4 +243,4 @@ addLoadEvent(go);