blob: c8847a7f5b4413156a1d1f859ba395051f97a3c9 [file] [log] [blame]
// Copyright 2015 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 "content/browser/navigator_connect/service_port_service_impl.h"
#include "content/browser/message_port_message_filter.h"
#include "content/browser/message_port_service.h"
#include "content/browser/navigator_connect/navigator_connect_context_impl.h"
#include "content/common/service_port_type_converters.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/common/message_port_types.h"
#include "mojo/common/common_type_converters.h"
#include "url/gurl.h"
namespace content {
// static
void ServicePortServiceImpl::Create(
const scoped_refptr<NavigatorConnectContextImpl>& navigator_connect_context,
const scoped_refptr<MessagePortMessageFilter>& message_port_message_filter,
mojo::InterfaceRequest<ServicePortService> request) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::Bind(&ServicePortServiceImpl::CreateOnIOThread,
navigator_connect_context, message_port_message_filter,
base::Passed(&request)));
}
ServicePortServiceImpl::~ServicePortServiceImpl() {
// Should always be destroyed on the IO thread, but can't check that with
// DCHECK_CURRENTLY_ON because this class could be destroyed during thread
// shutdown, at which point that check doesn't work.
navigator_connect_context_->ServicePortServiceDestroyed(this);
}
void ServicePortServiceImpl::PostMessageToClient(
int port_id,
const MessagePortMessage& message,
const std::vector<TransferredMessagePort>& sent_message_ports) {
DCHECK(client_.get());
// Hold messages on transferred message ports. Normally this wouldn't be
// needed, but since MessagePort uses regular IPC while this class uses mojo,
// without holding messages mojo IPC might overtake regular IPC resulting in a
// non-functional port. When WebMessagePortChannelImpl instances are
// constructed in the renderer, they will send
// MessagePortHostMsg_ReleaseMessages to release messages.
for (const auto& port : sent_message_ports)
MessagePortService::GetInstance()->HoldMessages(port.id);
std::vector<int> new_routing_ids;
message_port_message_filter_->UpdateMessagePortsWithNewRoutes(
sent_message_ports, &new_routing_ids);
client_->PostMessage(
port_id, mojo::String::From(message.message_as_string),
mojo::Array<MojoTransferredMessagePortPtr>::From(sent_message_ports),
mojo::Array<int32_t>::From(new_routing_ids));
}
// static
void ServicePortServiceImpl::CreateOnIOThread(
const scoped_refptr<NavigatorConnectContextImpl>& navigator_connect_context,
const scoped_refptr<MessagePortMessageFilter>& message_port_message_filter,
mojo::InterfaceRequest<ServicePortService> request) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
new ServicePortServiceImpl(navigator_connect_context,
message_port_message_filter, request.Pass());
}
ServicePortServiceImpl::ServicePortServiceImpl(
const scoped_refptr<NavigatorConnectContextImpl>& navigator_connect_context,
const scoped_refptr<MessagePortMessageFilter>& message_port_message_filter,
mojo::InterfaceRequest<ServicePortService> request)
: binding_(this, request.Pass()),
navigator_connect_context_(navigator_connect_context),
message_port_message_filter_(message_port_message_filter),
weak_ptr_factory_(this) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
}
void ServicePortServiceImpl::SetClient(ServicePortServiceClientPtr client) {
DCHECK(!client_.get());
// TODO(mek): Set ErrorHandler to listen for errors.
client_ = client.Pass();
}
void ServicePortServiceImpl::Connect(const mojo::String& target_url,
const mojo::String& origin,
const ConnectCallback& callback) {
navigator_connect_context_->Connect(
GURL(target_url), GURL(origin), this,
base::Bind(&ServicePortServiceImpl::OnConnectResult,
weak_ptr_factory_.GetWeakPtr(), callback));
}
void ServicePortServiceImpl::PostMessage(
int32_t port_id,
const mojo::String& message,
mojo::Array<MojoTransferredMessagePortPtr> ports) {
// TODO(mek): Similar to http://crbug.com/490222 this code should make sure
// port_id belongs to the process this IPC was received from.
std::vector<TransferredMessagePort> transferred_ports =
ports.To<std::vector<TransferredMessagePort>>();
MessagePortService* mps = MessagePortService::GetInstance();
// First, call QueueMessages for all transferred ports, since the ports
// haven't sent their own IPC for that.
for (const TransferredMessagePort& port : transferred_ports) {
mps->QueueMessages(port.id);
}
navigator_connect_context_->PostMessage(
port_id, MessagePortMessage(message.To<base::string16>()),
transferred_ports);
}
void ServicePortServiceImpl::ClosePort(int32_t port_id) {
MessagePortService::GetInstance()->Destroy(port_id);
}
void ServicePortServiceImpl::OnConnectResult(const ConnectCallback& callback,
int message_port_id,
bool success) {
callback.Run(success ? SERVICE_PORT_CONNECT_RESULT_ACCEPT
: SERVICE_PORT_CONNECT_RESULT_REJECT,
message_port_id);
}
} // namespace content