Chromium Code Reviews| 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 |