1 // Copyright (c) 2012 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.
5 #include "content/browser/plugin_data_remover_impl.h"
10 #include "base/metrics/histogram.h"
11 #include "base/sequenced_task_runner_helpers.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "base/synchronization/waitable_event.h"
14 #include "base/version.h"
15 #include "content/browser/plugin_process_host.h"
16 #include "content/browser/plugin_service_impl.h"
17 #include "content/browser/renderer_host/pepper/pepper_flash_file_message_filter.h"
18 #include "content/common/child_process_host_impl.h"
19 #include "content/common/plugin_process_messages.h"
20 #include "content/public/browser/browser_context.h"
21 #include "content/public/browser/browser_thread.h"
22 #include "content/public/common/child_process_host.h"
23 #include "content/public/common/content_constants.h"
24 #include "content/public/common/pepper_plugin_info.h"
25 #include "ppapi/proxy/ppapi_messages.h"
31 // The minimum Flash Player version that implements NPP_ClearSiteData.
32 const char kMinFlashVersion
[] = "10.3";
33 const int64 kRemovalTimeoutMs
= 10000;
34 const uint64 kClearAllData
= 0;
39 PluginDataRemover
* PluginDataRemover::Create(BrowserContext
* browser_context
) {
40 return new PluginDataRemoverImpl(browser_context
);
44 void PluginDataRemover::GetSupportedPlugins(
45 std::vector
<WebPluginInfo
>* supported_plugins
) {
46 bool allow_wildcard
= false;
47 std::vector
<WebPluginInfo
> plugins
;
48 PluginService::GetInstance()->GetPluginInfoArray(
49 GURL(), kFlashPluginSwfMimeType
, allow_wildcard
, &plugins
, NULL
);
50 Version
min_version(kMinFlashVersion
);
51 for (std::vector
<WebPluginInfo
>::iterator it
= plugins
.begin();
52 it
!= plugins
.end(); ++it
) {
54 WebPluginInfo::CreateVersionFromString(it
->version
, &version
);
55 if (version
.IsValid() && min_version
.CompareTo(version
) == -1)
56 supported_plugins
->push_back(*it
);
60 class PluginDataRemoverImpl::Context
61 : public PluginProcessHost::Client
,
62 public PpapiPluginProcessHost::BrokerClient
,
64 public base::RefCountedThreadSafe
<Context
,
65 BrowserThread::DeleteOnIOThread
> {
67 Context(base::Time begin_time
, BrowserContext
* browser_context
)
68 : event_(new base::WaitableEvent(true, false)),
69 begin_time_(begin_time
),
71 browser_context_path_(browser_context
->GetPath()),
72 resource_context_(browser_context
->GetResourceContext()) {
73 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
76 void Init(const std::string
& mime_type
) {
77 BrowserThread::PostTask(
80 base::Bind(&Context::InitOnIOThread
, this, mime_type
));
81 BrowserThread::PostDelayedTask(
84 base::Bind(&Context::OnTimeout
, this),
85 base::TimeDelta::FromMilliseconds(kRemovalTimeoutMs
));
88 void InitOnIOThread(const std::string
& mime_type
) {
89 PluginServiceImpl
* plugin_service
= PluginServiceImpl::GetInstance();
91 // Get the plugin file path.
92 std::vector
<WebPluginInfo
> plugins
;
93 plugin_service
->GetPluginInfoArray(
94 GURL(), mime_type
, false, &plugins
, NULL
);
96 if (plugins
.empty()) {
97 // May be empty for some tests and on the CrOS login OOBE screen.
102 base::FilePath plugin_path
= plugins
[0].path
;
104 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
105 remove_start_time_
= base::Time::Now();
107 // Balanced in On[Ppapi]ChannelOpened or OnError. Exactly one them will
108 // eventually be called, so we need to keep this object around until then.
111 PepperPluginInfo
* pepper_info
=
112 plugin_service
->GetRegisteredPpapiPluginInfo(plugin_path
);
114 plugin_name_
= pepper_info
->name
;
115 // Use the broker since we run this function outside the sandbox.
116 plugin_service
->OpenChannelToPpapiBroker(0, plugin_path
, this);
118 plugin_service
->OpenChannelToNpapiPlugin(
119 0, 0, GURL(), GURL(), mime_type
, this);
123 // Called when a timeout happens in order not to block the client
126 LOG_IF(ERROR
, is_removing_
) << "Timed out";
130 // PluginProcessHost::Client methods.
132 // Generate a unique identifier for this PluginProcessHostClient.
133 return ChildProcessHostImpl::GenerateChildProcessUniqueId();
136 bool OffTheRecord() override
{ return false; }
138 ResourceContext
* GetResourceContext() override
{ return resource_context_
; }
140 void SetPluginInfo(const WebPluginInfo
& info
) override
{}
142 void OnFoundPluginProcessHost(PluginProcessHost
* host
) override
{}
144 void OnSentPluginChannelRequest() override
{}
146 void OnChannelOpened(const IPC::ChannelHandle
& handle
) override
{
147 ConnectToChannel(handle
, false);
148 // Balancing the AddRef call.
152 void OnError() override
{
153 LOG(ERROR
) << "Couldn't open plugin channel";
155 // Balancing the AddRef call.
159 // PpapiPluginProcessHost::BrokerClient implementation.
160 void GetPpapiChannelInfo(base::ProcessHandle
* renderer_handle
,
161 int* renderer_id
) override
{
162 *renderer_handle
= base::kNullProcessHandle
;
166 void OnPpapiChannelOpened(const IPC::ChannelHandle
& channel_handle
,
167 base::ProcessId
/* peer_pid */,
168 int /* child_id */) override
{
169 if (!channel_handle
.name
.empty())
170 ConnectToChannel(channel_handle
, true);
172 // Balancing the AddRef call.
176 // IPC::Listener methods.
177 bool OnMessageReceived(const IPC::Message
& message
) override
{
178 IPC_BEGIN_MESSAGE_MAP(Context
, message
)
179 IPC_MESSAGE_HANDLER(PluginProcessHostMsg_ClearSiteDataResult
,
180 OnClearSiteDataResult
)
181 IPC_MESSAGE_HANDLER(PpapiHostMsg_ClearSiteDataResult
,
182 OnPpapiClearSiteDataResult
)
183 IPC_MESSAGE_UNHANDLED_ERROR()
184 IPC_END_MESSAGE_MAP()
189 void OnChannelError() override
{
191 NOTREACHED() << "Channel error";
196 base::WaitableEvent
* event() { return event_
.get(); }
199 friend struct BrowserThread::DeleteOnThread
<BrowserThread::IO
>;
200 friend class base::DeleteHelper
<Context
>;
201 ~Context() override
{}
203 IPC::Message
* CreatePpapiClearSiteDataMsg(uint64 max_age
) {
204 base::FilePath profile_path
=
205 PepperFlashFileMessageFilter::GetDataDirName(browser_context_path_
);
206 // TODO(vtl): This "duplicates" logic in webkit/plugins/ppapi/file_path.cc
207 // (which prepends the plugin name to the relative part of the path
208 // instead, with the absolute, profile-dependent part being enforced by
211 base::FilePath plugin_data_path
=
212 profile_path
.Append(base::FilePath(base::UTF8ToUTF16(plugin_name_
)));
214 base::FilePath plugin_data_path
=
215 profile_path
.Append(base::FilePath(plugin_name_
));
216 #endif // defined(OS_WIN)
217 return new PpapiMsg_ClearSiteData(0u, plugin_data_path
, std::string(),
218 kClearAllData
, max_age
);
221 // Connects the client side of a newly opened plugin channel.
222 void ConnectToChannel(const IPC::ChannelHandle
& handle
, bool is_ppapi
) {
223 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
225 // If we timed out, don't bother connecting.
229 DCHECK(!channel_
.get());
230 channel_
= IPC::Channel::CreateClient(
231 handle
, this, content::ChildProcessHost::GetAttachmentBroker());
232 if (!channel_
->Connect()) {
233 NOTREACHED() << "Couldn't connect to plugin";
238 uint64 max_age
= begin_time_
.is_null() ?
239 std::numeric_limits
<uint64
>::max() :
240 (base::Time::Now() - begin_time_
).InSeconds();
244 msg
= CreatePpapiClearSiteDataMsg(max_age
);
246 msg
= new PluginProcessMsg_ClearSiteData(
247 std::string(), kClearAllData
, max_age
);
249 if (!channel_
->Send(msg
)) {
250 NOTREACHED() << "Couldn't send ClearSiteData message";
256 // Handles the PpapiHostMsg_ClearSiteDataResult message by delegating to the
257 // PluginProcessHostMsg_ClearSiteDataResult handler.
258 void OnPpapiClearSiteDataResult(uint32 request_id
, bool success
) {
259 DCHECK_EQ(0u, request_id
);
260 OnClearSiteDataResult(success
);
263 // Handles the PluginProcessHostMsg_ClearSiteDataResult message.
264 void OnClearSiteDataResult(bool success
) {
265 LOG_IF(ERROR
, !success
) << "ClearSiteData returned error";
266 UMA_HISTOGRAM_TIMES("ClearPluginData.time",
267 base::Time::Now() - remove_start_time_
);
271 // Signals that we are finished with removing data (successful or not). This
272 // method is safe to call multiple times.
274 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
277 is_removing_
= false;
281 scoped_ptr
<base::WaitableEvent
> event_
;
282 // The point in time when we start removing data.
283 base::Time remove_start_time_
;
284 // The point in time from which on we remove data.
285 base::Time begin_time_
;
288 // Path for the current profile. Must be retrieved on the UI thread from the
289 // browser context when we start so we can use it later on the I/O thread.
290 base::FilePath browser_context_path_
;
292 // The resource context for the profile. Use only on the I/O thread.
293 ResourceContext
* resource_context_
;
295 // The name of the plugin. Use only on the I/O thread.
296 std::string plugin_name_
;
298 // The channel is NULL until we have opened a connection to the plugin
300 scoped_ptr
<IPC::Channel
> channel_
;
304 PluginDataRemoverImpl::PluginDataRemoverImpl(BrowserContext
* browser_context
)
305 : mime_type_(kFlashPluginSwfMimeType
),
306 browser_context_(browser_context
) {
309 PluginDataRemoverImpl::~PluginDataRemoverImpl() {
312 base::WaitableEvent
* PluginDataRemoverImpl::StartRemoving(
313 base::Time begin_time
) {
314 DCHECK(!context_
.get());
315 context_
= new Context(begin_time
, browser_context_
);
316 context_
->Init(mime_type_
);
317 return context_
->event();
320 } // namespace content