summaryrefslogtreecommitdiffstats
path: root/chrome/browser/ipc_status_view.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/browser/ipc_status_view.cc')
-rw-r--r--chrome/browser/ipc_status_view.cc393
1 files changed, 393 insertions, 0 deletions
diff --git a/chrome/browser/ipc_status_view.cc b/chrome/browser/ipc_status_view.cc
new file mode 100644
index 0000000..f3362dd
--- /dev/null
+++ b/chrome/browser/ipc_status_view.cc
@@ -0,0 +1,393 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "chrome/browser/ipc_status_view.h"
+
+#include <stdio.h>
+
+#include "base/logging.h"
+#include "base/string_util.h"
+#include "chrome/app/chrome_dll_resource.h"
+#include "chrome/common/chrome_constants.h"
+#include "chrome/common/ipc_logging.h"
+#include "chrome/common/plugin_messages.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/common/pref_service.h"
+#include "chrome/common/render_messages.h"
+
+#ifdef IPC_MESSAGE_LOG_ENABLED
+
+namespace {
+const wchar_t kTitleMsg[] = L"IPC Messages";
+
+const wchar_t kStartLoggingMsg[] = L"Start IPC Logging";
+const wchar_t kStopLoggingMsg[] = L"Stop IPC Logging";
+const wchar_t kClearMsg[] = L"Clear";
+const wchar_t kSettingsMsg[] = L"Filter";
+
+enum {
+ kTimeColumn = 0,
+ kChannelColumn,
+ kMessageColumn,
+ kFlagsColumn,
+ kDispatchColumn,
+ kProcessColumn,
+ kParamsColumn,
+};
+
+// This class ensures that we have a link dependency on render_messages.cc and
+// plugin_messages.cc, and at the same time sets up the message logger function
+// mappings.
+class RegisterLoggerFuncs {
+ public:
+ RegisterLoggerFuncs() {
+ RenderMessagesInit();
+ PluginMessagesInit();
+ }
+};
+
+RegisterLoggerFuncs g_register_logger_funcs;
+
+} // namespace
+
+IPCStatusView* IPCStatusView::current_;
+
+IPCStatusView::IPCStatusView()
+ : StatusView(TAB_CONTENTS_IPC_STATUS_VIEW) {
+ DCHECK(!current_);
+ current_ = this;
+ settings_dialog_ = NULL;
+ init_done_ = false;
+ view_ = NULL;
+ view_host_ = NULL;
+ plugin_ = NULL;
+ plugin_host_ = NULL;
+ npobject_ = NULL;
+ plugin_process_ = NULL;
+ plugin_process_host_ = NULL;
+
+ IPC::Logging::current()->SetConsumer(this);
+}
+
+IPCStatusView::~IPCStatusView() {
+ current_ = NULL;
+ IPC::Logging::current()->SetConsumer(NULL);
+
+ if (settings_dialog_ != NULL)
+ ::DestroyWindow(settings_dialog_);
+}
+
+const std::wstring IPCStatusView::GetDefaultTitle() {
+ return kTitleMsg;
+}
+
+void IPCStatusView::SetActive(bool active) {
+ StatusView::SetActive(active);
+
+ if (!disabled_messages_.empty() || !active)
+ return;
+
+ Profile* current_profile = profile();
+ if (!current_profile)
+ return;
+ PrefService* prefs = current_profile->GetPrefs();
+ if (prefs->IsPrefRegistered(prefs::kIpcDisabledMessages))
+ return;
+ prefs->RegisterListPref(prefs::kIpcDisabledMessages);
+ const ListValue* list = prefs->GetList(prefs::kIpcDisabledMessages);
+ if (!list)
+ return;
+ for (ListValue::const_iterator itr = list->begin();
+ itr != list->end();
+ ++itr) {
+ if (!(*itr)->IsType(Value::TYPE_INTEGER))
+ continue;
+ int value = 0;
+ if (!(*itr)->GetAsInteger(&value))
+ continue;
+ disabled_messages_.insert(value);
+ }
+}
+
+void IPCStatusView::OnCreate(const CRect& rect) {
+ CreateButton(IDC_START_LOGGING, kStartLoggingMsg);
+ CreateButton(IDC_STOP_LOGGING, kStopLoggingMsg);
+ CreateButton(IDC_CLEAR, kClearMsg);
+ CreateButton(IDC_SETTINGS, kSettingsMsg);
+
+ // Initialize the list view for messages.
+ // Don't worry about the size, we'll resize when we get WM_SIZE
+ message_list_.Create(GetContainerHWND(), const_cast<CRect&>(rect), NULL,
+ WS_CHILD | WS_VISIBLE | LVS_SORTASCENDING);
+ message_list_.SetViewType(LVS_REPORT);
+ message_list_.SetExtendedListViewStyle(LVS_EX_FULLROWSELECT);
+
+ int column_index = 0;
+ message_list_.InsertColumn(kTimeColumn, L"time", LVCFMT_LEFT, 80);
+ message_list_.InsertColumn(kChannelColumn, L"channel", LVCFMT_LEFT, 110);
+ message_list_.InsertColumn(kMessageColumn, L"message", LVCFMT_LEFT, 240);
+ message_list_.InsertColumn(kFlagsColumn, L"flags", LVCFMT_LEFT, 50);
+ message_list_.InsertColumn(kDispatchColumn, L"dispatch (ms)", LVCFMT_RIGHT, 80);
+ message_list_.InsertColumn(kProcessColumn, L"process (ms)", LVCFMT_RIGHT, 80);
+ message_list_.InsertColumn(kParamsColumn, L"parameters", LVCFMT_LEFT, 500);
+}
+
+void IPCStatusView::Log(const IPC::LogData& data) {
+ if (disabled_messages_.find(data.type) != disabled_messages_.end())
+ return; // Message type is filtered out.
+
+ Time sent = Time::FromInternalValue(data.sent);
+ Time::Exploded exploded;
+ sent.LocalExplode(&exploded);
+ if (exploded.hour > 12)
+ exploded.hour -= 12;
+
+ std::wstring sent_str = StringPrintf(L"%02d:%02d:%02d.%03d",
+ exploded.hour, exploded.minute, exploded.second, exploded.millisecond);
+
+ int count = message_list_.GetItemCount();
+ int index = message_list_.InsertItem(count, sent_str.c_str());
+
+ message_list_.SetItemText(index, kTimeColumn, sent_str.c_str());
+ message_list_.SetItemText(index, kChannelColumn, data.channel.c_str());
+
+ std::wstring message_name;
+ IPC::Logging::GetMessageText(data.type, &message_name, NULL, NULL);
+ message_list_.SetItemText(index, kMessageColumn, message_name.c_str());
+ message_list_.SetItemText(index, kFlagsColumn, data.flags.c_str());
+
+ int64 time_to_send = (Time::FromInternalValue(data.receive) -
+ sent).InMilliseconds();
+ // time can go backwards by a few ms (see Time), don't show that.
+ time_to_send = std::max(static_cast<int>(time_to_send), 0);
+ std::wstring temp = StringPrintf(L"%d", time_to_send);
+ message_list_.SetItemText(index, kDispatchColumn, temp.c_str());
+
+ int64 time_to_process = (Time::FromInternalValue(data.dispatch) -
+ Time::FromInternalValue(data.receive)).InMilliseconds();
+ time_to_process = std::max(static_cast<int>(time_to_process), 0);
+ temp = StringPrintf(L"%d", time_to_process);
+ message_list_.SetItemText(index, kProcessColumn, temp.c_str());
+
+ message_list_.SetItemText(index, kParamsColumn, data.params.c_str());
+ message_list_.EnsureVisible(index, FALSE);
+}
+
+void IPCStatusView::OnSize(const CRect& rect) {
+ message_list_.MoveWindow(rect);
+}
+
+void IPCStatusView::OnStartLogging(UINT code, int button_id, HWND hwnd) {
+ IPC::Logging::current()->Enable();
+}
+
+void IPCStatusView::OnStopLogging(UINT code, int button_id, HWND hwnd) {
+ IPC::Logging::current()->Disable();
+}
+
+void IPCStatusView::OnClear(UINT code, int button_id, HWND hwnd) {
+ message_list_.DeleteAllItems();
+}
+
+INT_PTR CALLBACK IPCStatusView::DialogProc(
+ HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
+ switch (msg) {
+ case WM_INITDIALOG:
+ current()->InitDialog(hwnd);
+ return FALSE; // Don't set keyboard focus.
+ case WM_SYSCOMMAND:
+ if (wparam == SC_CLOSE) {
+ current()->CloseDialog();
+ return FALSE;
+ }
+ break;
+ case WM_NOTIFY: {
+ NMLISTVIEW* info = reinterpret_cast<NM_LISTVIEW*>(lparam);
+ if ((wparam == IDC_View || wparam == IDC_ViewHost || wparam == IDC_Plugin ||
+ wparam == IDC_PluginHost || wparam == IDC_NPObject ||
+ wparam == IDC_PluginProcess || wparam == IDC_PluginProcessHost) &&
+ info->hdr.code == LVN_ITEMCHANGED) {
+ if (info->uChanged & LVIF_STATE) {
+ bool checked = (info->uNewState >> 12) == 2;
+ current()->OnCheck(static_cast<int>(info->lParam), checked);
+ }
+ return FALSE;
+ }
+ break;
+ }
+ case WM_COMMAND:
+ if (HIWORD(wparam) == BN_CLICKED)
+ current()->OnButtonClick(LOWORD(wparam));
+
+ break;
+ }
+ return FALSE;
+}
+
+void IPCStatusView::InitDialog(HWND hwnd) {
+ CreateColumn(ViewStart, ViewEnd, ::GetDlgItem(hwnd, IDC_View), &view_);
+ CreateColumn(ViewHostStart, ViewHostEnd, ::GetDlgItem(hwnd, IDC_ViewHost),
+ &view_host_);
+ CreateColumn(PluginStart, PluginEnd, ::GetDlgItem(hwnd, IDC_Plugin), &plugin_);
+ CreateColumn(PluginHostStart, PluginHostEnd,
+ ::GetDlgItem(hwnd, IDC_PluginHost), &plugin_host_);
+ CreateColumn(NPObjectStart, NPObjectEnd, ::GetDlgItem(hwnd, IDC_NPObject),
+ &npobject_);
+ CreateColumn(PluginProcessStart, PluginProcessEnd,
+ ::GetDlgItem(hwnd, IDC_PluginProcess), &plugin_process_);
+ CreateColumn(PluginProcessHostStart, PluginProcessHostEnd,
+ ::GetDlgItem(hwnd, IDC_PluginProcessHost), &plugin_process_host_);
+ init_done_ = true;
+}
+
+void IPCStatusView::CreateColumn(
+ uint16 start, uint16 end, HWND hwnd, CListViewCtrl** control) {
+ DCHECK(*control == NULL);
+ *control = new CListViewCtrl(hwnd);
+ CListViewCtrl* control_ptr = *control;
+ control_ptr->SetViewType(LVS_REPORT);
+ control_ptr->SetExtendedListViewStyle(LVS_EX_CHECKBOXES);
+ control_ptr->ModifyStyle(0, LVS_SORTASCENDING | LVS_NOCOLUMNHEADER);
+ control_ptr->InsertColumn(0, L"id", LVCFMT_LEFT, 230);
+
+ std::set<int>* disabled_messages = &current()->disabled_messages_;
+ for (uint16 i = start; i < end; i++) {
+ std::wstring name;
+ IPC::Logging::GetMessageText(i, &name, NULL, NULL);
+
+ int index = control_ptr->InsertItem(
+ LVIF_TEXT | LVIF_PARAM, 0, name.c_str(), 0, 0, 0, i);
+
+ control_ptr->SetItemText(index, 0, name.c_str());
+
+ if (disabled_messages->find(i) == disabled_messages->end())
+ control_ptr->SetCheckState(index, TRUE);
+ }
+}
+
+void IPCStatusView::CloseDialog() {
+ delete view_;
+ delete view_host_;
+ delete plugin_host_;
+ delete npobject_;
+ delete plugin_process_;
+ delete plugin_process_host_;
+ view_ = NULL;
+ view_host_ = NULL;
+ plugin_ = NULL;
+ plugin_host_ = NULL;
+ npobject_ = NULL;
+ plugin_process_ = NULL;
+ plugin_process_host_ = NULL;
+ init_done_ = false;
+
+ ::DestroyWindow(settings_dialog_);
+ settings_dialog_ = NULL;
+
+ Profile* current_profile = profile();
+ if (!current_profile)
+ return;
+ PrefService* prefs = current_profile->GetPrefs();
+ if (!prefs->IsPrefRegistered(prefs::kIpcDisabledMessages))
+ return;
+ ListValue* list = prefs->GetMutableList(prefs::kIpcDisabledMessages);
+ list->Clear();
+ for (std::set<int>::const_iterator itr = disabled_messages_.begin();
+ itr != disabled_messages_.end();
+ ++itr) {
+ list->Append(Value::CreateIntegerValue(*itr));
+ }
+}
+
+void IPCStatusView::OnCheck(int id, bool checked) {
+ if (!init_done_)
+ return;
+
+ if (checked) {
+ disabled_messages_.erase(id);
+ } else {
+ disabled_messages_.insert(id);
+ }
+}
+
+void IPCStatusView::OnButtonClick(int id) {
+ switch(id) {
+ case IDC_ViewAll:
+ CheckButtons(view_, true);
+ break;
+ case IDC_ViewNone:
+ CheckButtons(view_, false);
+ break;
+ case IDC_ViewHostAll:
+ CheckButtons(view_host_, true);
+ break;
+ case IDC_ViewHostNone:
+ CheckButtons(view_host_, false);
+ break;
+ case IDC_PluginAll:
+ CheckButtons(plugin_, true);
+ break;
+ case IDC_PluginNone:
+ CheckButtons(plugin_, false);
+ break;
+ case IDC_PluginHostAll:
+ CheckButtons(plugin_host_, true);
+ break;
+ case IDC_PluginHostNone:
+ CheckButtons(plugin_host_, false);
+ break;
+ case IDC_NPObjectAll:
+ CheckButtons(npobject_, true);
+ break;
+ case IDC_NPObjectNone:
+ CheckButtons(npobject_, false);
+ break;
+ }
+}
+
+void IPCStatusView::CheckButtons(CListViewCtrl* control, bool check) {
+ int count = control->GetItemCount();
+ for (int i = 0; i < count; ++i)
+ control->SetCheckState(i, check);
+}
+
+void IPCStatusView::OnSettings(UINT code, int button_id, HWND hwnd) {
+ if (settings_dialog_ != NULL)
+ return;
+
+ HINSTANCE module_handle = GetModuleHandle(chrome::kBrowserResourcesDll);
+
+ settings_dialog_ = CreateDialog(module_handle,
+ MAKEINTRESOURCE(IDD_IPC_SETTINGS),
+ NULL,
+ IPCStatusView::DialogProc);
+ ::ShowWindow(settings_dialog_, SW_SHOW);
+}
+
+#endif // IPC_MESSAGE_LOG_ENABLED \ No newline at end of file