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/synchronization/waitable_event.h"
13 #include "base/utf_string_conversions.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_messages.h"
20 #include "content/public/browser/browser_context.h"
21 #include "content/public/browser/browser_thread.h"
22 #include "content/public/common/pepper_plugin_info.h"
23 #include "ppapi/proxy/ppapi_messages.h"
24 #include "webkit/plugins/npapi/plugin_utils.h"
25 #include "webkit/plugins/plugin_constants.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
<webkit::WebPluginInfo
>* supported_plugins
) {
46 bool allow_wildcard
= false;
47 std::vector
<webkit::WebPluginInfo
> plugins
;
48 PluginService::GetInstance()->GetPluginInfoArray(
49 GURL(), kFlashPluginSwfMimeType
, allow_wildcard
, &plugins
, NULL
);
50 Version
min_version(kMinFlashVersion
);
51 for (std::vector
<webkit::WebPluginInfo
>::iterator it
= plugins
.begin();
52 it
!= plugins
.end(); ++it
) {
54 webkit::npapi::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()),
74 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
77 void Init(const std::string
& mime_type
) {
78 BrowserThread::PostTask(
81 base::Bind(&Context::InitOnIOThread
, this, mime_type
));
82 BrowserThread::PostDelayedTask(
85 base::Bind(&Context::OnTimeout
, this),
86 base::TimeDelta::FromMilliseconds(kRemovalTimeoutMs
));
89 void InitOnIOThread(const std::string
& mime_type
) {
90 PluginServiceImpl
* plugin_service
= PluginServiceImpl::GetInstance();
92 // Get the plugin file path.
93 std::vector
<webkit::WebPluginInfo
> plugins
;
94 plugin_service
->GetPluginInfoArray(
95 GURL(), mime_type
, false, &plugins
, NULL
);
97 if (!plugins
.empty()) // May be empty for some tests.
98 plugin_path
= plugins
[0].path
;
100 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
101 remove_start_time_
= base::Time::Now();
103 // 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.
107 PepperPluginInfo
* pepper_info
=
108 plugin_service
->GetRegisteredPpapiPluginInfo(plugin_path
);
110 plugin_name_
= pepper_info
->name
;
111 // Use the broker since we run this function outside the sandbox.
112 plugin_service
->OpenChannelToPpapiBroker(plugin_path
, this);
114 plugin_service
->OpenChannelToNpapiPlugin(
115 0, 0, GURL(), GURL(), mime_type
, this);
119 // Called when a timeout happens in order not to block the client
122 LOG_IF(ERROR
, is_removing_
) << "Timed out";
126 // PluginProcessHost::Client methods.
127 virtual int ID() OVERRIDE
{
128 // Generate a unique identifier for this PluginProcessHostClient.
129 return ChildProcessHostImpl::GenerateChildProcessUniqueId();
132 virtual bool OffTheRecord() OVERRIDE
{
136 virtual ResourceContext
* GetResourceContext() OVERRIDE
{
137 return resource_context_
;
140 virtual void SetPluginInfo(const webkit::WebPluginInfo
& info
) OVERRIDE
{}
142 virtual void OnFoundPluginProcessHost(PluginProcessHost
* host
) OVERRIDE
{}
144 virtual void OnSentPluginChannelRequest() OVERRIDE
{}
146 virtual void OnChannelOpened(const IPC::ChannelHandle
& handle
) OVERRIDE
{
147 ConnectToChannel(handle
, false);
148 // Balancing the AddRef call.
152 virtual void OnError() OVERRIDE
{
153 LOG(ERROR
) << "Couldn't open plugin channel";
155 // Balancing the AddRef call.
159 // PpapiPluginProcessHost::BrokerClient implementation.
160 virtual void GetPpapiChannelInfo(base::ProcessHandle
* renderer_handle
,
161 int* renderer_id
) OVERRIDE
{
162 *renderer_handle
= base::kNullProcessHandle
;
166 virtual void OnPpapiChannelOpened(
167 const IPC::ChannelHandle
& channel_handle
,
168 base::ProcessId
/* peer_pid */,
169 int /* child_id */) OVERRIDE
{
170 if (!channel_handle
.name
.empty())
171 ConnectToChannel(channel_handle
, true);
173 // Balancing the AddRef call.
177 // IPC::Listener methods.
178 virtual bool OnMessageReceived(const IPC::Message
& message
) OVERRIDE
{
179 IPC_BEGIN_MESSAGE_MAP(Context
, message
)
180 IPC_MESSAGE_HANDLER(PluginHostMsg_ClearSiteDataResult
,
181 OnClearSiteDataResult
)
182 IPC_MESSAGE_HANDLER(PpapiHostMsg_ClearSiteDataResult
,
183 OnPpapiClearSiteDataResult
)
184 IPC_MESSAGE_UNHANDLED_ERROR()
185 IPC_END_MESSAGE_MAP()
190 virtual void OnChannelError() OVERRIDE
{
192 NOTREACHED() << "Channel error";
197 base::WaitableEvent
* event() { return event_
.get(); }
200 friend struct BrowserThread::DeleteOnThread
<BrowserThread::IO
>;
201 friend class base::DeleteHelper
<Context
>;
202 virtual ~Context() {}
204 IPC::Message
* CreatePpapiClearSiteDataMsg(uint64 max_age
) {
205 FilePath profile_path
=
206 PepperFlashFileMessageFilter::GetDataDirName(browser_context_path_
);
207 // 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
212 FilePath plugin_data_path
=
213 profile_path
.Append(FilePath(UTF8ToUTF16(plugin_name_
)));
215 FilePath plugin_data_path
= profile_path
.Append(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 plug-in channel.
222 void ConnectToChannel(const IPC::ChannelHandle
& handle
, bool is_ppapi
) {
223 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
225 // If we timed out, don't bother connecting.
229 DCHECK(!channel_
.get());
230 channel_
.reset(new IPC::Channel(handle
, IPC::Channel::MODE_CLIENT
, this));
231 if (!channel_
->Connect()) {
232 NOTREACHED() << "Couldn't connect to plugin";
237 uint64 max_age
= begin_time_
.is_null() ?
238 std::numeric_limits
<uint64
>::max() :
239 (base::Time::Now() - begin_time_
).InSeconds();
243 msg
= CreatePpapiClearSiteDataMsg(max_age
);
245 msg
= new PluginMsg_ClearSiteData(std::string(), kClearAllData
, max_age
);
247 if (!channel_
->Send(msg
)) {
248 NOTREACHED() << "Couldn't send ClearSiteData message";
254 // Handles the PpapiHostMsg_ClearSiteDataResult message by delegating to the
255 // PluginHostMsg_ClearSiteDataResult handler.
256 void OnPpapiClearSiteDataResult(uint32 request_id
, bool success
) {
257 DCHECK_EQ(0u, request_id
);
258 OnClearSiteDataResult(success
);
261 // Handles the PluginHostMsg_ClearSiteDataResult message.
262 void OnClearSiteDataResult(bool success
) {
263 LOG_IF(ERROR
, !success
) << "ClearSiteData returned error";
264 UMA_HISTOGRAM_TIMES("ClearPluginData.time",
265 base::Time::Now() - remove_start_time_
);
269 // Signals that we are finished with removing data (successful or not). This
270 // method is safe to call multiple times.
272 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
275 is_removing_
= false;
279 scoped_ptr
<base::WaitableEvent
> event_
;
280 // The point in time when we start removing data.
281 base::Time remove_start_time_
;
282 // The point in time from which on we remove data.
283 base::Time begin_time_
;
286 // Path for the current profile. Must be retrieved on the UI thread from the
287 // browser context when we start so we can use it later on the I/O thread.
288 FilePath browser_context_path_
;
290 // The resource context for the profile. Use only on the I/O thread.
291 ResourceContext
* resource_context_
;
293 // The name of the plugin. Use only on the I/O thread.
294 std::string plugin_name_
;
296 // The channel is NULL until we have opened a connection to the plug-in
298 scoped_ptr
<IPC::Channel
> channel_
;
302 PluginDataRemoverImpl::PluginDataRemoverImpl(BrowserContext
* browser_context
)
303 : mime_type_(kFlashPluginSwfMimeType
),
304 browser_context_(browser_context
) {
307 PluginDataRemoverImpl::~PluginDataRemoverImpl() {
310 base::WaitableEvent
* PluginDataRemoverImpl::StartRemoving(
311 base::Time begin_time
) {
312 DCHECK(!context_
.get());
313 context_
= new Context(begin_time
, browser_context_
);
314 context_
->Init(mime_type_
);
315 return context_
->event();
318 } // namespace content