diff options
author | Ben Murdoch <benm@google.com> | 2010-08-06 12:13:06 +0100 |
---|---|---|
committer | Ben Murdoch <benm@google.com> | 2010-08-18 15:49:13 +0100 |
commit | 06741cbc25cd4227a9fba40dfd0273bfcc1a587a (patch) | |
tree | ca6f21dec86a8c4f6d3c50e78628c0cf31da0353 /chrome/common/webmessageportchannel_impl.cc | |
parent | aa0bf16ed53445f227734aee4274c7aef056f032 (diff) | |
download | external_chromium-06741cbc25cd4227a9fba40dfd0273bfcc1a587a.zip external_chromium-06741cbc25cd4227a9fba40dfd0273bfcc1a587a.tar.gz external_chromium-06741cbc25cd4227a9fba40dfd0273bfcc1a587a.tar.bz2 |
Add chrome/common @ 52593
Needed by autofill
Change-Id: Ibfea9ab92382af0bd0cfc6e94d21e4baa4b9d896
Diffstat (limited to 'chrome/common/webmessageportchannel_impl.cc')
-rw-r--r-- | chrome/common/webmessageportchannel_impl.cc | 237 |
1 files changed, 237 insertions, 0 deletions
diff --git a/chrome/common/webmessageportchannel_impl.cc b/chrome/common/webmessageportchannel_impl.cc new file mode 100644 index 0000000..24304fd --- /dev/null +++ b/chrome/common/webmessageportchannel_impl.cc @@ -0,0 +1,237 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/common/webmessageportchannel_impl.h" + +#include "chrome/common/child_process.h" +#include "chrome/common/child_thread.h" +#include "chrome/common/worker_messages.h" +#include "third_party/WebKit/WebKit/chromium/public/WebString.h" +#include "third_party/WebKit/WebKit/chromium/public/WebMessagePortChannelClient.h" + +using WebKit::WebMessagePortChannel; +using WebKit::WebMessagePortChannelArray; +using WebKit::WebMessagePortChannelClient; +using WebKit::WebString; + +WebMessagePortChannelImpl::WebMessagePortChannelImpl() + : client_(NULL), + route_id_(MSG_ROUTING_NONE), + message_port_id_(MSG_ROUTING_NONE) { + AddRef(); + Init(); +} + +WebMessagePortChannelImpl::WebMessagePortChannelImpl( + int route_id, + int message_port_id) + : client_(NULL), + route_id_(route_id), + message_port_id_(message_port_id) { + AddRef(); + Init(); +} + +WebMessagePortChannelImpl::~WebMessagePortChannelImpl() { + // If we have any queued messages with attached ports, manually destroy them. + while (!message_queue_.empty()) { + const std::vector<WebMessagePortChannelImpl*>& channel_array = + message_queue_.front().ports; + for (size_t i = 0; i < channel_array.size(); i++) { + channel_array[i]->destroy(); + } + message_queue_.pop(); + } + + if (message_port_id_ != MSG_ROUTING_NONE) + Send(new WorkerProcessHostMsg_DestroyMessagePort(message_port_id_)); + + if (route_id_ != MSG_ROUTING_NONE) + ChildThread::current()->RemoveRoute(route_id_); +} + +void WebMessagePortChannelImpl::setClient(WebMessagePortChannelClient* client) { + // Must lock here since client_ is called on the main thread. + AutoLock auto_lock(lock_); + client_ = client; +} + +void WebMessagePortChannelImpl::destroy() { + setClient(NULL); + + // Release the object on the main thread, since the destructor might want to + // send an IPC, and that has to happen on the main thread. + ChildThread::current()->message_loop()->ReleaseSoon(FROM_HERE, this); +} + +void WebMessagePortChannelImpl::entangle(WebMessagePortChannel* channel) { + // The message port ids might not be set up yet, if this channel wasn't + // created on the main thread. So need to wait until we're on the main thread + // before getting the other message port id. + scoped_refptr<WebMessagePortChannelImpl> webchannel = + static_cast<WebMessagePortChannelImpl*>(channel); + Entangle(webchannel); +} + +void WebMessagePortChannelImpl::postMessage( + const WebString& message, + WebMessagePortChannelArray* channels) { + if (MessageLoop::current() != ChildThread::current()->message_loop()) { + ChildThread::current()->message_loop()->PostTask(FROM_HERE, + NewRunnableMethod(this, &WebMessagePortChannelImpl::postMessage, + message, channels)); + return; + } + + std::vector<int> message_port_ids(channels ? channels->size() : 0); + if (channels) { + // Extract the port IDs from the source array, then free it. + for (size_t i = 0; i < channels->size(); ++i) { + WebMessagePortChannelImpl* webchannel = + static_cast<WebMessagePortChannelImpl*>((*channels)[i]); + message_port_ids[i] = webchannel->message_port_id(); + webchannel->QueueMessages(); + DCHECK(message_port_ids[i] != MSG_ROUTING_NONE); + } + delete channels; + } + + IPC::Message* msg = new WorkerProcessHostMsg_PostMessage( + message_port_id_, message, message_port_ids); + Send(msg); +} + +bool WebMessagePortChannelImpl::tryGetMessage( + WebString* message, + WebMessagePortChannelArray& channels) { + AutoLock auto_lock(lock_); + if (message_queue_.empty()) + return false; + + *message = message_queue_.front().message; + const std::vector<WebMessagePortChannelImpl*>& channel_array = + message_queue_.front().ports; + WebMessagePortChannelArray result_ports(channel_array.size()); + for (size_t i = 0; i < channel_array.size(); i++) { + result_ports[i] = channel_array[i]; + } + + channels.swap(result_ports); + message_queue_.pop(); + return true; +} + +void WebMessagePortChannelImpl::Init() { + if (MessageLoop::current() != ChildThread::current()->message_loop()) { + ChildThread::current()->message_loop()->PostTask(FROM_HERE, + NewRunnableMethod(this, &WebMessagePortChannelImpl::Init)); + return; + } + + if (route_id_ == MSG_ROUTING_NONE) { + DCHECK(message_port_id_ == MSG_ROUTING_NONE); + Send(new WorkerProcessHostMsg_CreateMessagePort( + &route_id_, &message_port_id_)); + } + + ChildThread::current()->AddRoute(route_id_, this); +} + +void WebMessagePortChannelImpl::Entangle( + scoped_refptr<WebMessagePortChannelImpl> channel) { + if (MessageLoop::current() != ChildThread::current()->message_loop()) { + ChildThread::current()->message_loop()->PostTask(FROM_HERE, + NewRunnableMethod(this, &WebMessagePortChannelImpl::Entangle, channel)); + return; + } + + Send(new WorkerProcessHostMsg_Entangle( + message_port_id_, channel->message_port_id())); +} + +void WebMessagePortChannelImpl::QueueMessages() { + if (MessageLoop::current() != ChildThread::current()->message_loop()) { + ChildThread::current()->message_loop()->PostTask(FROM_HERE, + NewRunnableMethod(this, &WebMessagePortChannelImpl::QueueMessages)); + return; + } + // This message port is being sent elsewhere (perhaps to another process). + // The new endpoint needs to receive the queued messages, including ones that + // could still be in-flight. So we tell the browser to queue messages, and it + // sends us an ack, whose receipt we know means that no more messages are + // in-flight. We then send the queued messages to the browser, which prepends + // them to the ones it queued and it sends them to the new endpoint. + Send(new WorkerProcessHostMsg_QueueMessages(message_port_id_)); + + // The process could potentially go away while we're still waiting for + // in-flight messages. Ensure it stays alive. + ChildProcess::current()->AddRefProcess(); +} + +void WebMessagePortChannelImpl::Send(IPC::Message* message) { + if (MessageLoop::current() != ChildThread::current()->message_loop()) { + DCHECK(!message->is_sync()); + ChildThread::current()->message_loop()->PostTask(FROM_HERE, + NewRunnableMethod(this, &WebMessagePortChannelImpl::Send, message)); + return; + } + + ChildThread::current()->Send(message); +} + +void WebMessagePortChannelImpl::OnMessageReceived(const IPC::Message& message) { + IPC_BEGIN_MESSAGE_MAP(WebMessagePortChannelImpl, message) + IPC_MESSAGE_HANDLER(WorkerProcessMsg_Message, OnMessage) + IPC_MESSAGE_HANDLER(WorkerProcessMsg_MessagesQueued, OnMessagedQueued) + IPC_END_MESSAGE_MAP() +} + +void WebMessagePortChannelImpl::OnMessage( + const string16& message, + const std::vector<int>& sent_message_port_ids, + const std::vector<int>& new_routing_ids) { + AutoLock auto_lock(lock_); + Message msg; + msg.message = message; + if (!sent_message_port_ids.empty()) { + msg.ports.resize(sent_message_port_ids.size()); + for (size_t i = 0; i < sent_message_port_ids.size(); ++i) { + msg.ports[i] = new WebMessagePortChannelImpl( + new_routing_ids[i], sent_message_port_ids[i]); + } + } + + bool was_empty = message_queue_.empty(); + message_queue_.push(msg); + if (client_ && was_empty) + client_->messageAvailable(); +} + +void WebMessagePortChannelImpl::OnMessagedQueued() { + std::vector<QueuedMessage> queued_messages; + + { + AutoLock auto_lock(lock_); + queued_messages.reserve(message_queue_.size()); + while (!message_queue_.empty()) { + string16 message = message_queue_.front().message; + const std::vector<WebMessagePortChannelImpl*>& channel_array = + message_queue_.front().ports; + std::vector<int> port_ids(channel_array.size()); + for (size_t i = 0; i < channel_array.size(); ++i) { + port_ids[i] = channel_array[i]->message_port_id(); + } + queued_messages.push_back(std::make_pair(message, port_ids)); + message_queue_.pop(); + } + } + + Send(new WorkerProcessHostMsg_SendQueuedMessages( + message_port_id_, queued_messages)); + + message_port_id_ = MSG_ROUTING_NONE; + + Release(); + ChildProcess::current()->ReleaseProcess(); +} |