diff options
author | sgurun <sgurun@chromium.org> | 2015-02-26 10:50:05 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-02-26 18:52:46 +0000 |
commit | 1f47db6eeea87febb755db2c498335fd9bb226b1 (patch) | |
tree | 0db5b47a4f754b6cd30903ef58c815a5dca5e04b | |
parent | d74986e2bed72beae3cb8b0bfc5f0fe73062000e (diff) | |
download | chromium_src-1f47db6eeea87febb755db2c498335fd9bb226b1.zip chromium_src-1f47db6eeea87febb755db2c498335fd9bb226b1.tar.gz chromium_src-1f47db6eeea87febb755db2c498335fd9bb226b1.tar.bz2 |
Implement the close() API for Message ports
The close API has to consider these cases:
1. A message port can be in a pending state
2. A message could be queued in renderer waiting for conversion
Therefore close() immediately closes the port, but it does not
cleanup the resources until all the messages are transferred.
BUG=393291
Review URL: https://codereview.chromium.org/956763002
Cr-Commit-Position: refs/heads/master@{#318271}
15 files changed, 294 insertions, 77 deletions
diff --git a/android_webview/browser/aw_message_port_message_filter.cc b/android_webview/browser/aw_message_port_message_filter.cc index 60b143e..fc2d314 100644 --- a/android_webview/browser/aw_message_port_message_filter.cc +++ b/android_webview/browser/aw_message_port_message_filter.cc @@ -35,6 +35,7 @@ bool AwMessagePortMessageFilter::OnMessageReceived( AwMessagePortService::OnConvertedWebToAppMessage) IPC_MESSAGE_HANDLER(AwMessagePortHostMsg_ConvertedAppToWebMessage, OnConvertedAppToWebMessage) + IPC_MESSAGE_HANDLER(AwMessagePortHostMsg_ClosePortAck, OnClosePortAck) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() return handled; @@ -44,10 +45,17 @@ void AwMessagePortMessageFilter::OnConvertedAppToWebMessage( int msg_port_id, const base::string16& message, const std::vector<int>& sent_message_port_ids) { + MessagePortProvider::PostMessageToPort(msg_port_id, message, sent_message_port_ids); } +void AwMessagePortMessageFilter::OnClosePortAck(int message_port_id) { + MessagePortProvider::ClosePort(message_port_id); + AwBrowserContext::GetDefault()->GetMessagePortService()-> + CleanupPort(message_port_id); +} + void AwMessagePortMessageFilter::OnDestruct() const { BrowserThread::DeleteOnIOThread::Destruct(this); } @@ -62,6 +70,10 @@ void AwMessagePortMessageFilter::SendAppToWebMessage( message, sent_message_port_ids)); } +void AwMessagePortMessageFilter::SendClosePortMessage(int message_port_id) { + Send(new AwMessagePortMsg_ClosePort(route_id_, message_port_id)); +} + void AwMessagePortMessageFilter::SendMessage( int msg_port_route_id, const base::string16& message, diff --git a/android_webview/browser/aw_message_port_message_filter.h b/android_webview/browser/aw_message_port_message_filter.h index 5e0b9a0..2845068 100644 --- a/android_webview/browser/aw_message_port_message_filter.h +++ b/android_webview/browser/aw_message_port_message_filter.h @@ -26,13 +26,13 @@ class AwMessagePortMessageFilter : public content::BrowserMessageFilter, void SendAppToWebMessage(int msg_port_route_id, const base::string16& message, const std::vector<int>& sent_message_port_ids); + void SendClosePortMessage(int message_port_id); // MessagePortDelegate implementation. void SendMessage(int msg_port_route_id, const base::string16& message, const std::vector<int>& sent_message_port_ids) override; void SendMessagesAreQueued(int route_id) override; - private: friend class content::BrowserThread; friend class base::DeleteHelper<AwMessagePortMessageFilter>; @@ -41,6 +41,7 @@ class AwMessagePortMessageFilter : public content::BrowserMessageFilter, int msg_port_id, const base::string16& message, const std::vector<int>& sent_message_port_ids); + void OnClosePortAck(int message_port_id); ~AwMessagePortMessageFilter() override; diff --git a/android_webview/browser/aw_message_port_service.h b/android_webview/browser/aw_message_port_service.h index 62f46f0..779d90c 100644 --- a/android_webview/browser/aw_message_port_service.h +++ b/android_webview/browser/aw_message_port_service.h @@ -25,6 +25,8 @@ class AwMessagePortService { virtual void OnMessagePortMessageFilterClosing( AwMessagePortMessageFilter* filter) = 0; + + virtual void CleanupPort(int message_port_id) = 0; }; } // namespace android_webview diff --git a/android_webview/common/aw_message_port_messages.h b/android_webview/common/aw_message_port_messages.h index 00ec171..f1b0bf3 100644 --- a/android_webview/common/aw_message_port_messages.h +++ b/android_webview/common/aw_message_port_messages.h @@ -58,6 +58,12 @@ IPC_MESSAGE_ROUTED3(AwMessagePortMsg_AppToWebMessage, base::string16 /* message */, std::vector<int> /* sent message port_ids */) +// Used to defer message port closing until after all in-flight messages +// are flushed from renderer to browser. Renderer piggy-backs the message +// to browser. +IPC_MESSAGE_ROUTED1(AwMessagePortMsg_ClosePort, + int /* message port id */) + //----------------------------------------------------------------------------- // These are messages sent from the renderer to the browser process. @@ -72,3 +78,7 @@ IPC_MESSAGE_ROUTED3(AwMessagePortHostMsg_ConvertedAppToWebMessage, int /* recipient message port id */, base::string16 /* converted message */, std::vector<int> /* sent message port_ids */) + +// Response to AwMessagePortMsg_ClosePort +IPC_MESSAGE_ROUTED1(AwMessagePortHostMsg_ClosePortAck, + int /* message port id */) diff --git a/android_webview/java/src/org/chromium/android_webview/AwContents.java b/android_webview/java/src/org/chromium/android_webview/AwContents.java index e53f4f7..c95137c 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwContents.java +++ b/android_webview/java/src/org/chromium/android_webview/AwContents.java @@ -1809,10 +1809,17 @@ public class AwContents implements SmartClipProvider, sentPorts); } - /** - * Posts a message to the destination frame for real. The unique message port - * ids of any transferred port should be known at this time. - */ + // Implements PostMessageSender.PostMessageSenderDelegate interface method. + @Override + public boolean isPostMessageSenderReady() { + return true; + } + + // Implements PostMessageSender.PostMessageSenderDelegate interface method. + @Override + public void onPostMessageQueueEmpty() { } + + // Implements PostMessageSender.PostMessageSenderDelegate interface method. @Override public void postMessageToWeb(String frameName, String message, String targetOrigin, int[] sentPortIds) { diff --git a/android_webview/java/src/org/chromium/android_webview/AwMessagePortService.java b/android_webview/java/src/org/chromium/android_webview/AwMessagePortService.java index 8d2c499..ddc09a0 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwMessagePortService.java +++ b/android_webview/java/src/org/chromium/android_webview/AwMessagePortService.java @@ -92,6 +92,12 @@ public class AwMessagePortService { private SparseArray<MessagePort> mMessagePorts = new SparseArray<MessagePort>(); private Object mLock = new Object(); + public void remove(int portId) { + synchronized (mLock) { + mMessagePorts.remove(portId); + } + } + public void put(int portId, MessagePort m) { synchronized (mLock) { mMessagePorts.put(portId, m); @@ -123,12 +129,17 @@ public class AwMessagePortService { mObserverList.removeObserver(observer); } + public void closePort(int messagePortId) { + mPortStorage.remove(messagePortId); + if (mNativeMessagePortService == 0) return; + nativeClosePort(mNativeMessagePortService, messagePortId); + } + public void postMessage(int senderId, String message, int[] sentPorts) { // verify that webview still owns the port (not transferred) if (mPortStorage.get(senderId) == null) { throw new IllegalStateException("Cannot post to unknown port " + senderId); } - removeSentPorts(sentPorts); if (mNativeMessagePortService == 0) return; nativePostAppToWebMessage(mNativeMessagePortService, senderId, message, sentPorts); } @@ -141,7 +152,7 @@ public class AwMessagePortService { if (p == null) { throw new IllegalStateException("Cannot transfer unknown port " + port); } - mPortStorage.put(port, null); + mPortStorage.remove(port); } } } @@ -190,4 +201,6 @@ public class AwMessagePortService { private native long nativeInitAwMessagePortService(); private native void nativePostAppToWebMessage(long nativeAwMessagePortServiceImpl, int senderId, String message, int[] portIds); + private native void nativeClosePort(long nativeAwMessagePortServiceImpl, + int messagePortId); } diff --git a/android_webview/java/src/org/chromium/android_webview/MessagePort.java b/android_webview/java/src/org/chromium/android_webview/MessagePort.java index 2d0e393..620cbbb 100644 --- a/android_webview/java/src/org/chromium/android_webview/MessagePort.java +++ b/android_webview/java/src/org/chromium/android_webview/MessagePort.java @@ -22,17 +22,17 @@ import android.util.Log; * 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 should be closed by the app when it is not needed any more. This will free - * any resources used by it. A closed port cannot receive/send messages and cannot be transferred. - * close() can be called multiple times. - * * 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. * + * A message port should be closed by the app when it is not needed any more. This will free + * any resources used by it. A closed port cannot receive/send messages and cannot be transferred. + * close() can be called multiple times. A transferred port cannot be closed by the application, + * since the ownership is also transferred during the transfer. Closing a transferred port will + * throw an exception. + * * TODO(sgurun) implement queueing messages while a port is in transfer - * TODO(sgurun) implement freeing resources in content/message_port_service when a port is - * closed */ public class MessagePort implements PostMessageSender.PostMessageSenderDelegate { @@ -43,23 +43,6 @@ public class MessagePort implements PostMessageSender.PostMessageSenderDelegate public abstract void onMessage(String message); }; - /** - * A specialized PostMessageSender for message channel message port. - */ - private static class MessagePortPostMessageSender extends PostMessageSender { - - private MessagePort mSender; - - public MessagePortPostMessageSender(MessagePort sender, AwMessagePortService service) { - super(sender, service); - mSender = sender; - } - @Override - protected boolean senderIsReady() { - return mSender.isReady(); - } - } - private static final String TAG = "MessagePort"; private static final int PENDING = -1; private int mPortId = PENDING; @@ -67,11 +50,11 @@ public class MessagePort implements PostMessageSender.PostMessageSenderDelegate private AwMessagePortService mMessagePortService; private boolean mClosed; private boolean mTransferred; - private MessagePortPostMessageSender mPostMessageSender; + private PostMessageSender mPostMessageSender; public MessagePort(AwMessagePortService messagePortService) { mMessagePortService = messagePortService; - mPostMessageSender = new MessagePortPostMessageSender(this, mMessagePortService); + mPostMessageSender = new PostMessageSender(this, mMessagePortService); mMessagePortService.addObserver(mPostMessageSender); } @@ -88,11 +71,17 @@ public class MessagePort implements PostMessageSender.PostMessageSenderDelegate } public void close() { - if (!mClosed) { - mClosed = true; - mMessagePortService.removeObserver(mPostMessageSender); - // TODO(sgurun) remove the port from AwMessagePortService and write a test - // to verify it. + if (mTransferred) { + throw new IllegalStateException("Port is already transferred"); + } + if (mClosed) return; + mClosed = true; + // 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(); } } @@ -130,7 +119,7 @@ public class MessagePort implements PostMessageSender.PostMessageSenderDelegate } if (msgPorts != null) { for (MessagePort port : msgPorts) { - if (port.portId() == mPortId) { + if (port.equals(this)) { throw new IllegalStateException("Source port cannot be transferred"); } } @@ -138,9 +127,30 @@ public class MessagePort implements PostMessageSender.PostMessageSenderDelegate mPostMessageSender.postMessage(null, message, null, msgPorts); } + // Implements PostMessageSender.PostMessageSenderDelegate interface method. + @Override + public boolean isPostMessageSenderReady() { + return isReady(); + } + + // 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); + } } diff --git a/android_webview/java/src/org/chromium/android_webview/PostMessageSender.java b/android_webview/java/src/org/chromium/android_webview/PostMessageSender.java index 7951838..01d7cae 100644 --- a/android_webview/java/src/org/chromium/android_webview/PostMessageSender.java +++ b/android_webview/java/src/org/chromium/android_webview/PostMessageSender.java @@ -22,6 +22,16 @@ public class PostMessageSender implements AwMessagePortService.MessageChannelObs */ void postMessageToWeb(String frameName, String message, String targetOrigin, int[] sentPortIds); + + /* + * Whether the post message sender is ready to post messages. + */ + boolean isPostMessageSenderReady(); + + /* + * Informs that all messages are posted and message queue is empty. + */ + void onPostMessageQueueEmpty(); }; // A struct to store Message parameters that are sent from App to Web. @@ -54,6 +64,12 @@ public class PostMessageSender implements AwMessagePortService.MessageChannelObs mService = service; } + // TODO(sgurun) in code review it was found this was implemented wrongly + // as mMessageQueue.size() > 0. write a test to catch this. + public boolean isMessageQueueEmpty() { + return mMessageQueue.size() == 0; + } + // Return true if any sent port is pending. private boolean anySentPortIsPending(MessagePort[] sentPorts) { if (sentPorts != null) { @@ -66,11 +82,6 @@ public class PostMessageSender implements AwMessagePortService.MessageChannelObs return false; } - // By default the sender is always ready. - protected boolean senderIsReady() { - return true; - } - // A message to a frame is queued if: // 1. Sender is not ready to post. When posting messages to frames, sender is always // ready. However, when posting messages using message channels, sender may be in @@ -80,7 +91,7 @@ public class PostMessageSender implements AwMessagePortService.MessageChannelObs private boolean shouldQueueMessage(MessagePort[] sentPorts) { // if messages to frames are already in queue mode, simply queue it, no need to // check ports. - if (mMessageQueue.size() > 0 || !senderIsReady()) { + if (mMessageQueue.size() > 0 || !mDelegate.isPostMessageSenderReady()) { return true; } if (anySentPortIsPending(sentPorts)) { @@ -131,7 +142,7 @@ public class PostMessageSender implements AwMessagePortService.MessageChannelObs public void onMessageChannelCreated() { PostMessageParams msg; - if (!senderIsReady()) { + if (!mDelegate.isPostMessageSenderReady()) { return; } @@ -143,5 +154,6 @@ public class PostMessageSender implements AwMessagePortService.MessageChannelObs mMessageQueue.remove(); postMessageToWeb(msg.frameName, msg.message, msg.targetOrigin, msg.sentPorts); } + mDelegate.onPostMessageQueueEmpty(); } } diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/PostMessageTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/PostMessageTest.java index 8849ec9..a9923be 100644 --- a/android_webview/javatests/src/org/chromium/android_webview/test/PostMessageTest.java +++ b/android_webview/javatests/src/org/chromium/android_webview/test/PostMessageTest.java @@ -122,6 +122,52 @@ public class PostMessageTest extends AwTestBase { + " </script>" + "</body></html>"; + // Concats all the data fields of the received messages and makes it + // available as page title. + private static final String TITLE_FROM_POSTMESSAGE_TO_FRAME = + "<!DOCTYPE html><html><body>" + + " <script>" + + " var received = '';" + + " onmessage = function (e) {" + + " received += e.data;" + + " document.title = received;" + + " }" + + " </script>" + + "</body></html>"; + + // Concats all the data fields of the received messages to the transferred channel + // and makes it available as page title. + private static final String TITLE_FROM_POSTMESSAGE_TO_CHANNEL = + "<!DOCTYPE html><html><body>" + + " <script>" + + " var received = '';" + + " onmessage = function (e) {" + + " var myport = e.ports[0];" + + " myport.onmessage = function (f) {" + + " received = received + f.data;" + + " document.title = received;" + + " }" + + " }" + + " </script>" + + "</body></html>"; + + // Call on non-UI thread. + private void expectTitle(final String title) throws Throwable { + assertTrue("Received title " + mAwContents.getTitle() + " while expecting " + title, + CriteriaHelper.pollForCriteria(new Criteria() { + @Override + public boolean isSatisfied() { + return ThreadUtils.runOnUiThreadBlockingNoException( + new Callable<Boolean>() { + @Override + public Boolean call() throws Exception { + return mAwContents.getTitle().equals(title); + } + }); + } + })); + } + private void loadPage(String page) throws Throwable { final String url = mWebServer.setResponse("/test.html", page, CommonResources.getTextHtmlHeaders(true)); @@ -271,6 +317,96 @@ public class PostMessageTest extends AwTestBase { boolean ignore = latch.await(TIMEOUT, java.util.concurrent.TimeUnit.MILLISECONDS); } + // Verify messages posted before closing a port is received at the destination port. + @SmallTest + @Feature({"AndroidWebView", "Android-PostMessage"}) + public void testMessagesPostedBeforeClosingPortAreTransferred() throws Throwable { + loadPage(TITLE_FROM_POSTMESSAGE_TO_CHANNEL); + runTestOnUiThread(new Runnable() { + @Override + public void run() { + MessagePort[] channel = mAwContents.createMessageChannel(); + mAwContents.postMessageToFrame(null, "1", mWebServer.getBaseUrl(), + new MessagePort[]{channel[1]}); + channel[0].postMessage("2", null); + channel[0].postMessage("3", null); + channel[0].close(); + } + }); + expectTitle("23"); + } + + // Verify a transferred port using postmessagetoframe cannot be closed. + @SmallTest + @Feature({"AndroidWebView", "Android-PostMessage"}) + public void testClosingTransferredPortToFrameThrowsAnException() throws Throwable { + loadPage(TEST_PAGE); + final CountDownLatch latch = new CountDownLatch(1); + runTestOnUiThread(new Runnable() { + @Override + public void run() { + MessagePort[] channel = mAwContents.createMessageChannel(); + mAwContents.postMessageToFrame(null, "1", mWebServer.getBaseUrl(), + new MessagePort[]{channel[1]}); + try { + channel[1].close(); + } catch (IllegalStateException ex) { + latch.countDown(); + return; + } + fail(); + } + }); + boolean ignore = latch.await(TIMEOUT, java.util.concurrent.TimeUnit.MILLISECONDS); + } + + // Verify a transferred port using postmessagetoframe cannot be closed. + @SmallTest + @Feature({"AndroidWebView", "Android-PostMessage"}) + public void testClosingTransferredPortToChannelThrowsAnException() throws Throwable { + loadPage(TEST_PAGE); + final CountDownLatch latch = new CountDownLatch(1); + runTestOnUiThread(new Runnable() { + @Override + public void run() { + MessagePort[] channel1 = mAwContents.createMessageChannel(); + mAwContents.postMessageToFrame(null, "1", mWebServer.getBaseUrl(), + new MessagePort[]{channel1[1]}); + MessagePort[] channel2 = mAwContents.createMessageChannel(); + channel1[0].postMessage("2", new MessagePort[]{channel2[0]}); + try { + channel2[0].close(); + } catch (IllegalStateException ex) { + latch.countDown(); + return; + } + fail(); + } + }); + boolean ignore = latch.await(TIMEOUT, java.util.concurrent.TimeUnit.MILLISECONDS); + } + + // Create two message channels, and while they are in pending state, transfer the + // second one in the first one. + @SmallTest + @Feature({"AndroidWebView", "Android-PostMessage"}) + public void testPendingPortCanBeTransferredInPendingPort() throws Throwable { + loadPage(TITLE_FROM_POSTMESSAGE_TO_CHANNEL); + final TestMessagePort testPort = + new TestMessagePort(getAwBrowserContext().getMessagePortService()); + runTestOnUiThread(new Runnable() { + @Override + public void run() { + MessagePort[] channel1 = mAwContents.createMessageChannel(); + mAwContents.postMessageToFrame(null, "1", mWebServer.getBaseUrl(), + new MessagePort[]{channel1[1]}); + MessagePort[] channel2 = mAwContents.createMessageChannel(); + channel1[0].postMessage("2", new MessagePort[]{channel2[0]}); + } + }); + expectTitle("2"); + } + private static class ChannelContainer { private boolean mReady; private MessagePort[] mChannel; @@ -475,42 +611,12 @@ public class PostMessageTest extends AwTestBase { assertEquals(HELLO, channelContainer.getMessage()); } - // concats all the data fields of the received messages and makes it - // available as page title. - private static final String TITLE_PAGE = - "<!DOCTYPE html><html><body>" - + " <script>" - + " var received = \"\";" - + " onmessage = function (e) {" - + " received = received + e.data;" - + " document.title = received;" - + " }" - + " </script>" - + "</body></html>"; - - // Call on non-UI thread. - private void expectTitle(final String title) throws Throwable { - assertTrue("Received title " + mAwContents.getTitle() + " while expecting " + title, - CriteriaHelper.pollForCriteria(new Criteria() { - @Override - public boolean isSatisfied() { - return ThreadUtils.runOnUiThreadBlockingNoException( - new Callable<Boolean>() { - @Override - public Boolean call() throws Exception { - return mAwContents.getTitle().equals(title); - } - }); - } - })); - } - // Post a message with a pending port to a frame and then post a bunch of messages // after that. Make sure that they are not ordered at the receiver side. @SmallTest @Feature({"AndroidWebView", "Android-PostMessage"}) public void testPostMessageToFrameNotReordersMessages() throws Throwable { - loadPage(TITLE_PAGE); + loadPage(TITLE_FROM_POSTMESSAGE_TO_FRAME); runTestOnUiThread(new Runnable() { @Override public void run() { @@ -586,7 +692,7 @@ public class PostMessageTest extends AwTestBase { @SmallTest @Feature({"AndroidWebView", "Android-PostMessage"}) public void testPostMessageToFrameNotSendsPendingMessages() throws Throwable { - loadPage(TITLE_PAGE); + loadPage(TITLE_FROM_POSTMESSAGE_TO_FRAME); final TestMessagePort testPort = new TestMessagePort(getAwBrowserContext().getMessagePortService()); runTestOnUiThread(new Runnable() { diff --git a/android_webview/native/aw_message_port_service_impl.cc b/android_webview/native/aw_message_port_service_impl.cc index d2e1fa4..b4bf2ca 100644 --- a/android_webview/native/aw_message_port_service_impl.cc +++ b/android_webview/native/aw_message_port_service_impl.cc @@ -135,6 +135,21 @@ void AwMessagePortServiceImpl::PostAppToWebMessage(JNIEnv* env, jobject obj, base::Owned(j_sent_ports))); } +// The message port service cannot immediately close the port, because +// it is possible that messages are still queued in the renderer process +// waiting for a conversion. Instead, it sends a special message with +// a flag which indicates that this message port should be closed. +void AwMessagePortServiceImpl::ClosePort(JNIEnv* env, jobject obj, + int message_port_id) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + BrowserThread::PostTask( + BrowserThread::IO, + FROM_HERE, + base::Bind(&AwMessagePortServiceImpl::PostClosePortMessage, + base::Unretained(this), + message_port_id)); +} + void AwMessagePortServiceImpl::RemoveSentPorts( const std::vector<int>& sent_ports) { DCHECK_CURRENTLY_ON(BrowserThread::IO); @@ -151,6 +166,15 @@ void AwMessagePortServiceImpl::PostAppToWebMessageOnIOThread( ports_[sender_id]->SendAppToWebMessage(sender_id, *message, *sent_ports); } +void AwMessagePortServiceImpl::PostClosePortMessage(int message_port_id) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + ports_[message_port_id]->SendClosePortMessage(message_port_id); +} + +void AwMessagePortServiceImpl::CleanupPort(int message_port_id) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + ports_.erase(message_port_id); +} void AwMessagePortServiceImpl::CreateMessageChannelOnIOThread( scoped_refptr<AwMessagePortMessageFilter> filter, diff --git a/android_webview/native/aw_message_port_service_impl.h b/android_webview/native/aw_message_port_service_impl.h index 3ab5b88..fcb83be 100644 --- a/android_webview/native/aw_message_port_service_impl.h +++ b/android_webview/native/aw_message_port_service_impl.h @@ -39,10 +39,12 @@ class AwMessagePortServiceImpl : public AwMessagePortService { const std::vector<int>& sent_message_port_ids) override; void OnMessagePortMessageFilterClosing( AwMessagePortMessageFilter* filter) override; + void CleanupPort(int message_port_id) override; // Methods called from Java. void PostAppToWebMessage(JNIEnv* env, jobject object, int sender_id, jstring message, jintArray sent_ports); + void ClosePort(JNIEnv* env, jobject object, int message_port_id); void RemoveSentPorts(const std::vector<int>& sent_ports); @@ -60,6 +62,7 @@ private: int* port1, int* port2); void AddPort(int message_port_id, AwMessagePortMessageFilter* filter); + void PostClosePortMessage(int message_port_id); JavaObjectWeakGlobalRef java_ref_; typedef std::map<int, AwMessagePortMessageFilter*> MessagePorts; diff --git a/android_webview/renderer/aw_message_port_client.cc b/android_webview/renderer/aw_message_port_client.cc index 7a5f67e..54edf28 100644 --- a/android_webview/renderer/aw_message_port_client.cc +++ b/android_webview/renderer/aw_message_port_client.cc @@ -34,6 +34,7 @@ bool AwMessagePortClient::OnMessageReceived( IPC_BEGIN_MESSAGE_MAP(AwMessagePortClient, message) IPC_MESSAGE_HANDLER(AwMessagePortMsg_WebToAppMessage, OnWebToAppMessage) IPC_MESSAGE_HANDLER(AwMessagePortMsg_AppToWebMessage, OnAppToWebMessage) + IPC_MESSAGE_HANDLER(AwMessagePortMsg_ClosePort, OnClosePort) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() @@ -95,4 +96,9 @@ void AwMessagePortClient::OnAppToWebMessage( result, sent_message_port_ids)); } +void AwMessagePortClient::OnClosePort(int message_port_id) { + Send(new AwMessagePortHostMsg_ClosePortAck(render_frame()->GetRoutingID(), + message_port_id)); +} + } diff --git a/android_webview/renderer/aw_message_port_client.h b/android_webview/renderer/aw_message_port_client.h index bd21472..a8b5253 100644 --- a/android_webview/renderer/aw_message_port_client.h +++ b/android_webview/renderer/aw_message_port_client.h @@ -30,6 +30,7 @@ class AwMessagePortClient : public content::RenderFrameObserver { void OnAppToWebMessage(int message_port_id, const base::string16& message, const std::vector<int>& sent_message_port_ids); + void OnClosePort(int message_port_id); DISALLOW_COPY_AND_ASSIGN(AwMessagePortClient); }; diff --git a/content/browser/message_port_provider.cc b/content/browser/message_port_provider.cc index fac53a9..ac329bc 100644 --- a/content/browser/message_port_provider.cc +++ b/content/browser/message_port_provider.cc @@ -90,6 +90,13 @@ void MessagePortProvider::PostMessageToPort( } // static +void MessagePortProvider::ClosePort(int message_port_id) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + MessagePortService* msp = MessagePortService::GetInstance(); + msp->ClosePort(message_port_id); +} + +// static void MessagePortProvider::OnMessagePortDelegateClosing( MessagePortDelegate* delegate) { MessagePortService::GetInstance()->OnMessagePortDelegateClosing(delegate); diff --git a/content/public/browser/message_port_provider.h b/content/public/browser/message_port_provider.h index 1042399..8a725de 100644 --- a/content/public/browser/message_port_provider.h +++ b/content/public/browser/message_port_provider.h @@ -47,6 +47,9 @@ class CONTENT_EXPORT MessagePortProvider { const base::string16& data, const std::vector<int>& sent_ports); + // Close the message port. Should be called on IO thread. + static void ClosePort(int message_port_id); + // Cleanup the message ports that belong to the closing delegate. static void OnMessagePortDelegateClosing(MessagePortDelegate * delegate); |