blob: e1efc1f82b56e47e05ed8c54526b1d9bbfc345bf [file] [log] [blame]
[email protected]5896fa042012-03-07 04:41:401// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]d8e682012011-11-17 18:31:542// 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
[email protected]c46cfe22012-09-27 22:11:557#include <limits>
8
[email protected]d8e682012011-11-17 18:31:549#include "base/bind.h"
10#include "base/metrics/histogram.h"
[email protected]fb441962013-05-08 05:35:2411#include "base/sequenced_task_runner_helpers.h"
[email protected]d8e682012011-11-17 18:31:5412#include "base/synchronization/waitable_event.h"
[email protected]1bf0fb22012-04-12 21:44:1613#include "base/utf_string_conversions.h"
[email protected]d8e682012011-11-17 18:31:5414#include "base/version.h"
[email protected]76b70f92011-11-21 19:31:1415#include "content/browser/plugin_process_host.h"
[email protected]e67385f2011-12-21 06:00:5616#include "content/browser/plugin_service_impl.h"
[email protected]49511a72012-12-21 02:47:4217#include "content/browser/renderer_host/pepper/pepper_flash_file_message_filter.h"
[email protected]4734d0b2011-12-03 07:10:4418#include "content/common/child_process_host_impl.h"
[email protected]d8e682012011-11-17 18:31:5419#include "content/common/plugin_messages.h"
[email protected]1bf0fb22012-04-12 21:44:1620#include "content/public/browser/browser_context.h"
[email protected]d8e682012011-11-17 18:31:5421#include "content/public/browser/browser_thread.h"
[email protected]1bf0fb22012-04-12 21:44:1622#include "content/public/common/pepper_plugin_info.h"
[email protected]c3cdc732012-12-07 09:16:5623#include "ppapi/proxy/ppapi_messages.h"
[email protected]61fcb162012-09-04 23:08:5424#include "webkit/plugins/npapi/plugin_utils.h"
[email protected]c46cfe22012-09-27 22:11:5525#include "webkit/plugins/plugin_constants.h"
[email protected]d8e682012011-11-17 18:31:5426
[email protected]1bf0fb22012-04-12 21:44:1627namespace content {
[email protected]d8e682012011-11-17 18:31:5428
29namespace {
30
[email protected]d8e682012011-11-17 18:31:5431// The minimum Flash Player version that implements NPP_ClearSiteData.
32const char kMinFlashVersion[] = "10.3";
33const int64 kRemovalTimeoutMs = 10000;
34const uint64 kClearAllData = 0;
35
36} // namespace
37
[email protected]d8e682012011-11-17 18:31:5438// static
[email protected]1bf0fb22012-04-12 21:44:1639PluginDataRemover* PluginDataRemover::Create(BrowserContext* browser_context) {
40 return new PluginDataRemoverImpl(browser_context);
[email protected]d8e682012011-11-17 18:31:5441}
42
43// static
[email protected]e3464242012-05-05 00:45:3844void PluginDataRemover::GetSupportedPlugins(
45 std::vector<webkit::WebPluginInfo>* supported_plugins) {
[email protected]d8e682012011-11-17 18:31:5446 bool allow_wildcard = false;
47 std::vector<webkit::WebPluginInfo> plugins;
48 PluginService::GetInstance()->GetPluginInfoArray(
[email protected]c46cfe22012-09-27 22:11:5549 GURL(), kFlashPluginSwfMimeType, allow_wildcard, &plugins, NULL);
[email protected]12126d372012-07-11 18:40:5350 Version min_version(kMinFlashVersion);
[email protected]e3464242012-05-05 00:45:3851 for (std::vector<webkit::WebPluginInfo>::iterator it = plugins.begin();
52 it != plugins.end(); ++it) {
[email protected]12126d372012-07-11 18:40:5353 Version version;
[email protected]61fcb162012-09-04 23:08:5454 webkit::npapi::CreateVersionFromString(it->version, &version);
[email protected]12126d372012-07-11 18:40:5355 if (version.IsValid() && min_version.CompareTo(version) == -1)
[email protected]e3464242012-05-05 00:45:3856 supported_plugins->push_back(*it);
57 }
[email protected]d8e682012011-11-17 18:31:5458}
59
[email protected]76b70f92011-11-21 19:31:1460class PluginDataRemoverImpl::Context
61 : public PluginProcessHost::Client,
[email protected]1bf0fb22012-04-12 21:44:1662 public PpapiPluginProcessHost::BrokerClient,
[email protected]d84effeb2012-06-25 17:03:1063 public IPC::Listener,
[email protected]1464ce12011-12-08 11:14:3264 public base::RefCountedThreadSafe<Context,
65 BrowserThread::DeleteOnIOThread> {
[email protected]76b70f92011-11-21 19:31:1466 public:
[email protected]1bf0fb22012-04-12 21:44:1667 Context(base::Time begin_time, BrowserContext* browser_context)
[email protected]76b70f92011-11-21 19:31:1468 : event_(new base::WaitableEvent(true, false)),
69 begin_time_(begin_time),
70 is_removing_(false),
[email protected]1bf0fb22012-04-12 21:44:1671 browser_context_path_(browser_context->GetPath()),
72 resource_context_(browser_context->GetResourceContext()),
[email protected]76b70f92011-11-21 19:31:1473 channel_(NULL) {
[email protected]1bf0fb22012-04-12 21:44:1674 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]1464ce12011-12-08 11:14:3275 }
76
[email protected]1464ce12011-12-08 11:14:3277 void Init(const std::string& mime_type) {
[email protected]76b70f92011-11-21 19:31:1478 BrowserThread::PostTask(
79 BrowserThread::IO,
80 FROM_HERE,
[email protected]1464ce12011-12-08 11:14:3281 base::Bind(&Context::InitOnIOThread, this, mime_type));
[email protected]76b70f92011-11-21 19:31:1482 BrowserThread::PostDelayedTask(
83 BrowserThread::IO,
84 FROM_HERE,
85 base::Bind(&Context::OnTimeout, this),
[email protected]5896fa042012-03-07 04:41:4086 base::TimeDelta::FromMilliseconds(kRemovalTimeoutMs));
[email protected]76b70f92011-11-21 19:31:1487 }
88
[email protected]1464ce12011-12-08 11:14:3289 void InitOnIOThread(const std::string& mime_type) {
[email protected]1bf0fb22012-04-12 21:44:1690 PluginServiceImpl* plugin_service = PluginServiceImpl::GetInstance();
91
92 // Get the plugin file path.
93 std::vector<webkit::WebPluginInfo> plugins;
94 plugin_service->GetPluginInfoArray(
95 GURL(), mime_type, false, &plugins, NULL);
[email protected]2dec8ec2013-02-07 19:20:3496 base::FilePath plugin_path;
[email protected]1bf0fb22012-04-12 21:44:1697 if (!plugins.empty()) // May be empty for some tests.
98 plugin_path = plugins[0].path;
99
[email protected]1464ce12011-12-08 11:14:32100 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
101 remove_start_time_ = base::Time::Now();
102 is_removing_ = true;
[email protected]1bf0fb22012-04-12 21:44:16103 // Balanced in On[Ppapi]ChannelOpened or OnError. Exactly one them will
104 // eventually be called, so we need to keep this object around until then.
[email protected]1464ce12011-12-08 11:14:32105 AddRef();
[email protected]1bf0fb22012-04-12 21:44:16106
107 PepperPluginInfo* pepper_info =
108 plugin_service->GetRegisteredPpapiPluginInfo(plugin_path);
109 if (pepper_info) {
[email protected]4cce3f3f2012-04-24 02:54:04110 plugin_name_ = pepper_info->name;
[email protected]1bf0fb22012-04-12 21:44:16111 // Use the broker since we run this function outside the sandbox.
[email protected]6be31d202013-02-01 18:20:54112 plugin_service->OpenChannelToPpapiBroker(0, plugin_path, this);
[email protected]1bf0fb22012-04-12 21:44:16113 } else {
114 plugin_service->OpenChannelToNpapiPlugin(
115 0, 0, GURL(), GURL(), mime_type, this);
116 }
[email protected]1464ce12011-12-08 11:14:32117 }
118
119 // Called when a timeout happens in order not to block the client
120 // indefinitely.
121 void OnTimeout() {
122 LOG_IF(ERROR, is_removing_) << "Timed out";
123 SignalDone();
[email protected]76b70f92011-11-21 19:31:14124 }
125
126 // PluginProcessHost::Client methods.
127 virtual int ID() OVERRIDE {
128 // Generate a unique identifier for this PluginProcessHostClient.
[email protected]4734d0b2011-12-03 07:10:44129 return ChildProcessHostImpl::GenerateChildProcessUniqueId();
[email protected]76b70f92011-11-21 19:31:14130 }
131
132 virtual bool OffTheRecord() OVERRIDE {
133 return false;
134 }
135
[email protected]1bf0fb22012-04-12 21:44:16136 virtual ResourceContext* GetResourceContext() OVERRIDE {
[email protected]76b70f92011-11-21 19:31:14137 return resource_context_;
138 }
139
[email protected]fb90c942012-04-27 23:40:50140 virtual void SetPluginInfo(const webkit::WebPluginInfo& info) OVERRIDE {}
[email protected]76b70f92011-11-21 19:31:14141
[email protected]fb90c942012-04-27 23:40:50142 virtual void OnFoundPluginProcessHost(PluginProcessHost* host) OVERRIDE {}
[email protected]76b70f92011-11-21 19:31:14143
[email protected]fb90c942012-04-27 23:40:50144 virtual void OnSentPluginChannelRequest() OVERRIDE {}
[email protected]76b70f92011-11-21 19:31:14145
146 virtual void OnChannelOpened(const IPC::ChannelHandle& handle) OVERRIDE {
[email protected]1bf0fb22012-04-12 21:44:16147 ConnectToChannel(handle, false);
[email protected]76b70f92011-11-21 19:31:14148 // Balancing the AddRef call.
149 Release();
150 }
151
152 virtual void OnError() OVERRIDE {
[email protected]791ce4ac2011-12-21 13:44:34153 LOG(ERROR) << "Couldn't open plugin channel";
[email protected]76b70f92011-11-21 19:31:14154 SignalDone();
155 // Balancing the AddRef call.
156 Release();
157 }
158
[email protected]1bf0fb22012-04-12 21:44:16159 // PpapiPluginProcessHost::BrokerClient implementation.
160 virtual void GetPpapiChannelInfo(base::ProcessHandle* renderer_handle,
161 int* renderer_id) OVERRIDE {
[email protected]54c23f12012-05-04 21:01:19162 *renderer_handle = base::kNullProcessHandle;
[email protected]1bf0fb22012-04-12 21:44:16163 *renderer_id = 0;
164 }
165
166 virtual void OnPpapiChannelOpened(
[email protected]8be45842012-04-13 19:49:29167 const IPC::ChannelHandle& channel_handle,
[email protected]108fd342013-01-04 20:46:54168 base::ProcessId /* peer_pid */,
[email protected]8be45842012-04-13 19:49:29169 int /* child_id */) OVERRIDE {
[email protected]54c23f12012-05-04 21:01:19170 if (!channel_handle.name.empty())
[email protected]1bf0fb22012-04-12 21:44:16171 ConnectToChannel(channel_handle, true);
172
173 // Balancing the AddRef call.
174 Release();
175 }
176
[email protected]d84effeb2012-06-25 17:03:10177 // IPC::Listener methods.
[email protected]76b70f92011-11-21 19:31:14178 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
179 IPC_BEGIN_MESSAGE_MAP(Context, message)
180 IPC_MESSAGE_HANDLER(PluginHostMsg_ClearSiteDataResult,
181 OnClearSiteDataResult)
[email protected]1bf0fb22012-04-12 21:44:16182 IPC_MESSAGE_HANDLER(PpapiHostMsg_ClearSiteDataResult,
[email protected]951ef0b2012-07-27 22:46:53183 OnPpapiClearSiteDataResult)
[email protected]76b70f92011-11-21 19:31:14184 IPC_MESSAGE_UNHANDLED_ERROR()
185 IPC_END_MESSAGE_MAP()
186
187 return true;
188 }
189
190 virtual void OnChannelError() OVERRIDE {
191 if (is_removing_) {
192 NOTREACHED() << "Channel error";
193 SignalDone();
194 }
195 }
196
[email protected]76b70f92011-11-21 19:31:14197 base::WaitableEvent* event() { return event_.get(); }
198
199 private:
[email protected]fb90c942012-04-27 23:40:50200 friend struct BrowserThread::DeleteOnThread<BrowserThread::IO>;
201 friend class base::DeleteHelper<Context>;
202 virtual ~Context() {}
203
[email protected]6d17f6392012-12-05 05:24:54204 IPC::Message* CreatePpapiClearSiteDataMsg(uint64 max_age) {
[email protected]2dec8ec2013-02-07 19:20:34205 base::FilePath profile_path =
[email protected]49511a72012-12-21 02:47:42206 PepperFlashFileMessageFilter::GetDataDirName(browser_context_path_);
[email protected]6d17f6392012-12-05 05:24:54207 // TODO(vtl): This "duplicates" logic in webkit/plugins/ppapi/file_path.cc
208 // (which prepends the plugin name to the relative part of the path
209 // instead, with the absolute, profile-dependent part being enforced by
210 // the browser).
211#if defined(OS_WIN)
[email protected]2dec8ec2013-02-07 19:20:34212 base::FilePath plugin_data_path =
213 profile_path.Append(base::FilePath(UTF8ToUTF16(plugin_name_)));
[email protected]6d17f6392012-12-05 05:24:54214#else
[email protected]2dec8ec2013-02-07 19:20:34215 base::FilePath plugin_data_path =
216 profile_path.Append(base::FilePath(plugin_name_));
[email protected]6d17f6392012-12-05 05:24:54217#endif // defined(OS_WIN)
218 return new PpapiMsg_ClearSiteData(0u, plugin_data_path, std::string(),
219 kClearAllData, max_age);
220 }
[email protected]6d17f6392012-12-05 05:24:54221
[email protected]76b70f92011-11-21 19:31:14222 // Connects the client side of a newly opened plug-in channel.
[email protected]1bf0fb22012-04-12 21:44:16223 void ConnectToChannel(const IPC::ChannelHandle& handle, bool is_ppapi) {
[email protected]76b70f92011-11-21 19:31:14224 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
225
226 // If we timed out, don't bother connecting.
227 if (!is_removing_)
228 return;
229
[email protected]1464ce12011-12-08 11:14:32230 DCHECK(!channel_.get());
231 channel_.reset(new IPC::Channel(handle, IPC::Channel::MODE_CLIENT, this));
[email protected]76b70f92011-11-21 19:31:14232 if (!channel_->Connect()) {
233 NOTREACHED() << "Couldn't connect to plugin";
234 SignalDone();
235 return;
236 }
237
[email protected]1bf0fb22012-04-12 21:44:16238 uint64 max_age = begin_time_.is_null() ?
239 std::numeric_limits<uint64>::max() :
240 (base::Time::Now() - begin_time_).InSeconds();
241
242 IPC::Message* msg;
243 if (is_ppapi) {
[email protected]6d17f6392012-12-05 05:24:54244 msg = CreatePpapiClearSiteDataMsg(max_age);
[email protected]1bf0fb22012-04-12 21:44:16245 } else {
246 msg = new PluginMsg_ClearSiteData(std::string(), kClearAllData, max_age);
247 }
248 if (!channel_->Send(msg)) {
[email protected]76b70f92011-11-21 19:31:14249 NOTREACHED() << "Couldn't send ClearSiteData message";
250 SignalDone();
251 return;
252 }
253 }
254
[email protected]951ef0b2012-07-27 22:46:53255 // Handles the PpapiHostMsg_ClearSiteDataResult message by delegating to the
256 // PluginHostMsg_ClearSiteDataResult handler.
257 void OnPpapiClearSiteDataResult(uint32 request_id, bool success) {
258 DCHECK_EQ(0u, request_id);
259 OnClearSiteDataResult(success);
260 }
261
262 // Handles the PluginHostMsg_ClearSiteDataResult message.
[email protected]76b70f92011-11-21 19:31:14263 void OnClearSiteDataResult(bool success) {
264 LOG_IF(ERROR, !success) << "ClearSiteData returned error";
265 UMA_HISTOGRAM_TIMES("ClearPluginData.time",
266 base::Time::Now() - remove_start_time_);
267 SignalDone();
268 }
269
[email protected]76b70f92011-11-21 19:31:14270 // Signals that we are finished with removing data (successful or not). This
271 // method is safe to call multiple times.
272 void SignalDone() {
273 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
274 if (!is_removing_)
275 return;
276 is_removing_ = false;
277 event_->Signal();
278 }
279
280 scoped_ptr<base::WaitableEvent> event_;
281 // The point in time when we start removing data.
282 base::Time remove_start_time_;
283 // The point in time from which on we remove data.
284 base::Time begin_time_;
285 bool is_removing_;
286
[email protected]1bf0fb22012-04-12 21:44:16287 // Path for the current profile. Must be retrieved on the UI thread from the
288 // browser context when we start so we can use it later on the I/O thread.
[email protected]2dec8ec2013-02-07 19:20:34289 base::FilePath browser_context_path_;
[email protected]1bf0fb22012-04-12 21:44:16290
291 // The resource context for the profile. Use only on the I/O thread.
292 ResourceContext* resource_context_;
[email protected]76b70f92011-11-21 19:31:14293
[email protected]4cce3f3f2012-04-24 02:54:04294 // The name of the plugin. Use only on the I/O thread.
295 std::string plugin_name_;
296
[email protected]1464ce12011-12-08 11:14:32297 // The channel is NULL until we have opened a connection to the plug-in
[email protected]76b70f92011-11-21 19:31:14298 // process.
[email protected]1464ce12011-12-08 11:14:32299 scoped_ptr<IPC::Channel> channel_;
[email protected]76b70f92011-11-21 19:31:14300};
301
302
[email protected]1bf0fb22012-04-12 21:44:16303PluginDataRemoverImpl::PluginDataRemoverImpl(BrowserContext* browser_context)
[email protected]c46cfe22012-09-27 22:11:55304 : mime_type_(kFlashPluginSwfMimeType),
[email protected]1bf0fb22012-04-12 21:44:16305 browser_context_(browser_context) {
[email protected]d8e682012011-11-17 18:31:54306}
307
308PluginDataRemoverImpl::~PluginDataRemoverImpl() {
[email protected]d8e682012011-11-17 18:31:54309}
310
311base::WaitableEvent* PluginDataRemoverImpl::StartRemoving(
312 base::Time begin_time) {
[email protected]76b70f92011-11-21 19:31:14313 DCHECK(!context_.get());
[email protected]1bf0fb22012-04-12 21:44:16314 context_ = new Context(begin_time, browser_context_);
[email protected]1464ce12011-12-08 11:14:32315 context_->Init(mime_type_);
[email protected]76b70f92011-11-21 19:31:14316 return context_->event();
[email protected]d8e682012011-11-17 18:31:54317}
[email protected]1bf0fb22012-04-12 21:44:16318
319} // namespace content