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 <windows.h> | 5 #include <windows.h> |
6 | 6 |
7 #include "chrome/browser/hang_monitor/hung_plugin_action.h" | 7 #include "chrome/browser/hang_monitor/hung_plugin_action.h" |
8 | 8 |
| 9 #include "base/metrics/histogram.h" |
| 10 #include "base/version.h" |
9 #include "chrome/browser/simple_message_box.h" | 11 #include "chrome/browser/simple_message_box.h" |
10 #include "chrome/common/logging_chrome.h" | 12 #include "chrome/common/logging_chrome.h" |
11 #include "grit/generated_resources.h" | 13 #include "grit/generated_resources.h" |
12 #include "ui/base/l10n/l10n_util.h" | 14 #include "ui/base/l10n/l10n_util.h" |
13 #include "ui/base/win/hwnd_util.h" | 15 #include "ui/base/win/hwnd_util.h" |
| 16 #include "webkit/plugins/npapi/plugin_group.h" |
14 #include "webkit/plugins/npapi/webplugin_delegate_impl.h" | 17 #include "webkit/plugins/npapi/webplugin_delegate_impl.h" |
15 | 18 |
| 19 namespace { |
| 20 |
| 21 const wchar_t kGTalkPluginName[] = L"Google Talk Plugin"; |
| 22 const int kGTalkPluginLogMinVersion = 26; // For version 2.6 and below. |
| 23 |
| 24 enum GTalkPluginLogVersion { |
| 25 GTALK_PLUGIN_VERSION_MIN = 0, |
| 26 GTALK_PLUGIN_VERSION_27, |
| 27 GTALK_PLUGIN_VERSION_28, |
| 28 GTALK_PLUGIN_VERSION_29, |
| 29 GTALK_PLUGIN_VERSION_30, |
| 30 GTALK_PLUGIN_VERSION_31, |
| 31 GTALK_PLUGIN_VERSION_32, |
| 32 GTALK_PLUGIN_VERSION_33, |
| 33 GTALK_PLUGIN_VERSION_34, |
| 34 GTALK_PLUGIN_VERSION_MAX |
| 35 }; |
| 36 |
| 37 // Converts the version string of Google Talk Plugin to a version enum. The |
| 38 // version format is "major(1 digit).minor(1 digit).sub(1 or 2 digits)", |
| 39 // for example, "2.7.10" and "2.8.1". Converts the string to a number as |
| 40 // 10 * major + minor - kGTalkPluginLogMinVersion. |
| 41 GTalkPluginLogVersion GetGTalkPluginVersion(const string16& version) { |
| 42 int gtalk_plugin_version = GTALK_PLUGIN_VERSION_MIN; |
| 43 scoped_ptr<Version> plugin_version( |
| 44 webkit::npapi::PluginGroup::CreateVersionFromString(version)); |
| 45 if (plugin_version.get() && plugin_version->components().size() >= 2) { |
| 46 gtalk_plugin_version = 10 * plugin_version->components()[0] + |
| 47 plugin_version->components()[1] - kGTalkPluginLogMinVersion; |
| 48 } |
| 49 |
| 50 if (gtalk_plugin_version < GTALK_PLUGIN_VERSION_MIN) |
| 51 return GTALK_PLUGIN_VERSION_MIN; |
| 52 if (gtalk_plugin_version > GTALK_PLUGIN_VERSION_MAX) |
| 53 return GTALK_PLUGIN_VERSION_MAX; |
| 54 return static_cast<GTalkPluginLogVersion>(gtalk_plugin_version); |
| 55 } |
| 56 |
| 57 } // namespace |
| 58 |
16 HungPluginAction::HungPluginAction() : current_hung_plugin_window_(NULL) { | 59 HungPluginAction::HungPluginAction() : current_hung_plugin_window_(NULL) { |
17 } | 60 } |
18 | 61 |
19 HungPluginAction::~HungPluginAction() { | 62 HungPluginAction::~HungPluginAction() { |
20 } | 63 } |
21 | 64 |
22 bool HungPluginAction::OnHungWindowDetected(HWND hung_window, | 65 bool HungPluginAction::OnHungWindowDetected(HWND hung_window, |
23 HWND top_level_window, | 66 HWND top_level_window, |
24 ActionOnHungWindow* action) { | 67 ActionOnHungWindow* action) { |
25 if (NULL == action) { | 68 if (NULL == action) { |
26 return false; | 69 return false; |
27 } | 70 } |
28 if (!IsWindow(hung_window)) { | 71 if (!IsWindow(hung_window)) { |
29 return false; | 72 return false; |
30 } | 73 } |
31 | 74 |
32 bool continue_hang_detection = true; | 75 bool continue_hang_detection = true; |
33 | 76 |
34 DWORD hung_window_process_id = 0; | 77 DWORD hung_window_process_id = 0; |
35 DWORD top_level_window_process_id = 0; | 78 DWORD top_level_window_process_id = 0; |
36 GetWindowThreadProcessId(hung_window, &hung_window_process_id); | 79 GetWindowThreadProcessId(hung_window, &hung_window_process_id); |
37 GetWindowThreadProcessId(top_level_window, &top_level_window_process_id); | 80 GetWindowThreadProcessId(top_level_window, &top_level_window_process_id); |
38 | 81 |
39 *action = HungWindowNotification::HUNG_WINDOW_IGNORE; | 82 *action = HungWindowNotification::HUNG_WINDOW_IGNORE; |
40 if (top_level_window_process_id != hung_window_process_id) { | 83 if (top_level_window_process_id != hung_window_process_id) { |
| 84 string16 plugin_name; |
| 85 string16 plugin_version; |
| 86 GetPluginNameAndVersion(hung_window, |
| 87 top_level_window_process_id, |
| 88 &plugin_name, |
| 89 &plugin_version); |
| 90 if (plugin_name.empty()) { |
| 91 plugin_name = l10n_util::GetStringUTF16(IDS_UNKNOWN_PLUGIN_NAME); |
| 92 } else if (kGTalkPluginName == plugin_name) { |
| 93 UMA_HISTOGRAM_ENUMERATION("GTalkPlugin.Hung", |
| 94 GetGTalkPluginVersion(plugin_version), |
| 95 GTALK_PLUGIN_VERSION_MAX + 1); |
| 96 } |
| 97 |
41 if (logging::DialogsAreSuppressed()) { | 98 if (logging::DialogsAreSuppressed()) { |
42 NOTREACHED() << "Terminated a hung plugin process."; | 99 NOTREACHED() << "Terminated a hung plugin process."; |
43 *action = HungWindowNotification::HUNG_WINDOW_TERMINATE_PROCESS; | 100 *action = HungWindowNotification::HUNG_WINDOW_TERMINATE_PROCESS; |
44 } else { | 101 } else { |
45 string16 plugin_name; | |
46 GetPluginName(hung_window, | |
47 top_level_window_process_id, | |
48 &plugin_name); | |
49 if (plugin_name.empty()) { | |
50 plugin_name = l10n_util::GetStringUTF16(IDS_UNKNOWN_PLUGIN_NAME); | |
51 } | |
52 string16 msg = l10n_util::GetStringFUTF16(IDS_BROWSER_HANGMONITOR, | 102 string16 msg = l10n_util::GetStringFUTF16(IDS_BROWSER_HANGMONITOR, |
53 plugin_name); | 103 plugin_name); |
54 string16 title = l10n_util::GetStringUTF16(IDS_BROWSER_HANGMONITOR_TITLE); | 104 string16 title = l10n_util::GetStringUTF16(IDS_BROWSER_HANGMONITOR_TITLE); |
55 // Before displaying the message box, invoke SendMessageCallback on the | 105 // Before displaying the message box, invoke SendMessageCallback on the |
56 // hung window. If the callback ever hits, the window is not hung anymore | 106 // hung window. If the callback ever hits, the window is not hung anymore |
57 // and we can dismiss the message box. | 107 // and we can dismiss the message box. |
58 SendMessageCallback(hung_window, | 108 SendMessageCallback(hung_window, |
59 WM_NULL, | 109 WM_NULL, |
60 0, | 110 0, |
61 0, | 111 0, |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
100 // The message timeout for this window should fallback to the default | 150 // The message timeout for this window should fallback to the default |
101 // timeout as this window is now responsive. | 151 // timeout as this window is now responsive. |
102 RemoveProp(window, HungWindowDetector::kHungChildWindowTimeout); | 152 RemoveProp(window, HungWindowDetector::kHungChildWindowTimeout); |
103 // The monitored plugin recovered. Let's dismiss the message box. | 153 // The monitored plugin recovered. Let's dismiss the message box. |
104 EnumThreadWindows(GetCurrentThreadId(), | 154 EnumThreadWindows(GetCurrentThreadId(), |
105 reinterpret_cast<WNDENUMPROC>(DismissMessageBox), | 155 reinterpret_cast<WNDENUMPROC>(DismissMessageBox), |
106 NULL); | 156 NULL); |
107 } | 157 } |
108 } | 158 } |
109 | 159 |
110 bool HungPluginAction::GetPluginName(HWND plugin_window, | 160 bool HungPluginAction::GetPluginNameAndVersion(HWND plugin_window, |
111 DWORD browser_process_id, | 161 DWORD browser_process_id, |
112 std::wstring* plugin_name) { | 162 string16* plugin_name, |
| 163 string16* plugin_version) { |
113 DCHECK(plugin_name); | 164 DCHECK(plugin_name); |
| 165 DCHECK(plugin_version); |
114 HWND window_to_check = plugin_window; | 166 HWND window_to_check = plugin_window; |
115 while (NULL != window_to_check) { | 167 while (NULL != window_to_check) { |
116 DWORD process_id = 0; | 168 DWORD process_id = 0; |
117 GetWindowThreadProcessId(window_to_check, &process_id); | 169 GetWindowThreadProcessId(window_to_check, &process_id); |
118 if (process_id == browser_process_id) { | 170 if (process_id == browser_process_id) { |
119 // If we have reached a window the that belongs to the browser process | 171 // If we have reached a window the that belongs to the browser process |
120 // we have gone too far. | 172 // we have gone too far. |
121 return false; | 173 return false; |
122 } | 174 } |
123 if (webkit::npapi::WebPluginDelegateImpl::GetPluginNameFromWindow( | 175 if (webkit::npapi::WebPluginDelegateImpl::GetPluginNameFromWindow( |
124 window_to_check, plugin_name)) { | 176 window_to_check, plugin_name)) { |
| 177 webkit::npapi::WebPluginDelegateImpl::GetPluginVersionFromWindow( |
| 178 window_to_check, plugin_version); |
125 return true; | 179 return true; |
126 } | 180 } |
127 window_to_check = GetParent(window_to_check); | 181 window_to_check = GetParent(window_to_check); |
128 } | 182 } |
129 return false; | 183 return false; |
130 } | 184 } |
131 | 185 |
132 // static | 186 // static |
133 BOOL CALLBACK HungPluginAction::DismissMessageBox(HWND window, LPARAM ignore) { | 187 BOOL CALLBACK HungPluginAction::DismissMessageBox(HWND window, LPARAM ignore) { |
134 string16 class_name = ui::GetClassName(window); | 188 string16 class_name = ui::GetClassName(window); |
(...skipping 10 matching lines...) Expand all Loading... |
145 void CALLBACK HungPluginAction::HungWindowResponseCallback(HWND target_window, | 199 void CALLBACK HungPluginAction::HungWindowResponseCallback(HWND target_window, |
146 UINT message, | 200 UINT message, |
147 ULONG_PTR data, | 201 ULONG_PTR data, |
148 LRESULT result) { | 202 LRESULT result) { |
149 HungPluginAction* instance = reinterpret_cast<HungPluginAction*>(data); | 203 HungPluginAction* instance = reinterpret_cast<HungPluginAction*>(data); |
150 DCHECK(NULL != instance); | 204 DCHECK(NULL != instance); |
151 if (NULL != instance) { | 205 if (NULL != instance) { |
152 instance->OnWindowResponsive(target_window); | 206 instance->OnWindowResponsive(target_window); |
153 } | 207 } |
154 } | 208 } |
OLD | NEW |