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

Side by Side Diff: content/renderer/pepper/message_channel.cc

Issue 605393002: Revert of PPAPI: Never re-enter JavaScript for PostMessage. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years, 2 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
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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 "content/renderer/pepper/message_channel.h" 5 #include "content/renderer/pepper/message_channel.h"
6 6
7 #include <cstdlib> 7 #include <cstdlib>
8 #include <string> 8 #include <string>
9 9
10 #include "base/bind.h" 10 #include "base/bind.h"
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after
97 MessageChannel* message_channel = new MessageChannel(instance); 97 MessageChannel* message_channel = new MessageChannel(instance);
98 v8::HandleScope handle_scope(instance->GetIsolate()); 98 v8::HandleScope handle_scope(instance->GetIsolate());
99 v8::Context::Scope context_scope(instance->GetContext()); 99 v8::Context::Scope context_scope(instance->GetContext());
100 gin::Handle<MessageChannel> handle = 100 gin::Handle<MessageChannel> handle =
101 gin::CreateHandle(instance->GetIsolate(), message_channel); 101 gin::CreateHandle(instance->GetIsolate(), message_channel);
102 result->Reset(instance->GetIsolate(), handle.ToV8()->ToObject()); 102 result->Reset(instance->GetIsolate(), handle.ToV8()->ToObject());
103 return message_channel; 103 return message_channel;
104 } 104 }
105 105
106 MessageChannel::~MessageChannel() { 106 MessageChannel::~MessageChannel() {
107 // Note it's unlikely but possible that we outlive the instance, and so we
108 // might have already unregistered in InstanceDeleted. That's OK, because
109 // removing an observer that's already removed is a no-op.
110 UnregisterSyncMessageStatusObserver();
111
112 passthrough_object_.Reset(); 107 passthrough_object_.Reset();
113 if (instance_) 108 if (instance_)
114 instance_->MessageChannelDestroyed(); 109 instance_->MessageChannelDestroyed();
115 } 110 }
116 111
117 void MessageChannel::InstanceDeleted() { 112 void MessageChannel::InstanceDeleted() {
118 UnregisterSyncMessageStatusObserver();
119 instance_ = NULL; 113 instance_ = NULL;
120 } 114 }
121 115
122 void MessageChannel::PostMessageToJavaScript(PP_Var message_data) { 116 void MessageChannel::PostMessageToJavaScript(PP_Var message_data) {
123 v8::HandleScope scope(v8::Isolate::GetCurrent()); 117 v8::HandleScope scope(v8::Isolate::GetCurrent());
124 118
125 // Because V8 is probably not on the stack for Native->JS calls, we need to 119 // Because V8 is probably not on the stack for Native->JS calls, we need to
126 // enter the appropriate context for the plugin. 120 // enter the appropriate context for the plugin.
127 v8::Local<v8::Context> context = instance_->GetContext(); 121 v8::Local<v8::Context> context = instance_->GetContext();
128 if (context.IsEmpty()) 122 if (context.IsEmpty())
129 return; 123 return;
130 124
131 v8::Context::Scope context_scope(context); 125 v8::Context::Scope context_scope(context);
132 126
133 v8::Handle<v8::Value> v8_val; 127 v8::Handle<v8::Value> v8_val;
134 if (!V8VarConverter(instance_->pp_instance()) 128 if (!V8VarConverter(instance_->pp_instance())
135 .ToV8Value(message_data, context, &v8_val)) { 129 .ToV8Value(message_data, context, &v8_val)) {
136 PpapiGlobals::Get()->LogWithSource(instance_->pp_instance(), 130 PpapiGlobals::Get()->LogWithSource(instance_->pp_instance(),
137 PP_LOGLEVEL_ERROR, 131 PP_LOGLEVEL_ERROR,
138 std::string(), 132 std::string(),
139 kVarToV8ConversionError); 133 kVarToV8ConversionError);
140 return; 134 return;
141 } 135 }
142 136
143 WebSerializedScriptValue serialized_val = 137 WebSerializedScriptValue serialized_val =
144 WebSerializedScriptValue::serialize(v8_val); 138 WebSerializedScriptValue::serialize(v8_val);
145 139
146 if (js_message_queue_state_ != SEND_DIRECTLY) { 140 if (early_message_queue_state_ != SEND_DIRECTLY) {
147 // We can't just PostTask here; the messages would arrive out of 141 // We can't just PostTask here; the messages would arrive out of
148 // order. Instead, we queue them up until we're ready to post 142 // order. Instead, we queue them up until we're ready to post
149 // them. 143 // them.
150 js_message_queue_.push_back(serialized_val); 144 early_message_queue_.push_back(serialized_val);
151 } else { 145 } else {
152 // The proxy sent an asynchronous message, so the plugin is already 146 // The proxy sent an asynchronous message, so the plugin is already
153 // unblocked. Therefore, there's no need to PostTask. 147 // unblocked. Therefore, there's no need to PostTask.
154 DCHECK(js_message_queue_.empty()); 148 DCHECK(early_message_queue_.empty());
155 PostMessageToJavaScriptImpl(serialized_val); 149 PostMessageToJavaScriptImpl(serialized_val);
156 } 150 }
157 } 151 }
158 152
159 void MessageChannel::Start() { 153 void MessageChannel::Start() {
160 DCHECK_EQ(WAITING_TO_START, js_message_queue_state_); 154 // We PostTask here instead of draining the message queue directly
161 DCHECK_EQ(WAITING_TO_START, plugin_message_queue_state_); 155 // since we haven't finished initializing the PepperWebPluginImpl yet, so
162 156 // the plugin isn't available in the DOM.
163 ppapi::proxy::HostDispatcher* dispatcher = 157 base::MessageLoop::current()->PostTask(
164 ppapi::proxy::HostDispatcher::GetForInstance(instance_->pp_instance()); 158 FROM_HERE,
165 // The dispatcher is NULL for in-process. 159 base::Bind(&MessageChannel::DrainEarlyMessageQueue,
166 if (dispatcher) 160 weak_ptr_factory_.GetWeakPtr()));
167 dispatcher->AddSyncMessageStatusObserver(this);
168
169 // We can't drain the JS message queue directly since we haven't finished
170 // initializing the PepperWebPluginImpl yet, so the plugin isn't available in
171 // the DOM.
172 DrainJSMessageQueueSoon();
173
174 plugin_message_queue_state_ = SEND_DIRECTLY;
175 DrainCompletedPluginMessages();
176 } 161 }
177 162
178 void MessageChannel::SetPassthroughObject(v8::Handle<v8::Object> passthrough) { 163 void MessageChannel::SetPassthroughObject(v8::Handle<v8::Object> passthrough) {
179 passthrough_object_.Reset(instance_->GetIsolate(), passthrough); 164 passthrough_object_.Reset(instance_->GetIsolate(), passthrough);
180 } 165 }
181 166
182 void MessageChannel::SetReadOnlyProperty(PP_Var key, PP_Var value) { 167 void MessageChannel::SetReadOnlyProperty(PP_Var key, PP_Var value) {
183 StringVar* key_string = StringVar::FromPPVar(key); 168 StringVar* key_string = StringVar::FromPPVar(key);
184 if (key_string) { 169 if (key_string) {
185 internal_named_properties_[key_string->value()] = ScopedPPVar(value); 170 internal_named_properties_[key_string->value()] = ScopedPPVar(value);
186 } else { 171 } else {
187 NOTREACHED(); 172 NOTREACHED();
188 } 173 }
189 } 174 }
190 175
191 MessageChannel::MessageChannel(PepperPluginInstanceImpl* instance) 176 MessageChannel::MessageChannel(PepperPluginInstanceImpl* instance)
192 : gin::NamedPropertyInterceptor(instance->GetIsolate(), this), 177 : gin::NamedPropertyInterceptor(instance->GetIsolate(), this),
193 instance_(instance), 178 instance_(instance),
194 js_message_queue_state_(WAITING_TO_START), 179 early_message_queue_state_(QUEUE_MESSAGES),
195 blocking_message_depth_(0),
196 plugin_message_queue_state_(WAITING_TO_START),
197 weak_ptr_factory_(this) { 180 weak_ptr_factory_(this) {
198 } 181 }
199 182
200 gin::ObjectTemplateBuilder MessageChannel::GetObjectTemplateBuilder( 183 gin::ObjectTemplateBuilder MessageChannel::GetObjectTemplateBuilder(
201 v8::Isolate* isolate) { 184 v8::Isolate* isolate) {
202 return Wrappable<MessageChannel>::GetObjectTemplateBuilder(isolate) 185 return Wrappable<MessageChannel>::GetObjectTemplateBuilder(isolate)
203 .AddNamedPropertyInterceptor(); 186 .AddNamedPropertyInterceptor();
204 } 187 }
205 188
206 void MessageChannel::BeginBlockOnSyncMessage() {
207 js_message_queue_state_ = QUEUE_MESSAGES;
208 ++blocking_message_depth_;
209 }
210
211 void MessageChannel::EndBlockOnSyncMessage() {
212 DCHECK_GT(blocking_message_depth_, 0);
213 --blocking_message_depth_;
214 if (!blocking_message_depth_)
215 DrainJSMessageQueueSoon();
216 }
217
218 v8::Local<v8::Value> MessageChannel::GetNamedProperty( 189 v8::Local<v8::Value> MessageChannel::GetNamedProperty(
219 v8::Isolate* isolate, 190 v8::Isolate* isolate,
220 const std::string& identifier) { 191 const std::string& identifier) {
221 if (!instance_) 192 if (!instance_)
222 return v8::Local<v8::Value>(); 193 return v8::Local<v8::Value>();
223 194
224 PepperTryCatchV8 try_catch(instance_, V8VarConverter::kDisallowObjectVars, 195 PepperTryCatchV8 try_catch(instance_, V8VarConverter::kDisallowObjectVars,
225 isolate); 196 isolate);
226 if (identifier == kPostMessage) { 197 if (identifier == kPostMessage) {
227 return gin::CreateFunctionTemplate(isolate, 198 return gin::CreateFunctionTemplate(isolate,
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
308 try_catch.ThrowException( 279 try_catch.ThrowException(
309 "postMessageAndAwaitResponse requires one argument"); 280 "postMessageAndAwaitResponse requires one argument");
310 return; 281 return;
311 } 282 }
312 283
313 v8::Handle<v8::Value> message_data; 284 v8::Handle<v8::Value> message_data;
314 if (!args->GetNext(&message_data)) { 285 if (!args->GetNext(&message_data)) {
315 NOTREACHED(); 286 NOTREACHED();
316 } 287 }
317 288
318 if (plugin_message_queue_state_ == WAITING_TO_START) { 289 if (early_message_queue_state_ == QUEUE_MESSAGES) {
319 try_catch.ThrowException( 290 try_catch.ThrowException(
320 "Attempted to call a synchronous method on a plugin that was not " 291 "Attempted to call a synchronous method on a plugin that was not "
321 "yet loaded."); 292 "yet loaded.");
322 return; 293 return;
323 } 294 }
324 295
325 // If the queue of messages to the plugin is non-empty, we're still waiting on 296 // If the queue of messages to the plugin is non-empty, we're still waiting on
326 // pending Var conversions. This means at some point in the past, JavaScript 297 // pending Var conversions. This means at some point in the past, JavaScript
327 // called postMessage (the async one) and passed us something with a browser- 298 // called postMessage (the async one) and passed us something with a browser-
328 // side host (e.g., FileSystem) and we haven't gotten a response from the 299 // side host (e.g., FileSystem) and we haven't gotten a response from the
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
421 const ScopedPPVar& result, 392 const ScopedPPVar& result,
422 bool success) { 393 bool success) {
423 if (!instance_) 394 if (!instance_)
424 return; 395 return;
425 result_holder->ConversionCompleted(result, success); 396 result_holder->ConversionCompleted(result, success);
426 DrainCompletedPluginMessages(); 397 DrainCompletedPluginMessages();
427 } 398 }
428 399
429 void MessageChannel::DrainCompletedPluginMessages() { 400 void MessageChannel::DrainCompletedPluginMessages() {
430 DCHECK(instance_); 401 DCHECK(instance_);
431 if (plugin_message_queue_state_ == WAITING_TO_START) 402 if (early_message_queue_state_ == QUEUE_MESSAGES)
432 return; 403 return;
433 404
434 while (!plugin_message_queue_.empty() && 405 while (!plugin_message_queue_.empty() &&
435 plugin_message_queue_.front().conversion_completed()) { 406 plugin_message_queue_.front().conversion_completed()) {
436 const VarConversionResult& front = plugin_message_queue_.front(); 407 const VarConversionResult& front = plugin_message_queue_.front();
437 if (front.success()) { 408 if (front.success()) {
438 instance_->HandleMessage(front.var()); 409 instance_->HandleMessage(front.var());
439 } else { 410 } else {
440 PpapiGlobals::Get()->LogWithSource(instance()->pp_instance(), 411 PpapiGlobals::Get()->LogWithSource(instance()->pp_instance(),
441 PP_LOGLEVEL_ERROR, 412 PP_LOGLEVEL_ERROR,
442 std::string(), 413 std::string(),
443 kV8ToVarConversionError); 414 kV8ToVarConversionError);
444 } 415 }
445 plugin_message_queue_.pop_front(); 416 plugin_message_queue_.pop_front();
446 } 417 }
447 } 418 }
448 419
449 void MessageChannel::DrainJSMessageQueue() { 420 void MessageChannel::DrainEarlyMessageQueue() {
450 if (!instance_) 421 if (!instance_)
451 return; 422 return;
452 if (js_message_queue_state_ == SEND_DIRECTLY) 423 DCHECK(early_message_queue_state_ == QUEUE_MESSAGES);
453 return;
454 424
455 // Take a reference on the PluginInstance. This is because JavaScript code 425 // Take a reference on the PluginInstance. This is because JavaScript code
456 // may delete the plugin, which would destroy the PluginInstance and its 426 // may delete the plugin, which would destroy the PluginInstance and its
457 // corresponding MessageChannel. 427 // corresponding MessageChannel.
458 scoped_refptr<PepperPluginInstanceImpl> instance_ref(instance_); 428 scoped_refptr<PepperPluginInstanceImpl> instance_ref(instance_);
459 while (!js_message_queue_.empty()) { 429 while (!early_message_queue_.empty()) {
460 PostMessageToJavaScriptImpl(js_message_queue_.front()); 430 PostMessageToJavaScriptImpl(early_message_queue_.front());
461 js_message_queue_.pop_front(); 431 early_message_queue_.pop_front();
462 } 432 }
463 js_message_queue_state_ = SEND_DIRECTLY; 433 early_message_queue_state_ = SEND_DIRECTLY;
464 }
465 434
466 void MessageChannel::DrainJSMessageQueueSoon() { 435 DrainCompletedPluginMessages();
467 base::MessageLoop::current()->PostTask(
468 FROM_HERE,
469 base::Bind(&MessageChannel::DrainJSMessageQueue,
470 weak_ptr_factory_.GetWeakPtr()));
471 }
472
473 void MessageChannel::UnregisterSyncMessageStatusObserver() {
474 if (!instance_)
475 return;
476 ppapi::proxy::HostDispatcher* dispatcher =
477 ppapi::proxy::HostDispatcher::GetForInstance(instance_->pp_instance());
478 // The dispatcher is NULL for in-process.
479 if (dispatcher)
480 dispatcher->RemoveSyncMessageStatusObserver(this);
481 } 436 }
482 437
483 } // namespace content 438 } // namespace content
OLDNEW
« no previous file with comments | « content/renderer/pepper/message_channel.h ('k') | content/renderer/pepper/pepper_hung_plugin_filter.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698