plugin_data_remover.cc revision 21d179b334e59e9a3bfcaed4c4430bef1bc5759d
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
3// found in the LICENSE file.
4
5#include "chrome/browser/plugin_data_remover.h"
6
7#include "base/message_loop_proxy.h"
8#include "base/metrics/histogram.h"
9#include "base/version.h"
10#include "chrome/browser/browser_thread.h"
11#include "chrome/browser/plugin_service.h"
12#include "chrome/common/plugin_messages.h"
13#include "webkit/plugins/npapi/plugin_group.h"
14#include "webkit/plugins/npapi/plugin_list.h"
15
16#if defined(OS_POSIX)
17#include "ipc/ipc_channel_posix.h"
18#endif
19
20namespace {
21const char* g_flash_mime_type = "application/x-shockwave-flash";
22// TODO(bauerb): Update minimum required Flash version as soon as there is one
23// implementing the API.
24const char* g_min_flash_version = "100";
25const int64 g_timeout_ms = 10000;
26}  // namespace
27
28PluginDataRemover::PluginDataRemover()
29    : is_removing_(false),
30      channel_(NULL) { }
31
32PluginDataRemover::~PluginDataRemover() {
33  DCHECK(!is_removing_);
34  if (channel_)
35    BrowserThread::DeleteSoon(BrowserThread::IO, FROM_HERE, channel_);
36}
37
38void PluginDataRemover::StartRemoving(base::Time begin_time, Task* done_task) {
39  DCHECK(!done_task_.get());
40  DCHECK(!is_removing_);
41  remove_start_time_ = base::Time::Now();
42  begin_time_ = begin_time;
43
44  message_loop_ = base::MessageLoopProxy::CreateForCurrentThread();
45  done_task_.reset(done_task);
46  is_removing_ = true;
47
48  AddRef();
49  PluginService::GetInstance()->OpenChannelToPlugin(
50      GURL(), g_flash_mime_type, this);
51
52  BrowserThread::PostDelayedTask(
53      BrowserThread::IO,
54      FROM_HERE,
55      NewRunnableMethod(this, &PluginDataRemover::OnTimeout),
56      g_timeout_ms);
57}
58
59int PluginDataRemover::ID() {
60  // Generate an ID for the browser process.
61  return ChildProcessInfo::GenerateChildProcessUniqueId();
62}
63
64bool PluginDataRemover::OffTheRecord() {
65  return false;
66}
67
68void PluginDataRemover::SetPluginInfo(
69    const webkit::npapi::WebPluginInfo& info) {
70}
71
72void PluginDataRemover::OnChannelOpened(const IPC::ChannelHandle& handle) {
73  ConnectToChannel(handle);
74  Release();
75}
76
77void PluginDataRemover::ConnectToChannel(const IPC::ChannelHandle& handle) {
78  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
79
80  // If we timed out, don't bother connecting.
81  if (!is_removing_)
82    return;
83
84  DCHECK(!channel_);
85  channel_ = new IPC::Channel(handle, IPC::Channel::MODE_CLIENT, this);
86  if (!channel_->Connect()) {
87    LOG(DFATAL) << "Couldn't connect to plugin";
88    SignalDone();
89    return;
90  }
91
92  if (!channel_->Send(
93          new PluginMsg_ClearSiteData(0, std::string(), begin_time_))) {
94    LOG(DFATAL) << "Couldn't send ClearSiteData message";
95    SignalDone();
96  }
97}
98
99void PluginDataRemover::OnError() {
100  NOTREACHED() << "Couldn't open plugin channel";
101  SignalDone();
102  Release();
103}
104
105void PluginDataRemover::OnClearSiteDataResult(bool success) {
106  if (!success)
107    LOG(DFATAL) << "ClearSiteData returned error";
108  UMA_HISTOGRAM_TIMES("ClearPluginData.time",
109                      base::Time::Now() - remove_start_time_);
110  SignalDone();
111}
112
113void PluginDataRemover::OnTimeout() {
114  NOTREACHED() << "Timed out";
115  SignalDone();
116}
117
118bool PluginDataRemover::OnMessageReceived(const IPC::Message& msg) {
119  IPC_BEGIN_MESSAGE_MAP(PluginDataRemover, msg)
120    IPC_MESSAGE_HANDLER(PluginHostMsg_ClearSiteDataResult,
121                        OnClearSiteDataResult)
122    IPC_MESSAGE_UNHANDLED_ERROR()
123  IPC_END_MESSAGE_MAP()
124
125  return true;
126}
127
128void PluginDataRemover::OnChannelError() {
129  LOG(DFATAL) << "Channel error";
130  SignalDone();
131}
132
133void PluginDataRemover::SignalDone() {
134  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
135  if (!is_removing_)
136    return;
137  is_removing_ = false;
138  if (done_task_.get()) {
139    message_loop_->PostTask(FROM_HERE, done_task_.release());
140    message_loop_ = NULL;
141  }
142}
143
144// static
145bool PluginDataRemover::IsSupported() {
146  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
147  bool allow_wildcard = false;
148  webkit::npapi::WebPluginInfo plugin;
149  std::string mime_type;
150  if (!webkit::npapi::PluginList::Singleton()->GetPluginInfo(GURL(),
151                                                             g_flash_mime_type,
152                                                             allow_wildcard,
153                                                             &plugin,
154                                                             &mime_type))
155    return false;
156  scoped_ptr<Version> version(
157      webkit::npapi::PluginGroup::CreateVersionFromString(plugin.version));
158  scoped_ptr<Version> min_version(
159      Version::GetVersionFromString(g_min_flash_version));
160  return plugin.enabled &&
161         version.get() &&
162         min_version->CompareTo(*version) == -1;
163}
164