OLD | NEW |
---|---|
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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/host/plugin/host_script_object.h" | 5 #include "remoting/host/plugin/host_script_object.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/message_loop.h" | 8 #include "base/message_loop.h" |
9 #include "base/message_loop_proxy.h" | 9 #include "base/message_loop_proxy.h" |
10 #include "base/threading/platform_thread.h" | 10 #include "base/threading/platform_thread.h" |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
65 const char* kAttrNameError = "ERROR"; | 65 const char* kAttrNameError = "ERROR"; |
66 | 66 |
67 const int kMaxLoginAttempts = 5; | 67 const int kMaxLoginAttempts = 5; |
68 | 68 |
69 } // namespace | 69 } // namespace |
70 | 70 |
71 // This flag blocks LOGs to the UI if we're already in the middle of logging | 71 // This flag blocks LOGs to the UI if we're already in the middle of logging |
72 // to the UI. This prevents a potential infinite loop if we encounter an error | 72 // to the UI. This prevents a potential infinite loop if we encounter an error |
73 // while sending the log message to the UI. | 73 // while sending the log message to the UI. |
74 static bool g_logging_to_plugin = false; | 74 static bool g_logging_to_plugin = false; |
75 static bool g_has_registered_log_handler = false; | |
75 static HostNPScriptObject* g_logging_scriptable_object = NULL; | 76 static HostNPScriptObject* g_logging_scriptable_object = NULL; |
76 static logging::LogMessageHandlerFunction g_logging_old_handler = NULL; | 77 static logging::LogMessageHandlerFunction g_logging_old_handler = NULL; |
77 | 78 |
78 HostNPScriptObject::HostNPScriptObject(NPP plugin, NPObject* parent) | 79 HostNPScriptObject::HostNPScriptObject(NPP plugin, NPObject* parent) |
79 : plugin_(plugin), | 80 : plugin_(plugin), |
80 parent_(parent), | 81 parent_(parent), |
81 state_(kDisconnected), | 82 state_(kDisconnected), |
82 log_debug_info_func_(NULL), | 83 log_debug_info_func_(NULL), |
83 on_state_changed_func_(NULL), | 84 on_state_changed_func_(NULL), |
84 np_thread_id_(base::PlatformThread::CurrentId()), | 85 np_thread_id_(base::PlatformThread::CurrentId()), |
85 failed_login_attempts_(0), | 86 failed_login_attempts_(0), |
86 disconnected_event_(true, false) { | 87 disconnected_event_(true, false) { |
87 // Set up log message handler. | 88 // Register this script object as the one that will handle all logging calls |
88 // Note that this approach doesn't quite support having multiple instances | 89 // and display them to the user. |
89 // of Chromoting running. In that case, the most recently opened tab will | 90 // If multiple plugins are run, then the last one registered will handle all |
90 // grab all the debug log messages, and when any Chromoting tab is closed | 91 // logging for all instances. |
91 // the logging handler will go away. | |
92 // Since having multiple Chromoting tabs is not a primary use case, and this | |
93 // is just debug logging, we're punting improving debug log support for that | |
94 // case. | |
95 if (g_logging_old_handler == NULL) | |
96 g_logging_old_handler = logging::GetLogMessageHandler(); | |
97 logging::SetLogMessageHandler(&LogToUI); | |
98 g_logging_scriptable_object = this; | 92 g_logging_scriptable_object = this; |
99 | 93 |
100 VLOG(2) << "HostNPScriptObject"; | 94 VLOG(2) << "HostNPScriptObject"; |
101 host_context_.SetUITaskPostFunction(base::Bind( | 95 host_context_.SetUITaskPostFunction(base::Bind( |
102 &HostNPScriptObject::PostTaskToNPThread, base::Unretained(this))); | 96 &HostNPScriptObject::PostTaskToNPThread, base::Unretained(this))); |
103 } | 97 } |
104 | 98 |
105 HostNPScriptObject::~HostNPScriptObject() { | 99 HostNPScriptObject::~HostNPScriptObject() { |
106 CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_); | 100 CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_); |
107 | 101 |
108 // Shutdown DesktopEnvironment first so that it doesn't try to post | 102 // Shutdown DesktopEnvironment first so that it doesn't try to post |
109 // tasks on the UI thread while we are stopping the host. | 103 // tasks on the UI thread while we are stopping the host. |
110 desktop_environment_->Shutdown(); | 104 desktop_environment_->Shutdown(); |
111 | 105 |
112 logging::SetLogMessageHandler(g_logging_old_handler); | 106 // Unregister this script object for logging. |
113 g_logging_old_handler = NULL; | 107 // If there are multiple instances and this is the one that was registered |
108 // last, then all logging to the UI will be stopped. | |
114 g_logging_scriptable_object = NULL; | 109 g_logging_scriptable_object = NULL; |
115 | 110 |
116 // Disconnect synchronously. We cannot disconnect asynchronously | 111 // Disconnect synchronously. We cannot disconnect asynchronously |
117 // here because |host_context_| needs to be stopped on the plugin | 112 // here because |host_context_| needs to be stopped on the plugin |
118 // thread, but the plugin thread may not exist after the instance | 113 // thread, but the plugin thread may not exist after the instance |
119 // is destroyed. | 114 // is destroyed. |
120 destructing_.Set(); | 115 destructing_.Set(); |
121 disconnected_event_.Reset(); | 116 disconnected_event_.Reset(); |
122 DisconnectInternal(); | 117 DisconnectInternal(); |
123 disconnected_event_.Wait(); | 118 disconnected_event_.Wait(); |
(...skipping 401 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
525 } | 520 } |
526 state_ = state; | 521 state_ = state; |
527 if (on_state_changed_func_) { | 522 if (on_state_changed_func_) { |
528 VLOG(2) << "Calling state changed " << state; | 523 VLOG(2) << "Calling state changed " << state; |
529 bool is_good = InvokeAndIgnoreResult(on_state_changed_func_, NULL, 0); | 524 bool is_good = InvokeAndIgnoreResult(on_state_changed_func_, NULL, 0); |
530 LOG_IF(ERROR, !is_good) << "OnStateChanged failed"; | 525 LOG_IF(ERROR, !is_good) << "OnStateChanged failed"; |
531 } | 526 } |
532 } | 527 } |
533 | 528 |
534 // static | 529 // static |
530 void HostNPScriptObject::RegisterLogger() { | |
531 DCHECK(!g_has_registered_log_handler); | |
532 | |
533 LOG(INFO) << "Registering global log handler"; | |
534 | |
535 // Record previous handler so we can call it in a chain. | |
536 g_logging_old_handler = logging::GetLogMessageHandler(); | |
537 | |
538 // Set up log message handler. | |
539 // Note that this will not log anything until a scriptable object instance | |
540 // has been created to handle the log message display. | |
541 logging::SetLogMessageHandler(&LogToUI); | |
542 | |
543 g_has_registered_log_handler = true; | |
544 } | |
545 | |
546 // static | |
547 void HostNPScriptObject::UnregisterLogger() { | |
548 // Restore previous handler. | |
549 logging::SetLogMessageHandler(g_logging_old_handler); | |
550 g_logging_old_handler = NULL; | |
551 g_has_registered_log_handler = false; | |
552 | |
553 LOG(INFO) << "Unregistering global log handler"; | |
Wez
2011/08/16 00:05:45
Why not have these in host_plugin.cc, since that's
garykac
2011/08/16 00:19:40
Because having it here keeps all of the logic (and
Wez
2011/08/16 00:30:52
Could they live in their own code file? The only
garykac
2011/08/29 23:27:15
Done.
| |
554 } | |
555 | |
556 // static | |
535 bool HostNPScriptObject::LogToUI(int severity, const char* file, int line, | 557 bool HostNPScriptObject::LogToUI(int severity, const char* file, int line, |
536 size_t message_start, | 558 size_t message_start, |
537 const std::string& str) { | 559 const std::string& str) { |
538 // The |g_logging_to_plugin| check is to prevent logging to the scriptable | 560 // The |g_logging_to_plugin| check is to prevent logging to the scriptable |
539 // object if we're already in the middle of logging. | 561 // object if we're already in the middle of logging. |
540 // This can occur if we try to log an error while we're in the scriptable | 562 // This can occur if we try to log an error while we're in the scriptable |
541 // object logging code. | 563 // object logging code. |
542 if (g_logging_scriptable_object && !g_logging_to_plugin) { | 564 if (g_logging_scriptable_object && !g_logging_to_plugin) { |
543 g_logging_to_plugin = true; | 565 g_logging_to_plugin = true; |
544 std::string message = remoting::GetTimestampString(); | 566 std::string message = remoting::GetTimestampString(); |
545 message += (str.c_str() + message_start); | 567 message += (str.c_str() + message_start); |
546 g_logging_scriptable_object->LogDebugInfo(message); | 568 g_logging_scriptable_object->LogDebugInfo(message); |
Wez
2011/08/16 00:05:45
Are we guaranteed that LogToUI will always be call
garykac
2011/08/16 00:19:40
I don't think so, but LogDebugInfo below switches
Wez
2011/08/16 00:30:52
To do that, though, it touches members of the Host
garykac
2011/08/29 23:27:15
Note that the code has changed.
For logging, it n
| |
547 g_logging_to_plugin = false; | 569 g_logging_to_plugin = false; |
548 } | 570 } |
549 if (g_logging_old_handler) | 571 if (g_logging_old_handler) |
550 return (g_logging_old_handler)(severity, file, line, message_start, str); | 572 return (g_logging_old_handler)(severity, file, line, message_start, str); |
551 return false; | 573 return false; |
552 } | 574 } |
553 | 575 |
554 void HostNPScriptObject::LogDebugInfo(const std::string& message) { | 576 void HostNPScriptObject::LogDebugInfo(const std::string& message) { |
555 if (destructing_.IsSet()) | 577 if (destructing_.IsSet()) |
556 return; | 578 return; |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
603 } | 625 } |
604 | 626 |
605 // static | 627 // static |
606 void HostNPScriptObject::NPTaskSpringboard(void* task) { | 628 void HostNPScriptObject::NPTaskSpringboard(void* task) { |
607 base::Closure* real_task = reinterpret_cast<base::Closure*>(task); | 629 base::Closure* real_task = reinterpret_cast<base::Closure*>(task); |
608 real_task->Run(); | 630 real_task->Run(); |
609 delete real_task; | 631 delete real_task; |
610 } | 632 } |
611 | 633 |
612 } // namespace remoting | 634 } // namespace remoting |
OLD | NEW |