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
3 // found in the LICENSE file.
4
5 #include "chrome/browser/plugin_data_remover.h"
6
7 #include "base/command_line.h"
8 #include "base/message_loop_proxy.h"
9 #include "base/metrics/histogram.h"
10 #include "base/synchronization/waitable_event.h"
11 #include "base/version.h"
12 #include "chrome/common/chrome_switches.h"
13 #include "content/browser/browser_thread.h"
14 #include "content/browser/plugin_service.h"
15 #include "content/common/plugin_messages.h"
16 #include "webkit/plugins/npapi/plugin_group.h"
17 #include "webkit/plugins/npapi/plugin_list.h"
18
19 #if defined(OS_POSIX)
20 #include "ipc/ipc_channel_posix.h"
21 #endif
22
23 namespace {
24
25 const char* kFlashMimeType = "application/x-shockwave-flash";
26 // The minimum Flash Player version that implements NPP_ClearSiteData.
27 const char* kMinFlashVersion = "10.3";
28 const int64 kRemovalTimeoutMs = 10000;
29 const uint64 kClearAllData = 0;
30
31 } // namespace
32
PluginDataRemover()33 PluginDataRemover::PluginDataRemover()
34 : mime_type_(kFlashMimeType),
35 is_removing_(false),
36 event_(new base::WaitableEvent(true, false)),
37 channel_(NULL) {
38 }
39
~PluginDataRemover()40 PluginDataRemover::~PluginDataRemover() {
41 DCHECK(!is_removing_);
42 if (channel_)
43 BrowserThread::DeleteSoon(BrowserThread::IO, FROM_HERE, channel_);
44 }
45
StartRemoving(base::Time begin_time)46 base::WaitableEvent* PluginDataRemover::StartRemoving(base::Time begin_time) {
47 DCHECK(!is_removing_);
48 remove_start_time_ = base::Time::Now();
49 begin_time_ = begin_time;
50
51 is_removing_ = true;
52
53 // Balanced in OnChannelOpened or OnError. Exactly one them will eventually be
54 // called, so we need to keep this object around until then.
55 AddRef();
56 PluginService::GetInstance()->OpenChannelToNpapiPlugin(
57 0, 0, GURL(), mime_type_, this);
58
59 BrowserThread::PostDelayedTask(
60 BrowserThread::IO,
61 FROM_HERE,
62 NewRunnableMethod(this, &PluginDataRemover::OnTimeout),
63 kRemovalTimeoutMs);
64
65 return event_.get();
66 }
67
Wait()68 void PluginDataRemover::Wait() {
69 base::Time start_time(base::Time::Now());
70 bool result = true;
71 if (is_removing_)
72 result = event_->Wait();
73 UMA_HISTOGRAM_TIMES("ClearPluginData.wait_at_shutdown",
74 base::Time::Now() - start_time);
75 UMA_HISTOGRAM_TIMES("ClearPluginData.time_at_shutdown",
76 base::Time::Now() - remove_start_time_);
77 DCHECK(result) << "Error waiting for plugin process";
78 }
79
ID()80 int PluginDataRemover::ID() {
81 // Generate a unique identifier for this PluginProcessHostClient.
82 return ChildProcessInfo::GenerateChildProcessUniqueId();
83 }
84
OffTheRecord()85 bool PluginDataRemover::OffTheRecord() {
86 return false;
87 }
88
SetPluginInfo(const webkit::npapi::WebPluginInfo & info)89 void PluginDataRemover::SetPluginInfo(
90 const webkit::npapi::WebPluginInfo& info) {
91 }
92
OnChannelOpened(const IPC::ChannelHandle & handle)93 void PluginDataRemover::OnChannelOpened(const IPC::ChannelHandle& handle) {
94 ConnectToChannel(handle);
95 // Balancing the AddRef call in StartRemoving.
96 Release();
97 }
98
ConnectToChannel(const IPC::ChannelHandle & handle)99 void PluginDataRemover::ConnectToChannel(const IPC::ChannelHandle& handle) {
100 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
101
102 // If we timed out, don't bother connecting.
103 if (!is_removing_)
104 return;
105
106 DCHECK(!channel_);
107 channel_ = new IPC::Channel(handle, IPC::Channel::MODE_CLIENT, this);
108 if (!channel_->Connect()) {
109 NOTREACHED() << "Couldn't connect to plugin";
110 SignalDone();
111 return;
112 }
113
114 if (!channel_->Send(new PluginMsg_ClearSiteData(std::string(),
115 kClearAllData,
116 begin_time_))) {
117 NOTREACHED() << "Couldn't send ClearSiteData message";
118 SignalDone();
119 return;
120 }
121 }
122
OnError()123 void PluginDataRemover::OnError() {
124 LOG(DFATAL) << "Couldn't open plugin channel";
125 SignalDone();
126 // Balancing the AddRef call in StartRemoving.
127 Release();
128 }
129
OnClearSiteDataResult(bool success)130 void PluginDataRemover::OnClearSiteDataResult(bool success) {
131 LOG_IF(DFATAL, !success) << "ClearSiteData returned error";
132 UMA_HISTOGRAM_TIMES("ClearPluginData.time",
133 base::Time::Now() - remove_start_time_);
134 SignalDone();
135 }
136
OnTimeout()137 void PluginDataRemover::OnTimeout() {
138 LOG_IF(DFATAL, is_removing_) << "Timed out";
139 SignalDone();
140 }
141
OnMessageReceived(const IPC::Message & msg)142 bool PluginDataRemover::OnMessageReceived(const IPC::Message& msg) {
143 IPC_BEGIN_MESSAGE_MAP(PluginDataRemover, msg)
144 IPC_MESSAGE_HANDLER(PluginHostMsg_ClearSiteDataResult,
145 OnClearSiteDataResult)
146 IPC_MESSAGE_UNHANDLED_ERROR()
147 IPC_END_MESSAGE_MAP()
148
149 return true;
150 }
151
OnChannelError()152 void PluginDataRemover::OnChannelError() {
153 if (is_removing_) {
154 NOTREACHED() << "Channel error";
155 SignalDone();
156 }
157 }
158
SignalDone()159 void PluginDataRemover::SignalDone() {
160 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
161 if (!is_removing_)
162 return;
163 is_removing_ = false;
164 event_->Signal();
165 }
166
167 // static
IsSupported()168 bool PluginDataRemover::IsSupported() {
169 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
170 bool allow_wildcard = false;
171 webkit::npapi::WebPluginInfo plugin;
172 std::string mime_type;
173 if (!webkit::npapi::PluginList::Singleton()->GetPluginInfo(
174 GURL(), kFlashMimeType, allow_wildcard, &plugin, &mime_type)) {
175 return false;
176 }
177 scoped_ptr<Version> version(
178 webkit::npapi::PluginGroup::CreateVersionFromString(plugin.version));
179 scoped_ptr<Version> min_version(Version::GetVersionFromString(
180 CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
181 switches::kMinClearSiteDataFlashVersion)));
182 if (!min_version.get())
183 min_version.reset(Version::GetVersionFromString(kMinFlashVersion));
184 return webkit::npapi::IsPluginEnabled(plugin) &&
185 version.get() &&
186 min_version->CompareTo(*version) == -1;
187 }
188