Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(82)

Side by Side Diff: extensions/renderer/messaging_bindings.cc

Issue 1178273004: Move Extension messaging port release functionality from JS to C++. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: cleanup Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | extensions/renderer/resources/messaging.js » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "extensions/renderer/messaging_bindings.h" 5 #include "extensions/renderer/messaging_bindings.h"
6 6
7 #include <map> 7 #include <map>
8 #include <string> 8 #include <string>
9 9
10 #include "base/basictypes.h" 10 #include "base/basictypes.h"
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after
112 // Function to run when |object_| bound to this GCCallback is GC'd. 112 // Function to run when |object_| bound to this GCCallback is GC'd.
113 v8::Global<v8::Function> callback_; 113 v8::Global<v8::Function> callback_;
114 114
115 // Function to run if context is invalidated before we have a chance 115 // Function to run if context is invalidated before we have a chance
116 // to execute |callback_|. 116 // to execute |callback_|.
117 base::Closure fallback_; 117 base::Closure fallback_;
118 118
119 DISALLOW_COPY_AND_ASSIGN(GCCallback); 119 DISALLOW_COPY_AND_ASSIGN(GCCallback);
120 }; 120 };
121 121
122 struct ExtensionData { 122 // Maintains the set of ScriptContexts that reference each Port, by ID.
123 struct PortData { 123 class PortTracker {
124 int ref_count; // how many contexts have a handle to this port 124 public:
125 PortData() : ref_count(0) {} 125 PortTracker() {}
126 }; 126
127 std::map<int, PortData> ports; // port ID -> data 127 // Returns true if |context| references |port_id|.
128 bool HasReference(ScriptContext* context, int port_id) const {
129 auto ports = contexts_to_ports_.find(context);
130 if (ports == contexts_to_ports_.end())
131 return false;
132 return ports->second.count(port_id) > 0;
133 }
134
135 // Marks |context| and |port_id| as referencing each other.
136 void AddReference(ScriptContext* context, int port_id) {
137 if (contexts_to_ports_[context].insert(port_id).second)
138 ++port_refcount_[port_id];
139 }
140
141 // Removes the references between |context| and |port_id|.
142 void RemoveReference(ScriptContext* context, int port_id) {
143 auto ports = contexts_to_ports_.find(context);
144 if (ports == contexts_to_ports_.end()) {
145 return;
146 }
147 if (ports->second.erase(port_id) == 0)
148 return;
149 if (ports->second.size() == 0)
150 contexts_to_ports_.erase(context);
151 if (--port_refcount_[port_id] == 0)
152 port_refcount_.erase(port_id);
153 }
154
155 // Returns true if this tracker has any reference to |port_id|.
156 bool HasPort(int port_id) const {
157 return port_refcount_.find(port_id) != port_refcount_.end();
158 }
159
160 // Deletes all references to |port_id|.
161 void DeletePort(int port_id) {
162 port_refcount_.erase(port_id);
163 for (auto it = contexts_to_ports_.begin();
164 it != contexts_to_ports_.end();) {
165 if (it->second.erase(port_id) > 0 && it->second.empty())
166 contexts_to_ports_.erase(it++);
167 else
168 ++it;
169 }
170 }
171
172 // Gets every port ID that has a reference to |context|.
173 std::set<int> GetPorts(ScriptContext* context) const {
174 auto ports = contexts_to_ports_.find(context);
175 return ports == contexts_to_ports_.end() ? std::set<int>() : ports->second;
176 }
177
178 private:
179 // Maps ScriptContexts to the port IDs that have a reference to it.
180 std::map<ScriptContext*, std::set<int>> contexts_to_ports_;
181
182 // Maps port IDs to the number of ScriptContexts that have a reference to it.
183 std::map<int, int> port_refcount_;
184
185 DISALLOW_COPY_AND_ASSIGN(PortTracker);
128 }; 186 };
129 187
130 base::LazyInstance<ExtensionData> g_extension_data = LAZY_INSTANCE_INITIALIZER; 188 base::LazyInstance<PortTracker> g_port_tracker = LAZY_INSTANCE_INITIALIZER;
131
132 bool HasPortData(int port_id) {
133 return g_extension_data.Get().ports.find(port_id) !=
134 g_extension_data.Get().ports.end();
135 }
136
137 ExtensionData::PortData& GetPortData(int port_id) {
138 return g_extension_data.Get().ports[port_id];
139 }
140
141 void ClearPortData(int port_id) {
142 g_extension_data.Get().ports.erase(port_id);
143 }
144 189
145 const char kPortClosedError[] = "Attempting to use a disconnected port object"; 190 const char kPortClosedError[] = "Attempting to use a disconnected port object";
146 const char kReceivingEndDoesntExistError[] = 191 const char kReceivingEndDoesntExistError[] =
147 "Could not establish connection. Receiving end does not exist."; 192 "Could not establish connection. Receiving end does not exist.";
148 193
149 class ExtensionImpl : public ObjectBackedNativeHandler { 194 class ExtensionImpl : public ObjectBackedNativeHandler {
150 public: 195 public:
151 ExtensionImpl(Dispatcher* dispatcher, ScriptContext* context) 196 ExtensionImpl(Dispatcher* dispatcher, ScriptContext* context)
152 : ObjectBackedNativeHandler(context), 197 : ObjectBackedNativeHandler(context),
153 dispatcher_(dispatcher), 198 dispatcher_(dispatcher),
154 weak_ptr_factory_(this) { 199 weak_ptr_factory_(this) {
155 RouteFunction( 200 RouteFunction(
156 "CloseChannel", 201 "CloseChannel",
157 base::Bind(&ExtensionImpl::CloseChannel, base::Unretained(this))); 202 base::Bind(&ExtensionImpl::CloseChannel, base::Unretained(this)));
158 RouteFunction( 203 RouteFunction(
159 "PortAddRef", 204 "PortAddRef",
160 base::Bind(&ExtensionImpl::PortAddRef, base::Unretained(this))); 205 base::Bind(&ExtensionImpl::PortAddRef, base::Unretained(this)));
161 RouteFunction( 206 RouteFunction(
162 "PortRelease", 207 "PortRelease",
163 base::Bind(&ExtensionImpl::PortRelease, base::Unretained(this))); 208 base::Bind(&ExtensionImpl::PortRelease, base::Unretained(this)));
164 RouteFunction( 209 RouteFunction(
165 "PostMessage", 210 "PostMessage",
166 base::Bind(&ExtensionImpl::PostMessage, base::Unretained(this))); 211 base::Bind(&ExtensionImpl::PostMessage, base::Unretained(this)));
167 // TODO(fsamuel, kalman): Move BindToGC out of messaging natives. 212 // TODO(fsamuel, kalman): Move BindToGC out of messaging natives.
168 RouteFunction("BindToGC", 213 RouteFunction("BindToGC",
169 base::Bind(&ExtensionImpl::BindToGC, base::Unretained(this))); 214 base::Bind(&ExtensionImpl::BindToGC, base::Unretained(this)));
215
216 // Observe |context| so that port references to it can be cleared.
217 context->AddInvalidationObserver(base::Bind(
218 &ExtensionImpl::OnContextInvalidated, weak_ptr_factory_.GetWeakPtr()));
170 } 219 }
171 220
172 ~ExtensionImpl() override {} 221 ~ExtensionImpl() override {}
173 222
174 private: 223 private:
224 void OnContextInvalidated() {
225 for (int port_id : g_port_tracker.Get().GetPorts(context()))
226 ReleasePort(port_id);
227 }
228
175 void ClearPortDataAndNotifyDispatcher(int port_id) { 229 void ClearPortDataAndNotifyDispatcher(int port_id) {
176 ClearPortData(port_id); 230 g_port_tracker.Get().DeletePort(port_id);
177 dispatcher_->ClearPortData(port_id); 231 dispatcher_->ClearPortData(port_id);
178 } 232 }
179 233
180 // Sends a message along the given channel. 234 // Sends a message along the given channel.
181 void PostMessage(const v8::FunctionCallbackInfo<v8::Value>& args) { 235 void PostMessage(const v8::FunctionCallbackInfo<v8::Value>& args) {
182 content::RenderFrame* renderframe = context()->GetRenderFrame(); 236 content::RenderFrame* renderframe = context()->GetRenderFrame();
183 if (!renderframe) 237 if (!renderframe)
184 return; 238 return;
185 239
186 // Arguments are (int32 port_id, string message). 240 // Arguments are (int32 port_id, string message).
187 CHECK(args.Length() == 2 && args[0]->IsInt32() && args[1]->IsString()); 241 CHECK(args.Length() == 2 && args[0]->IsInt32() && args[1]->IsString());
188 242
189 int port_id = args[0]->Int32Value(); 243 int port_id = args[0]->Int32Value();
190 if (!HasPortData(port_id)) { 244 if (!g_port_tracker.Get().HasPort(port_id)) {
191 args.GetIsolate()->ThrowException(v8::Exception::Error( 245 args.GetIsolate()->ThrowException(v8::Exception::Error(
192 v8::String::NewFromUtf8(args.GetIsolate(), kPortClosedError))); 246 v8::String::NewFromUtf8(args.GetIsolate(), kPortClosedError)));
193 return; 247 return;
194 } 248 }
195 249
196 renderframe->Send(new ExtensionHostMsg_PostMessage( 250 renderframe->Send(new ExtensionHostMsg_PostMessage(
197 renderframe->GetRoutingID(), port_id, 251 renderframe->GetRoutingID(), port_id,
198 Message(*v8::String::Utf8Value(args[1]), 252 Message(*v8::String::Utf8Value(args[1]),
199 blink::WebUserGestureIndicator::isProcessingUserGesture()))); 253 blink::WebUserGestureIndicator::isProcessingUserGesture())));
200 } 254 }
201 255
202 // Forcefully disconnects a port. 256 // Forcefully disconnects a port.
203 void CloseChannel(const v8::FunctionCallbackInfo<v8::Value>& args) { 257 void CloseChannel(const v8::FunctionCallbackInfo<v8::Value>& args) {
204 // Arguments are (int32 port_id, boolean notify_browser). 258 // Arguments are (int32 port_id, boolean notify_browser).
205 CHECK_EQ(2, args.Length()); 259 CHECK_EQ(2, args.Length());
206 CHECK(args[0]->IsInt32()); 260 CHECK(args[0]->IsInt32());
207 CHECK(args[1]->IsBoolean()); 261 CHECK(args[1]->IsBoolean());
208 262
209 int port_id = args[0]->Int32Value(); 263 int port_id = args[0]->Int32Value();
210 if (!HasPortData(port_id)) 264 if (!g_port_tracker.Get().HasPort(port_id))
211 return; 265 return;
212 266
213 // Send via the RenderThread because the RenderFrame might be closing. 267 // Send via the RenderThread because the RenderFrame might be closing.
214 bool notify_browser = args[1]->BooleanValue(); 268 bool notify_browser = args[1]->BooleanValue();
215 if (notify_browser) { 269 if (notify_browser) {
216 content::RenderThread::Get()->Send( 270 content::RenderThread::Get()->Send(
217 new ExtensionHostMsg_CloseChannel(port_id, std::string())); 271 new ExtensionHostMsg_CloseChannel(port_id, std::string()));
218 } 272 }
219 273
220 ClearPortDataAndNotifyDispatcher(port_id); 274 ClearPortDataAndNotifyDispatcher(port_id);
221 } 275 }
222 276
223 // A new port has been created for a context. This occurs both when script 277 // A new port has been created for a context. This occurs both when script
224 // opens a connection, and when a connection is opened to this script. 278 // opens a connection, and when a connection is opened to this script.
225 void PortAddRef(const v8::FunctionCallbackInfo<v8::Value>& args) { 279 void PortAddRef(const v8::FunctionCallbackInfo<v8::Value>& args) {
226 // Arguments are (int32 port_id). 280 // Arguments are (int32 port_id).
227 CHECK_EQ(1, args.Length()); 281 CHECK_EQ(1, args.Length());
228 CHECK(args[0]->IsInt32()); 282 CHECK(args[0]->IsInt32());
229 283
230 int port_id = args[0]->Int32Value(); 284 int port_id = args[0]->Int32Value();
231 ++GetPortData(port_id).ref_count; 285 g_port_tracker.Get().AddReference(context(), port_id);
232 } 286 }
233 287
234 // The frame a port lived in has been destroyed. When there are no more 288 // The frame a port lived in has been destroyed. When there are no more
235 // frames with a reference to a given port, we will disconnect it and notify 289 // frames with a reference to a given port, we will disconnect it and notify
236 // the other end of the channel. 290 // the other end of the channel.
237 void PortRelease(const v8::FunctionCallbackInfo<v8::Value>& args) { 291 void PortRelease(const v8::FunctionCallbackInfo<v8::Value>& args) {
238 // Arguments are (int32 port_id). 292 // Arguments are (int32 port_id).
239 CHECK(args.Length() == 1 && args[0]->IsInt32()); 293 CHECK(args.Length() == 1 && args[0]->IsInt32());
240 ReleasePort(args[0]->Int32Value()); 294 ReleasePort(args[0]->Int32Value());
241 } 295 }
242 296
243 // Implementation of both the PortRelease native handler call, and callback 297 // Releases the reference to |port_id| for this context, and clears all port
244 // when contexts are invalidated to release their ports. 298 // data if there are no more references.
245 void ReleasePort(int port_id) { 299 void ReleasePort(int port_id) {
246 if (HasPortData(port_id) && --GetPortData(port_id).ref_count == 0) { 300 g_port_tracker.Get().RemoveReference(context(), port_id);
301 if (!g_port_tracker.Get().HasPort(port_id)) {
247 // Send via the RenderThread because the RenderFrame might be closing. 302 // Send via the RenderThread because the RenderFrame might be closing.
248 content::RenderThread::Get()->Send( 303 content::RenderThread::Get()->Send(
249 new ExtensionHostMsg_CloseChannel(port_id, std::string())); 304 new ExtensionHostMsg_CloseChannel(port_id, std::string()));
250 ClearPortDataAndNotifyDispatcher(port_id); 305 ClearPortDataAndNotifyDispatcher(port_id);
251 } 306 }
252 } 307 }
253 308
254 // void BindToGC(object, callback, port_id) 309 // void BindToGC(object, callback, port_id)
255 // 310 //
256 // Binds |callback| to be invoked *sometime after* |object| is garbage 311 // Binds |callback| to be invoked *sometime after* |object| is garbage
(...skipping 227 matching lines...) Expand 10 before | Expand all | Expand 10 after
484 // TODO(robwu): ScriptContextSet.ForEach should accept RenderFrame*. 539 // TODO(robwu): ScriptContextSet.ForEach should accept RenderFrame*.
485 content::RenderView* restrict_to_render_view = 540 content::RenderView* restrict_to_render_view =
486 restrict_to_render_frame ? restrict_to_render_frame->GetRenderView() 541 restrict_to_render_frame ? restrict_to_render_frame->GetRenderView()
487 : NULL; 542 : NULL;
488 context_set.ForEach( 543 context_set.ForEach(
489 restrict_to_render_view, 544 restrict_to_render_view,
490 base::Bind(&DispatchOnDisconnectToScriptContext, port_id, error_message)); 545 base::Bind(&DispatchOnDisconnectToScriptContext, port_id, error_message));
491 } 546 }
492 547
493 } // namespace extensions 548 } // namespace extensions
OLDNEW
« no previous file with comments | « no previous file | extensions/renderer/resources/messaging.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698