Home | History | Annotate | Download | only in plugin
      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
      3 // found in the LICENSE file.
      4 
      5 #include "remoting/host/plugin/host_log_handler.h"
      6 
      7 #include "base/lazy_instance.h"
      8 #include "remoting/base/logging.h"
      9 #include "remoting/base/util.h"
     10 #include "remoting/host/plugin/host_script_object.h"
     11 
     12 namespace remoting {
     13 
     14 // Records whether or not we have a scriptable object registered for logging.
     15 // This is set inside the lock, but is read (in LogToUI) outside of a lock so
     16 // that we don't needlessly slow down the system when we log.
     17 static bool g_has_logging_scriptable_object = false;
     18 
     19 // The lock that protects the logging globals.
     20 static base::LazyInstance<base::Lock>::Leaky
     21     g_logging_lock = LAZY_INSTANCE_INITIALIZER;
     22 
     23 // The scriptable object that will display the log information to the user.
     24 static HostNPScriptObject* g_logging_scriptable_object = NULL;
     25 
     26 // The previously registered LogMessageHandler. If not NULL, we call this after
     27 // we're doing processing the log message.
     28 static logging::LogMessageHandlerFunction g_logging_old_handler = NULL;
     29 
     30 // Set to true when we register our global log handler so that we don't try
     31 // to register it twice.
     32 static bool g_has_registered_log_handler = false;
     33 
     34 // static
     35 void HostLogHandler::RegisterLogMessageHandler() {
     36   base::AutoLock lock(g_logging_lock.Get());
     37 
     38   if (g_has_registered_log_handler)
     39     return;
     40 
     41   HOST_LOG << "Registering global log handler";
     42 
     43   // Record previous handler so we can call it in a chain.
     44   g_logging_old_handler = logging::GetLogMessageHandler();
     45 
     46   // Set up log message handler.
     47   // This is not thread-safe so we need it within our lock.
     48   // Note that this will not log anything until a scriptable object instance
     49   // has been created to handle the log message display.
     50   logging::SetLogMessageHandler(&LogToUI);
     51   g_has_registered_log_handler = true;
     52 }
     53 
     54 // static
     55 void HostLogHandler::RegisterLoggingScriptObject(
     56     HostNPScriptObject* script_object) {
     57   base::AutoLock lock(g_logging_lock.Get());
     58 
     59   VLOG(1) << "Registering log handler scriptable object";
     60 
     61   // Register this script object as the one that will handle all logging calls
     62   // and display them to the user.
     63   // If multiple plugins are run, then the last one registered will handle all
     64   // logging for all instances.
     65   g_logging_scriptable_object = script_object;
     66   g_has_logging_scriptable_object = true;
     67 }
     68 
     69 // static
     70 void HostLogHandler::UnregisterLoggingScriptObject(
     71     HostNPScriptObject* script_object) {
     72   base::AutoLock lock(g_logging_lock.Get());
     73 
     74   // Ignore unless we're the currently registered script object.
     75   if (script_object != g_logging_scriptable_object)
     76     return;
     77 
     78   // Unregister this script object for logging.
     79   g_has_logging_scriptable_object = false;
     80   g_logging_scriptable_object = NULL;
     81 
     82   VLOG(1) << "Unregistering log handler scriptable object";
     83 }
     84 
     85 // static
     86 bool HostLogHandler::LogToUI(int severity, const char* file, int line,
     87                              size_t message_start,
     88                              const std::string& str) {
     89   // Note: We're reading |g_has_logging_scriptable_object| outside of a lock.
     90   // This lockless read is done so that we don't needlessly slow down global
     91   // logging with a lock for each log message.
     92   //
     93   // This lockless read is safe because:
     94   //
     95   // Misreading a false value (when it should be true) means that we'll simply
     96   // skip processing a few log messages.
     97   //
     98   // Misreading a true value (when it should be false) means that we'll take
     99   // the lock and check |g_logging_scriptable_object| unnecessarily. This is not
    100   // problematic because we always set |g_logging_scriptable_object| inside a
    101   // lock.
    102   //
    103   // Misreading an old cached value is also not problematic for the same
    104   // reasons: a mis-read either skips a log message or causes us to take a lock
    105   // unnecessarily.
    106   if (g_has_logging_scriptable_object) {
    107     base::AutoLock lock(g_logging_lock.Get());
    108 
    109     if (g_logging_scriptable_object) {
    110       std::string message = remoting::GetTimestampString();
    111       message += (str.c_str() + message_start);
    112       g_logging_scriptable_object->PostLogDebugInfo(message);
    113     }
    114   }
    115 
    116   // Call the next log handler in the chain.
    117   if (g_logging_old_handler)
    118     return (g_logging_old_handler)(severity, file, line, message_start, str);
    119 
    120   return false;
    121 }
    122 
    123 }  // namespace remoting
    124