Index: chrome/browser/plugin_data_remover.cc |
diff --git a/chrome/browser/plugin_data_remover.cc b/chrome/browser/plugin_data_remover.cc |
index 4e6ac7f3c71bf5ca4a9ba8d6be6bad0c2e75bd59..1b2c6c31744bc41717c510b8e0956ecf92d27de7 100644 |
--- a/chrome/browser/plugin_data_remover.cc |
+++ b/chrome/browser/plugin_data_remover.cc |
@@ -7,6 +7,7 @@ |
#include "base/message_loop_proxy.h" |
#include "base/metrics/histogram.h" |
#include "base/version.h" |
+#include "chrome/browser/browser_process.h" |
#include "chrome/browser/browser_thread.h" |
#include "chrome/browser/plugin_service.h" |
#include "chrome/common/plugin_messages.h" |
@@ -28,6 +29,9 @@ const uint64 kClearAllData = 0; |
PluginDataRemover::PluginDataRemover() |
: is_removing_(false), |
+ has_browser_ref_(false), |
+ plugin_process_(NULL), |
+ handle_(base::kNullProcessHandle), |
channel_(NULL) { } |
PluginDataRemover::~PluginDataRemover() { |
@@ -36,16 +40,22 @@ PluginDataRemover::~PluginDataRemover() { |
BrowserThread::DeleteSoon(BrowserThread::IO, FROM_HERE, channel_); |
} |
-void PluginDataRemover::StartRemoving(base::Time begin_time, Task* done_task) { |
+void PluginDataRemover::StartRemoving(const base::Time& begin_time, |
+ bool terminate, |
+ Task* done_task) { |
DCHECK(!done_task_.get()); |
DCHECK(!is_removing_); |
remove_start_time_ = base::Time::Now(); |
begin_time_ = begin_time; |
+ terminate_process_ = terminate; |
message_loop_ = base::MessageLoopProxy::CreateForCurrentThread(); |
done_task_.reset(done_task); |
is_removing_ = true; |
+ // Don't quit the main message loop until the process has started. |
+ g_browser_process->AddRefModule(); |
+ has_browser_ref_ = true; |
AddRef(); |
PluginService::GetInstance()->OpenChannelToPlugin( |
GURL(), kFlashMimeType, this); |
@@ -57,6 +67,20 @@ void PluginDataRemover::StartRemoving(base::Time begin_time, Task* done_task) { |
kRemovalTimeoutMs); |
} |
+void PluginDataRemover::WaitForPluginToExit() { |
+ DCHECK(terminate_process_); |
+ if (!is_removing_) |
+ return; |
+ DCHECK_NE(base::kNullProcessHandle, handle_); |
+ base::Time start_time(base::Time::Now()); |
+ bool result = base::WaitForSingleProcess(handle_, kRemovalTimeoutMs); |
+ UMA_HISTOGRAM_TIMES("ClearPluginData.wait_at_shutdown", |
+ base::Time::Now() - start_time); |
+ UMA_HISTOGRAM_TIMES("ClearPluginData.time_at_shutdown", |
+ base::Time::Now() - remove_start_time_); |
+ DCHECK(result) << "Error waiting for plugin process"; |
+} |
+ |
int PluginDataRemover::ID() { |
// Generate an ID for the browser process. |
return ChildProcessInfo::GenerateChildProcessUniqueId(); |
@@ -70,11 +94,24 @@ void PluginDataRemover::SetPluginInfo( |
const webkit::npapi::WebPluginInfo& info) { |
} |
+void PluginDataRemover::OnPluginProcessFound(PluginProcessHost* process) { |
+ plugin_process_ = process; |
+} |
+ |
void PluginDataRemover::OnChannelOpened(const IPC::ChannelHandle& handle) { |
ConnectToChannel(handle); |
+ DCHECK(has_browser_ref_); |
+ BrowserThread::PostTask( |
+ BrowserThread::UI, FROM_HERE, |
+ NewRunnableMethod(this, &PluginDataRemover::ReleaseBrowserProcess)); |
+ has_browser_ref_ = false; |
Release(); |
} |
+void PluginDataRemover::ReleaseBrowserProcess() { |
+ g_browser_process->ReleaseModule(); |
+} |
+ |
void PluginDataRemover::ConnectToChannel(const IPC::ChannelHandle& handle) { |
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
@@ -85,7 +122,7 @@ void PluginDataRemover::ConnectToChannel(const IPC::ChannelHandle& handle) { |
DCHECK(!channel_); |
channel_ = new IPC::Channel(handle, IPC::Channel::MODE_CLIENT, this); |
if (!channel_->Connect()) { |
- LOG(DFATAL) << "Couldn't connect to plugin"; |
+ NOTREACHED() << "Couldn't connect to plugin"; |
SignalDone(); |
return; |
} |
@@ -94,27 +131,51 @@ void PluginDataRemover::ConnectToChannel(const IPC::ChannelHandle& handle) { |
new PluginMsg_ClearSiteData(std::string(), |
kClearAllData, |
begin_time_))) { |
- LOG(DFATAL) << "Couldn't send ClearSiteData message"; |
+ NOTREACHED() << "Couldn't send ClearSiteData message"; |
SignalDone(); |
+ return; |
+ } |
+ |
+ // Save the process handle so we can wait for the process to exit. |
+ handle_ = plugin_process_->handle(); |
+ if (terminate_process_) { |
+ plugin_process_->ForceShutdown(); |
} |
} |
void PluginDataRemover::OnError() { |
- NOTREACHED() << "Couldn't open plugin channel"; |
+ LOG(DFATAL) << "Couldn't open plugin channel"; |
SignalDone(); |
+ if (has_browser_ref_) { |
+ BrowserThread::PostTask( |
+ BrowserThread::UI, FROM_HERE, |
+ NewRunnableMethod(this, &PluginDataRemover::ReleaseBrowserProcess)); |
+ has_browser_ref_ = false; |
+ } |
Release(); |
} |
void PluginDataRemover::OnClearSiteDataResult(bool success) { |
- if (!success) |
- LOG(DFATAL) << "ClearSiteData returned error"; |
+ LOG_IF(DFATAL, !success) << "ClearSiteData returned error"; |
UMA_HISTOGRAM_TIMES("ClearPluginData.time", |
base::Time::Now() - remove_start_time_); |
SignalDone(); |
} |
+void PluginDataRemover::OnPluginShuttingDown() { |
+ VLOG(1) << "Plugin shutting down"; |
+} |
+ |
void PluginDataRemover::OnTimeout() { |
- NOTREACHED() << "Timed out"; |
+ if (is_removing_) { |
+ LOG(DFATAL) << "Timed out"; |
+ if (has_browser_ref_) { |
+ BrowserThread::PostTask( |
+ BrowserThread::UI, FROM_HERE, |
+ NewRunnableMethod(this, &PluginDataRemover::ReleaseBrowserProcess)); |
+ has_browser_ref_ = false; |
+ } |
+ } |
SignalDone(); |
} |
@@ -122,6 +183,8 @@ bool PluginDataRemover::OnMessageReceived(const IPC::Message& msg) { |
IPC_BEGIN_MESSAGE_MAP(PluginDataRemover, msg) |
IPC_MESSAGE_HANDLER(PluginHostMsg_ClearSiteDataResult, |
OnClearSiteDataResult) |
+ IPC_MESSAGE_HANDLER(PluginHostMsg_PluginShuttingDown, |
+ OnPluginShuttingDown) |
IPC_MESSAGE_UNHANDLED_ERROR() |
IPC_END_MESSAGE_MAP() |
@@ -129,8 +192,10 @@ bool PluginDataRemover::OnMessageReceived(const IPC::Message& msg) { |
} |
void PluginDataRemover::OnChannelError() { |
- LOG(DFATAL) << "Channel error"; |
- SignalDone(); |
+ if (is_removing_) { |
+ NOTREACHED() << "Channel error"; |
+ SignalDone(); |
+ } |
} |
void PluginDataRemover::SignalDone() { |