Bug 876397 - Inter-App Communication API (part 2, manifest registry). r=nsm

This commit is contained in:
Gene Lian 2013-08-16 17:48:37 +08:00
parent 1f00287b51
commit a621fc19cd
8 changed files with 249 additions and 0 deletions

View File

@ -506,6 +506,7 @@
@BINPATH@/components/PushServiceLauncher.js
@BINPATH@/components/InterAppComm.manifest
@BINPATH@/components/InterAppCommService.js
@BINPATH@/components/InterAppConnection.js
@BINPATH@/components/InterAppMessagePort.js

View File

@ -551,6 +551,10 @@ ManifestHelper.prototype = {
return this._localeProp("description");
},
get type() {
return this._localeProp("type");
},
get version() {
return this._localeProp("version");
},

View File

@ -6,3 +6,7 @@ contract @mozilla.org/dom/inter-app-connection-request;1 {6a77e9e0-0645-11e3-b90
component {c66e0f8c-e3cb-11e2-9e85-43ef6244b884} InterAppMessagePort.js
contract @mozilla.org/dom/inter-app-message-port;1 {c66e0f8c-e3cb-11e2-9e85-43ef6244b884}
component {3dd15ce6-e7be-11e2-82bc-77967e7a63e6} InterAppCommService.js
contract @mozilla.org/inter-app-communication-service;1 {3dd15ce6-e7be-11e2-82bc-77967e7a63e6}
category profile-after-change InterAppCommService @mozilla.org/inter-app-communication-service;1

View File

@ -0,0 +1,113 @@
/* 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/. */
"use strict";
const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
function debug(aMsg) {
// dump("-- InterAppCommService: " + Date.now() + ": " + aMsg + "\n");
}
function InterAppCommService() {
Services.obs.addObserver(this, "xpcom-shutdown", false);
// This matrix is used for saving the inter-app connection info registered in
// the app manifest. The object literal is defined as below:
//
// {
// "keyword1": {
// "subAppManifestURL1": {
// /* subscribed info */
// },
// "subAppManifestURL2": {
// /* subscribed info */
// },
// ...
// },
// "keyword2": {
// "subAppManifestURL3": {
// /* subscribed info */
// },
// ...
// },
// ...
// }
//
// For example:
//
// {
// "foo": {
// "app://subApp1.gaiamobile.org/manifest.webapp": {
// pageURL: "app://subApp1.gaiamobile.org/handler.html",
// description: "blah blah",
// appStatus: Ci.nsIPrincipal.APP_STATUS_CERTIFIED,
// rules: { ... }
// },
// "app://subApp2.gaiamobile.org/manifest.webapp": {
// pageURL: "app://subApp2.gaiamobile.org/handler.html",
// description: "blah blah",
// appStatus: Ci.nsIPrincipal.APP_STATUS_PRIVILEGED,
// rules: { ... }
// }
// },
// "bar": {
// "app://subApp3.gaiamobile.org/manifest.webapp": {
// pageURL: "app://subApp3.gaiamobile.org/handler.html",
// description: "blah blah",
// appStatus: Ci.nsIPrincipal.APP_STATUS_INSTALLED,
// rules: { ... }
// }
// }
// }
//
// TODO Bug 908999 - Update registered connections when app gets uninstalled.
this._registeredConnections = {};
}
InterAppCommService.prototype = {
registerConnection: function(aKeyword, aHandlerPageURI, aManifestURI,
aDescription, aAppStatus, aRules) {
let manifestURL = aManifestURI.spec;
let pageURL = aHandlerPageURI.spec;
debug("registerConnection: aKeyword: " + aKeyword +
" manifestURL: " + manifestURL + " pageURL: " + pageURL +
" aDescription: " + aDescription + " aAppStatus: " + aAppStatus +
" aRules.minimumAccessLevel: " + aRules.minimumAccessLevel +
" aRules.manifestURLs: " + aRules.manifestURLs +
" aRules.installOrigins: " + aRules.installOrigins);
let subAppManifestURLs = this._registeredConnections[aKeyword];
if (!subAppManifestURLs) {
subAppManifestURLs = this._registeredConnections[aKeyword] = {};
}
subAppManifestURLs[manifestURL] = {
pageURL: pageURL,
description: aDescription,
appStatus: aAppStatus,
rules: aRules,
manifestURL: manifestURL
};
},
observe: function(aSubject, aTopic, aData) {
switch (aTopic) {
case "xpcom-shutdown":
Services.obs.removeObserver(this, "xpcom-shutdown");
break;
}
},
classID: Components.ID("{3dd15ce6-e7be-11e2-82bc-77967e7a63e6}"),
QueryInterface: XPCOMUtils.generateQI([Ci.nsIInterAppCommService,
Ci.nsIObserver])
}
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([InterAppCommService]);

View File

@ -60,6 +60,11 @@ XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
"@mozilla.org/childprocessmessagemanager;1",
"nsIMessageSender");
XPCOMUtils.defineLazyGetter(this, "interAppCommService", function() {
return Cc["@mozilla.org/inter-app-communication-service;1"]
.getService(Ci.nsIInterAppCommService);
});
XPCOMUtils.defineLazyGetter(this, "msgmgr", function() {
return Cc["@mozilla.org/system-message-internal;1"]
.getService(Ci.nsISystemMessagesInternal);
@ -530,6 +535,8 @@ this.DOMApplicationRegistry = {
// |aEntryPoint| is either the entry_point name or the null in which case we
// use the root of the manifest.
//
// TODO Bug 908094 Refine _registerSystemMessagesForEntryPoint(...).
_registerSystemMessagesForEntryPoint: function(aManifest, aApp, aEntryPoint) {
let root = aManifest;
if (aEntryPoint && aManifest.entry_points[aEntryPoint]) {
@ -571,6 +578,69 @@ this.DOMApplicationRegistry = {
});
},
// |aEntryPoint| is either the entry_point name or the null in which case we
// use the root of the manifest.
//
// TODO Bug 908094 Refine _registerInterAppConnectionsForEntryPoint(...).
_registerInterAppConnectionsForEntryPoint: function(aManifest, aApp,
aEntryPoint) {
let root = aManifest;
if (aEntryPoint && aManifest.entry_points[aEntryPoint]) {
root = aManifest.entry_points[aEntryPoint];
}
let connections = root.connections;
if (!connections) {
return;
}
if ((typeof connections) !== "object") {
debug("|connections| is not an object. Skipping: " + connections);
return;
}
let manifest = new ManifestHelper(aManifest, aApp.origin);
let launchPathURI = Services.io.newURI(manifest.fullLaunchPath(aEntryPoint),
null, null);
let manifestURI = Services.io.newURI(aApp.manifestURL, null, null);
for (let keyword in connections) {
let connection = connections[keyword];
// Resolve the handler path from origin. If |handler_path| is absent,
// use |launch_path| as default.
let fullHandlerPath;
let handlerPath = connection.handler_path;
if (handlerPath) {
try {
fullHandlerPath = manifest.resolveFromOrigin(handlerPath);
} catch(e) {
debug("Connection's handler path is invalid. Skipping: keyword: " +
keyword + " handler_path: " + handlerPath);
continue;
}
}
let handlerPageURI = fullHandlerPath
? Services.io.newURI(fullHandlerPath, null, null)
: launchPathURI;
if (SystemMessagePermissionsChecker
.isSystemMessagePermittedToRegister("connection",
aApp.origin,
aManifest)) {
msgmgr.registerPage("connection", handlerPageURI, manifestURI);
}
interAppCommService.
registerConnection(keyword,
handlerPageURI,
manifestURI,
connection.description,
AppsUtils.getAppManifestStatus(manifest),
connection.rules);
}
},
_registerSystemMessages: function(aManifest, aApp) {
this._registerSystemMessagesForEntryPoint(aManifest, aApp, null);
@ -583,6 +653,19 @@ this.DOMApplicationRegistry = {
}
},
_registerInterAppConnections: function(aManifest, aApp) {
this._registerInterAppConnectionsForEntryPoint(aManifest, aApp, null);
if (!aManifest.entry_points) {
return;
}
for (let entryPoint in aManifest.entry_points) {
this._registerInterAppConnectionsForEntryPoint(aManifest, aApp,
entryPoint);
}
},
// |aEntryPoint| is either the entry_point name or the null in which case we
// use the root of the manifest.
_createActivitiesToRegister: function(aManifest, aApp, aEntryPoint, aRunUpdate) {
@ -745,6 +828,7 @@ this.DOMApplicationRegistry = {
app.redirects = this.sanitizeRedirects(manifest.redirects);
}
this._registerSystemMessages(manifest, app);
this._registerInterAppConnections(manifest, app);
appsToRegister.push({ manifest: manifest, app: app });
}, this);
this._registerActivitiesForApps(appsToRegister, aRunUpdate);
@ -1396,6 +1480,7 @@ this.DOMApplicationRegistry = {
}
this._registerSystemMessages(aNewManifest, aApp);
this._registerActivities(aNewManifest, aApp, true);
this._registerInterAppConnections(aNewManifest, aApp);
} else {
// Nothing else to do but notifying we're ready.
this.notifyAppsRegistryReady();

View File

@ -16,6 +16,7 @@ EXTRA_COMPONENTS += [
'AppsService.js',
'AppsService.manifest',
'InterAppComm.manifest',
'InterAppCommService.js',
'InterAppConnection.js',
'InterAppMessagePort.js',
'Webapps.js',

View File

@ -11,6 +11,7 @@ XPIDL_SOURCES += [
'nsIDOMApplicationRegistry.idl',
'nsIDOMApplicationRegistry2.idl',
'nsIDOMMozApplicationEvent.idl',
'nsIInterAppCommService.idl',
]
XPIDL_MODULE = 'dom_apps'

View File

@ -0,0 +1,40 @@
/* 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 "domstubs.idl"
interface nsIURI;
/**
* Implemented by the contract id @mozilla.org/inter-app-communication-service;1
*
* This interface contains helpers for Inter-App Communication API [1] related
* purposes. A singleton service of this interface will be instantiated during
* the system boot-up, which plays the role of the central service receiving
* messages from and interacting with the content processes.
*
* [1] https://wiki.mozilla.org/WebAPI/Inter_App_Communication_Alt_proposal
*/
[scriptable, uuid(7fdd8b68-0b0a-11e3-9b4c-afbc236da250)]
interface nsIInterAppCommService : nsISupports
{
/*
* Registration of a page that wants to be connected to other apps through
* the Inter-App Communication API.
*
* @param keyword The connection's keyword.
* @param handlerPageURI The URI of the handler's page.
* @param manifestURI The webapp's manifest URI.
* @param description The connection's description.
* @param appStatus The app status can be Ci.nsIPrincipal.APP_STATUS_[
* NOT_INSTALLED, INSTALLED, PRIVILEGED, CERTIFIED].
* @param rules The connection's rules.
*/
void registerConnection(in DOMString keyword,
in nsIURI handlerPageURI,
in nsIURI manifestURI,
in DOMString description,
in unsigned short appStatus,
in jsval rules);
};