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 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(scoped_refptr<base::SingleThreadTaskRunner>, |
| 101 g_logging_task_runner, ()); | |
| 102 CR_DEFINE_STATIC_LOCAL(base::WeakPtr<ChromotingInstance>, g_logging_instance, | |
|
Sergey Ulanov
2012/05/30 00:30:37
nit: Might be more readable if formatted as follow
Wez
2012/05/30 00:54:02
Done.
| |
| 103 ()); | |
| 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 21 matching lines...) Expand all Loading... | |
| 132 | 135 |
| 133 return true; | 136 return true; |
| 134 } | 137 } |
| 135 | 138 |
| 136 ChromotingInstance::ChromotingInstance(PP_Instance pp_instance) | 139 ChromotingInstance::ChromotingInstance(PP_Instance pp_instance) |
| 137 : pp::InstancePrivate(pp_instance), | 140 : pp::InstancePrivate(pp_instance), |
| 138 initialized_(false), | 141 initialized_(false), |
| 139 plugin_message_loop_( | 142 plugin_message_loop_( |
| 140 new PluginMessageLoopProxy(&plugin_thread_delegate_)), | 143 new PluginMessageLoopProxy(&plugin_thread_delegate_)), |
| 141 context_(plugin_message_loop_), | 144 context_(plugin_message_loop_), |
| 142 thread_proxy_(new ScopedThreadProxy(plugin_message_loop_)) { | 145 weak_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { |
| 143 RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE | PP_INPUTEVENT_CLASS_WHEEL); | 146 RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE | PP_INPUTEVENT_CLASS_WHEEL); |
| 144 RequestFilteringInputEvents(PP_INPUTEVENT_CLASS_KEYBOARD); | 147 RequestFilteringInputEvents(PP_INPUTEVENT_CLASS_KEYBOARD); |
| 145 | 148 |
| 146 // Resister this instance to handle debug log messsages. | 149 // Resister this instance to handle debug log messsages. |
| 147 RegisterLoggingInstance(); | 150 RegisterLoggingInstance(); |
| 148 | 151 |
| 149 // Send hello message. | 152 // Send hello message. |
| 150 scoped_ptr<base::DictionaryValue> data(new base::DictionaryValue()); | 153 scoped_ptr<base::DictionaryValue> data(new base::DictionaryValue()); |
| 151 data->SetInteger("apiVersion", kApiVersion); | 154 data->SetInteger("apiVersion", kApiVersion); |
| 152 data->SetString("apiFeatures", kApiFeatures); | 155 data->SetString("apiFeatures", kApiFeatures); |
| 153 data->SetInteger("apiMinVersion", kApiMinMessagingVersion); | 156 data->SetInteger("apiMinVersion", kApiMinMessagingVersion); |
| 154 PostChromotingMessage("hello", data.Pass()); | 157 PostChromotingMessage("hello", data.Pass()); |
| 155 } | 158 } |
| 156 | 159 |
| 157 ChromotingInstance::~ChromotingInstance() { | 160 ChromotingInstance::~ChromotingInstance() { |
| 158 DCHECK(plugin_message_loop_->BelongsToCurrentThread()); | 161 DCHECK(plugin_message_loop_->BelongsToCurrentThread()); |
| 159 | 162 |
| 160 // Detach the log proxy so we don't log anything else to the UI. | 163 // 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. | 164 // This needs to be done before the instance is unregistered for logging. |
| 162 thread_proxy_->Detach(); | 165 //thread_proxy_->Detach(); |
|
Sergey Ulanov
2012/05/30 00:30:37
Did you mean to make this part for this CL?
I'm no
Wez
2012/05/30 00:54:02
We now identify the ChromotingInstance to direct l
| |
| 163 | 166 |
| 164 // Unregister this instance so that debug log messages will no longer be sent | 167 // 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. | 168 // to it. This will stop all logging in all Chromoting instances. |
| 166 UnregisterLoggingInstance(); | 169 UnregisterLoggingInstance(); |
| 167 | 170 |
| 168 if (client_.get()) { | 171 if (client_.get()) { |
| 169 base::WaitableEvent done_event(true, false); | 172 base::WaitableEvent done_event(true, false); |
| 170 client_->Stop(base::Bind(&base::WaitableEvent::Signal, | 173 client_->Stop(base::Bind(&base::WaitableEvent::Signal, |
| 171 base::Unretained(&done_event))); | 174 base::Unretained(&done_event))); |
| 172 done_event.Wait(); | 175 done_event.Wait(); |
| 173 } | 176 } |
| 174 | 177 |
| 175 // Stopping the context shuts down all chromoting threads. | 178 // Stopping the context shuts down all chromoting threads. |
| 176 context_.Stop(); | 179 context_.Stop(); |
| 177 | 180 |
| 178 // Delete |thread_proxy_| before we detach |plugin_message_loop_|, | 181 // 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(); | 182 plugin_message_loop_->Detach(); |
| 183 } | 183 } |
| 184 | 184 |
| 185 bool ChromotingInstance::Init(uint32_t argc, | 185 bool ChromotingInstance::Init(uint32_t argc, |
| 186 const char* argn[], | 186 const char* argn[], |
| 187 const char* argv[]) { | 187 const char* argv[]) { |
| 188 CHECK(!initialized_); | 188 CHECK(!initialized_); |
| 189 initialized_ = true; | 189 initialized_ = true; |
| 190 | 190 |
| 191 VLOG(1) << "Started ChromotingInstance::Init"; | 191 VLOG(1) << "Started ChromotingInstance::Init"; |
| (...skipping 415 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 607 logging::SetLogMessageHandler(&LogToUI); | 607 logging::SetLogMessageHandler(&LogToUI); |
| 608 } | 608 } |
| 609 | 609 |
| 610 void ChromotingInstance::RegisterLoggingInstance() { | 610 void ChromotingInstance::RegisterLoggingInstance() { |
| 611 base::AutoLock lock(g_logging_lock.Get()); | 611 base::AutoLock lock(g_logging_lock.Get()); |
| 612 | 612 |
| 613 // Register this instance as the one that will handle all logging calls | 613 // Register this instance as the one that will handle all logging calls |
| 614 // and display them to the user. | 614 // and display them to the user. |
| 615 // If multiple plugins are run, then the last one registered will handle all | 615 // If multiple plugins are run, then the last one registered will handle all |
| 616 // logging for all instances. | 616 // logging for all instances. |
| 617 g_logging_instance = this; | 617 g_logging_instance = weak_factory_.GetWeakPtr(); |
| 618 g_logging_task_runner = plugin_message_loop_; | |
| 618 g_has_logging_instance = true; | 619 g_has_logging_instance = true; |
| 619 } | 620 } |
| 620 | 621 |
| 621 void ChromotingInstance::UnregisterLoggingInstance() { | 622 void ChromotingInstance::UnregisterLoggingInstance() { |
| 622 base::AutoLock lock(g_logging_lock.Get()); | 623 base::AutoLock lock(g_logging_lock.Get()); |
| 623 | 624 |
| 624 // Don't unregister unless we're the currently registered instance. | 625 // Don't unregister unless we're the currently registered instance. |
| 625 if (this != g_logging_instance) | 626 if (this != g_logging_instance.get()) |
| 626 return; | 627 return; |
| 627 | 628 |
| 628 // Unregister this instance for logging. | 629 // Unregister this instance for logging. |
| 629 g_has_logging_instance = false; | 630 g_has_logging_instance = false; |
| 630 g_logging_instance = NULL; | 631 g_logging_instance.reset(); |
| 632 g_logging_task_runner = NULL; | |
| 631 | 633 |
| 632 VLOG(1) << "Unregistering global log handler"; | 634 VLOG(1) << "Unregistering global log handler"; |
| 633 } | 635 } |
| 634 | 636 |
| 635 // static | 637 // static |
| 636 bool ChromotingInstance::LogToUI(int severity, const char* file, int line, | 638 bool ChromotingInstance::LogToUI(int severity, const char* file, int line, |
| 637 size_t message_start, | 639 size_t message_start, |
| 638 const std::string& str) { | 640 const std::string& str) { |
| 639 // Note that we're reading |g_has_logging_instance| outside of a lock. | 641 // 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 | 642 // This lockless read is done so that we don't needlessly slow down global |
| 641 // logging with a lock for each log message. | 643 // logging with a lock for each log message. |
| 642 // | 644 // |
| 643 // This lockless read is safe because: | 645 // This lockless read is safe because: |
| 644 // | 646 // |
| 645 // Misreading a false value (when it should be true) means that we'll simply | 647 // Misreading a false value (when it should be true) means that we'll simply |
| 646 // skip processing a few log messages. | 648 // skip processing a few log messages. |
| 647 // | 649 // |
| 648 // Misreading a true value (when it should be false) means that we'll take | 650 // 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 | 651 // the lock and check |g_logging_instance| unnecessarily. This is not |
| 650 // problematic because we always set |g_logging_instance| inside a lock. | 652 // problematic because we always set |g_logging_instance| inside a lock. |
| 651 if (g_has_logging_instance) { | 653 if (g_has_logging_instance) { |
| 652 // Do not LOG anything while holding this lock or else the code will | 654 scoped_refptr<base::SingleThreadTaskRunner> logging_task_runner; |
| 653 // deadlock while trying to re-get the lock we're already in. | 655 |
| 654 base::AutoLock lock(g_logging_lock.Get()); | 656 { |
| 655 if (g_logging_instance && | 657 base::AutoLock lock(g_logging_lock.Get()); |
| 656 // If |g_logging_to_plugin| is set and we're on the logging thread, then | 658 // 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 | 659 // this LOG action was generated while processing a previous one, in which |
| 658 // should skip it to avoid an infinite loop of LOG messages. | 660 // case we |
|
Wez
2012/05/30 00:54:02
Gah, uploaded mid-edit!
| |
| 659 // We don't have a lock around |g_in_processtoui|, but that's OK since | 661 // If |g_logging_to_plugin| is set and we're on the logging thread, then |
| 660 // the value is only read/written on the logging thread. | 662 // this LOG message came from handling a previous LOG message and we |
| 661 (!g_logging_instance->plugin_message_loop_->BelongsToCurrentThread() || | 663 // should skip it to avoid an infinite loop of LOG messages. |
| 662 !g_logging_to_plugin)) { | 664 // We don't have a lock around |g_in_processtoui|, but that's OK since |
| 665 // the value is only read/written on the logging thread. | |
| 666 if (!g_logging_task_runner->BelongsToCurrentThread() || | |
| 667 !g_logging_to_plugin) { | |
| 668 logging_task_runner = g_logging_task_runner; | |
| 669 } | |
| 670 } | |
| 671 | |
| 672 if (logging_task_runner.get()) { | |
| 663 std::string message = remoting::GetTimestampString(); | 673 std::string message = remoting::GetTimestampString(); |
| 664 message += (str.c_str() + message_start); | 674 message += (str.c_str() + message_start); |
| 665 // |thread_proxy_| is safe to use here because we detach it before | 675 |
| 666 // tearing down the |g_logging_instance|. | 676 g_logging_task_runner->PostTask( |
| 667 g_logging_instance->thread_proxy_->PostTask( | |
| 668 FROM_HERE, base::Bind(&ChromotingInstance::ProcessLogToUI, | 677 FROM_HERE, base::Bind(&ChromotingInstance::ProcessLogToUI, |
| 669 base::Unretained(g_logging_instance), message)); | 678 g_logging_instance, message)); |
| 670 } | 679 } |
| 671 } | 680 } |
| 672 | 681 |
| 673 if (g_logging_old_handler) | 682 if (g_logging_old_handler) |
| 674 return (g_logging_old_handler)(severity, file, line, message_start, str); | 683 return (g_logging_old_handler)(severity, file, line, message_start, str); |
| 675 return false; | 684 return false; |
| 676 } | 685 } |
| 677 | 686 |
| 678 void ChromotingInstance::ProcessLogToUI(const std::string& message) { | 687 void ChromotingInstance::ProcessLogToUI(const std::string& message) { |
| 679 DCHECK(plugin_message_loop_->BelongsToCurrentThread()); | 688 DCHECK(plugin_message_loop_->BelongsToCurrentThread()); |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 692 } | 701 } |
| 693 g_logging_to_plugin = false; | 702 g_logging_to_plugin = false; |
| 694 } | 703 } |
| 695 | 704 |
| 696 bool ChromotingInstance::IsConnected() { | 705 bool ChromotingInstance::IsConnected() { |
| 697 return host_connection_.get() && | 706 return host_connection_.get() && |
| 698 (host_connection_->state() == protocol::ConnectionToHost::CONNECTED); | 707 (host_connection_->state() == protocol::ConnectionToHost::CONNECTED); |
| 699 } | 708 } |
| 700 | 709 |
| 701 } // namespace remoting | 710 } // namespace remoting |
| OLD | NEW |