| OLD | NEW | 
| (Empty) |  | 
 |    1 // Copyright (c) 2006-2008 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 "ipc/ipc_logging.h" | 
 |    6  | 
 |    7 #if defined(OS_POSIX) | 
 |    8 #ifdef IPC_MESSAGE_LOG_ENABLED | 
 |    9 // This will cause render_messages.h etc to define ViewMsgLog and friends. | 
 |   10 #define IPC_MESSAGE_MACROS_LOG_ENABLED | 
 |   11 #endif | 
 |   12 #endif | 
 |   13  | 
 |   14 #include "base/command_line.h" | 
 |   15 #include "base/logging.h" | 
 |   16 #include "base/message_loop.h" | 
 |   17 #include "base/string_util.h" | 
 |   18 #include "base/thread.h" | 
 |   19 #include "base/time.h" | 
 |   20 #include "base/waitable_event.h" | 
 |   21 #include "base/waitable_event_watcher.h" | 
 |   22 #include "ipc/ipc_switches.h" | 
 |   23 #include "ipc/ipc_sync_message.h" | 
 |   24 #include "ipc/ipc_message_utils.h" | 
 |   25  | 
 |   26 #if defined(OS_POSIX) | 
 |   27 #include "base/string_util.h" | 
 |   28 #include <unistd.h> | 
 |   29 #endif | 
 |   30  | 
 |   31 #ifdef IPC_MESSAGE_LOG_ENABLED | 
 |   32  | 
 |   33 using base::Time; | 
 |   34  | 
 |   35 // IPC::Logging is allocated as a singleton, so we don't need any kind of | 
 |   36 // special retention program. | 
 |   37 template <> | 
 |   38 struct RunnableMethodTraits<IPC::Logging> { | 
 |   39   static void RetainCallee(IPC::Logging*) {} | 
 |   40   static void ReleaseCallee(IPC::Logging*) {} | 
 |   41 }; | 
 |   42  | 
 |   43 namespace IPC { | 
 |   44  | 
 |   45 const wchar_t kLoggingEventName[] = L"ChromeIPCLog.%d"; | 
 |   46 const int kLogSendDelayMs = 100; | 
 |   47  | 
 |   48 // We use a pointer to the function table to avoid any linker dependencies on | 
 |   49 // all the traits used as IPC message parameters. | 
 |   50 Logging::LogFunction *Logging::log_function_mapping_; | 
 |   51  | 
 |   52 Logging::Logging() | 
 |   53     : logging_event_on_(NULL), | 
 |   54       logging_event_off_(NULL), | 
 |   55       enabled_(false), | 
 |   56       queue_invoke_later_pending_(false), | 
 |   57       sender_(NULL), | 
 |   58       main_thread_(MessageLoop::current()), | 
 |   59       consumer_(NULL) { | 
 |   60   // Create an event for this browser instance that's set when logging is | 
 |   61   // enabled, so child processes can know when logging is enabled. | 
 |   62  | 
 |   63 #if defined(OS_WIN) | 
 |   64   // On Windows we have a couple of named events which switch logging on and | 
 |   65   // off. | 
 |   66   int browser_pid; | 
 |   67   const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess(); | 
 |   68   std::wstring process_type = | 
 |   69     parsed_command_line.GetSwitchValue(switches::kProcessType); | 
 |   70   if (process_type.empty()) { | 
 |   71     browser_pid = GetCurrentProcessId(); | 
 |   72   } else { | 
 |   73     std::wstring channel_name = | 
 |   74         parsed_command_line.GetSwitchValue(switches::kProcessChannelID); | 
 |   75  | 
 |   76     browser_pid = _wtoi(channel_name.c_str()); | 
 |   77     DCHECK(browser_pid != 0); | 
 |   78   } | 
 |   79  | 
 |   80   std::wstring event_name = GetEventName(browser_pid, true); | 
 |   81   logging_event_on_.reset(new base::WaitableEvent( | 
 |   82       CreateEvent(NULL, TRUE, FALSE, event_name.c_str()))); | 
 |   83  | 
 |   84   event_name = GetEventName(browser_pid, false); | 
 |   85   logging_event_off_.reset(new base::WaitableEvent( | 
 |   86       CreateEvent(NULL, TRUE, FALSE, event_name.c_str()))); | 
 |   87  | 
 |   88   RegisterWaitForEvent(true); | 
 |   89 #elif defined(OS_POSIX) | 
 |   90   if (getenv("CHROME_IPC_LOGGING")) | 
 |   91     enabled_ = true; | 
 |   92 #endif | 
 |   93  | 
 |   94   MessageLoop::current()->AddDestructionObserver(this); | 
 |   95 } | 
 |   96  | 
 |   97 Logging::~Logging() { | 
 |   98 } | 
 |   99  | 
 |  100 Logging* Logging::current() { | 
 |  101   return Singleton<Logging>::get(); | 
 |  102 } | 
 |  103  | 
 |  104 void Logging::RegisterWaitForEvent(bool enabled) { | 
 |  105   watcher_.StopWatching(); | 
 |  106   watcher_.StartWatching( | 
 |  107       enabled ? logging_event_on_.get() : logging_event_off_.get(), this); | 
 |  108 } | 
 |  109  | 
 |  110 void Logging::OnWaitableEventSignaled(base::WaitableEvent* event) { | 
 |  111   enabled_ = event == logging_event_on_.get(); | 
 |  112   RegisterWaitForEvent(!enabled_); | 
 |  113 } | 
 |  114  | 
 |  115 void Logging::WillDestroyCurrentMessageLoop() { | 
 |  116   watcher_.StopWatching(); | 
 |  117 } | 
 |  118  | 
 |  119 void Logging::SetLoggerFunctions(LogFunction *functions) { | 
 |  120   log_function_mapping_ = functions; | 
 |  121 } | 
 |  122  | 
 |  123 #if defined(OS_WIN) | 
 |  124 std::wstring Logging::GetEventName(bool enabled) { | 
 |  125   return current()->GetEventName(GetCurrentProcessId(), enabled); | 
 |  126 } | 
 |  127 #endif | 
 |  128  | 
 |  129 std::wstring Logging::GetEventName(int browser_pid, bool enabled) { | 
 |  130   std::wstring result = StringPrintf(kLoggingEventName, browser_pid); | 
 |  131   result += enabled ? L"on" : L"off"; | 
 |  132   return result; | 
 |  133 } | 
 |  134  | 
 |  135 void Logging::SetConsumer(Consumer* consumer) { | 
 |  136   consumer_ = consumer; | 
 |  137 } | 
 |  138  | 
 |  139 void Logging::Enable() { | 
 |  140   logging_event_off_->Reset(); | 
 |  141   logging_event_on_->Signal(); | 
 |  142 } | 
 |  143  | 
 |  144 void Logging::Disable() { | 
 |  145   logging_event_on_->Reset(); | 
 |  146   logging_event_off_->Signal(); | 
 |  147 } | 
 |  148  | 
 |  149 void Logging::OnSendLogs() { | 
 |  150   queue_invoke_later_pending_ = false; | 
 |  151   if (!sender_) | 
 |  152     return; | 
 |  153  | 
 |  154   Message* msg = new Message( | 
 |  155       MSG_ROUTING_CONTROL, IPC_LOGGING_ID, Message::PRIORITY_NORMAL); | 
 |  156   WriteParam(msg, queued_logs_); | 
 |  157   queued_logs_.clear(); | 
 |  158   sender_->Send(msg); | 
 |  159 } | 
 |  160  | 
 |  161 void Logging::SetIPCSender(IPC::Message::Sender* sender) { | 
 |  162   sender_ = sender; | 
 |  163 } | 
 |  164  | 
 |  165 void Logging::OnReceivedLoggingMessage(const Message& message) { | 
 |  166   std::vector<LogData> data; | 
 |  167   void* iter = NULL; | 
 |  168   if (!ReadParam(&message, &iter, &data)) | 
 |  169     return; | 
 |  170  | 
 |  171   for (size_t i = 0; i < data.size(); ++i) { | 
 |  172     Log(data[i]); | 
 |  173   } | 
 |  174 } | 
 |  175  | 
 |  176 void Logging::OnSendMessage(Message* message, const std::string& channel_id) { | 
 |  177   if (!Enabled()) | 
 |  178     return; | 
 |  179  | 
 |  180   if (message->is_reply()) { | 
 |  181     LogData* data = message->sync_log_data(); | 
 |  182     if (!data) | 
 |  183       return; | 
 |  184  | 
 |  185     // This is actually the delayed reply to a sync message.  Create a string | 
 |  186     // of the output parameters, add it to the LogData that was earlier stashed | 
 |  187     // with the reply, and log the result. | 
 |  188     data->channel = channel_id; | 
 |  189     GenerateLogData("", *message, data); | 
 |  190     Log(*data); | 
 |  191     delete data; | 
 |  192     message->set_sync_log_data(NULL); | 
 |  193   } else { | 
 |  194     // If the time has already been set (i.e. by ChannelProxy), keep that time | 
 |  195     // instead as it's more accurate. | 
 |  196     if (!message->sent_time()) | 
 |  197       message->set_sent_time(Time::Now().ToInternalValue()); | 
 |  198   } | 
 |  199 } | 
 |  200  | 
 |  201 void Logging::OnPreDispatchMessage(const Message& message) { | 
 |  202   message.set_received_time(Time::Now().ToInternalValue()); | 
 |  203 } | 
 |  204  | 
 |  205 void Logging::OnPostDispatchMessage(const Message& message, | 
 |  206                                     const std::string& channel_id) { | 
 |  207   if (!Enabled() || | 
 |  208 #if defined(OS_WIN) | 
 |  209       !message.sent_time() || | 
 |  210 #endif | 
 |  211       message.dont_log()) | 
 |  212     return; | 
 |  213  | 
 |  214   LogData data; | 
 |  215   GenerateLogData(channel_id, message, &data); | 
 |  216  | 
 |  217   if (MessageLoop::current() == main_thread_) { | 
 |  218     Log(data); | 
 |  219   } else { | 
 |  220     main_thread_->PostTask(FROM_HERE, NewRunnableMethod( | 
 |  221         this, &Logging::Log, data)); | 
 |  222   } | 
 |  223 } | 
 |  224  | 
 |  225 void Logging::GetMessageText(uint16 type, std::wstring* name, | 
 |  226                              const Message* message, | 
 |  227                              std::wstring* params) { | 
 |  228   if (!log_function_mapping_) | 
 |  229     return; | 
 |  230  | 
 |  231   int message_class = type >> 12; | 
 |  232   if (log_function_mapping_[message_class] != NULL) { | 
 |  233     log_function_mapping_[message_class](type, name, message, params); | 
 |  234   } else { | 
 |  235     DLOG(INFO) << "No logger function associated with message class " << | 
 |  236         message_class; | 
 |  237   } | 
 |  238 } | 
 |  239  | 
 |  240 void Logging::Log(const LogData& data) { | 
 |  241 #if defined(OS_WIN) | 
 |  242   if (consumer_) { | 
 |  243     // We're in the browser process. | 
 |  244     consumer_->Log(data); | 
 |  245   } else { | 
 |  246     // We're in the renderer or plugin processes. | 
 |  247     if (sender_) { | 
 |  248       queued_logs_.push_back(data); | 
 |  249       if (!queue_invoke_later_pending_) { | 
 |  250         queue_invoke_later_pending_ = true; | 
 |  251         MessageLoop::current()->PostDelayedTask(FROM_HERE, NewRunnableMethod( | 
 |  252             this, &Logging::OnSendLogs), kLogSendDelayMs); | 
 |  253       } | 
 |  254     } | 
 |  255   } | 
 |  256 #elif defined(OS_POSIX) | 
 |  257   // On POSIX, for now, we just dump the log to stderr | 
 |  258   fprintf(stderr, "ipc %s %d %d %s %s %s\n", | 
 |  259           data.channel.c_str(), | 
 |  260           data.routing_id, | 
 |  261           data.type, | 
 |  262           WideToUTF8(data.flags).c_str(), | 
 |  263           WideToUTF8(data.message_name).c_str(), | 
 |  264           WideToUTF8(data.params).c_str()); | 
 |  265 #endif | 
 |  266 } | 
 |  267  | 
 |  268 void GenerateLogData(const std::string& channel, const Message& message, | 
 |  269                      LogData* data) { | 
 |  270   if (message.is_reply()) { | 
 |  271     // "data" should already be filled in. | 
 |  272     std::wstring params; | 
 |  273     Logging::GetMessageText(data->type, NULL, &message, ¶ms); | 
 |  274  | 
 |  275     if (!data->params.empty() && !params.empty()) | 
 |  276       data->params += L", "; | 
 |  277  | 
 |  278     data->flags += L" DR"; | 
 |  279  | 
 |  280     data->params += params; | 
 |  281   } else { | 
 |  282     std::wstring flags; | 
 |  283     if (message.is_sync()) | 
 |  284       flags = L"S"; | 
 |  285  | 
 |  286     if (message.is_reply()) | 
 |  287       flags += L"R"; | 
 |  288  | 
 |  289     if (message.is_reply_error()) | 
 |  290       flags += L"E"; | 
 |  291  | 
 |  292     std::wstring params, message_name; | 
 |  293     Logging::GetMessageText(message.type(), &message_name, &message, ¶ms); | 
 |  294  | 
 |  295     data->channel = channel; | 
 |  296     data->routing_id = message.routing_id(); | 
 |  297     data->type = message.type(); | 
 |  298     data->flags = flags; | 
 |  299     data->sent = message.sent_time(); | 
 |  300     data->receive = message.received_time(); | 
 |  301     data->dispatch = Time::Now().ToInternalValue(); | 
 |  302     data->params = params; | 
 |  303     data->message_name = message_name; | 
 |  304   } | 
 |  305 } | 
 |  306  | 
 |  307 } | 
 |  308  | 
 |  309 #endif  // IPC_MESSAGE_LOG_ENABLED | 
| OLD | NEW |