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 static scoped_refptr<base::MessageLoopProxy> g_logging_message_loop; |
|
Sergey Ulanov
2012/05/29 18:58:30
This adds a static finalizer. Use CR_DEFINE_STATIC
Sergey Ulanov
2012/05/29 18:58:30
SingleThreadTaskRunner please.
Wez
2012/05/30 00:18:39
Done.
Wez
2012/05/30 00:18:39
Done.
| |
| 101 static base::WeakPtr<ChromotingInstance> g_logging_instance; | |
|
Sergey Ulanov
2012/05/29 18:58:30
This adds a static finalizer. Use CR_DEFINE_STATIC
Wez
2012/05/30 00:18:39
Done.
| |
| 101 static logging::LogMessageHandlerFunction g_logging_old_handler = NULL; | 102 static logging::LogMessageHandlerFunction g_logging_old_handler = NULL; |
| 102 | 103 |
| 103 static base::LazyInstance<base::Lock>::Leaky | 104 static base::LazyInstance<base::Lock>::Leaky |
| 104 g_logging_lock = LAZY_INSTANCE_INITIALIZER; | 105 g_logging_lock = LAZY_INSTANCE_INITIALIZER; |
| 105 | 106 |
| 106 // String sent in the "hello" message to the plugin to describe features. | 107 // String sent in the "hello" message to the plugin to describe features. |
| 107 const char ChromotingInstance::kApiFeatures[] = | 108 const char ChromotingInstance::kApiFeatures[] = |
| 108 "highQualityScaling injectKeyEvent sendClipboardItem remapKey trapKey " | 109 "highQualityScaling injectKeyEvent sendClipboardItem remapKey trapKey " |
| 109 "notifyClientDimensions pauseVideo"; | 110 "notifyClientDimensions pauseVideo"; |
| 110 | 111 |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 132 | 133 |
| 133 return true; | 134 return true; |
| 134 } | 135 } |
| 135 | 136 |
| 136 ChromotingInstance::ChromotingInstance(PP_Instance pp_instance) | 137 ChromotingInstance::ChromotingInstance(PP_Instance pp_instance) |
| 137 : pp::InstancePrivate(pp_instance), | 138 : pp::InstancePrivate(pp_instance), |
| 138 initialized_(false), | 139 initialized_(false), |
| 139 plugin_message_loop_( | 140 plugin_message_loop_( |
| 140 new PluginMessageLoopProxy(&plugin_thread_delegate_)), | 141 new PluginMessageLoopProxy(&plugin_thread_delegate_)), |
| 141 context_(plugin_message_loop_), | 142 context_(plugin_message_loop_), |
| 142 thread_proxy_(new ScopedThreadProxy(plugin_message_loop_)) { | 143 weak_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { |
| 143 RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE | PP_INPUTEVENT_CLASS_WHEEL); | 144 RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE | PP_INPUTEVENT_CLASS_WHEEL); |
| 144 RequestFilteringInputEvents(PP_INPUTEVENT_CLASS_KEYBOARD); | 145 RequestFilteringInputEvents(PP_INPUTEVENT_CLASS_KEYBOARD); |
| 145 | 146 |
| 146 // Resister this instance to handle debug log messsages. | 147 // Resister this instance to handle debug log messsages. |
| 147 RegisterLoggingInstance(); | 148 RegisterLoggingInstance(); |
| 148 | 149 |
| 149 // Send hello message. | 150 // Send hello message. |
| 150 scoped_ptr<base::DictionaryValue> data(new base::DictionaryValue()); | 151 scoped_ptr<base::DictionaryValue> data(new base::DictionaryValue()); |
| 151 data->SetInteger("apiVersion", kApiVersion); | 152 data->SetInteger("apiVersion", kApiVersion); |
| 152 data->SetString("apiFeatures", kApiFeatures); | 153 data->SetString("apiFeatures", kApiFeatures); |
| 153 data->SetInteger("apiMinVersion", kApiMinMessagingVersion); | 154 data->SetInteger("apiMinVersion", kApiMinMessagingVersion); |
| 154 PostChromotingMessage("hello", data.Pass()); | 155 PostChromotingMessage("hello", data.Pass()); |
| 155 } | 156 } |
| 156 | 157 |
| 157 ChromotingInstance::~ChromotingInstance() { | 158 ChromotingInstance::~ChromotingInstance() { |
| 158 DCHECK(plugin_message_loop_->BelongsToCurrentThread()); | 159 DCHECK(plugin_message_loop_->BelongsToCurrentThread()); |
| 159 | 160 |
| 160 // Detach the log proxy so we don't log anything else to the UI. | 161 // 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 // This needs to be done before the instance is unregistered for logging. |
| 162 thread_proxy_->Detach(); | 163 //thread_proxy_->Detach(); |
| 163 | 164 |
| 164 // Unregister this instance so that debug log messages will no longer be sent | 165 // 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. | 166 // to it. This will stop all logging in all Chromoting instances. |
| 166 UnregisterLoggingInstance(); | 167 UnregisterLoggingInstance(); |
| 167 | 168 |
| 168 if (client_.get()) { | 169 if (client_.get()) { |
| 169 base::WaitableEvent done_event(true, false); | 170 base::WaitableEvent done_event(true, false); |
| 170 client_->Stop(base::Bind(&base::WaitableEvent::Signal, | 171 client_->Stop(base::Bind(&base::WaitableEvent::Signal, |
| 171 base::Unretained(&done_event))); | 172 base::Unretained(&done_event))); |
| 172 done_event.Wait(); | 173 done_event.Wait(); |
| 173 } | 174 } |
| 174 | 175 |
| 175 // Stopping the context shuts down all chromoting threads. | 176 // Stopping the context shuts down all chromoting threads. |
| 176 context_.Stop(); | 177 context_.Stop(); |
| 177 | 178 |
| 178 // Delete |thread_proxy_| before we detach |plugin_message_loop_|, | 179 // 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(); | 180 plugin_message_loop_->Detach(); |
| 183 } | 181 } |
| 184 | 182 |
| 185 bool ChromotingInstance::Init(uint32_t argc, | 183 bool ChromotingInstance::Init(uint32_t argc, |
| 186 const char* argn[], | 184 const char* argn[], |
| 187 const char* argv[]) { | 185 const char* argv[]) { |
| 188 CHECK(!initialized_); | 186 CHECK(!initialized_); |
| 189 initialized_ = true; | 187 initialized_ = true; |
| 190 | 188 |
| 191 VLOG(1) << "Started ChromotingInstance::Init"; | 189 VLOG(1) << "Started ChromotingInstance::Init"; |
| (...skipping 415 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 607 logging::SetLogMessageHandler(&LogToUI); | 605 logging::SetLogMessageHandler(&LogToUI); |
| 608 } | 606 } |
| 609 | 607 |
| 610 void ChromotingInstance::RegisterLoggingInstance() { | 608 void ChromotingInstance::RegisterLoggingInstance() { |
| 611 base::AutoLock lock(g_logging_lock.Get()); | 609 base::AutoLock lock(g_logging_lock.Get()); |
| 612 | 610 |
| 613 // Register this instance as the one that will handle all logging calls | 611 // Register this instance as the one that will handle all logging calls |
| 614 // and display them to the user. | 612 // and display them to the user. |
| 615 // If multiple plugins are run, then the last one registered will handle all | 613 // If multiple plugins are run, then the last one registered will handle all |
| 616 // logging for all instances. | 614 // logging for all instances. |
| 617 g_logging_instance = this; | 615 g_logging_instance = weak_factory_.GetWeakPtr(); |
| 616 g_logging_message_loop = plugin_message_loop_; | |
| 618 g_has_logging_instance = true; | 617 g_has_logging_instance = true; |
| 619 } | 618 } |
| 620 | 619 |
| 621 void ChromotingInstance::UnregisterLoggingInstance() { | 620 void ChromotingInstance::UnregisterLoggingInstance() { |
| 622 base::AutoLock lock(g_logging_lock.Get()); | 621 base::AutoLock lock(g_logging_lock.Get()); |
| 623 | 622 |
| 624 // Don't unregister unless we're the currently registered instance. | 623 // Don't unregister unless we're the currently registered instance. |
| 625 if (this != g_logging_instance) | 624 if (this != g_logging_instance.get()) |
| 626 return; | 625 return; |
| 627 | 626 |
| 628 // Unregister this instance for logging. | 627 // Unregister this instance for logging. |
| 629 g_has_logging_instance = false; | 628 g_has_logging_instance = false; |
| 630 g_logging_instance = NULL; | 629 g_logging_instance.reset(); |
| 630 g_logging_message_loop = NULL; | |
| 631 | 631 |
| 632 VLOG(1) << "Unregistering global log handler"; | 632 VLOG(1) << "Unregistering global log handler"; |
| 633 } | 633 } |
| 634 | 634 |
| 635 // static | 635 // static |
| 636 bool ChromotingInstance::LogToUI(int severity, const char* file, int line, | 636 bool ChromotingInstance::LogToUI(int severity, const char* file, int line, |
| 637 size_t message_start, | 637 size_t message_start, |
| 638 const std::string& str) { | 638 const std::string& str) { |
| 639 // Note that we're reading |g_has_logging_instance| outside of a lock. | 639 // 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 | 640 // This lockless read is done so that we don't needlessly slow down global |
| 641 // logging with a lock for each log message. | 641 // logging with a lock for each log message. |
| 642 // | 642 // |
| 643 // This lockless read is safe because: | 643 // This lockless read is safe because: |
| 644 // | 644 // |
| 645 // Misreading a false value (when it should be true) means that we'll simply | 645 // Misreading a false value (when it should be true) means that we'll simply |
| 646 // skip processing a few log messages. | 646 // skip processing a few log messages. |
| 647 // | 647 // |
| 648 // Misreading a true value (when it should be false) means that we'll take | 648 // 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 | 649 // the lock and check |g_logging_instance| unnecessarily. This is not |
| 650 // problematic because we always set |g_logging_instance| inside a lock. | 650 // problematic because we always set |g_logging_instance| inside a lock. |
| 651 if (g_has_logging_instance) { | 651 if (g_has_logging_instance) { |
| 652 // Do not LOG anything while holding this lock or else the code will | 652 // Do not LOG anything while holding this lock or else the code will |
| 653 // deadlock while trying to re-get the lock we're already in. | 653 // deadlock while trying to re-get the lock we're already in. |
| 654 base::AutoLock lock(g_logging_lock.Get()); | 654 base::AutoLock lock(g_logging_lock.Get()); |
| 655 if (g_logging_instance && | 655 if (g_logging_message_loop.get() && |
| 656 // If |g_logging_to_plugin| is set and we're on the logging thread, then | 656 // If |g_logging_to_plugin| is set and we're on the logging thread, then |
| 657 // this LOG message came from handling a previous LOG message and we | 657 // this LOG message came from handling a previous LOG message and we |
| 658 // should skip it to avoid an infinite loop of LOG messages. | 658 // 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 | 659 // We don't have a lock around |g_in_processtoui|, but that's OK since |
| 660 // the value is only read/written on the logging thread. | 660 // the value is only read/written on the logging thread. |
| 661 (!g_logging_instance->plugin_message_loop_->BelongsToCurrentThread() || | 661 (!g_logging_message_loop->BelongsToCurrentThread() || |
|
Sergey Ulanov
2012/05/29 18:58:30
Races are still possible in this code. The logging
Wez
2012/05/30 00:18:39
There is already a lock held at this point (g_logg
| |
| 662 !g_logging_to_plugin)) { | 662 !g_logging_to_plugin)) { |
| 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_message_loop->PostTask( |
| 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, message)); |
| 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()); |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 692 } | 691 } |
| 693 g_logging_to_plugin = false; | 692 g_logging_to_plugin = false; |
| 694 } | 693 } |
| 695 | 694 |
| 696 bool ChromotingInstance::IsConnected() { | 695 bool ChromotingInstance::IsConnected() { |
| 697 return host_connection_.get() && | 696 return host_connection_.get() && |
| 698 (host_connection_->state() == protocol::ConnectionToHost::CONNECTED); | 697 (host_connection_->state() == protocol::ConnectionToHost::CONNECTED); |
| 699 } | 698 } |
| 700 | 699 |
| 701 } // namespace remoting | 700 } // namespace remoting |
| OLD | NEW |