Index: remoting/host/plugin/host_script_object.cc |
diff --git a/remoting/host/plugin/host_script_object.cc b/remoting/host/plugin/host_script_object.cc |
index 035641fe8d7885ec0e8dd9ff25a32e6b4daa261e..460458dccc1089567b9370b021c6b679baab5d32 100644 |
--- a/remoting/host/plugin/host_script_object.cc |
+++ b/remoting/host/plugin/host_script_object.cc |
@@ -8,6 +8,7 @@ |
#include "base/message_loop.h" |
#include "base/threading/platform_thread.h" |
#include "remoting/base/auth_token_util.h" |
+#include "remoting/base/util.h" |
#include "remoting/host/chromoting_host.h" |
#include "remoting/host/chromoting_host_context.h" |
#include "remoting/host/desktop_environment.h" |
@@ -66,6 +67,13 @@ const int kMaxLoginAttempts = 5; |
} // namespace |
+// This flag blocks LOGs to the UI if we're already in the middle of logging |
+// to the UI. This prevents a potential infinite loop if we encounter an error |
+// while sending the log message to the UI. |
+static bool g_logging_to_plugin = false; |
+static HostNPScriptObject* g_logging_scriptable_object = NULL; |
+static logging::LogMessageHandlerFunction g_logging_old_handler = NULL; |
+ |
HostNPScriptObject::HostNPScriptObject(NPP plugin, NPObject* parent) |
: plugin_(plugin), |
parent_(parent), |
@@ -75,8 +83,20 @@ HostNPScriptObject::HostNPScriptObject(NPP plugin, NPObject* parent) |
np_thread_id_(base::PlatformThread::CurrentId()), |
failed_login_attempts_(0), |
disconnected_event_(true, false) { |
- logger_.reset(new HostPluginLogger(this)); |
- logger_->VLog(2, "HostNPScriptObject"); |
+ // Set up log message handler. |
+ // Note that this approach doesn't quite support having multiple instances |
+ // of Chromoting running. In that case, the most recently opened tab will |
+ // grab all the debug log messages, and when any Chromoting tab is closed |
+ // the logging handler will go away. |
+ // Since having multiple Chromoting tabs is not a primary use case, and this |
+ // is just debug logging, we're punting improving debug log support for that |
+ // case. |
+ if (g_logging_old_handler == NULL) |
+ g_logging_old_handler = logging::GetLogMessageHandler(); |
+ logging::SetLogMessageHandler(&LogToUI); |
+ g_logging_scriptable_object = this; |
+ |
+ VLOG(2) << "HostNPScriptObject"; |
host_context_.SetUITaskPostFunction(base::Bind( |
&HostNPScriptObject::PostTaskToNPThread, base::Unretained(this))); |
} |
@@ -88,6 +108,10 @@ HostNPScriptObject::~HostNPScriptObject() { |
// tasks on the UI thread while we are stopping the host. |
desktop_environment_->Shutdown(); |
+ logging::SetLogMessageHandler(g_logging_old_handler); |
+ g_logging_old_handler = NULL; |
+ g_logging_scriptable_object = NULL; |
+ |
// Disconnect synchronously. We cannot disconnect asynchronously |
// here because |host_context_| needs to be stopped on the plugin |
// thread, but the plugin thread may not exist after the instance |
@@ -109,14 +133,14 @@ HostNPScriptObject::~HostNPScriptObject() { |
} |
bool HostNPScriptObject::Init() { |
- logger_->VLog(2, "Init"); |
+ VLOG(2) << "Init"; |
// TODO(wez): This starts a bunch of threads, which might fail. |
host_context_.Start(); |
return true; |
} |
bool HostNPScriptObject::HasMethod(const std::string& method_name) { |
- logger_->VLog(2, "HasMethod %s", method_name.c_str()); |
+ VLOG(2) << "HasMethod " << method_name; |
CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_); |
return (method_name == kFuncNameConnect || |
method_name == kFuncNameDisconnect); |
@@ -125,7 +149,7 @@ bool HostNPScriptObject::HasMethod(const std::string& method_name) { |
bool HostNPScriptObject::InvokeDefault(const NPVariant* args, |
uint32_t argCount, |
NPVariant* result) { |
- logger_->VLog(2, "InvokeDefault"); |
+ VLOG(2) << "InvokeDefault"; |
CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_); |
SetException("exception during default invocation"); |
return false; |
@@ -135,7 +159,7 @@ bool HostNPScriptObject::Invoke(const std::string& method_name, |
const NPVariant* args, |
uint32_t argCount, |
NPVariant* result) { |
- logger_->VLog(2, "Invoke %s", method_name.c_str()); |
+ VLOG(2) << "Invoke " << method_name; |
CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_); |
if (method_name == kFuncNameConnect) { |
return Connect(args, argCount, result); |
@@ -148,7 +172,7 @@ bool HostNPScriptObject::Invoke(const std::string& method_name, |
} |
bool HostNPScriptObject::HasProperty(const std::string& property_name) { |
- logger_->VLog(2, "HasProperty %s", property_name.c_str()); |
+ VLOG(2) << "HasProperty " << property_name; |
CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_); |
return (property_name == kAttrNameAccessCode || |
property_name == kAttrNameAccessCodeLifetime || |
@@ -166,7 +190,7 @@ bool HostNPScriptObject::HasProperty(const std::string& property_name) { |
bool HostNPScriptObject::GetProperty(const std::string& property_name, |
NPVariant* result) { |
- logger_->VLog(2, "GetProperty %s", property_name.c_str()); |
+ VLOG(2) << "GetProperty " << property_name; |
CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_); |
if (!result) { |
SetException("GetProperty: NULL result"); |
@@ -217,7 +241,7 @@ bool HostNPScriptObject::GetProperty(const std::string& property_name, |
bool HostNPScriptObject::SetProperty(const std::string& property_name, |
const NPVariant* value) { |
- logger_->VLog(2, "SetProperty %s", property_name.c_str()); |
+ VLOG(2) << "SetProperty " << property_name; |
CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_); |
if (property_name == kAttrNameOnStateChanged) { |
@@ -258,13 +282,13 @@ bool HostNPScriptObject::SetProperty(const std::string& property_name, |
} |
bool HostNPScriptObject::RemoveProperty(const std::string& property_name) { |
- logger_->VLog(2, "RemoveProperty %s", property_name.c_str()); |
+ VLOG(2) << "RemoveProperty " << property_name; |
CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_); |
return false; |
} |
bool HostNPScriptObject::Enumerate(std::vector<std::string>* values) { |
- logger_->VLog(2, "Enumerate"); |
+ VLOG(2) << "Enumerate"; |
CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_); |
const char* entries[] = { |
kAttrNameAccessCode, |
@@ -330,7 +354,7 @@ bool HostNPScriptObject::Connect(const NPVariant* args, |
NPVariant* result) { |
CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_); |
- LogDebugInfo("Connecting..."); |
+ LOG(INFO) << "Connecting..."; |
if (arg_count != 2) { |
SetException("connect: bad number of arguments"); |
@@ -408,7 +432,7 @@ void HostNPScriptObject::ConnectInternal( |
// TODO(sergeyu): Use firewall traversal policy settings here. |
host_ = ChromotingHost::Create( |
&host_context_, host_config_, desktop_environment_.get(), |
- access_verifier.release(), logger_.get(), false); |
+ access_verifier.release(), false); |
host_->AddStatusObserver(this); |
host_->AddStatusObserver(register_request_.get()); |
host_->set_it2me(true); |
@@ -500,12 +524,32 @@ void HostNPScriptObject::OnStateChanged(State state) { |
} |
state_ = state; |
if (on_state_changed_func_) { |
- logger_->VLog(2, "Calling state changed %s", state); |
+ VLOG(2) << "Calling state changed " << state; |
bool is_good = InvokeAndIgnoreResult(on_state_changed_func_, NULL, 0); |
LOG_IF(ERROR, !is_good) << "OnStateChanged failed"; |
} |
} |
+// static |
+bool HostNPScriptObject::LogToUI(int severity, const char* file, int line, |
+ size_t message_start, |
+ const std::string& str) { |
+ // The |g_logging_to_plugin| check is to prevent logging to the scriptable |
+ // object if we're already in the middle of logging. |
+ // This can occur if we try to log an error while we're in the scriptable |
+ // object logging code. |
+ if (g_logging_scriptable_object && !g_logging_to_plugin) { |
+ g_logging_to_plugin = true; |
+ std::string message = remoting::GetTimestampString(); |
+ message += (str.c_str() + message_start); |
+ g_logging_scriptable_object->LogDebugInfo(message); |
+ g_logging_to_plugin = false; |
+ } |
+ if (g_logging_old_handler) |
+ return (g_logging_old_handler)(severity, file, line, message_start, str); |
+ return false; |
+} |
+ |
void HostNPScriptObject::LogDebugInfo(const std::string& message) { |
if (destructing_.IsSet()) |
return; |
@@ -516,6 +560,7 @@ void HostNPScriptObject::LogDebugInfo(const std::string& message) { |
base::Unretained(this), message)); |
return; |
} |
+ |
if (log_debug_info_func_) { |
NPVariant* arg = new NPVariant(); |
STRINGZ_TO_NPVARIANT(message.c_str(), *arg); |
@@ -527,7 +572,7 @@ void HostNPScriptObject::LogDebugInfo(const std::string& message) { |
void HostNPScriptObject::SetException(const std::string& exception_string) { |
CHECK_EQ(base::PlatformThread::CurrentId(), np_thread_id_); |
g_npnetscape_funcs->setexception(parent_, exception_string.c_str()); |
- LogDebugInfo(exception_string); |
+ LOG(INFO) << exception_string; |
} |
bool HostNPScriptObject::InvokeAndIgnoreResult(NPObject* func, |