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/content_constants.h"
23 #include "content/public/common/pepper_plugin_info.h"
24 #include "ppapi/proxy/ppapi_messages.h"
30 // The minimum Flash Player version that implements NPP_ClearSiteData.
31 const char kMinFlashVersion
[] = "10.3";
32 const int64 kRemovalTimeoutMs
= 10000;
33 const uint64 kClearAllData
= 0;
38 PluginDataRemover
* PluginDataRemover::Create(BrowserContext
* browser_context
) {
39 return new PluginDataRemoverImpl(browser_context
);
43 void PluginDataRemover::GetSupportedPlugins(
44 std::vector
<WebPluginInfo
>* supported_plugins
) {
45 bool allow_wildcard
= false;
46 std::vector
<WebPluginInfo
> plugins
;
47 PluginService::GetInstance()->GetPluginInfoArray(
48 GURL(), kFlashPluginSwfMimeType
, allow_wildcard
, &plugins
, NULL
);
49 Version
min_version(kMinFlashVersion
);
50 for (std::vector
<WebPluginInfo
>::iterator it
= plugins
.begin();
51 it
!= plugins
.end(); ++it
) {
53 WebPluginInfo::CreateVersionFromString(it
->version
, &version
);
54 if (version
.IsValid() && min_version
.CompareTo(version
) == -1)
55 supported_plugins
->push_back(*it
);
59 class PluginDataRemoverImpl::Context
60 : public PluginProcessHost::Client
,
61 public PpapiPluginProcessHost::BrokerClient
,
63 public base::RefCountedThreadSafe
<Context
,
64 BrowserThread::DeleteOnIOThread
> {
66 Context(base::Time begin_time
, BrowserContext
* browser_context
)
67 : event_(new base::WaitableEvent(true, false)),
68 begin_time_(begin_time
),
70 browser_context_path_(browser_context
->GetPath()),
71 resource_context_(browser_context
->GetResourceContext()) {
72 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
75 void Init(const std::string
& mime_type
) {
76 BrowserThread::PostTask(
79 base::Bind(&Context::InitOnIOThread
, this, mime_type
));
80 BrowserThread::PostDelayedTask(
83 base::Bind(&Context::OnTimeout
, this),
84 base::TimeDelta::FromMilliseconds(kRemovalTimeoutMs
));
87 void InitOnIOThread(const std::string
& mime_type
) {
88 PluginServiceImpl
* plugin_service
= PluginServiceImpl::GetInstance();
90 // Get the plugin file path.
91 std::vector
<WebPluginInfo
> plugins
;
92 plugin_service
->GetPluginInfoArray(
93 GURL(), mime_type
, false, &plugins
, NULL
);
94 base::FilePath plugin_path
;
95 if (!plugins
.empty()) // May be empty for some tests.
96 plugin_path
= plugins
[0].path
;
98 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
99 remove_start_time_
= base::Time::Now();
101 // Balanced in On[Ppapi]ChannelOpened or OnError. Exactly one them will
102 // eventually be called, so we need to keep this object around until then.
105 PepperPluginInfo
* pepper_info
=
106 plugin_service
->GetRegisteredPpapiPluginInfo(plugin_path
);
108 plugin_name_
= pepper_info
->name
;
109 // Use the broker since we run this function outside the sandbox.
110 plugin_service
->OpenChannelToPpapiBroker(0, plugin_path
, this);
112 plugin_service
->OpenChannelToNpapiPlugin(
113 0, 0, GURL(), GURL(), mime_type
, this);
117 // Called when a timeout happens in order not to block the client
120 LOG_IF(ERROR
, is_removing_
) << "Timed out";
124 // PluginProcessHost::Client methods.
126 // Generate a unique identifier for this PluginProcessHostClient.
127 return ChildProcessHostImpl::GenerateChildProcessUniqueId();
130 bool OffTheRecord() override
{ return false; }
132 ResourceContext
* GetResourceContext() override
{ return resource_context_
; }
134 void SetPluginInfo(const WebPluginInfo
& info
) override
{}
136 void OnFoundPluginProcessHost(PluginProcessHost
* host
) override
{}
138 void OnSentPluginChannelRequest() override
{}
140 void OnChannelOpened(const IPC::ChannelHandle
& handle
) override
{
141 ConnectToChannel(handle
, false);
142 // Balancing the AddRef call.
146 void OnError() override
{
147 LOG(ERROR
) << "Couldn't open plugin channel";
149 // Balancing the AddRef call.
153 // PpapiPluginProcessHost::BrokerClient implementation.
154 void GetPpapiChannelInfo(base::ProcessHandle
* renderer_handle
,
155 int* renderer_id
) override
{
156 *renderer_handle
= base::kNullProcessHandle
;
160 void OnPpapiChannelOpened(const IPC::ChannelHandle
& channel_handle
,
161 base::ProcessId
/* peer_pid */,
162 int /* child_id */) override
{
163 if (!channel_handle
.name
.empty())
164 ConnectToChannel(channel_handle
, true);
166 // Balancing the AddRef call.
170 // IPC::Listener methods.
171 bool OnMessageReceived(const IPC::Message
& message
) override
{
172 IPC_BEGIN_MESSAGE_MAP(Context
, message
)
173 IPC_MESSAGE_HANDLER(PluginProcessHostMsg_ClearSiteDataResult
,
174 OnClearSiteDataResult
)
175 IPC_MESSAGE_HANDLER(PpapiHostMsg_ClearSiteDataResult
,
176 OnPpapiClearSiteDataResult
)
177 IPC_MESSAGE_UNHANDLED_ERROR()
178 IPC_END_MESSAGE_MAP()
183 void OnChannelError() override
{
185 NOTREACHED() << "Channel error";
190 base::WaitableEvent
* event() { return event_
.get(); }
193 friend struct BrowserThread::DeleteOnThread
<BrowserThread::IO
>;
194 friend class base::DeleteHelper
<Context
>;
195 ~Context() override
{}
197 IPC::Message
* CreatePpapiClearSiteDataMsg(uint64 max_age
) {
198 base::FilePath profile_path
=
199 PepperFlashFileMessageFilter::GetDataDirName(browser_context_path_
);
200 // TODO(vtl): This "duplicates" logic in webkit/plugins/ppapi/file_path.cc
201 // (which prepends the plugin name to the relative part of the path
202 // instead, with the absolute, profile-dependent part being enforced by
205 base::FilePath plugin_data_path
=
206 profile_path
.Append(base::FilePath(base::UTF8ToUTF16(plugin_name_
)));
208 base::FilePath plugin_data_path
=
209 profile_path
.Append(base::FilePath(plugin_name_
));
210 #endif // defined(OS_WIN)
211 return new PpapiMsg_ClearSiteData(0u, plugin_data_path
, std::string(),
212 kClearAllData
, max_age
);
215 // Connects the client side of a newly opened plug-in channel.
216 void ConnectToChannel(const IPC::ChannelHandle
& handle
, bool is_ppapi
) {
217 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
219 // If we timed out, don't bother connecting.
223 DCHECK(!channel_
.get());
224 channel_
= IPC::Channel::CreateClient(handle
, this);
225 if (!channel_
->Connect()) {
226 NOTREACHED() << "Couldn't connect to plugin";
231 uint64 max_age
= begin_time_
.is_null() ?
232 std::numeric_limits
<uint64
>::max() :
233 (base::Time::Now() - begin_time_
).InSeconds();
237 msg
= CreatePpapiClearSiteDataMsg(max_age
);
239 msg
= new PluginProcessMsg_ClearSiteData(
240 std::string(), kClearAllData
, max_age
);
242 if (!channel_
->Send(msg
)) {
243 NOTREACHED() << "Couldn't send ClearSiteData message";
249 // Handles the PpapiHostMsg_ClearSiteDataResult message by delegating to the
250 // PluginProcessHostMsg_ClearSiteDataResult handler.
251 void OnPpapiClearSiteDataResult(uint32 request_id
, bool success
) {
252 DCHECK_EQ(0u, request_id
);
253 OnClearSiteDataResult(success
);
256 // Handles the PluginProcessHostMsg_ClearSiteDataResult message.
257 void OnClearSiteDataResult(bool success
) {
258 LOG_IF(ERROR
, !success
) << "ClearSiteData returned error";
259 UMA_HISTOGRAM_TIMES("ClearPluginData.time",
260 base::Time::Now() - remove_start_time_
);
264 // Signals that we are finished with removing data (successful or not). This
265 // method is safe to call multiple times.
267 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
270 is_removing_
= false;
274 scoped_ptr
<base::WaitableEvent
> event_
;
275 // The point in time when we start removing data.
276 base::Time remove_start_time_
;
277 // The point in time from which on we remove data.
278 base::Time begin_time_
;
281 // Path for the current profile. Must be retrieved on the UI thread from the
282 // browser context when we start so we can use it later on the I/O thread.
283 base::FilePath browser_context_path_
;
285 // The resource context for the profile. Use only on the I/O thread.
286 ResourceContext
* resource_context_
;
288 // The name of the plugin. Use only on the I/O thread.
289 std::string plugin_name_
;
291 // The channel is NULL until we have opened a connection to the plug-in
293 scoped_ptr
<IPC::Channel
> channel_
;
297 PluginDataRemoverImpl::PluginDataRemoverImpl(BrowserContext
* browser_context
)
298 : mime_type_(kFlashPluginSwfMimeType
),
299 browser_context_(browser_context
) {
302 PluginDataRemoverImpl::~PluginDataRemoverImpl() {
305 base::WaitableEvent
* PluginDataRemoverImpl::StartRemoving(
306 base::Time begin_time
) {
307 DCHECK(!context_
.get());
308 context_
= new Context(begin_time
, browser_context_
);
309 context_
->Init(mime_type_
);
310 return context_
->event();
313 } // namespace content