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 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
71 | 71 |
72 } // namespace | 72 } // namespace |
73 | 73 |
74 // This flag blocks LOGs to the UI if we're already in the middle of logging | 74 // This flag blocks LOGs to the UI if we're already in the middle of logging |
75 // to the UI. This prevents a potential infinite loop if we encounter an error | 75 // to the UI. This prevents a potential infinite loop if we encounter an error |
76 // while sending the log message to the UI. | 76 // while sending the log message to the UI. |
77 static bool g_logging_to_plugin = false; | 77 static bool g_logging_to_plugin = false; |
78 static HostNPScriptObject* g_logging_scriptable_object = NULL; | 78 static HostNPScriptObject* g_logging_scriptable_object = NULL; |
79 static logging::LogMessageHandlerFunction g_logging_old_handler = NULL; | 79 static logging::LogMessageHandlerFunction g_logging_old_handler = NULL; |
80 | 80 |
81 HostNPScriptObject::HostNPScriptObject(NPP plugin, NPObject* parent) | 81 HostNPScriptObject::HostNPScriptObject( |
82 NPP plugin, | |
83 NPObject* parent, | |
84 PluginMessageLoopProxy::Delegate* plugin_thread_delegate) | |
82 : plugin_(plugin), | 85 : plugin_(plugin), |
83 parent_(parent), | 86 parent_(parent), |
84 state_(kDisconnected), | 87 state_(kDisconnected), |
85 np_thread_id_(base::PlatformThread::CurrentId()), | 88 np_thread_id_(base::PlatformThread::CurrentId()), |
89 plugin_message_loop_proxy_( | |
90 new PluginMessageLoopProxy(plugin_thread_delegate)), | |
91 host_context_(plugin_message_loop_proxy_), | |
86 failed_login_attempts_(0), | 92 failed_login_attempts_(0), |
87 disconnected_event_(true, false), | 93 disconnected_event_(true, false), |
88 nat_traversal_enabled_(false), | 94 nat_traversal_enabled_(false), |
89 policy_received_(false) { | 95 policy_received_(false) { |
90 // Set up log message handler. | 96 // Set up log message handler. |
91 // Note that this approach doesn't quite support having multiple instances | 97 // Note that this approach doesn't quite support having multiple instances |
92 // of Chromoting running. In that case, the most recently opened tab will | 98 // of Chromoting running. In that case, the most recently opened tab will |
93 // grab all the debug log messages, and when any Chromoting tab is closed | 99 // grab all the debug log messages, and when any Chromoting tab is closed |
94 // the logging handler will go away. | 100 // the logging handler will go away. |
95 // Since having multiple Chromoting tabs is not a primary use case, and this | 101 // Since having multiple Chromoting tabs is not a primary use case, and this |
96 // is just debug logging, we're punting improving debug log support for that | 102 // is just debug logging, we're punting improving debug log support for that |
97 // case. | 103 // case. |
98 if (g_logging_old_handler == NULL) | 104 if (g_logging_old_handler == NULL) |
99 g_logging_old_handler = logging::GetLogMessageHandler(); | 105 g_logging_old_handler = logging::GetLogMessageHandler(); |
100 logging::SetLogMessageHandler(&LogToUI); | 106 logging::SetLogMessageHandler(&LogToUI); |
101 g_logging_scriptable_object = this; | 107 g_logging_scriptable_object = this; |
102 | |
103 VLOG(2) << "HostNPScriptObject"; | |
104 host_context_.SetUITaskPostFunction(base::Bind( | |
105 &HostNPScriptObject::PostTaskToNPThread, base::Unretained(this))); | |
106 } | 108 } |
107 | 109 |
108 HostNPScriptObject::~HostNPScriptObject() { | 110 HostNPScriptObject::~HostNPScriptObject() { |
109 CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_); | 111 CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_); |
110 | 112 |
111 // Shutdown DesktopEnvironment first so that it doesn't try to post | 113 // Shutdown DesktopEnvironment first so that it doesn't try to post |
112 // tasks on the UI thread while we are stopping the host. | 114 // tasks on the UI thread while we are stopping the host. |
113 desktop_environment_->Shutdown(); | 115 desktop_environment_->Shutdown(); |
114 | 116 |
115 logging::SetLogMessageHandler(g_logging_old_handler); | 117 logging::SetLogMessageHandler(g_logging_old_handler); |
116 g_logging_old_handler = NULL; | 118 g_logging_old_handler = NULL; |
117 g_logging_scriptable_object = NULL; | 119 g_logging_scriptable_object = NULL; |
118 | 120 |
121 plugin_message_loop_proxy_->Detach(); | |
122 | |
119 // Stop listening for policy updates. | 123 // Stop listening for policy updates. |
120 if (nat_policy_.get()) { | 124 if (nat_policy_.get()) { |
121 base::WaitableEvent nat_policy_stopped_(true, false); | 125 base::WaitableEvent nat_policy_stopped_(true, false); |
122 nat_policy_->StopWatching(&nat_policy_stopped_); | 126 nat_policy_->StopWatching(&nat_policy_stopped_); |
123 nat_policy_stopped_.Wait(); | 127 nat_policy_stopped_.Wait(); |
124 nat_policy_.reset(); | 128 nat_policy_.reset(); |
125 } | 129 } |
126 | 130 |
127 // Disconnect synchronously. We cannot disconnect asynchronously | 131 // Disconnect synchronously. We cannot disconnect asynchronously |
128 // here because |host_context_| needs to be stopped on the plugin | 132 // here because |host_context_| needs to be stopped on the plugin |
129 // thread, but the plugin thread may not exist after the instance | 133 // thread, but the plugin thread may not exist after the instance |
130 // is destroyed. | 134 // is destroyed. |
131 destructing_.Set(); | |
awong
2011/08/18 01:49:14
Doesn't this still need to be around Sergey?
| |
132 disconnected_event_.Reset(); | 135 disconnected_event_.Reset(); |
133 DisconnectInternal(); | 136 DisconnectInternal(); |
134 disconnected_event_.Wait(); | 137 disconnected_event_.Wait(); |
135 | 138 |
136 // Stop all threads. | 139 // Stop all threads. |
137 host_context_.Stop(); | 140 host_context_.Stop(); |
138 } | 141 } |
139 | 142 |
140 bool HostNPScriptObject::Init() { | 143 bool HostNPScriptObject::Init() { |
141 VLOG(2) << "Init"; | 144 VLOG(2) << "Init"; |
(...skipping 428 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
570 access_code_lifetime_ = lifetime; | 573 access_code_lifetime_ = lifetime; |
571 | 574 |
572 // Tell the ChromotingHost the access code, to use as shared-secret. | 575 // Tell the ChromotingHost the access code, to use as shared-secret. |
573 host_->set_access_code(access_code_); | 576 host_->set_access_code(access_code_); |
574 | 577 |
575 // Let the caller know that life is good. | 578 // Let the caller know that life is good. |
576 OnStateChanged(kReceivedAccessCode); | 579 OnStateChanged(kReceivedAccessCode); |
577 } | 580 } |
578 | 581 |
579 void HostNPScriptObject::OnStateChanged(State state) { | 582 void HostNPScriptObject::OnStateChanged(State state) { |
580 if (destructing_.IsSet()) | 583 if (!plugin_message_loop_proxy_->BelongsToCurrentThread()) { |
581 return; | 584 plugin_message_loop_proxy_->PostTask( |
582 | |
583 if (!host_context_.IsUIThread()) { | |
584 host_context_.PostTaskToUIThread( | |
585 FROM_HERE, base::Bind(&HostNPScriptObject::OnStateChanged, | 585 FROM_HERE, base::Bind(&HostNPScriptObject::OnStateChanged, |
586 base::Unretained(this), state)); | 586 base::Unretained(this), state)); |
587 return; | 587 return; |
588 } | 588 } |
589 state_ = state; | 589 state_ = state; |
590 if (on_state_changed_func_.get()) { | 590 if (on_state_changed_func_.get()) { |
591 VLOG(2) << "Calling state changed " << state; | 591 VLOG(2) << "Calling state changed " << state; |
592 bool is_good = InvokeAndIgnoreResult(on_state_changed_func_.get(), NULL, 0); | 592 bool is_good = InvokeAndIgnoreResult(on_state_changed_func_.get(), NULL, 0); |
593 LOG_IF(ERROR, !is_good) << "OnStateChanged failed"; | 593 LOG_IF(ERROR, !is_good) << "OnStateChanged failed"; |
594 } | 594 } |
(...skipping 13 matching lines...) Expand all Loading... | |
608 message += (str.c_str() + message_start); | 608 message += (str.c_str() + message_start); |
609 g_logging_scriptable_object->LogDebugInfo(message); | 609 g_logging_scriptable_object->LogDebugInfo(message); |
610 g_logging_to_plugin = false; | 610 g_logging_to_plugin = false; |
611 } | 611 } |
612 if (g_logging_old_handler) | 612 if (g_logging_old_handler) |
613 return (g_logging_old_handler)(severity, file, line, message_start, str); | 613 return (g_logging_old_handler)(severity, file, line, message_start, str); |
614 return false; | 614 return false; |
615 } | 615 } |
616 | 616 |
617 void HostNPScriptObject::LogDebugInfo(const std::string& message) { | 617 void HostNPScriptObject::LogDebugInfo(const std::string& message) { |
618 if (destructing_.IsSet()) | 618 if (!plugin_message_loop_proxy_->BelongsToCurrentThread()) { |
619 return; | 619 plugin_message_loop_proxy_->PostTask( |
620 | |
621 if (!host_context_.IsUIThread()) { | |
622 host_context_.PostTaskToUIThread( | |
623 FROM_HERE, base::Bind(&HostNPScriptObject::LogDebugInfo, | 620 FROM_HERE, base::Bind(&HostNPScriptObject::LogDebugInfo, |
624 base::Unretained(this), message)); | 621 base::Unretained(this), message)); |
625 return; | 622 return; |
626 } | 623 } |
627 | 624 |
628 if (log_debug_info_func_.get()) { | 625 if (log_debug_info_func_.get()) { |
629 NPVariant log_message; | 626 NPVariant log_message; |
630 STRINGZ_TO_NPVARIANT(message.c_str(), log_message); | 627 STRINGZ_TO_NPVARIANT(message.c_str(), log_message); |
631 bool is_good = InvokeAndIgnoreResult(log_debug_info_func_.get(), | 628 bool is_good = InvokeAndIgnoreResult(log_debug_info_func_.get(), |
632 &log_message, 1); | 629 &log_message, 1); |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
697 const NPVariant* args, | 694 const NPVariant* args, |
698 uint32_t argCount) { | 695 uint32_t argCount) { |
699 NPVariant np_result; | 696 NPVariant np_result; |
700 bool is_good = g_npnetscape_funcs->invokeDefault(plugin_, func, args, | 697 bool is_good = g_npnetscape_funcs->invokeDefault(plugin_, func, args, |
701 argCount, &np_result); | 698 argCount, &np_result); |
702 if (is_good) | 699 if (is_good) |
703 g_npnetscape_funcs->releasevariantvalue(&np_result); | 700 g_npnetscape_funcs->releasevariantvalue(&np_result); |
704 return is_good; | 701 return is_good; |
705 } | 702 } |
706 | 703 |
707 void HostNPScriptObject::PostTaskToNPThread( | |
708 const tracked_objects::Location& from_here, const base::Closure& task) { | |
709 // The NPAPI functions cannot make use of |from_here|, but this method is | |
710 // passed as a callback to ChromotingHostContext, so it needs to have the | |
711 // appropriate signature. | |
712 | |
713 // Copy task to the heap so that we can pass it to NPTaskSpringboard(). | |
714 base::Closure* task_in_heap = new base::Closure(task); | |
715 | |
716 // Can be called from any thread. | |
717 g_npnetscape_funcs->pluginthreadasynccall(plugin_, &NPTaskSpringboard, | |
718 task_in_heap); | |
719 } | |
720 | |
721 // static | |
722 void HostNPScriptObject::NPTaskSpringboard(void* task) { | |
723 base::Closure* real_task = reinterpret_cast<base::Closure*>(task); | |
724 real_task->Run(); | |
725 delete real_task; | |
726 } | |
727 | |
728 } // namespace remoting | 704 } // namespace remoting |
OLD | NEW |