| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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 "remoting/host/plugin/host_script_object.h" | 5 #include "remoting/host/plugin/host_script_object.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/message_loop.h" | 8 #include "base/message_loop.h" |
| 9 #include "base/message_loop_proxy.h" | 9 #include "base/message_loop_proxy.h" |
| 10 #include "base/threading/platform_thread.h" | 10 #include "base/threading/platform_thread.h" |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 68 | 68 |
| 69 } // namespace | 69 } // namespace |
| 70 | 70 |
| 71 // This flag blocks LOGs to the UI if we're already in the middle of logging | 71 // This flag blocks LOGs to the UI if we're already in the middle of logging |
| 72 // to the UI. This prevents a potential infinite loop if we encounter an error | 72 // to the UI. This prevents a potential infinite loop if we encounter an error |
| 73 // while sending the log message to the UI. | 73 // while sending the log message to the UI. |
| 74 static bool g_logging_to_plugin = false; | 74 static bool g_logging_to_plugin = false; |
| 75 static HostNPScriptObject* g_logging_scriptable_object = NULL; | 75 static HostNPScriptObject* g_logging_scriptable_object = NULL; |
| 76 static logging::LogMessageHandlerFunction g_logging_old_handler = NULL; | 76 static logging::LogMessageHandlerFunction g_logging_old_handler = NULL; |
| 77 | 77 |
| 78 HostNPScriptObject::HostNPScriptObject(NPP plugin, NPObject* parent) | 78 HostNPScriptObject::HostNPScriptObject( |
| 79 NPP plugin, |
| 80 NPObject* parent, |
| 81 PluginMessageLoopProxy::Delegate* plugin_thread_delegate) |
| 79 : plugin_(plugin), | 82 : plugin_(plugin), |
| 80 parent_(parent), | 83 parent_(parent), |
| 81 state_(kDisconnected), | 84 state_(kDisconnected), |
| 82 log_debug_info_func_(NULL), | 85 log_debug_info_func_(NULL), |
| 83 on_state_changed_func_(NULL), | 86 on_state_changed_func_(NULL), |
| 84 np_thread_id_(base::PlatformThread::CurrentId()), | 87 np_thread_id_(base::PlatformThread::CurrentId()), |
| 88 plugin_message_loop_proxy_( |
| 89 new PluginMessageLoopProxy(plugin_thread_delegate)), |
| 90 host_context_(plugin_message_loop_proxy_), |
| 85 failed_login_attempts_(0), | 91 failed_login_attempts_(0), |
| 86 disconnected_event_(true, false) { | 92 disconnected_event_(true, false) { |
| 87 // Set up log message handler. | 93 // Set up log message handler. |
| 88 // Note that this approach doesn't quite support having multiple instances | 94 // Note that this approach doesn't quite support having multiple instances |
| 89 // of Chromoting running. In that case, the most recently opened tab will | 95 // of Chromoting running. In that case, the most recently opened tab will |
| 90 // grab all the debug log messages, and when any Chromoting tab is closed | 96 // grab all the debug log messages, and when any Chromoting tab is closed |
| 91 // the logging handler will go away. | 97 // the logging handler will go away. |
| 92 // Since having multiple Chromoting tabs is not a primary use case, and this | 98 // Since having multiple Chromoting tabs is not a primary use case, and this |
| 93 // is just debug logging, we're punting improving debug log support for that | 99 // is just debug logging, we're punting improving debug log support for that |
| 94 // case. | 100 // case. |
| 95 if (g_logging_old_handler == NULL) | 101 if (g_logging_old_handler == NULL) |
| 96 g_logging_old_handler = logging::GetLogMessageHandler(); | 102 g_logging_old_handler = logging::GetLogMessageHandler(); |
| 97 logging::SetLogMessageHandler(&LogToUI); | 103 logging::SetLogMessageHandler(&LogToUI); |
| 98 g_logging_scriptable_object = this; | 104 g_logging_scriptable_object = this; |
| 99 | |
| 100 VLOG(2) << "HostNPScriptObject"; | |
| 101 host_context_.SetUITaskPostFunction(base::Bind( | |
| 102 &HostNPScriptObject::PostTaskToNPThread, base::Unretained(this))); | |
| 103 } | 105 } |
| 104 | 106 |
| 105 HostNPScriptObject::~HostNPScriptObject() { | 107 HostNPScriptObject::~HostNPScriptObject() { |
| 106 CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_); | 108 CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_); |
| 107 | 109 |
| 108 // Shutdown DesktopEnvironment first so that it doesn't try to post | 110 // Shutdown DesktopEnvironment first so that it doesn't try to post |
| 109 // tasks on the UI thread while we are stopping the host. | 111 // tasks on the UI thread while we are stopping the host. |
| 110 desktop_environment_->Shutdown(); | 112 desktop_environment_->Shutdown(); |
| 111 | 113 |
| 112 logging::SetLogMessageHandler(g_logging_old_handler); | 114 logging::SetLogMessageHandler(g_logging_old_handler); |
| 113 g_logging_old_handler = NULL; | 115 g_logging_old_handler = NULL; |
| 114 g_logging_scriptable_object = NULL; | 116 g_logging_scriptable_object = NULL; |
| 115 | 117 |
| 118 plugin_message_loop_proxy_->Detach(); |
| 119 |
| 116 // Disconnect synchronously. We cannot disconnect asynchronously | 120 // Disconnect synchronously. We cannot disconnect asynchronously |
| 117 // here because |host_context_| needs to be stopped on the plugin | 121 // here because |host_context_| needs to be stopped on the plugin |
| 118 // thread, but the plugin thread may not exist after the instance | 122 // thread, but the plugin thread may not exist after the instance |
| 119 // is destroyed. | 123 // is destroyed. |
| 120 destructing_.Set(); | |
| 121 disconnected_event_.Reset(); | 124 disconnected_event_.Reset(); |
| 122 DisconnectInternal(); | 125 DisconnectInternal(); |
| 123 disconnected_event_.Wait(); | 126 disconnected_event_.Wait(); |
| 124 | 127 |
| 125 // Stop all threads. | 128 // Stop all threads. |
| 126 host_context_.Stop(); | 129 host_context_.Stop(); |
| 127 | 130 |
| 128 if (log_debug_info_func_) { | 131 if (log_debug_info_func_) { |
| 129 g_npnetscape_funcs->releaseobject(log_debug_info_func_); | 132 g_npnetscape_funcs->releaseobject(log_debug_info_func_); |
| 130 } | 133 } |
| (...skipping 376 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 507 access_code_lifetime_ = lifetime; | 510 access_code_lifetime_ = lifetime; |
| 508 | 511 |
| 509 // Tell the ChromotingHost the access code, to use as shared-secret. | 512 // Tell the ChromotingHost the access code, to use as shared-secret. |
| 510 host_->set_access_code(access_code_); | 513 host_->set_access_code(access_code_); |
| 511 | 514 |
| 512 // Let the caller know that life is good. | 515 // Let the caller know that life is good. |
| 513 OnStateChanged(kReceivedAccessCode); | 516 OnStateChanged(kReceivedAccessCode); |
| 514 } | 517 } |
| 515 | 518 |
| 516 void HostNPScriptObject::OnStateChanged(State state) { | 519 void HostNPScriptObject::OnStateChanged(State state) { |
| 517 if (destructing_.IsSet()) | 520 if (!plugin_message_loop_proxy_->BelongsToCurrentThread()) { |
| 518 return; | 521 plugin_message_loop_proxy_->PostTask( |
| 519 | |
| 520 if (!host_context_.IsUIThread()) { | |
| 521 host_context_.PostTaskToUIThread( | |
| 522 FROM_HERE, base::Bind(&HostNPScriptObject::OnStateChanged, | 522 FROM_HERE, base::Bind(&HostNPScriptObject::OnStateChanged, |
| 523 base::Unretained(this), state)); | 523 base::Unretained(this), state)); |
| 524 return; | 524 return; |
| 525 } | 525 } |
| 526 state_ = state; | 526 state_ = state; |
| 527 if (on_state_changed_func_) { | 527 if (on_state_changed_func_) { |
| 528 VLOG(2) << "Calling state changed " << state; | 528 VLOG(2) << "Calling state changed " << state; |
| 529 bool is_good = InvokeAndIgnoreResult(on_state_changed_func_, NULL, 0); | 529 bool is_good = InvokeAndIgnoreResult(on_state_changed_func_, NULL, 0); |
| 530 LOG_IF(ERROR, !is_good) << "OnStateChanged failed"; | 530 LOG_IF(ERROR, !is_good) << "OnStateChanged failed"; |
| 531 } | 531 } |
| (...skipping 13 matching lines...) Expand all Loading... |
| 545 message += (str.c_str() + message_start); | 545 message += (str.c_str() + message_start); |
| 546 g_logging_scriptable_object->LogDebugInfo(message); | 546 g_logging_scriptable_object->LogDebugInfo(message); |
| 547 g_logging_to_plugin = false; | 547 g_logging_to_plugin = false; |
| 548 } | 548 } |
| 549 if (g_logging_old_handler) | 549 if (g_logging_old_handler) |
| 550 return (g_logging_old_handler)(severity, file, line, message_start, str); | 550 return (g_logging_old_handler)(severity, file, line, message_start, str); |
| 551 return false; | 551 return false; |
| 552 } | 552 } |
| 553 | 553 |
| 554 void HostNPScriptObject::LogDebugInfo(const std::string& message) { | 554 void HostNPScriptObject::LogDebugInfo(const std::string& message) { |
| 555 if (destructing_.IsSet()) | 555 if (!plugin_message_loop_proxy_->BelongsToCurrentThread()) { |
| 556 return; | 556 plugin_message_loop_proxy_->PostTask( |
| 557 | |
| 558 if (!host_context_.IsUIThread()) { | |
| 559 host_context_.PostTaskToUIThread( | |
| 560 FROM_HERE, base::Bind(&HostNPScriptObject::LogDebugInfo, | 557 FROM_HERE, base::Bind(&HostNPScriptObject::LogDebugInfo, |
| 561 base::Unretained(this), message)); | 558 base::Unretained(this), message)); |
| 562 return; | 559 return; |
| 563 } | 560 } |
| 564 | 561 |
| 565 if (log_debug_info_func_) { | 562 if (log_debug_info_func_) { |
| 566 NPVariant log_message; | 563 NPVariant log_message; |
| 567 STRINGZ_TO_NPVARIANT(message.c_str(), log_message); | 564 STRINGZ_TO_NPVARIANT(message.c_str(), log_message); |
| 568 bool is_good = InvokeAndIgnoreResult(log_debug_info_func_, | 565 bool is_good = InvokeAndIgnoreResult(log_debug_info_func_, |
| 569 &log_message, 1); | 566 &log_message, 1); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 581 const NPVariant* args, | 578 const NPVariant* args, |
| 582 uint32_t argCount) { | 579 uint32_t argCount) { |
| 583 NPVariant np_result; | 580 NPVariant np_result; |
| 584 bool is_good = g_npnetscape_funcs->invokeDefault(plugin_, func, args, | 581 bool is_good = g_npnetscape_funcs->invokeDefault(plugin_, func, args, |
| 585 argCount, &np_result); | 582 argCount, &np_result); |
| 586 if (is_good) | 583 if (is_good) |
| 587 g_npnetscape_funcs->releasevariantvalue(&np_result); | 584 g_npnetscape_funcs->releasevariantvalue(&np_result); |
| 588 return is_good; | 585 return is_good; |
| 589 } | 586 } |
| 590 | 587 |
| 591 void HostNPScriptObject::PostTaskToNPThread( | |
| 592 const tracked_objects::Location& from_here, const base::Closure& task) { | |
| 593 // The NPAPI functions cannot make use of |from_here|, but this method is | |
| 594 // passed as a callback to ChromotingHostContext, so it needs to have the | |
| 595 // appropriate signature. | |
| 596 | |
| 597 // Copy task to the heap so that we can pass it to NPTaskSpringboard(). | |
| 598 base::Closure* task_in_heap = new base::Closure(task); | |
| 599 | |
| 600 // Can be called from any thread. | |
| 601 g_npnetscape_funcs->pluginthreadasynccall(plugin_, &NPTaskSpringboard, | |
| 602 task_in_heap); | |
| 603 } | |
| 604 | |
| 605 // static | |
| 606 void HostNPScriptObject::NPTaskSpringboard(void* task) { | |
| 607 base::Closure* real_task = reinterpret_cast<base::Closure*>(task); | |
| 608 real_task->Run(); | |
| 609 delete real_task; | |
| 610 } | |
| 611 | |
| 612 } // namespace remoting | 588 } // namespace remoting |
| OLD | NEW |