blob: 87469f9166f32f2d2f8d10c192b95fba9bf366f2 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
|
// 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/browser/extensions/extension_message_service.h"
#include "base/singleton.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/extensions/extension.h"
#include "chrome/browser/extensions/extension_view.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/browser/renderer_host/resource_message_filter.h"
#include "chrome/common/render_messages.h"
// Since we have 2 ports for every channel, we just index channels by half the
// port ID.
#define GET_CHANNEL_ID(port_id) (port_id / 2)
// Port1 is always even, port2 is always odd.
#define IS_PORT1_ID(port_id) ((port_id & 1) == 0)
// Change even to odd and vice versa, to get the other side of a given channel.
#define GET_OPPOSITE_PORT_ID(source_port_id) (source_port_id ^ 1)
ExtensionMessageService* ExtensionMessageService::GetInstance() {
return Singleton<ExtensionMessageService>::get();
}
ExtensionMessageService::ExtensionMessageService()
: next_port_id_(0) {
}
void ExtensionMessageService::RegisterExtension(
const std::string& extension_id, int render_process_id) {
AutoLock lock(renderers_lock_);
// TODO(mpcomplete): We need to ensure an extension always ends up in a single
// process. I think this means having an ExtensionProcessManager which holds
// a BrowsingContext for each extension.
//DCHECK(process_ids_.find(extension_id) == process_ids_.end());
process_ids_[extension_id] = render_process_id;
}
int ExtensionMessageService::OpenChannelToExtension(
const std::string& extension_id, ResourceMessageFilter* source) {
DCHECK(MessageLoop::current() ==
ChromeThread::GetMessageLoop(ChromeThread::IO));
// Lookup the targeted extension process.
ResourceMessageFilter* dest = NULL;
{
AutoLock lock(renderers_lock_);
ProcessIDMap::iterator process_id = process_ids_.find(extension_id);
if (process_id == process_ids_.end())
return -1;
RendererMap::iterator renderer = renderers_.find(process_id->second);
if (renderer == renderers_.end())
return -1;
dest = renderer->second;
}
// Create a channel ID for both sides of the channel.
int port1_id = next_port_id_++;
int port2_id = next_port_id_++;
DCHECK(IS_PORT1_ID(port1_id));
DCHECK(GET_OPPOSITE_PORT_ID(port1_id) == port2_id);
DCHECK(GET_OPPOSITE_PORT_ID(port2_id) == port1_id);
DCHECK(GET_CHANNEL_ID(port1_id) == GET_CHANNEL_ID(port2_id));
MessageChannel channel;
channel.port1 = source;
channel.port2 = dest;
channels_[GET_CHANNEL_ID(port1_id)] = channel;
// Send each process the id for the opposite port.
dest->Send(new ViewMsg_ExtensionHandleConnect(port1_id));
return port2_id;
}
void ExtensionMessageService::PostMessageFromRenderer(
int port_id, const std::string& message, ResourceMessageFilter* source) {
DCHECK(MessageLoop::current() ==
ChromeThread::GetMessageLoop(ChromeThread::IO));
// Look up the channel by port1's ID.
MessageChannelMap::iterator iter =
channels_.find(GET_CHANNEL_ID(port_id));
if (iter == channels_.end())
return;
MessageChannel& channel = iter->second;
// Figure out which port the ID corresponds to.
ResourceMessageFilter* dest = NULL;
if (IS_PORT1_ID(port_id)) {
dest = channel.port1;
DCHECK(source == channel.port2);
} else {
dest = channel.port2;
DCHECK(source == channel.port1);
}
int source_port_id = GET_OPPOSITE_PORT_ID(port_id);
dest->Send(new ViewMsg_ExtensionHandleMessage(message, source_port_id));
}
void ExtensionMessageService::RendererReady(ResourceMessageFilter* renderer) {
AutoLock lock(renderers_lock_);
DCHECK(renderers_.find(renderer->GetProcessId()) == renderers_.end());
renderers_[renderer->GetProcessId()] = renderer;
}
void ExtensionMessageService::RendererShutdown(
ResourceMessageFilter* renderer) {
{
AutoLock lock(renderers_lock_);
DCHECK(renderers_.find(renderer->GetProcessId()) != renderers_.end());
renderers_.erase(renderer->GetProcessId());
}
// Close any channels that share this filter.
// TODO(mpcomplete): should we notify the other side of the port?
for (MessageChannelMap::iterator it = channels_.begin();
it != channels_.end(); ) {
MessageChannelMap::iterator current = it++;
if (current->second.port1 == renderer || current->second.port2 == renderer)
channels_.erase(current);
}
}
|