Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(287)

Unified Diff: content/public/android/java/src/org/chromium/content/browser/AppWebMessagePort.java

Issue 2422793002: HTML MessagePort as mojo::MessagePipeHandle (Closed)
Patch Set: Add missing ScopedAsyncTaskScheduler instance for the new unit tests; required by a recent change t… Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: content/public/android/java/src/org/chromium/content/browser/AppWebMessagePort.java
diff --git a/content/public/android/java/src/org/chromium/content/browser/AppWebMessagePort.java b/content/public/android/java/src/org/chromium/content/browser/AppWebMessagePort.java
index 30e50d02e8a3cdbd6f60a0ac75b155cf90cd1162..17a60d78e9cc863ac56191e48b66cc6ca926beb8 100644
--- a/content/public/android/java/src/org/chromium/content/browser/AppWebMessagePort.java
+++ b/content/public/android/java/src/org/chromium/content/browser/AppWebMessagePort.java
@@ -9,6 +9,8 @@ import android.os.Looper;
import android.os.Message;
import org.chromium.base.Log;
+import org.chromium.base.annotations.CalledByNative;
+import org.chromium.base.annotations.JNINamespace;
import org.chromium.content_public.browser.MessagePort;
import java.util.Arrays;
@@ -19,16 +21,6 @@ import java.util.Arrays;
*
* State management:
*
- * Initially a message port will be in a pending state. It will be ready once it is created in
- * content/ (in IO thread) and a message port id is assigned.
- * A pending message port cannnot be transferred, and cannot send or receive messages. However,
- * these details are hidden from the user. If a message port is in the pending state:
- * 1. Any messages posted in this port will be queued until the port is ready
- * 2. Transferring the port using a message channel will cause the message (and any subsequent
- * messages sent) to be queued until the port is ready
- * 3. Transferring the pending port via postMessageToFrame will cause the message (and all
- * subsequent messages posted via postMessageToFrame) to be queued until the port is ready.
- *
* A message port can be in transferred state while a transfer is pending or complete. An
* application cannot use a transferred port to post messages. If a transferred port
* receives messages, they will be queued. This state is not visible to embedder app.
@@ -48,7 +40,7 @@ import java.util.Arrays;
* the code below
* 1. var c1 = new MessageChannel();
* 2. var c2 = new MessageChannel();
- * 3. c1.port2.onmessage= function(e) { console.log("1"); }
+ * 3. c1.port2.onmessage = function(e) { console.log("1"); }
* 4. c2.port2.onmessage = function(e) {
* 5. e.ports[0].onmessage = function(f) {
* 6. console.log("3");
@@ -73,25 +65,13 @@ import java.util.Arrays;
* transferring data. As a return, it simplifies implementation and prevents hard
* to debug, racy corner cases while receiving/sending data.
*/
-public class AppWebMessagePort implements MessagePort, PostMessageSender.PostMessageSenderDelegate {
- private static final String TAG = "MessagePort";
- private static final int PENDING = -1;
-
- // the what value for POST_MESSAGE
- private static final int POST_MESSAGE = 1;
+@JNINamespace("content")
+public class AppWebMessagePort implements MessagePort {
+ private static final String TAG = "AppWebMessagePort";
+ private static final long UNINITIALIZED_PORT_NATIVE_PTR = 0;
- private static class PostMessageFromWeb {
- public AppWebMessagePort port;
- public String message;
- public AppWebMessagePort[] sentPorts;
-
- public PostMessageFromWeb(
- AppWebMessagePort port, String message, AppWebMessagePort[] sentPorts) {
- this.port = port;
- this.message = message;
- this.sentPorts = sentPorts;
- }
- }
+ // The |what| value for handleMessage.
+ private static final int MESSAGES_AVAILABLE = 1;
// Implements the handler to handle messageport messages received from web.
// These messages are received on IO thread and normally handled in main
@@ -102,9 +82,9 @@ public class AppWebMessagePort implements MessagePort, PostMessageSender.PostMes
}
@Override
public void handleMessage(Message msg) {
- if (msg.what == POST_MESSAGE) {
- PostMessageFromWeb m = (PostMessageFromWeb) msg.obj;
- m.port.onMessage(m.message, m.sentPorts);
+ if (msg.what == MESSAGES_AVAILABLE) {
+ AppWebMessagePort port = (AppWebMessagePort) msg.obj;
+ port.dispatchReceivedMessages();
return;
}
throw new IllegalStateException("undefined message");
@@ -114,35 +94,38 @@ public class AppWebMessagePort implements MessagePort, PostMessageSender.PostMes
private static final MessageHandler sDefaultHandler =
new MessageHandler(Looper.getMainLooper());
- private int mPortId = PENDING;
+ private long mNativeAppWebMessagePort = UNINITIALIZED_PORT_NATIVE_PTR;
private MessageCallback mMessageCallback;
- private AppWebMessagePortService mMessagePortService;
private boolean mClosed;
private boolean mTransferred;
private boolean mStarted;
- private boolean mReleasedMessages;
- private PostMessageSender mPostMessageSender;
private MessageHandler mHandler;
private final Object mLock = new Object();
- public AppWebMessagePort(AppWebMessagePortService messagePortService) {
- mMessagePortService = messagePortService;
- mPostMessageSender = new PostMessageSender(this, mMessagePortService);
- mMessagePortService.addObserver(mPostMessageSender);
+ // Called to create an entangled pair of ports.
+ public static AppWebMessagePort[] createPair() {
+ AppWebMessagePort[] ports =
+ new AppWebMessagePort[] { new AppWebMessagePort(), new AppWebMessagePort() };
+ nativeInitializeAppWebMessagePortPair(ports);
+ return ports;
}
@Override
public boolean isReady() {
- return mPortId != PENDING;
+ return mNativeAppWebMessagePort != UNINITIALIZED_PORT_NATIVE_PTR;
}
- public int portId() {
- return mPortId;
+ @CalledByNative
+ private void setNativeAppWebMessagePort(long nativeAppWebMessagePort) {
+ mNativeAppWebMessagePort = nativeAppWebMessagePort;
}
- public void setPortId(int id) {
- mPortId = id;
- releaseMessages();
+ @CalledByNative
+ private long releaseNativePortForTransfer() {
+ mTransferred = true;
+ long port = mNativeAppWebMessagePort;
+ mNativeAppWebMessagePort = UNINITIALIZED_PORT_NATIVE_PTR;
+ return port;
}
@Override
@@ -150,16 +133,19 @@ public class AppWebMessagePort implements MessagePort, PostMessageSender.PostMes
if (mTransferred) {
throw new IllegalStateException("Port is already transferred");
}
+ if (mClosed) return;
+ mClosed = true;
+ // Synchronize with dispatchReceivedMessages to ensure that the native
+ // port is not closed too soon, but avoid holding mLock while calling
+ // nativeCloseMessagePort as that could result in a dead-lock (racing
+ // with onMessagesAvailable).
+ long port = UNINITIALIZED_PORT_NATIVE_PTR;
synchronized (mLock) {
- if (mClosed) return;
- mClosed = true;
+ port = mNativeAppWebMessagePort;
+ mNativeAppWebMessagePort = UNINITIALIZED_PORT_NATIVE_PTR;
}
- // If the port is already ready, and no messages are waiting in the
- // queue to be transferred, onPostMessageQueueEmpty() callback is not
- // received (it is received only after messages are purged). In this
- // case do the cleanup here.
- if (isReady() && mPostMessageSender.isMessageQueueEmpty()) {
- cleanup();
+ if (port != UNINITIALIZED_PORT_NATIVE_PTR) {
+ nativeCloseMessagePort(port);
}
}
@@ -173,10 +159,6 @@ public class AppWebMessagePort implements MessagePort, PostMessageSender.PostMes
return mTransferred;
}
- public void setTransferred() {
- mTransferred = true;
- }
-
@Override
public boolean isStarted() {
return mStarted;
@@ -185,6 +167,9 @@ public class AppWebMessagePort implements MessagePort, PostMessageSender.PostMes
// Only called on UI thread
@Override
public void setMessageCallback(MessageCallback messageCallback, Handler handler) {
+ if (isClosed() || isTransferred()) {
+ throw new IllegalStateException("Port is already closed or transferred");
+ }
mStarted = true;
synchronized (mLock) {
mMessageCallback = messageCallback;
@@ -192,40 +177,41 @@ public class AppWebMessagePort implements MessagePort, PostMessageSender.PostMes
mHandler = new MessageHandler(handler.getLooper());
}
}
- releaseMessages();
+ nativeStartReceivingMessages(mNativeAppWebMessagePort);
}
- // Only called on IO thread.
- public void onReceivedMessage(String message, AppWebMessagePort[] sentPorts) {
+ // Called on a background thread.
+ @CalledByNative
+ private void onMessagesAvailable() {
synchronized (mLock) {
- PostMessageFromWeb m = new PostMessageFromWeb(this, message, sentPorts);
Handler handler = mHandler != null ? mHandler : sDefaultHandler;
- Message msg = handler.obtainMessage(POST_MESSAGE, m);
+ Message msg = handler.obtainMessage(MESSAGES_AVAILABLE, this);
handler.sendMessage(msg);
}
}
- private void releaseMessages() {
- if (mReleasedMessages || !isReady() || mMessageCallback == null) {
+ // This method is called by nativeDispatchNextMessage while mLock is held.
+ @CalledByNative
+ private void onReceivedMessage(String message, AppWebMessagePort[] ports) {
+ if (mMessageCallback == null) {
+ Log.w(TAG, "No handler set for port [" + mNativeAppWebMessagePort
+ + "], dropping message " + message);
return;
}
- mReleasedMessages = true;
- mMessagePortService.releaseMessages(mPortId);
- }
-
- // This method may be called on a different thread than UI thread.
- public void onMessage(String message, AppWebMessagePort[] ports) {
- synchronized (mLock) {
- if (isClosed()) {
- Log.w(TAG, "Port [" + mPortId + "] received message in closed state");
- return;
- }
- if (mMessageCallback == null) {
- Log.w(TAG,
- "No handler set for port [" + mPortId + "], dropping message " + message);
- return;
+ mMessageCallback.onMessage(message, ports);
+ }
+
+ // This method may be called on either the UI thread or a background thread.
+ private void dispatchReceivedMessages() {
+ // Dispatch all of the available messages unless interrupted by close().
+ // NOTE: nativeDispatchNextMessage returns true and calls onReceivedMessage
+ // if a message is available else it returns false.
+ while (true) {
+ synchronized (mLock) {
+ if (!(isReady() && nativeDispatchNextMessage(mNativeAppWebMessagePort))) {
+ break;
+ }
}
- mMessageCallback.onMessage(message, ports);
}
}
@@ -240,37 +226,24 @@ public class AppWebMessagePort implements MessagePort, PostMessageSender.PostMes
if (port.equals(this)) {
throw new IllegalStateException("Source port cannot be transferred");
}
+ if (port.isClosed() || port.isTransferred()) {
+ throw new IllegalStateException("Port is already closed or transferred");
+ }
+ if (port.isStarted()) {
+ throw new IllegalStateException("Port is already started");
+ }
}
ports = Arrays.copyOf(sentPorts, sentPorts.length, AppWebMessagePort[].class);
}
mStarted = true;
- mPostMessageSender.postMessage(null, message, null, ports);
+ nativePostMessage(mNativeAppWebMessagePort, message, ports);
}
- // Implements PostMessageSender.PostMessageSenderDelegate interface method.
- @Override
- public boolean isPostMessageSenderReady() {
- return isReady();
- }
+ private static native void nativeInitializeAppWebMessagePortPair(AppWebMessagePort[] ports);
- // Implements PostMessageSender.PostMessageSenderDelegate interface method.
- @Override
- public void onPostMessageQueueEmpty() {
- if (isClosed()) {
- cleanup();
- }
- }
-
- // Implements PostMessageSender.PostMessageSenderDelegate interface method.
- @Override
- public void postMessageToWeb(
- String frameName, String message, String targetOrigin, int[] sentPortIds) {
- mMessagePortService.postMessage(mPortId, message, sentPortIds);
- }
-
- private void cleanup() {
- mMessagePortService.removeObserver(mPostMessageSender);
- mPostMessageSender = null;
- mMessagePortService.closePort(mPortId);
- }
+ private native void nativeCloseMessagePort(long nativeAppWebMessagePort);
+ private native void nativePostMessage(long nativeAppWebMessagePort, String message,
+ AppWebMessagePort[] ports);
+ private native boolean nativeDispatchNextMessage(long nativeAppWebMessagePort);
+ private native void nativeStartReceivingMessages(long nativeAppWebMessagePort);
}

Powered by Google App Engine
This is Rietveld 408576698