Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Comments on Inter App Communication (Gecko point of view)

80 views
Skip to first unread message

Gene Lian

unread,
May 28, 2013, 11:31:33 AM5/28/13
to Mounir Lamouri, ferjm...@gmail.com, dev-w...@lists.mozilla.org
Hi Mounir and Fernando,

I'd like to ask some questions from the Gecko point of view regarding the API prototyping at [1]. Some of them might be worth clarifying and discussing to improve the API's usability. Could you please return some feedback to me when you're available? Thanks a lot! Btw, I'm just starting with the API implementation at bug 876397.

1. First of all, all these APIs are going to be managed under |interface mozIDOMApplication|. Right?

2. I'm very confused about the following 2 APIs:

// The returned Future will contain true if at least a peer has been
// selected, false otherwise.
Future registerConnections(DOMString keyword);

// The returned Future will contain true if at least a peer is allowed
// to communicate with the application, false otherwise.
Future connectionsRegistered(DOMString keyword);

My understanding is the .registerConnections(...) means an app is wanting to add itself to the connection pool and the .connectionsRegistered(...) means an app is wanting to ask if other applications have been added into the connection pool. If my understanding is right, what does the return of .registerConnections(...) mean when it returns true? Does it mean there have already been some applications in the pool excluding itself? Isn't it just returning the same thing like .connectionsRegistered(...)?

3. If the "connect" system message can be sent to the apps that have registrations in their manifests, what's the main purpose of .registerConnections(...)? May I explain the difference in the following way?

a. System message registration is setting a static condition during the start-up registration.
b. .registerConnections(...) is setting a dynamic condition during the run-time.

Both (a) and (b) have to be satisfied and then the connection can be successfully established.

4. This might be a stupid question because I didn't join the prototyping process in the first place. The |Future|s of all these APIs practically represent |DOMRequest|s. Right? If yes, the |.then(...)| actually stands for .onsuccess(...)/.onerror(...). Correct?

5. What's happening if the sender is calling .postMessage(...) but the receiver hasn't called .onmessage(...) or .start() yet? Does the Gecko need to temporally cache the posts and then resend them after the receiver is ready ? Or just discard the posts? Actually, my main concern is: the sender has no way to know whether the receiver is ready to catch the posts. Is |request.accept()| exactly doing the acknowledgement I'm taking about?

6. It's not very clear to me what's the main difference between |request.accept()| and |port.start()|. They sound the same thing to me. That is, allowing the establishment of communication between apps. Could you please elaborate more regarding the difference?


[1] https://wiki.mozilla.org/WebAPI/Inter_App_Communication

Gene

Fernando Jiménez

unread,
May 28, 2013, 1:54:39 PM5/28/13
to Gene Lian, dev-w...@lists.mozilla.org, Mounir Lamouri
Hi!

On 28/05/2013, at 17:31, Gene Lian wrote:

> Hi Mounir and Fernando,
>
> I'd like to ask some questions from the Gecko point of view regarding the API prototyping at [1]. Some of them might be worth clarifying and discussing to improve the API's usability. Could you please return some feedback to me when you're available? Thanks a lot! Btw, I'm just starting with the API implementation at bug 876397.

Probably Mounir is the right person to reply to this questions, but I'll try my best answering with what I understood from this API :)

>
> 1. First of all, all these APIs are going to be managed under |interface mozIDOMApplication|. Right?

That's also my understanding. The Caller API is a "partial interface Application" so I guess this API will be part of mozIDOMApplication [1]

>
> 2. I'm very confused about the following 2 APIs:
>
> // The returned Future will contain true if at least a peer has been
> // selected, false otherwise.
> Future registerConnections(DOMString keyword);
>
> // The returned Future will contain true if at least a peer is allowed
> // to communicate with the application, false otherwise.
> Future connectionsRegistered(DOMString keyword);
>
> My understanding is the .registerConnections(...) means an app is wanting to add itself to the connection pool and the .connectionsRegistered(...) means an app is wanting to ask if other applications have been added into the connection pool. If my understanding is right, what does the return of .registerConnections(...) mean when it returns true? Does it mean there have already been some applications in the pool excluding itself? Isn't it just returning the same thing like .connectionsRegistered(...)?

The way I got it is that a call to .registerConnections("randomKeyword") will internally retrieve the list of apps that has previously registered themselves (via manifest) as able to connect based on the given keyword ("randomKeyword" in this case) and will show this list to the user in some kind of UI (to be defined) so she can choose which app(s) she wants to allow to connect. If the user chooses no application from this list, the result contained in the Future returned by the .registerConnections() call will be *false*. Or it will be *true* if at least one application has been selected and so allowed to connect. At that point (or probably before returning the result through the Future object), the implementation will need to add each of the selected apps to what you called the connection pool.

.connectionsRegistered("randomKeyword") will get *true* within the returned Future object if at least one app has been selected in the previous step.

> 3. If the "connect" system message can be sent to the apps that have registrations in their manifests, what's the main purpose of .registerConnections(...)? May I explain the difference in the following way?
>
> a. System message registration is setting a static condition during the start-up registration.
> b. .registerConnections(...) is setting a dynamic condition during the run-time.
>
> Both (a) and (b) have to be satisfied and then the connection can be successfully established.


I think an example will help you understand it better. So an example flow would be something like:

1 - App A registers itself as able to connect based on the "comms" keyword by adding the following to its manifest:

{
name: "Communications app A",
keywords: ["comms"]
}

2 - App B does exactly the same:

{
name: "Communications app B",
keywords: ["comms"]
}

3 - App C calls .registerConnections("comms"):

let future = app.registerConnections("comms");
future.then() = function(result) {
// See step 5
};

4. Before "future.then()" is called, the UI shows a list of apps that advertise themselves as able to connect based on the "comms" keyword. So the user will see something like (sorry for the crappy UI representation):

"
Do you want to allow a connection between App C and:
1. Communications app A (checkbox)
2. Communications app B (checkbox)

Accept | Cancel (buttons)
"

5. The user selects only App A and clicks "Accept". At that point "future.then()" is triggered:

future.then() = function(result) {
// "result" is true cause the user has allowed *at least* one app to connect.
// At this point we can call .connectionsRegistered("comms") and we'll get true.

// And we can also call .connect("comms");
app.connect("comms").then(function onconnect(ports) {
// Here "ports" is an array with an unique MessagePort that connects App C with App B.
});
};


>
> 4. This might be a stupid question because I didn't join the prototyping process in the first place. The |Future|s of all these APIs practically represent |DOMRequest|s. Right? If yes, the |.then(...)| actually stands for .onsuccess(...)/.onerror(...). Correct?

No. Actually this will be the Futures being implemented at [2] :)


> 5. What's happening if the sender is calling .postMessage(...) but the receiver hasn't called .onmessage(...) or .start() yet? Does the Gecko need to temporally cache the posts and then resend them after the receiver is ready ? Or just discard the posts? Actually, my main concern is: the sender has no way to know whether the receiver is ready to catch the posts. Is |request.accept()| exactly doing the acknowledgement I'm taking about?

That's a really good question!

As far as I can see the proposal doesn't specify if there will be a persistent message queue that can be delivered to an application that was getting messages before setting the message handler.

AFAICT request.accept() is a requirement for properly setting up the communication channel, so no message would be delivered to the receiver until it explicitly accepts the connection, but it is not telling the sender that the channel is properly set. However, |port.start()| seems to be doing that job instead. I agree that might be confusing.

>
> 6. It's not very clear to me what's the main difference between |request.accept()| and |port.start()|. They sound the same thing to me. That is, allowing the establishment of communication between apps. Could you please elaborate more regarding the difference?

Let's get back to the example above. On the receiver application (App B) once App C calls .connect("comms"), we will get a '"connect" system message:

navigator.setMessageHandler("connect", function(request) {

// At this point app B can accept the request or not, most likely based on the request origin.
// As the proposal specifies, not explicitly accepting the request, will reject the connection.
// Let's say we (as App B) want to connect with App C
port = request.accept();

// "port" is an instance of MessagePort.

// We have accepted the connection at this point,
// but that doesn't mean that we are ready to start receiving messages.
// We need to set the message handlers.
port.onmessage = function(evt) {
// Whatever we want to do with the messages.
};

// And now that we have the handlers ready, we can notify App C to start sending messages.
port.start();
});


I hope this helps. Mounir, correct me if I was wrong with any of my assumptions, please.

Cheers,

/ Fernando

[1] https://mxr.mozilla.org/mozilla-central/source/dom/interfaces/apps/nsIDOMApplicationRegistry.idl#11
[2] https://bugzilla.mozilla.org/show_bug.cgi?id=856410

Gene Lian

unread,
May 30, 2013, 5:47:56 AM5/30/13
to Fernando Jiménez, dev-w...@lists.mozilla.org, Mounir Lamouri
Hi Fernando,

Thanks for all the detailed examples. They are very helpful. I still have some concerns and questions which need to be clarified to help the implementation. Please see the in-lines.

Btw, it seems there is another thread discussing using XHR instead of IAC, though. :O

----- Original Message -----
> From: "Fernando Jiménez" <ferjm...@gmail.com>
> To: "Gene Lian" <cl...@mozilla.com>
> Cc: "Mounir Lamouri" <mou...@mozilla.com>, dev-w...@lists.mozilla.org
> Sent: Wednesday, May 29, 2013 1:54:39 AM
> Subject: Re: Comments on Inter App Communication (Gecko point of view)

> The way I got it is that a call to
> .registerConnections("randomKeyword") will internally retrieve the
> list of apps that has previously registered themselves (via
> manifest) as able to connect based on the given keyword
> ("randomKeyword" in this case) and will show this list to the user
> in some kind of UI (to be defined) so she can choose which app(s)
> she wants to allow to connect.

Regarding the UI behaviour of calling .registerConnections(...), do you have any idea for how can the Gecko practically notify the Gaia to pop up the prompt? In my opinion, maybe the Gecko can fire an mozChromeEvent to the System App (specifically, window_manager.js) to trigger that.

> AFAICT request.accept() is a requirement for properly setting up the
> communication channel, so no message would be delivered to the
> receiver until it explicitly accepts the connection, but it is not
> telling the sender that the channel is properly set. However,
> |port.start()| seems to be doing that job instead. I agree that
> might be confusing.

Even so, the |request.accept()| and |port.start()| seem to be doing the same task. I mean, the communication channel is only valid and working after the |port.start()| is being called. Why do we still need a |request.accept()|? It simply plays the role of returning a MessagePort object to be used. Why not just firing the system message with that MessagePort object directly. For example,

navigator.setMessageHandler('connect', function(aMessagePort) {
if (aMessagePort.origin != 'http://foobar.com') {
return;
}
aMessagePort.onmessage = function(e) { alert(e.data); };
aMessagePort.start();
});

then we don't need to call an extra |request.accept()| which sounds very redundant to me.

Another big concern is, on the Wikipage I don't see how the sender handles the response from |port.start()|. In the current design, the sender can immediately start to call .postMessage() to send messages after calling .connect(). However, the system message can be delivered to the receiver's app after 100 years. We definitely need an acknowledgement mechanism to notify the sender "OK! You can now post messages to me!" when the receiver calls |port.start()|.

Also, what's happening if the receiver fails to call |port.start()| due to any unexpected reasons? For example, the receiver's app could probably be killed at any time (OOM'ed) before the |port.start()| is being called (even if it has been wakened up by the system message). The sender would just be waiting there and doesn't know what to do.

I'll try to work out an acknowledgement mechanism to address these issues. Any input is welcomed at the same time. Thanks!

Gene

Thinker K.F. Li

unread,
Jun 27, 2013, 11:34:03 PM6/27/13
to dev-w...@lists.mozilla.org
Gene Lian <cl...@mozilla.com> writes:
>
> [1] https://wiki.mozilla.org/WebAPI/Inter_App_Communication
>

I am very curious for why don't reuse websocket api for this?

For example, if an applicaiton want to talk to another application with
app_id as the app ID or the origin.

var socket = WebSocket("wsapp://app_id", "PROTOCOL_NAME");
socket.onopen = ......

For the application provide the service

navigator.setMessageHandler("wsconnect", function (request) {
var socket = request.websocket; // an websocket.
if (socket.clientProtocols.indexOf("PROTOCOL_NAME") >= 0) {
// client's socket.protocol will be "PROTOCOL_NAME"
socket.accpet("PROTOCOL_NAME");
socket.onmessage = function () {
......
socket.send(...);
......
}
} else {
// deny it
socket.close();
}
}



--
Sinker
--
天教懶漫帶疏狂

Gene Lian

unread,
Jul 1, 2013, 5:54:03 AM7/1/13
to dev-w...@lists.mozilla.org
Just having a meeting with Fernando, Thinker, Borja and Fred. We decided to refine the Inter-App Communication API by the following conclusions:

1. We don't need |.registerConnections(...)| anymore. The |.connect(...)| will be in charge of popping up the app selector and directly return the selected apps in its callback.

2. The Gecko can use the chrome event to launch the Gaia's selector and the Gaia can use the content event to return the selected results to the Gecko.

3. We decide to remove the |.accept()| and directly pass an |MessagePort| object in the system message. In the end, the system message to be handled is going to be:

Dictionary ConnectionRequest {
MessagePort port;
DOMString keyword;
DOMString origin;
};

4. We decide to remove the |.start()| from the |MessagePort|, because the assignment of |port.onmessage| implicitly implies the start. In the end, the |MessagePort| only has the following two capabilities:

interface MessagePort {
void postMessage(...);
attribute jsval onmessage;
};

5. We decide to maintain a queue in the Gecko to save the sender's messages if the receiver's end doesn't set its |port.onmessage| yet. To avoid exploding the memory, we might need to use DB to maintain the queue.

6. Fernando suggested we should specify CRUD (i.e., Create/Read/Update/Delete) for each keyword in the app's manifest so that the receiver can decide which kinds of requesters are allowed to do the connection. Fernando will elaborate more on the design later.

Cheers,
Gene

nsm.n...@gmail.com

unread,
Jul 1, 2013, 3:59:48 PM7/1/13
to
On Monday, July 1, 2013 2:54:03 AM UTC-7, Gene Lian wrote:
> Just having a meeting with Fernando, Thinker, Borja and Fred. We decided to refine the Inter-App Communication API by the following conclusions:
>
>

Sorry for joining this discussion a little late, but I'd like to discuss some points. Forgive me if they've already been discussed before, but I couldn't find anything on dev.webapi.

>
> 1. We don't need |.registerConnections(...)| anymore. The |.connect(...)| will be in charge of popping up the app selector and directly return the selected apps in its callback.
>
>
>
> 2. The Gecko can use the chrome event to launch the Gaia's selector and the Gaia can use the content event to return the selected results to the Gecko.

Is there really a value gain in asking a user for permission about this? In all likelihood, users are going to just say accept. At least on the wiki page the use cases of this API are not well defined. It seems most applications will be only talking to a few other apps, that is, a lockscreen applet for music would only interact with the music player, a collection of email apps might interact only with some sort of background email service. With a permission UI, yes the user could select "Don't allow StealMyAccountInfo to access my email", but there is hardly anything to stop MyCuteEmailApp to pretend to be nice and then steal my account info. It is the sender of a message that shouldn't be sending confidential/private information over these channels.

> 5. We decide to maintain a queue in the Gecko to save the sender's messages if the receiver's end doesn't set its |port.onmessage| yet. To avoid exploding the memory, we might need to use DB to maintain the queue.

What sort of delivery guarantees are we making on this. We should answer that before working on an implementation. I think we're effectively implementing a pub-sub system. Would it be better to replace/unify system messages and this API and rather than engineer a fault tolerant system in JS from scratch, use an existing IPC mechanism like D-BUS or use a broker like MQTT which has reliable delivery guarantees, and build a JS bridge to them? My point being, it may be easier to get existing software working under our environment constraints.

Further it seems like another complication to have to define the keywords in the manifest. What advantage does that give to Gecko or to apps?
>
>
>
> 6. Fernando suggested we should specify CRUD (i.e., Create/Read/Update/Delete) for each keyword in the app's manifest so that the receiver can decide which kinds of requesters are allowed to do the connection. Fernando will elaborate more on the design later.

I'd like to know more about this. It feels like over-engineering to me. Ideally I'd like to avoid having the manifest involved in this API.

Regards,
Nikhil

Gene Lian

unread,
Jul 17, 2013, 7:12:31 AM7/17/13
to nsm nikhil, dev-w...@lists.mozilla.org
Hi Nikhil!

----- Original Message -----
> From: "nsm nikhil" <nsm.n...@gmail.com>
> To: dev-w...@lists.mozilla.org
> Sent: Tuesday, July 2, 2013 3:59:48 AM
> Subject: Re: Comments on Inter App Communication (Gecko point of view)
>
> > 2. The Gecko can use the chrome event to launch the Gaia's selector and the
> > Gaia can use the content event to return the selected results to the
> > Gecko.
>
> Is there really a value gain in asking a user for permission about this? In
> all likelihood, users are going to just say accept. At least on the wiki
> page the use cases of this API are not well defined. It seems most
> applications will be only talking to a few other apps, that is, a lockscreen
> applet for music would only interact with the music player, a collection of
> email apps might interact only with some sort of background email service.
> With a permission UI, yes the user could select "Don't allow
> StealMyAccountInfo to access my email", but there is hardly anything to stop
> MyCuteEmailApp to pretend to be nice and then steal my account info. It is
> the sender of a message that shouldn't be sending confidential/private
> information over these channels.

I don't have strong opinion on that. However, as far as I can tell, some people would still treat this kind of prompt seriously, though. Note that all the apps you're taking about here are certified/privileged. Note that we still desire to let arbitrary apps be able to use Inter-App Communication API. We don't plan to set any limitations regarding the app's type.

Fernando is working on a prototype for this prompt on the Gaia end. Let's wait and see if it really makes sense. Supposing we don't really want that, removing this kind of prompt will be easy from the Gecko's point of view.

>
> > 5. We decide to maintain a queue in the Gecko to save the sender's messages
> > if the receiver's end doesn't set its |port.onmessage| yet. To avoid
> > exploding the memory, we might need to use DB to maintain the queue.
>
> What sort of delivery guarantees are we making on this. We should answer that
> before working on an implementation. I think we're effectively implementing
> a pub-sub system. Would it be better to replace/unify system messages and
> this API and rather than engineer a fault tolerant system in JS from
> scratch, use an existing IPC mechanism like D-BUS or use a broker like MQTT
> which has reliable delivery guarantees, and build a JS bridge to them? My
> point being, it may be easier to get existing software working under our
> environment constraints.

Yeap, I'm thinking about the same thing. There are indeed some possibilities to integrate Inter-App Communication into System Message mechanism. However, Inter-App Communication API has a natural difference with System Message API. First of all, it's triggered based on the .mozApps and the System Message is used via window. Secondly, it's aimed to pass messages across different *ports*, where the System Message is designed for passing messages across *pages*. I'll check if it's worth merging them or at least refactorizing some parts of the codes. No matter what we decide, the System Message is still playing the role of waking up apps for the Inter-App Communication API and delivering communication ports to the receivers.

I'm not an expert of D-BUS or MQTT. Mozilla has our own IPC mechanism and it works well by far to pass all kinds of JS objects among processes. It sounds just an implementation detail to me if we can achieve our goal in any way.

Gene
0 new messages