blob: 6ee76456c74a818db54b685856055e5a23dd354c [file] [log] [blame]
// Copyright 2017 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 "extensions/renderer/ipc_message_sender.h"
#include <map>
#include "base/guid.h"
#include "content/public/child/worker_thread.h"
#include "content/public/renderer/render_frame.h"
#include "content/public/renderer/render_thread.h"
#include "extensions/common/extension_messages.h"
#include "extensions/common/features/feature.h"
#include "extensions/renderer/script_context.h"
#include "extensions/renderer/worker_thread_dispatcher.h"
namespace extensions {
namespace {
const int kMainThreadId = 0;
class MainThreadIPCMessageSender : public IPCMessageSender {
public:
MainThreadIPCMessageSender() : render_thread_(content::RenderThread::Get()) {}
~MainThreadIPCMessageSender() override {}
void SendRequestIPC(ScriptContext* context,
std::unique_ptr<ExtensionHostMsg_Request_Params> params,
binding::RequestThread thread) override {
content::RenderFrame* frame = context->GetRenderFrame();
if (!frame)
return;
switch (thread) {
case binding::RequestThread::UI:
frame->Send(
new ExtensionHostMsg_Request(frame->GetRoutingID(), *params));
break;
case binding::RequestThread::IO:
frame->Send(new ExtensionHostMsg_RequestForIOThread(
frame->GetRoutingID(), *params));
break;
}
}
void SendOnRequestResponseReceivedIPC(int request_id) override {}
void SendAddUnfilteredEventListenerIPC(
ScriptContext* context,
const std::string& event_name) override {
DCHECK_NE(Feature::SERVICE_WORKER_CONTEXT, context->context_type());
DCHECK_EQ(kMainThreadId, content::WorkerThread::GetCurrentId());
render_thread_->Send(new ExtensionHostMsg_AddListener(
context->GetExtensionID(), context->url(), event_name, kMainThreadId));
}
void SendRemoveUnfilteredEventListenerIPC(
ScriptContext* context,
const std::string& event_name) override {
DCHECK_NE(Feature::SERVICE_WORKER_CONTEXT, context->context_type());
DCHECK_EQ(kMainThreadId, content::WorkerThread::GetCurrentId());
render_thread_->Send(new ExtensionHostMsg_RemoveListener(
context->GetExtensionID(), context->url(), event_name, kMainThreadId));
}
void SendAddUnfilteredLazyEventListenerIPC(
ScriptContext* context,
const std::string& event_name) override {
DCHECK_NE(Feature::SERVICE_WORKER_CONTEXT, context->context_type());
DCHECK_EQ(kMainThreadId, content::WorkerThread::GetCurrentId());
render_thread_->Send(new ExtensionHostMsg_AddLazyListener(
context->GetExtensionID(), event_name));
}
void SendRemoveUnfilteredLazyEventListenerIPC(
ScriptContext* context,
const std::string& event_name) override {
DCHECK_NE(Feature::SERVICE_WORKER_CONTEXT, context->context_type());
DCHECK_EQ(kMainThreadId, content::WorkerThread::GetCurrentId());
render_thread_->Send(new ExtensionHostMsg_RemoveLazyListener(
context->GetExtensionID(), event_name));
}
void SendAddFilteredEventListenerIPC(ScriptContext* context,
const std::string& event_name,
const base::DictionaryValue& filter,
bool is_lazy) override {
DCHECK_NE(Feature::SERVICE_WORKER_CONTEXT, context->context_type());
DCHECK_EQ(kMainThreadId, content::WorkerThread::GetCurrentId());
render_thread_->Send(new ExtensionHostMsg_AddFilteredListener(
context->GetExtensionID(), event_name, filter, is_lazy));
}
void SendRemoveFilteredEventListenerIPC(ScriptContext* context,
const std::string& event_name,
const base::DictionaryValue& filter,
bool remove_lazy_listener) override {
DCHECK_NE(Feature::SERVICE_WORKER_CONTEXT, context->context_type());
DCHECK_EQ(kMainThreadId, content::WorkerThread::GetCurrentId());
render_thread_->Send(new ExtensionHostMsg_RemoveFilteredListener(
context->GetExtensionID(), event_name, filter, remove_lazy_listener));
}
private:
content::RenderThread* const render_thread_;
DISALLOW_COPY_AND_ASSIGN(MainThreadIPCMessageSender);
};
class WorkerThreadIPCMessageSender : public IPCMessageSender {
public:
WorkerThreadIPCMessageSender(WorkerThreadDispatcher* dispatcher,
int64_t service_worker_version_id)
: dispatcher_(dispatcher),
service_worker_version_id_(service_worker_version_id) {}
~WorkerThreadIPCMessageSender() override {}
void SendRequestIPC(ScriptContext* context,
std::unique_ptr<ExtensionHostMsg_Request_Params> params,
binding::RequestThread thread) override {
DCHECK(!context->GetRenderFrame());
DCHECK_EQ(Feature::SERVICE_WORKER_CONTEXT, context->context_type());
DCHECK_EQ(binding::RequestThread::UI, thread);
DCHECK_NE(kMainThreadId, content::WorkerThread::GetCurrentId());
int worker_thread_id = content::WorkerThread::GetCurrentId();
params->worker_thread_id = worker_thread_id;
params->service_worker_version_id = service_worker_version_id_;
std::string guid = base::GenerateGUID();
request_id_to_guid_[params->request_id] = guid;
// Keeps the worker alive during extension function call. Balanced in
// HandleWorkerResponse().
dispatcher_->Send(new ExtensionHostMsg_IncrementServiceWorkerActivity(
service_worker_version_id_, guid));
dispatcher_->Send(new ExtensionHostMsg_RequestWorker(*params));
}
void SendOnRequestResponseReceivedIPC(int request_id) override {
std::map<int, std::string>::iterator iter =
request_id_to_guid_.find(request_id);
DCHECK(iter != request_id_to_guid_.end());
dispatcher_->Send(new ExtensionHostMsg_DecrementServiceWorkerActivity(
service_worker_version_id_, iter->second));
request_id_to_guid_.erase(iter);
}
void SendAddUnfilteredEventListenerIPC(
ScriptContext* context,
const std::string& event_name) override {
DCHECK_EQ(Feature::SERVICE_WORKER_CONTEXT, context->context_type());
DCHECK_NE(kMainThreadId, content::WorkerThread::GetCurrentId());
dispatcher_->Send(new ExtensionHostMsg_AddListener(
context->GetExtensionID(), context->service_worker_scope(), event_name,
content::WorkerThread::GetCurrentId()));
}
void SendRemoveUnfilteredEventListenerIPC(
ScriptContext* context,
const std::string& event_name) override {
DCHECK_EQ(Feature::SERVICE_WORKER_CONTEXT, context->context_type());
DCHECK_NE(kMainThreadId, content::WorkerThread::GetCurrentId());
dispatcher_->Send(new ExtensionHostMsg_RemoveListener(
context->GetExtensionID(), context->service_worker_scope(), event_name,
content::WorkerThread::GetCurrentId()));
}
void SendAddUnfilteredLazyEventListenerIPC(
ScriptContext* context,
const std::string& event_name) override {
DCHECK_EQ(Feature::SERVICE_WORKER_CONTEXT, context->context_type());
DCHECK_NE(kMainThreadId, content::WorkerThread::GetCurrentId());
dispatcher_->Send(new ExtensionHostMsg_AddLazyServiceWorkerListener(
context->GetExtensionID(), event_name,
context->service_worker_scope()));
}
void SendRemoveUnfilteredLazyEventListenerIPC(
ScriptContext* context,
const std::string& event_name) override {
DCHECK_EQ(Feature::SERVICE_WORKER_CONTEXT, context->context_type());
DCHECK_NE(kMainThreadId, content::WorkerThread::GetCurrentId());
dispatcher_->Send(new ExtensionHostMsg_RemoveLazyServiceWorkerListener(
context->GetExtensionID(), event_name,
context->service_worker_scope()));
}
void SendAddFilteredEventListenerIPC(ScriptContext* context,
const std::string& event_name,
const base::DictionaryValue& filter,
bool is_lazy) override {
DCHECK_EQ(Feature::SERVICE_WORKER_CONTEXT, context->context_type());
DCHECK_NE(kMainThreadId, content::WorkerThread::GetCurrentId());
NOTIMPLEMENTED();
}
void SendRemoveFilteredEventListenerIPC(ScriptContext* context,
const std::string& event_name,
const base::DictionaryValue& filter,
bool remove_lazy_listener) override {
DCHECK_EQ(Feature::SERVICE_WORKER_CONTEXT, context->context_type());
DCHECK_NE(kMainThreadId, content::WorkerThread::GetCurrentId());
NOTIMPLEMENTED();
}
private:
WorkerThreadDispatcher* const dispatcher_;
const int64_t service_worker_version_id_;
// request id -> GUID map for each outstanding requests.
std::map<int, std::string> request_id_to_guid_;
DISALLOW_COPY_AND_ASSIGN(WorkerThreadIPCMessageSender);
};
} // namespace
IPCMessageSender::IPCMessageSender() {}
IPCMessageSender::~IPCMessageSender() = default;
// static
std::unique_ptr<IPCMessageSender>
IPCMessageSender::CreateMainThreadIPCMessageSender() {
return base::MakeUnique<MainThreadIPCMessageSender>();
}
// static
std::unique_ptr<IPCMessageSender>
IPCMessageSender::CreateWorkerThreadIPCMessageSender(
WorkerThreadDispatcher* dispatcher,
int64_t service_worker_version_id) {
return base::MakeUnique<WorkerThreadIPCMessageSender>(
dispatcher, service_worker_version_id);
}
} // namespace extensions