OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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 "chrome/browser/plugin_data_remover.h" | 5 #include "chrome/browser/plugin_data_remover.h" |
6 | 6 |
7 #include "base/message_loop_proxy.h" | 7 #include "base/message_loop_proxy.h" |
8 #include "base/metrics/histogram.h" | 8 #include "base/metrics/histogram.h" |
9 #include "base/version.h" | 9 #include "base/version.h" |
| 10 #include "chrome/browser/browser_process.h" |
10 #include "chrome/browser/browser_thread.h" | 11 #include "chrome/browser/browser_thread.h" |
11 #include "chrome/browser/plugin_service.h" | 12 #include "chrome/browser/plugin_service.h" |
12 #include "chrome/common/plugin_messages.h" | 13 #include "chrome/common/plugin_messages.h" |
13 #include "webkit/plugins/npapi/plugin_group.h" | 14 #include "webkit/plugins/npapi/plugin_group.h" |
14 #include "webkit/plugins/npapi/plugin_list.h" | 15 #include "webkit/plugins/npapi/plugin_list.h" |
15 | 16 |
16 #if defined(OS_POSIX) | 17 #if defined(OS_POSIX) |
17 #include "ipc/ipc_channel_posix.h" | 18 #include "ipc/ipc_channel_posix.h" |
18 #endif | 19 #endif |
19 | 20 |
20 namespace { | 21 namespace { |
21 const char* kFlashMimeType = "application/x-shockwave-flash"; | 22 const char* kFlashMimeType = "application/x-shockwave-flash"; |
22 // TODO(bauerb): Update minimum required Flash version as soon as there is one | 23 // TODO(bauerb): Update minimum required Flash version as soon as there is one |
23 // implementing the API. | 24 // implementing the API. |
24 const char* kMinFlashVersion = "100"; | 25 const char* kMinFlashVersion = "100"; |
25 const int64 kRemovalTimeoutMs = 10000; | 26 const int64 kRemovalTimeoutMs = 10000; |
26 const uint64 kClearAllData = 0; | 27 const uint64 kClearAllData = 0; |
27 } // namespace | 28 } // namespace |
28 | 29 |
29 PluginDataRemover::PluginDataRemover() | 30 PluginDataRemover::PluginDataRemover() |
30 : is_removing_(false), | 31 : is_removing_(false), |
| 32 has_browser_ref_(false), |
| 33 plugin_process_(NULL), |
| 34 handle_(base::kNullProcessHandle), |
31 channel_(NULL) { } | 35 channel_(NULL) { } |
32 | 36 |
33 PluginDataRemover::~PluginDataRemover() { | 37 PluginDataRemover::~PluginDataRemover() { |
34 DCHECK(!is_removing_); | 38 DCHECK(!is_removing_); |
35 if (channel_) | 39 if (channel_) |
36 BrowserThread::DeleteSoon(BrowserThread::IO, FROM_HERE, channel_); | 40 BrowserThread::DeleteSoon(BrowserThread::IO, FROM_HERE, channel_); |
37 } | 41 } |
38 | 42 |
39 void PluginDataRemover::StartRemoving(base::Time begin_time, Task* done_task) { | 43 void PluginDataRemover::StartRemoving(const base::Time& begin_time, |
| 44 bool terminate, |
| 45 Task* done_task) { |
40 DCHECK(!done_task_.get()); | 46 DCHECK(!done_task_.get()); |
41 DCHECK(!is_removing_); | 47 DCHECK(!is_removing_); |
42 remove_start_time_ = base::Time::Now(); | 48 remove_start_time_ = base::Time::Now(); |
43 begin_time_ = begin_time; | 49 begin_time_ = begin_time; |
| 50 terminate_process_ = terminate; |
44 | 51 |
45 message_loop_ = base::MessageLoopProxy::CreateForCurrentThread(); | 52 message_loop_ = base::MessageLoopProxy::CreateForCurrentThread(); |
46 done_task_.reset(done_task); | 53 done_task_.reset(done_task); |
47 is_removing_ = true; | 54 is_removing_ = true; |
48 | 55 |
| 56 // Don't quit the main message loop until the process has started. |
| 57 g_browser_process->AddRefModule(); |
| 58 has_browser_ref_ = true; |
49 AddRef(); | 59 AddRef(); |
50 PluginService::GetInstance()->OpenChannelToPlugin( | 60 PluginService::GetInstance()->OpenChannelToPlugin( |
51 GURL(), kFlashMimeType, this); | 61 GURL(), kFlashMimeType, this); |
52 | 62 |
53 BrowserThread::PostDelayedTask( | 63 BrowserThread::PostDelayedTask( |
54 BrowserThread::IO, | 64 BrowserThread::IO, |
55 FROM_HERE, | 65 FROM_HERE, |
56 NewRunnableMethod(this, &PluginDataRemover::OnTimeout), | 66 NewRunnableMethod(this, &PluginDataRemover::OnTimeout), |
57 kRemovalTimeoutMs); | 67 kRemovalTimeoutMs); |
58 } | 68 } |
59 | 69 |
| 70 void PluginDataRemover::WaitForPluginToExit() { |
| 71 DCHECK(terminate_process_); |
| 72 if (!is_removing_) |
| 73 return; |
| 74 DCHECK_NE(base::kNullProcessHandle, handle_); |
| 75 base::Time start_time(base::Time::Now()); |
| 76 bool result = base::WaitForSingleProcess(handle_, kRemovalTimeoutMs); |
| 77 UMA_HISTOGRAM_TIMES("ClearPluginData.wait_at_shutdown", |
| 78 base::Time::Now() - start_time); |
| 79 UMA_HISTOGRAM_TIMES("ClearPluginData.time_at_shutdown", |
| 80 base::Time::Now() - remove_start_time_); |
| 81 DCHECK(result) << "Error waiting for plugin process"; |
| 82 } |
| 83 |
60 int PluginDataRemover::ID() { | 84 int PluginDataRemover::ID() { |
61 // Generate an ID for the browser process. | 85 // Generate an ID for the browser process. |
62 return ChildProcessInfo::GenerateChildProcessUniqueId(); | 86 return ChildProcessInfo::GenerateChildProcessUniqueId(); |
63 } | 87 } |
64 | 88 |
65 bool PluginDataRemover::OffTheRecord() { | 89 bool PluginDataRemover::OffTheRecord() { |
66 return false; | 90 return false; |
67 } | 91 } |
68 | 92 |
69 void PluginDataRemover::SetPluginInfo( | 93 void PluginDataRemover::SetPluginInfo( |
70 const webkit::npapi::WebPluginInfo& info) { | 94 const webkit::npapi::WebPluginInfo& info) { |
71 } | 95 } |
72 | 96 |
| 97 void PluginDataRemover::OnPluginProcessFound(PluginProcessHost* process) { |
| 98 plugin_process_ = process; |
| 99 } |
| 100 |
73 void PluginDataRemover::OnChannelOpened(const IPC::ChannelHandle& handle) { | 101 void PluginDataRemover::OnChannelOpened(const IPC::ChannelHandle& handle) { |
74 ConnectToChannel(handle); | 102 ConnectToChannel(handle); |
| 103 DCHECK(has_browser_ref_); |
| 104 BrowserThread::PostTask( |
| 105 BrowserThread::UI, FROM_HERE, |
| 106 NewRunnableMethod(this, &PluginDataRemover::ReleaseBrowserProcess)); |
| 107 has_browser_ref_ = false; |
75 Release(); | 108 Release(); |
76 } | 109 } |
77 | 110 |
| 111 void PluginDataRemover::ReleaseBrowserProcess() { |
| 112 g_browser_process->ReleaseModule(); |
| 113 } |
| 114 |
78 void PluginDataRemover::ConnectToChannel(const IPC::ChannelHandle& handle) { | 115 void PluginDataRemover::ConnectToChannel(const IPC::ChannelHandle& handle) { |
79 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 116 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
80 | 117 |
81 // If we timed out, don't bother connecting. | 118 // If we timed out, don't bother connecting. |
82 if (!is_removing_) | 119 if (!is_removing_) |
83 return; | 120 return; |
84 | 121 |
85 DCHECK(!channel_); | 122 DCHECK(!channel_); |
86 channel_ = new IPC::Channel(handle, IPC::Channel::MODE_CLIENT, this); | 123 channel_ = new IPC::Channel(handle, IPC::Channel::MODE_CLIENT, this); |
87 if (!channel_->Connect()) { | 124 if (!channel_->Connect()) { |
88 LOG(DFATAL) << "Couldn't connect to plugin"; | 125 NOTREACHED() << "Couldn't connect to plugin"; |
89 SignalDone(); | 126 SignalDone(); |
90 return; | 127 return; |
91 } | 128 } |
92 | 129 |
93 if (!channel_->Send( | 130 if (!channel_->Send( |
94 new PluginMsg_ClearSiteData(std::string(), | 131 new PluginMsg_ClearSiteData(std::string(), |
95 kClearAllData, | 132 kClearAllData, |
96 begin_time_))) { | 133 begin_time_))) { |
97 LOG(DFATAL) << "Couldn't send ClearSiteData message"; | 134 NOTREACHED() << "Couldn't send ClearSiteData message"; |
98 SignalDone(); | 135 SignalDone(); |
| 136 return; |
| 137 } |
| 138 |
| 139 // Save the process handle so we can wait for the process to exit. |
| 140 handle_ = plugin_process_->handle(); |
| 141 if (terminate_process_) { |
| 142 plugin_process_->ForceShutdown(); |
99 } | 143 } |
100 } | 144 } |
101 | 145 |
102 void PluginDataRemover::OnError() { | 146 void PluginDataRemover::OnError() { |
103 NOTREACHED() << "Couldn't open plugin channel"; | 147 LOG(DFATAL) << "Couldn't open plugin channel"; |
104 SignalDone(); | 148 SignalDone(); |
| 149 if (has_browser_ref_) { |
| 150 BrowserThread::PostTask( |
| 151 BrowserThread::UI, FROM_HERE, |
| 152 NewRunnableMethod(this, &PluginDataRemover::ReleaseBrowserProcess)); |
| 153 has_browser_ref_ = false; |
| 154 } |
105 Release(); | 155 Release(); |
106 } | 156 } |
107 | 157 |
108 void PluginDataRemover::OnClearSiteDataResult(bool success) { | 158 void PluginDataRemover::OnClearSiteDataResult(bool success) { |
109 if (!success) | 159 LOG_IF(DFATAL, !success) << "ClearSiteData returned error"; |
110 LOG(DFATAL) << "ClearSiteData returned error"; | |
111 UMA_HISTOGRAM_TIMES("ClearPluginData.time", | 160 UMA_HISTOGRAM_TIMES("ClearPluginData.time", |
112 base::Time::Now() - remove_start_time_); | 161 base::Time::Now() - remove_start_time_); |
113 SignalDone(); | 162 SignalDone(); |
114 } | 163 } |
115 | 164 |
| 165 void PluginDataRemover::OnPluginShuttingDown() { |
| 166 VLOG(1) << "Plugin shutting down"; |
| 167 } |
| 168 |
116 void PluginDataRemover::OnTimeout() { | 169 void PluginDataRemover::OnTimeout() { |
117 NOTREACHED() << "Timed out"; | 170 if (is_removing_) { |
| 171 LOG(DFATAL) << "Timed out"; |
| 172 if (has_browser_ref_) { |
| 173 BrowserThread::PostTask( |
| 174 BrowserThread::UI, FROM_HERE, |
| 175 NewRunnableMethod(this, &PluginDataRemover::ReleaseBrowserProcess)); |
| 176 has_browser_ref_ = false; |
| 177 } |
| 178 } |
118 SignalDone(); | 179 SignalDone(); |
119 } | 180 } |
120 | 181 |
121 bool PluginDataRemover::OnMessageReceived(const IPC::Message& msg) { | 182 bool PluginDataRemover::OnMessageReceived(const IPC::Message& msg) { |
122 IPC_BEGIN_MESSAGE_MAP(PluginDataRemover, msg) | 183 IPC_BEGIN_MESSAGE_MAP(PluginDataRemover, msg) |
123 IPC_MESSAGE_HANDLER(PluginHostMsg_ClearSiteDataResult, | 184 IPC_MESSAGE_HANDLER(PluginHostMsg_ClearSiteDataResult, |
124 OnClearSiteDataResult) | 185 OnClearSiteDataResult) |
| 186 IPC_MESSAGE_HANDLER(PluginHostMsg_PluginShuttingDown, |
| 187 OnPluginShuttingDown) |
125 IPC_MESSAGE_UNHANDLED_ERROR() | 188 IPC_MESSAGE_UNHANDLED_ERROR() |
126 IPC_END_MESSAGE_MAP() | 189 IPC_END_MESSAGE_MAP() |
127 | 190 |
128 return true; | 191 return true; |
129 } | 192 } |
130 | 193 |
131 void PluginDataRemover::OnChannelError() { | 194 void PluginDataRemover::OnChannelError() { |
132 LOG(DFATAL) << "Channel error"; | 195 if (is_removing_) { |
133 SignalDone(); | 196 NOTREACHED() << "Channel error"; |
| 197 SignalDone(); |
| 198 } |
134 } | 199 } |
135 | 200 |
136 void PluginDataRemover::SignalDone() { | 201 void PluginDataRemover::SignalDone() { |
137 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 202 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
138 if (!is_removing_) | 203 if (!is_removing_) |
139 return; | 204 return; |
140 is_removing_ = false; | 205 is_removing_ = false; |
141 if (done_task_.get()) { | 206 if (done_task_.get()) { |
142 message_loop_->PostTask(FROM_HERE, done_task_.release()); | 207 message_loop_->PostTask(FROM_HERE, done_task_.release()); |
143 message_loop_ = NULL; | 208 message_loop_ = NULL; |
(...skipping 11 matching lines...) Expand all Loading... |
155 return false; | 220 return false; |
156 } | 221 } |
157 scoped_ptr<Version> version( | 222 scoped_ptr<Version> version( |
158 webkit::npapi::PluginGroup::CreateVersionFromString(plugin.version)); | 223 webkit::npapi::PluginGroup::CreateVersionFromString(plugin.version)); |
159 scoped_ptr<Version> min_version( | 224 scoped_ptr<Version> min_version( |
160 Version::GetVersionFromString(kMinFlashVersion)); | 225 Version::GetVersionFromString(kMinFlashVersion)); |
161 return plugin.enabled && | 226 return plugin.enabled && |
162 version.get() && | 227 version.get() && |
163 min_version->CompareTo(*version) == -1; | 228 min_version->CompareTo(*version) == -1; |
164 } | 229 } |
OLD | NEW |