OLD | NEW |
---|---|
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 "remoting/client/plugin/chromoting_instance.h" | 5 #include "remoting/client/plugin/chromoting_instance.h" |
6 | 6 |
7 #include <string> | 7 #include <string> |
8 #include <vector> | 8 #include <vector> |
9 | 9 |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
83 return "INCOMPATIBLE_PROTOCOL"; | 83 return "INCOMPATIBLE_PROTOCOL"; |
84 case ChromotingInstance::ERROR_NETWORK_FAILURE: | 84 case ChromotingInstance::ERROR_NETWORK_FAILURE: |
85 return "NETWORK_FAILURE"; | 85 return "NETWORK_FAILURE"; |
86 case ChromotingInstance::ERROR_HOST_OVERLOAD: | 86 case ChromotingInstance::ERROR_HOST_OVERLOAD: |
87 return "HOST_OVERLOAD"; | 87 return "HOST_OVERLOAD"; |
88 } | 88 } |
89 NOTREACHED(); | 89 NOTREACHED(); |
90 return ""; | 90 return ""; |
91 } | 91 } |
92 | 92 |
93 } // namespace | |
94 | |
95 // This flag blocks LOGs to the UI if we're already in the middle of logging | 93 // This flag blocks LOGs to the UI if we're already in the middle of logging |
96 // to the UI. This prevents a potential infinite loop if we encounter an error | 94 // to the UI. This prevents a potential infinite loop if we encounter an error |
97 // while sending the log message to the UI. | 95 // while sending the log message to the UI. |
98 static bool g_logging_to_plugin = false; | 96 bool g_logging_to_plugin = false; |
99 static bool g_has_logging_instance = false; | 97 bool g_has_logging_instance = false; |
100 static ChromotingInstance* g_logging_instance = NULL; | 98 base::LazyInstance<scoped_refptr<base::SingleThreadTaskRunner> >::Leaky |
101 static logging::LogMessageHandlerFunction g_logging_old_handler = NULL; | 99 g_logging_task_runner = LAZY_INSTANCE_INITIALIZER; |
100 base::LazyInstance<base::WeakPtr<ChromotingInstance> >::Leaky | |
101 g_logging_instance = LAZY_INSTANCE_INITIALIZER; | |
102 base::LazyInstance<base::Lock>::Leaky | |
103 g_logging_lock = LAZY_INSTANCE_INITIALIZER; | |
104 logging::LogMessageHandlerFunction g_logging_old_handler = NULL; | |
102 | 105 |
103 static base::LazyInstance<base::Lock>::Leaky | 106 } // namespace |
104 g_logging_lock = LAZY_INSTANCE_INITIALIZER; | |
105 | 107 |
106 // String sent in the "hello" message to the plugin to describe features. | 108 // String sent in the "hello" message to the plugin to describe features. |
107 const char ChromotingInstance::kApiFeatures[] = | 109 const char ChromotingInstance::kApiFeatures[] = |
108 "highQualityScaling injectKeyEvent sendClipboardItem remapKey trapKey " | 110 "highQualityScaling injectKeyEvent sendClipboardItem remapKey trapKey " |
109 "notifyClientDimensions pauseVideo"; | 111 "notifyClientDimensions pauseVideo"; |
110 | 112 |
111 bool ChromotingInstance::ParseAuthMethods(const std::string& auth_methods_str, | 113 bool ChromotingInstance::ParseAuthMethods(const std::string& auth_methods_str, |
112 ClientConfig* config) { | 114 ClientConfig* config) { |
113 if (auth_methods_str == "v1_token") { | 115 if (auth_methods_str == "v1_token") { |
114 config->use_v1_authenticator = true; | 116 config->use_v1_authenticator = true; |
(...skipping 17 matching lines...) Expand all Loading... | |
132 | 134 |
133 return true; | 135 return true; |
134 } | 136 } |
135 | 137 |
136 ChromotingInstance::ChromotingInstance(PP_Instance pp_instance) | 138 ChromotingInstance::ChromotingInstance(PP_Instance pp_instance) |
137 : pp::InstancePrivate(pp_instance), | 139 : pp::InstancePrivate(pp_instance), |
138 initialized_(false), | 140 initialized_(false), |
139 plugin_message_loop_( | 141 plugin_message_loop_( |
140 new PluginMessageLoopProxy(&plugin_thread_delegate_)), | 142 new PluginMessageLoopProxy(&plugin_thread_delegate_)), |
141 context_(plugin_message_loop_), | 143 context_(plugin_message_loop_), |
142 thread_proxy_(new ScopedThreadProxy(plugin_message_loop_)) { | 144 weak_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { |
143 RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE | PP_INPUTEVENT_CLASS_WHEEL); | 145 RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE | PP_INPUTEVENT_CLASS_WHEEL); |
144 RequestFilteringInputEvents(PP_INPUTEVENT_CLASS_KEYBOARD); | 146 RequestFilteringInputEvents(PP_INPUTEVENT_CLASS_KEYBOARD); |
145 | 147 |
146 // Resister this instance to handle debug log messsages. | 148 // Resister this instance to handle debug log messsages. |
147 RegisterLoggingInstance(); | 149 RegisterLoggingInstance(); |
148 | 150 |
149 // Send hello message. | 151 // Send hello message. |
150 scoped_ptr<base::DictionaryValue> data(new base::DictionaryValue()); | 152 scoped_ptr<base::DictionaryValue> data(new base::DictionaryValue()); |
151 data->SetInteger("apiVersion", kApiVersion); | 153 data->SetInteger("apiVersion", kApiVersion); |
152 data->SetString("apiFeatures", kApiFeatures); | 154 data->SetString("apiFeatures", kApiFeatures); |
153 data->SetInteger("apiMinVersion", kApiMinMessagingVersion); | 155 data->SetInteger("apiMinVersion", kApiMinMessagingVersion); |
154 PostChromotingMessage("hello", data.Pass()); | 156 PostChromotingMessage("hello", data.Pass()); |
155 } | 157 } |
156 | 158 |
157 ChromotingInstance::~ChromotingInstance() { | 159 ChromotingInstance::~ChromotingInstance() { |
158 DCHECK(plugin_message_loop_->BelongsToCurrentThread()); | 160 DCHECK(plugin_message_loop_->BelongsToCurrentThread()); |
159 | 161 |
160 // Detach the log proxy so we don't log anything else to the UI. | |
161 // This needs to be done before the instance is unregistered for logging. | |
162 thread_proxy_->Detach(); | |
163 | |
164 // Unregister this instance so that debug log messages will no longer be sent | 162 // Unregister this instance so that debug log messages will no longer be sent |
165 // to it. This will stop all logging in all Chromoting instances. | 163 // to it. This will stop all logging in all Chromoting instances. |
166 UnregisterLoggingInstance(); | 164 UnregisterLoggingInstance(); |
167 | 165 |
168 if (client_.get()) { | 166 if (client_.get()) { |
169 base::WaitableEvent done_event(true, false); | 167 base::WaitableEvent done_event(true, false); |
170 client_->Stop(base::Bind(&base::WaitableEvent::Signal, | 168 client_->Stop(base::Bind(&base::WaitableEvent::Signal, |
171 base::Unretained(&done_event))); | 169 base::Unretained(&done_event))); |
172 done_event.Wait(); | 170 done_event.Wait(); |
173 } | 171 } |
174 | 172 |
175 // Stopping the context shuts down all chromoting threads. | 173 // Stopping the context shuts down all chromoting threads. |
176 context_.Stop(); | 174 context_.Stop(); |
177 | 175 |
178 // Delete |thread_proxy_| before we detach |plugin_message_loop_|, | 176 // Ensure that nothing touches the plugin thread delegate after this point. |
179 // otherwise ScopedThreadProxy may DCHECK when being destroyed. | |
180 thread_proxy_.reset(); | |
181 | |
182 plugin_message_loop_->Detach(); | 177 plugin_message_loop_->Detach(); |
183 } | 178 } |
184 | 179 |
185 bool ChromotingInstance::Init(uint32_t argc, | 180 bool ChromotingInstance::Init(uint32_t argc, |
186 const char* argn[], | 181 const char* argn[], |
187 const char* argv[]) { | 182 const char* argv[]) { |
188 CHECK(!initialized_); | 183 CHECK(!initialized_); |
189 initialized_ = true; | 184 initialized_ = true; |
190 | 185 |
191 VLOG(1) << "Started ChromotingInstance::Init"; | 186 VLOG(1) << "Started ChromotingInstance::Init"; |
(...skipping 415 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
607 logging::SetLogMessageHandler(&LogToUI); | 602 logging::SetLogMessageHandler(&LogToUI); |
608 } | 603 } |
609 | 604 |
610 void ChromotingInstance::RegisterLoggingInstance() { | 605 void ChromotingInstance::RegisterLoggingInstance() { |
611 base::AutoLock lock(g_logging_lock.Get()); | 606 base::AutoLock lock(g_logging_lock.Get()); |
612 | 607 |
613 // Register this instance as the one that will handle all logging calls | 608 // Register this instance as the one that will handle all logging calls |
614 // and display them to the user. | 609 // and display them to the user. |
615 // If multiple plugins are run, then the last one registered will handle all | 610 // If multiple plugins are run, then the last one registered will handle all |
616 // logging for all instances. | 611 // logging for all instances. |
617 g_logging_instance = this; | 612 g_logging_instance.Get() = weak_factory_.GetWeakPtr(); |
613 g_logging_task_runner.Get() = plugin_message_loop_; | |
618 g_has_logging_instance = true; | 614 g_has_logging_instance = true; |
619 } | 615 } |
620 | 616 |
621 void ChromotingInstance::UnregisterLoggingInstance() { | 617 void ChromotingInstance::UnregisterLoggingInstance() { |
622 base::AutoLock lock(g_logging_lock.Get()); | 618 base::AutoLock lock(g_logging_lock.Get()); |
623 | 619 |
624 // Don't unregister unless we're the currently registered instance. | 620 // Don't unregister unless we're the currently registered instance. |
625 if (this != g_logging_instance) | 621 if (this != g_logging_instance.Get().get()) |
626 return; | 622 return; |
627 | 623 |
628 // Unregister this instance for logging. | 624 // Unregister this instance for logging. |
629 g_has_logging_instance = false; | 625 g_has_logging_instance = false; |
630 g_logging_instance = NULL; | 626 g_logging_instance.Get().reset(); |
627 g_logging_task_runner.Get() = NULL; | |
631 | 628 |
632 VLOG(1) << "Unregistering global log handler"; | 629 VLOG(1) << "Unregistering global log handler"; |
633 } | 630 } |
634 | 631 |
635 // static | 632 // static |
636 bool ChromotingInstance::LogToUI(int severity, const char* file, int line, | 633 bool ChromotingInstance::LogToUI(int severity, const char* file, int line, |
637 size_t message_start, | 634 size_t message_start, |
638 const std::string& str) { | 635 const std::string& str) { |
639 // Note that we're reading |g_has_logging_instance| outside of a lock. | 636 // Note that we're reading |g_has_logging_instance| outside of a lock. |
640 // This lockless read is done so that we don't needlessly slow down global | 637 // This lockless read is done so that we don't needlessly slow down global |
641 // logging with a lock for each log message. | 638 // logging with a lock for each log message. |
642 // | 639 // |
643 // This lockless read is safe because: | 640 // This lockless read is safe because: |
644 // | 641 // |
645 // Misreading a false value (when it should be true) means that we'll simply | 642 // Misreading a false value (when it should be true) means that we'll simply |
646 // skip processing a few log messages. | 643 // skip processing a few log messages. |
647 // | 644 // |
648 // Misreading a true value (when it should be false) means that we'll take | 645 // Misreading a true value (when it should be false) means that we'll take |
649 // the lock and check |g_logging_instance| unnecessarily. This is not | 646 // the lock and check |g_logging_instance| unnecessarily. This is not |
650 // problematic because we always set |g_logging_instance| inside a lock. | 647 // problematic because we always set |g_logging_instance| inside a lock. |
651 if (g_has_logging_instance) { | 648 if (g_has_logging_instance) { |
652 // Do not LOG anything while holding this lock or else the code will | 649 scoped_refptr<base::SingleThreadTaskRunner> logging_task_runner; |
653 // deadlock while trying to re-get the lock we're already in. | 650 |
654 base::AutoLock lock(g_logging_lock.Get()); | 651 { |
655 if (g_logging_instance && | 652 base::AutoLock lock(g_logging_lock.Get()); |
656 // If |g_logging_to_plugin| is set and we're on the logging thread, then | 653 // If we're on the logging thread and |g_logging_to_plugin| is set then |
657 // this LOG message came from handling a previous LOG message and we | 654 // this LOG message came from handling a previous LOG message and we |
658 // should skip it to avoid an infinite loop of LOG messages. | 655 // should skip it to avoid an infinite loop of LOG messages. |
659 // We don't have a lock around |g_in_processtoui|, but that's OK since | 656 if (!g_logging_task_runner.Get()->BelongsToCurrentThread() || |
660 // the value is only read/written on the logging thread. | 657 !g_logging_to_plugin) { |
661 (!g_logging_instance->plugin_message_loop_->BelongsToCurrentThread() || | 658 logging_task_runner = g_logging_task_runner.Get(); |
662 !g_logging_to_plugin)) { | 659 } |
660 } | |
661 | |
662 if (logging_task_runner.get()) { | |
663 std::string message = remoting::GetTimestampString(); | 663 std::string message = remoting::GetTimestampString(); |
664 message += (str.c_str() + message_start); | 664 message += (str.c_str() + message_start); |
665 // |thread_proxy_| is safe to use here because we detach it before | 665 |
666 // tearing down the |g_logging_instance|. | 666 g_logging_task_runner.Get()->PostTask( |
Sergey Ulanov
2012/06/02 00:57:45
This should be logging_task_runner instead of g_lo
Wez
2012/06/07 16:28:53
Done.
| |
667 g_logging_instance->thread_proxy_->PostTask( | |
668 FROM_HERE, base::Bind(&ChromotingInstance::ProcessLogToUI, | 667 FROM_HERE, base::Bind(&ChromotingInstance::ProcessLogToUI, |
669 base::Unretained(g_logging_instance), message)); | 668 g_logging_instance.Get(), message)); |
Sergey Ulanov
2012/06/02 00:57:45
should we also copy g_logging_instance with g_logg
Wez
2012/06/07 16:28:53
Done.
| |
670 } | 669 } |
671 } | 670 } |
672 | 671 |
673 if (g_logging_old_handler) | 672 if (g_logging_old_handler) |
674 return (g_logging_old_handler)(severity, file, line, message_start, str); | 673 return (g_logging_old_handler)(severity, file, line, message_start, str); |
675 return false; | 674 return false; |
676 } | 675 } |
677 | 676 |
678 void ChromotingInstance::ProcessLogToUI(const std::string& message) { | 677 void ChromotingInstance::ProcessLogToUI(const std::string& message) { |
679 DCHECK(plugin_message_loop_->BelongsToCurrentThread()); | 678 DCHECK(plugin_message_loop_->BelongsToCurrentThread()); |
680 | 679 |
681 // This flag (which is set only here) is used to prevent LogToUI from posting | 680 // This flag (which is set only here) is used to prevent LogToUI from posting |
682 // new tasks while we're in the middle of servicing a LOG call. This can | 681 // new tasks while we're in the middle of servicing a LOG call. This can |
683 // happen if the call to LogDebugInfo tries to LOG anything. | 682 // happen if the call to LogDebugInfo tries to LOG anything. |
683 // Since it is read on the plugin thread, we don't need to lock to set it. | |
684 g_logging_to_plugin = true; | 684 g_logging_to_plugin = true; |
685 ChromotingScriptableObject* scriptable_object = GetScriptableObject(); | 685 ChromotingScriptableObject* scriptable_object = GetScriptableObject(); |
686 if (scriptable_object) { | 686 if (scriptable_object) { |
687 scoped_ptr<base::DictionaryValue> data(new base::DictionaryValue()); | 687 scoped_ptr<base::DictionaryValue> data(new base::DictionaryValue()); |
688 data->SetString("message", message); | 688 data->SetString("message", message); |
689 PostChromotingMessage("logDebugMessage", data.Pass()); | 689 PostChromotingMessage("logDebugMessage", data.Pass()); |
690 | 690 |
691 scriptable_object->LogDebugInfo(message); | 691 scriptable_object->LogDebugInfo(message); |
692 } | 692 } |
693 g_logging_to_plugin = false; | 693 g_logging_to_plugin = false; |
694 } | 694 } |
695 | 695 |
696 bool ChromotingInstance::IsConnected() { | 696 bool ChromotingInstance::IsConnected() { |
697 return host_connection_.get() && | 697 return host_connection_.get() && |
698 (host_connection_->state() == protocol::ConnectionToHost::CONNECTED); | 698 (host_connection_->state() == protocol::ConnectionToHost::CONNECTED); |
699 } | 699 } |
700 | 700 |
701 } // namespace remoting | 701 } // namespace remoting |
OLD | NEW |