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