blob: 7d2669076c34ddf706e788e1afd390bf7244c607 [file] [log] [blame]
[email protected]d8e682012011-11-17 18:31:541// 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 "content/browser/plugin_data_remover_impl.h"
6
7#include "base/bind.h"
8#include "base/metrics/histogram.h"
9#include "base/synchronization/waitable_event.h"
10#include "base/version.h"
[email protected]76b70f92011-11-21 19:31:1411#include "content/browser/plugin_process_host.h"
[email protected]d8e682012011-11-17 18:31:5412#include "content/browser/plugin_service.h"
[email protected]4734d0b2011-12-03 07:10:4413#include "content/common/child_process_host_impl.h"
[email protected]d8e682012011-11-17 18:31:5414#include "content/common/plugin_messages.h"
15#include "content/public/browser/browser_thread.h"
16#include "webkit/plugins/npapi/plugin_group.h"
17
18using content::BrowserThread;
[email protected]4734d0b2011-12-03 07:10:4419using content::ChildProcessHostImpl;
[email protected]d8e682012011-11-17 18:31:5420
21namespace {
22
23const char kFlashMimeType[] = "application/x-shockwave-flash";
24// The minimum Flash Player version that implements NPP_ClearSiteData.
25const char kMinFlashVersion[] = "10.3";
26const int64 kRemovalTimeoutMs = 10000;
27const uint64 kClearAllData = 0;
28
29} // namespace
30
31namespace content {
32
33// static
34PluginDataRemover* PluginDataRemover::Create(
35 const content::ResourceContext& resource_context) {
36 return new PluginDataRemoverImpl(resource_context);
37}
38
39// static
40bool PluginDataRemover::IsSupported(webkit::WebPluginInfo* plugin) {
41 bool allow_wildcard = false;
42 std::vector<webkit::WebPluginInfo> plugins;
43 PluginService::GetInstance()->GetPluginInfoArray(
44 GURL(), kFlashMimeType, allow_wildcard, &plugins, NULL);
45 std::vector<webkit::WebPluginInfo>::iterator plugin_it = plugins.begin();
46 if (plugin_it == plugins.end())
47 return false;
48 scoped_ptr<Version> version(
49 webkit::npapi::PluginGroup::CreateVersionFromString(plugin_it->version));
50 scoped_ptr<Version> min_version(
51 Version::GetVersionFromString(kMinFlashVersion));
52 bool rv = version.get() && min_version->CompareTo(*version) == -1;
53 if (rv)
54 *plugin = *plugin_it;
55 return rv;
56}
57
58}
59
[email protected]76b70f92011-11-21 19:31:1460class PluginDataRemoverImpl::Context
61 : public PluginProcessHost::Client,
62 public IPC::Channel::Listener,
[email protected]1464ce12011-12-08 11:14:3263 public base::RefCountedThreadSafe<Context,
64 BrowserThread::DeleteOnIOThread> {
[email protected]76b70f92011-11-21 19:31:1465 public:
[email protected]1464ce12011-12-08 11:14:3266 Context(base::Time begin_time,
[email protected]76b70f92011-11-21 19:31:1467 const content::ResourceContext& resource_context)
68 : event_(new base::WaitableEvent(true, false)),
69 begin_time_(begin_time),
70 is_removing_(false),
71 resource_context_(resource_context),
72 channel_(NULL) {
[email protected]1464ce12011-12-08 11:14:3273 }
74
75 virtual ~Context() {
76 }
77
78 void Init(const std::string& mime_type) {
[email protected]76b70f92011-11-21 19:31:1479 BrowserThread::PostTask(
80 BrowserThread::IO,
81 FROM_HERE,
[email protected]1464ce12011-12-08 11:14:3282 base::Bind(&Context::InitOnIOThread, this, mime_type));
[email protected]76b70f92011-11-21 19:31:1483 BrowserThread::PostDelayedTask(
84 BrowserThread::IO,
85 FROM_HERE,
86 base::Bind(&Context::OnTimeout, this),
87 kRemovalTimeoutMs);
88 }
89
[email protected]1464ce12011-12-08 11:14:3290 // Initialize on the IO thread.
91 void InitOnIOThread(const std::string& mime_type) {
92 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
93 remove_start_time_ = base::Time::Now();
94 is_removing_ = true;
95 // Balanced in OnChannelOpened or OnError. Exactly one them will eventually
96 // be called, so we need to keep this object around until then.
97 AddRef();
98 PluginService::GetInstance()->OpenChannelToNpapiPlugin(
99 0, 0, GURL(), GURL(), mime_type, this);
100 }
101
102 // Called when a timeout happens in order not to block the client
103 // indefinitely.
104 void OnTimeout() {
105 LOG_IF(ERROR, is_removing_) << "Timed out";
106 SignalDone();
[email protected]76b70f92011-11-21 19:31:14107 }
108
109 // PluginProcessHost::Client methods.
110 virtual int ID() OVERRIDE {
111 // Generate a unique identifier for this PluginProcessHostClient.
[email protected]4734d0b2011-12-03 07:10:44112 return ChildProcessHostImpl::GenerateChildProcessUniqueId();
[email protected]76b70f92011-11-21 19:31:14113 }
114
115 virtual bool OffTheRecord() OVERRIDE {
116 return false;
117 }
118
119 virtual const content::ResourceContext& GetResourceContext() OVERRIDE {
120 return resource_context_;
121 }
122
123 virtual void SetPluginInfo(const webkit::WebPluginInfo& info) OVERRIDE {
124 }
125
126 virtual void OnFoundPluginProcessHost(PluginProcessHost* host) OVERRIDE {
127 }
128
129 virtual void OnSentPluginChannelRequest() OVERRIDE {
130 }
131
132 virtual void OnChannelOpened(const IPC::ChannelHandle& handle) OVERRIDE {
133 ConnectToChannel(handle);
134 // Balancing the AddRef call.
135 Release();
136 }
137
138 virtual void OnError() OVERRIDE {
139 LOG(DFATAL) << "Couldn't open plugin channel";
140 SignalDone();
141 // Balancing the AddRef call.
142 Release();
143 }
144
145 // IPC::Channel::Listener methods.
146 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
147 IPC_BEGIN_MESSAGE_MAP(Context, message)
148 IPC_MESSAGE_HANDLER(PluginHostMsg_ClearSiteDataResult,
149 OnClearSiteDataResult)
150 IPC_MESSAGE_UNHANDLED_ERROR()
151 IPC_END_MESSAGE_MAP()
152
153 return true;
154 }
155
156 virtual void OnChannelError() OVERRIDE {
157 if (is_removing_) {
158 NOTREACHED() << "Channel error";
159 SignalDone();
160 }
161 }
162
[email protected]76b70f92011-11-21 19:31:14163 base::WaitableEvent* event() { return event_.get(); }
164
165 private:
[email protected]76b70f92011-11-21 19:31:14166 // Connects the client side of a newly opened plug-in channel.
167 void ConnectToChannel(const IPC::ChannelHandle& handle) {
168 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
169
170 // If we timed out, don't bother connecting.
171 if (!is_removing_)
172 return;
173
[email protected]1464ce12011-12-08 11:14:32174 DCHECK(!channel_.get());
175 channel_.reset(new IPC::Channel(handle, IPC::Channel::MODE_CLIENT, this));
[email protected]76b70f92011-11-21 19:31:14176 if (!channel_->Connect()) {
177 NOTREACHED() << "Couldn't connect to plugin";
178 SignalDone();
179 return;
180 }
181
182 if (!channel_->Send(new PluginMsg_ClearSiteData(std::string(),
183 kClearAllData,
184 begin_time_))) {
185 NOTREACHED() << "Couldn't send ClearSiteData message";
186 SignalDone();
187 return;
188 }
189 }
190
191 // Handles the PluginHostMsg_ClearSiteDataResult message.
192 void OnClearSiteDataResult(bool success) {
193 LOG_IF(ERROR, !success) << "ClearSiteData returned error";
194 UMA_HISTOGRAM_TIMES("ClearPluginData.time",
195 base::Time::Now() - remove_start_time_);
196 SignalDone();
197 }
198
[email protected]76b70f92011-11-21 19:31:14199 // Signals that we are finished with removing data (successful or not). This
200 // method is safe to call multiple times.
201 void SignalDone() {
202 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
203 if (!is_removing_)
204 return;
205 is_removing_ = false;
206 event_->Signal();
207 }
208
209 scoped_ptr<base::WaitableEvent> event_;
210 // The point in time when we start removing data.
211 base::Time remove_start_time_;
212 // The point in time from which on we remove data.
213 base::Time begin_time_;
214 bool is_removing_;
215
216 // The resource context for the profile.
217 const content::ResourceContext& resource_context_;
218
[email protected]1464ce12011-12-08 11:14:32219 // The channel is NULL until we have opened a connection to the plug-in
[email protected]76b70f92011-11-21 19:31:14220 // process.
[email protected]1464ce12011-12-08 11:14:32221 scoped_ptr<IPC::Channel> channel_;
[email protected]76b70f92011-11-21 19:31:14222};
223
224
[email protected]d8e682012011-11-17 18:31:54225PluginDataRemoverImpl::PluginDataRemoverImpl(
226 const content::ResourceContext& resource_context)
227 : mime_type_(kFlashMimeType),
[email protected]76b70f92011-11-21 19:31:14228 resource_context_(resource_context) {
[email protected]d8e682012011-11-17 18:31:54229}
230
231PluginDataRemoverImpl::~PluginDataRemoverImpl() {
[email protected]d8e682012011-11-17 18:31:54232}
233
234base::WaitableEvent* PluginDataRemoverImpl::StartRemoving(
235 base::Time begin_time) {
[email protected]76b70f92011-11-21 19:31:14236 DCHECK(!context_.get());
[email protected]1464ce12011-12-08 11:14:32237 context_ = new Context(begin_time, resource_context_);
238 context_->Init(mime_type_);
[email protected]76b70f92011-11-21 19:31:14239 return context_->event();
[email protected]d8e682012011-11-17 18:31:54240}