123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493 |
- // 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 "base/memory/weak_ptr.h"
- #include "base/metrics/histogram_macros.h"
- #include "content/public/renderer/render_frame.h"
- #include "content/public/renderer/render_thread.h"
- #include "content/public/renderer/worker_thread.h"
- #include "extensions/common/api/messaging/messaging_endpoint.h"
- #include "extensions/common/constants.h"
- #include "extensions/common/extension_messages.h"
- #include "extensions/common/features/feature.h"
- #include "extensions/common/mojom/event_router.mojom.h"
- #include "extensions/common/mojom/frame.mojom.h"
- #include "extensions/common/trace_util.h"
- #include "extensions/renderer/dispatcher.h"
- #include "extensions/renderer/extension_frame_helper.h"
- #include "extensions/renderer/extensions_renderer_client.h"
- #include "extensions/renderer/message_target.h"
- #include "extensions/renderer/native_extension_bindings_system.h"
- #include "extensions/renderer/script_context.h"
- #include "extensions/renderer/trace_util.h"
- #include "extensions/renderer/worker_thread_dispatcher.h"
- #include "ipc/ipc_sync_channel.h"
- #include "mojo/public/cpp/bindings/associated_remote.h"
- #include "third_party/abseil-cpp/absl/types/optional.h"
- #include "third_party/blink/public/mojom/service_worker/service_worker_registration.mojom.h"
- namespace extensions {
- namespace {
- class MainThreadIPCMessageSender : public IPCMessageSender {
- public:
- MainThreadIPCMessageSender() : render_thread_(content::RenderThread::Get()) {}
- MainThreadIPCMessageSender(const MainThreadIPCMessageSender&) = delete;
- MainThreadIPCMessageSender& operator=(const MainThreadIPCMessageSender&) =
- delete;
- ~MainThreadIPCMessageSender() override {}
- void SendRequestIPC(ScriptContext* context,
- mojom::RequestParamsPtr params) override {
- content::RenderFrame* frame = context->GetRenderFrame();
- if (!frame)
- return;
- int request_id = params->request_id;
- ExtensionFrameHelper::Get(frame)->GetLocalFrameHost()->Request(
- std::move(params),
- base::BindOnce(&MainThreadIPCMessageSender::OnResponse,
- weak_ptr_factory_.GetWeakPtr(), request_id));
- }
- void SendOnRequestResponseReceivedIPC(int request_id) override {}
- mojom::EventListenerParamPtr GetEventListenerParam(ScriptContext* context) {
- return !context->GetExtensionID().empty()
- ? mojom::EventListenerParam::NewExtensionId(
- context->GetExtensionID())
- : mojom::EventListenerParam::NewListenerUrl(context->url());
- }
- void SendAddUnfilteredEventListenerIPC(
- ScriptContext* context,
- const std::string& event_name) override {
- DCHECK(!context->IsForServiceWorker());
- DCHECK_EQ(kMainThreadId, content::WorkerThread::GetCurrentId());
- GetEventRouter()->AddListenerForMainThread(GetEventListenerParam(context),
- event_name);
- }
- void SendRemoveUnfilteredEventListenerIPC(
- ScriptContext* context,
- const std::string& event_name) override {
- DCHECK(!context->IsForServiceWorker());
- DCHECK_EQ(kMainThreadId, content::WorkerThread::GetCurrentId());
- GetEventRouter()->RemoveListenerForMainThread(
- GetEventListenerParam(context), event_name);
- }
- void SendAddUnfilteredLazyEventListenerIPC(
- ScriptContext* context,
- const std::string& event_name) override {
- DCHECK(!context->IsForServiceWorker());
- DCHECK_EQ(kMainThreadId, content::WorkerThread::GetCurrentId());
- GetEventRouter()->AddLazyListenerForMainThread(context->GetExtensionID(),
- event_name);
- }
- void SendRemoveUnfilteredLazyEventListenerIPC(
- ScriptContext* context,
- const std::string& event_name) override {
- DCHECK(!context->IsForServiceWorker());
- DCHECK_EQ(kMainThreadId, content::WorkerThread::GetCurrentId());
- GetEventRouter()->RemoveLazyListenerForMainThread(context->GetExtensionID(),
- event_name);
- }
- void SendAddFilteredEventListenerIPC(ScriptContext* context,
- const std::string& event_name,
- const base::DictionaryValue& filter,
- bool is_lazy) override {
- DCHECK(!context->IsForServiceWorker());
- DCHECK_EQ(kMainThreadId, content::WorkerThread::GetCurrentId());
- GetEventRouter()->AddFilteredListenerForMainThread(
- GetEventListenerParam(context), event_name, filter.Clone(), is_lazy);
- }
- void SendRemoveFilteredEventListenerIPC(ScriptContext* context,
- const std::string& event_name,
- const base::DictionaryValue& filter,
- bool remove_lazy_listener) override {
- DCHECK(!context->IsForServiceWorker());
- DCHECK_EQ(kMainThreadId, content::WorkerThread::GetCurrentId());
- GetEventRouter()->RemoveFilteredListenerForMainThread(
- GetEventListenerParam(context), event_name, filter.Clone(),
- remove_lazy_listener);
- }
- void SendOpenMessageChannel(ScriptContext* script_context,
- const PortId& port_id,
- const MessageTarget& target,
- const std::string& channel_name) override {
- content::RenderFrame* render_frame = script_context->GetRenderFrame();
- DCHECK(render_frame);
- PortContext frame_context =
- PortContext::ForFrame(render_frame->GetRoutingID());
- const Extension* extension = script_context->extension();
- switch (target.type) {
- case MessageTarget::EXTENSION: {
- ExtensionMsg_ExternalConnectionInfo info;
- if (extension && !extension->is_hosted_app()) {
- info.source_endpoint =
- script_context->context_type() == Feature::CONTENT_SCRIPT_CONTEXT
- ? MessagingEndpoint::ForContentScript(extension->id())
- : MessagingEndpoint::ForExtension(extension->id());
- } else {
- info.source_endpoint = MessagingEndpoint::ForWebPage();
- }
- info.target_id = *target.extension_id;
- info.source_url = script_context->url();
- TRACE_RENDERER_EXTENSION_EVENT(
- "MainThreadIPCMessageSender::SendOpenMessageChannel/extension",
- *target.extension_id);
- render_thread_->Send(new ExtensionHostMsg_OpenChannelToExtension(
- frame_context, info, channel_name, port_id));
- break;
- }
- case MessageTarget::TAB: {
- DCHECK(extension);
- DCHECK_NE(script_context->context_type(),
- Feature::CONTENT_SCRIPT_CONTEXT);
- ExtensionMsg_TabTargetConnectionInfo info;
- info.tab_id = *target.tab_id;
- info.frame_id = *target.frame_id;
- if (target.document_id)
- info.document_id = *target.document_id;
- render_frame->Send(new ExtensionHostMsg_OpenChannelToTab(
- frame_context, info, extension->id(), channel_name, port_id));
- break;
- }
- case MessageTarget::NATIVE_APP:
- render_frame->Send(new ExtensionHostMsg_OpenChannelToNativeApp(
- frame_context, *target.native_application_name, port_id));
- break;
- }
- }
- void SendOpenMessagePort(int routing_id, const PortId& port_id) override {
- render_thread_->Send(new ExtensionHostMsg_OpenMessagePort(
- PortContext::ForFrame(routing_id), port_id));
- }
- void SendCloseMessagePort(int routing_id,
- const PortId& port_id,
- bool close_channel) override {
- render_thread_->Send(new ExtensionHostMsg_CloseMessagePort(
- PortContext::ForFrame(routing_id), port_id, close_channel));
- }
- void SendPostMessageToPort(const PortId& port_id,
- const Message& message) override {
- render_thread_->Send(new ExtensionHostMsg_PostMessage(port_id, message));
- }
- void SendMessageResponsePending(int routing_id,
- const PortId& port_id) override {
- render_thread_->Send(new ExtensionHostMsg_ResponsePending(
- PortContext::ForFrame(routing_id), port_id));
- }
- void SendActivityLogIPC(
- const ExtensionId& extension_id,
- ActivityLogCallType call_type,
- const ExtensionHostMsg_APIActionOrEvent_Params& params) override {
- switch (call_type) {
- case ActivityLogCallType::APICALL:
- render_thread_->Send(new ExtensionHostMsg_AddAPIActionToActivityLog(
- extension_id, params));
- break;
- case ActivityLogCallType::EVENT:
- render_thread_->Send(
- new ExtensionHostMsg_AddEventToActivityLog(extension_id, params));
- break;
- }
- }
- private:
- void OnResponse(int request_id,
- bool success,
- base::Value::List response,
- const std::string& error) {
- ExtensionsRendererClient::Get()
- ->GetDispatcher()
- ->bindings_system()
- ->HandleResponse(request_id, success, std::move(response), error);
- }
- mojom::EventRouter* GetEventRouter() {
- if (!event_router_remote_.is_bound()) {
- render_thread_->GetChannel()->GetRemoteAssociatedInterface(
- &event_router_remote_);
- }
- return event_router_remote_.get();
- }
- content::RenderThread* const render_thread_;
- mojo::AssociatedRemote<mojom::EventRouter> event_router_remote_;
- base::WeakPtrFactory<MainThreadIPCMessageSender> weak_ptr_factory_{this};
- };
- 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(const WorkerThreadIPCMessageSender&) = delete;
- WorkerThreadIPCMessageSender& operator=(const WorkerThreadIPCMessageSender&) =
- delete;
- ~WorkerThreadIPCMessageSender() override {}
- void SendRequestIPC(ScriptContext* context,
- mojom::RequestParamsPtr params) override {
- DCHECK(!context->GetRenderFrame());
- DCHECK(context->IsForServiceWorker());
- 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 {
- auto 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(context->IsForServiceWorker());
- DCHECK_NE(kMainThreadId, content::WorkerThread::GetCurrentId());
- DCHECK_NE(blink::mojom::kInvalidServiceWorkerVersionId,
- context->service_worker_version_id());
- dispatcher_->SendAddEventListener(
- context->GetExtensionID(), context->service_worker_scope(), event_name,
- context->service_worker_version_id(),
- content::WorkerThread::GetCurrentId());
- }
- void SendRemoveUnfilteredEventListenerIPC(
- ScriptContext* context,
- const std::string& event_name) override {
- DCHECK(context->IsForServiceWorker());
- DCHECK_NE(kMainThreadId, content::WorkerThread::GetCurrentId());
- DCHECK_NE(blink::mojom::kInvalidServiceWorkerVersionId,
- context->service_worker_version_id());
- dispatcher_->SendRemoveEventListener(
- context->GetExtensionID(), context->service_worker_scope(), event_name,
- context->service_worker_version_id(),
- content::WorkerThread::GetCurrentId());
- }
- void SendAddUnfilteredLazyEventListenerIPC(
- ScriptContext* context,
- const std::string& event_name) override {
- DCHECK(context->IsForServiceWorker());
- DCHECK_NE(kMainThreadId, content::WorkerThread::GetCurrentId());
- dispatcher_->SendAddEventLazyListener(
- context->GetExtensionID(), context->service_worker_scope(), event_name);
- }
- void SendRemoveUnfilteredLazyEventListenerIPC(
- ScriptContext* context,
- const std::string& event_name) override {
- DCHECK(context->IsForServiceWorker());
- DCHECK_NE(kMainThreadId, content::WorkerThread::GetCurrentId());
- dispatcher_->SendRemoveEventLazyListener(
- context->GetExtensionID(), context->service_worker_scope(), event_name);
- }
- void SendAddFilteredEventListenerIPC(ScriptContext* context,
- const std::string& event_name,
- const base::DictionaryValue& filter,
- bool is_lazy) override {
- DCHECK(context->IsForServiceWorker());
- DCHECK_NE(kMainThreadId, content::WorkerThread::GetCurrentId());
- DCHECK_NE(blink::mojom::kInvalidServiceWorkerVersionId,
- context->service_worker_version_id());
- dispatcher_->SendAddEventFilteredListener(
- context->GetExtensionID(), context->service_worker_scope(), event_name,
- context->service_worker_version_id(),
- content::WorkerThread::GetCurrentId(), filter.Clone(), is_lazy);
- }
- void SendRemoveFilteredEventListenerIPC(ScriptContext* context,
- const std::string& event_name,
- const base::DictionaryValue& filter,
- bool remove_lazy_listener) override {
- DCHECK(context->IsForServiceWorker());
- DCHECK_NE(kMainThreadId, content::WorkerThread::GetCurrentId());
- DCHECK_NE(blink::mojom::kInvalidServiceWorkerVersionId,
- context->service_worker_version_id());
- dispatcher_->SendRemoveEventFilteredListener(
- context->GetExtensionID(), context->service_worker_scope(), event_name,
- context->service_worker_version_id(),
- content::WorkerThread::GetCurrentId(), filter.Clone(),
- remove_lazy_listener);
- }
- void SendOpenMessageChannel(ScriptContext* script_context,
- const PortId& port_id,
- const MessageTarget& target,
- const std::string& channel_name) override {
- DCHECK(!script_context->GetRenderFrame());
- DCHECK(script_context->IsForServiceWorker());
- const Extension* extension = script_context->extension();
- switch (target.type) {
- case MessageTarget::EXTENSION: {
- ExtensionMsg_ExternalConnectionInfo info;
- if (extension && !extension->is_hosted_app()) {
- info.source_endpoint =
- MessagingEndpoint::ForExtension(extension->id());
- }
- info.target_id = *target.extension_id;
- info.source_url = script_context->url();
- TRACE_RENDERER_EXTENSION_EVENT(
- "WorkerThreadIPCMessageSender::SendOpenMessageChannel/extension",
- *target.extension_id);
- dispatcher_->Send(new ExtensionHostMsg_OpenChannelToExtension(
- PortContextForCurrentWorker(), info, channel_name, port_id));
- break;
- }
- case MessageTarget::TAB: {
- DCHECK(extension);
- ExtensionMsg_TabTargetConnectionInfo info;
- info.tab_id = *target.tab_id;
- info.frame_id = *target.frame_id;
- dispatcher_->Send(new ExtensionHostMsg_OpenChannelToTab(
- PortContextForCurrentWorker(), info, extension->id(), channel_name,
- port_id));
- break;
- }
- case MessageTarget::NATIVE_APP:
- dispatcher_->Send(new ExtensionHostMsg_OpenChannelToNativeApp(
- PortContextForCurrentWorker(), *target.native_application_name,
- port_id));
- break;
- }
- }
- void SendOpenMessagePort(int routing_id, const PortId& port_id) override {
- DCHECK_EQ(MSG_ROUTING_NONE, routing_id);
- dispatcher_->Send(new ExtensionHostMsg_OpenMessagePort(
- PortContextForCurrentWorker(), port_id));
- }
- void SendCloseMessagePort(int routing_id,
- const PortId& port_id,
- bool close_channel) override {
- DCHECK_EQ(MSG_ROUTING_NONE, routing_id);
- dispatcher_->Send(new ExtensionHostMsg_CloseMessagePort(
- PortContextForCurrentWorker(), port_id, close_channel));
- }
- void SendPostMessageToPort(const PortId& port_id,
- const Message& message) override {
- dispatcher_->Send(new ExtensionHostMsg_PostMessage(port_id, message));
- }
- void SendMessageResponsePending(int routing_id,
- const PortId& port_id) override {
- DCHECK_EQ(MSG_ROUTING_NONE, routing_id);
- dispatcher_->Send(new ExtensionHostMsg_ResponsePending(
- PortContextForCurrentWorker(), port_id));
- }
- void SendActivityLogIPC(
- const ExtensionId& extension_id,
- ActivityLogCallType call_type,
- const ExtensionHostMsg_APIActionOrEvent_Params& params) override {
- switch (call_type) {
- case ActivityLogCallType::APICALL:
- dispatcher_->Send(new ExtensionHostMsg_AddAPIActionToActivityLog(
- extension_id, params));
- break;
- case ActivityLogCallType::EVENT:
- dispatcher_->Send(
- new ExtensionHostMsg_AddEventToActivityLog(extension_id, params));
- break;
- }
- }
- private:
- const ExtensionId& GetExtensionId() {
- if (!extension_id_)
- extension_id_ = dispatcher_->GetScriptContext()->extension()->id();
- return *extension_id_;
- }
- PortContext PortContextForCurrentWorker() {
- return PortContext::ForWorker(content::WorkerThread::GetCurrentId(),
- service_worker_version_id_, GetExtensionId());
- }
- WorkerThreadDispatcher* const dispatcher_;
- const int64_t service_worker_version_id_;
- absl::optional<ExtensionId> extension_id_;
- // request id -> GUID map for each outstanding requests.
- std::map<int, std::string> request_id_to_guid_;
- };
- } // namespace
- IPCMessageSender::IPCMessageSender() {}
- IPCMessageSender::~IPCMessageSender() = default;
- // static
- std::unique_ptr<IPCMessageSender>
- IPCMessageSender::CreateMainThreadIPCMessageSender() {
- return std::make_unique<MainThreadIPCMessageSender>();
- }
- // static
- std::unique_ptr<IPCMessageSender>
- IPCMessageSender::CreateWorkerThreadIPCMessageSender(
- WorkerThreadDispatcher* dispatcher,
- int64_t service_worker_version_id) {
- return std::make_unique<WorkerThreadIPCMessageSender>(
- dispatcher, service_worker_version_id);
- }
- } // namespace extensions
|