• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // 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 "chrome/browser/plugin_data_remover.h"
6 
7 #include "base/command_line.h"
8 #include "base/message_loop_proxy.h"
9 #include "base/metrics/histogram.h"
10 #include "base/synchronization/waitable_event.h"
11 #include "base/version.h"
12 #include "chrome/common/chrome_switches.h"
13 #include "content/browser/browser_thread.h"
14 #include "content/browser/plugin_service.h"
15 #include "content/common/plugin_messages.h"
16 #include "webkit/plugins/npapi/plugin_group.h"
17 #include "webkit/plugins/npapi/plugin_list.h"
18 
19 #if defined(OS_POSIX)
20 #include "ipc/ipc_channel_posix.h"
21 #endif
22 
23 namespace {
24 
25 const char* kFlashMimeType = "application/x-shockwave-flash";
26 // The minimum Flash Player version that implements NPP_ClearSiteData.
27 const char* kMinFlashVersion = "10.3";
28 const int64 kRemovalTimeoutMs = 10000;
29 const uint64 kClearAllData = 0;
30 
31 }  // namespace
32 
PluginDataRemover()33 PluginDataRemover::PluginDataRemover()
34     : mime_type_(kFlashMimeType),
35       is_removing_(false),
36       event_(new base::WaitableEvent(true, false)),
37       channel_(NULL) {
38 }
39 
~PluginDataRemover()40 PluginDataRemover::~PluginDataRemover() {
41   DCHECK(!is_removing_);
42   if (channel_)
43     BrowserThread::DeleteSoon(BrowserThread::IO, FROM_HERE, channel_);
44 }
45 
StartRemoving(base::Time begin_time)46 base::WaitableEvent* PluginDataRemover::StartRemoving(base::Time begin_time) {
47   DCHECK(!is_removing_);
48   remove_start_time_ = base::Time::Now();
49   begin_time_ = begin_time;
50 
51   is_removing_ = true;
52 
53   // Balanced in OnChannelOpened or OnError. Exactly one them will eventually be
54   // called, so we need to keep this object around until then.
55   AddRef();
56   PluginService::GetInstance()->OpenChannelToNpapiPlugin(
57       0, 0, GURL(), mime_type_, this);
58 
59   BrowserThread::PostDelayedTask(
60       BrowserThread::IO,
61       FROM_HERE,
62       NewRunnableMethod(this, &PluginDataRemover::OnTimeout),
63       kRemovalTimeoutMs);
64 
65   return event_.get();
66 }
67 
Wait()68 void PluginDataRemover::Wait() {
69   base::Time start_time(base::Time::Now());
70   bool result = true;
71   if (is_removing_)
72     result = event_->Wait();
73   UMA_HISTOGRAM_TIMES("ClearPluginData.wait_at_shutdown",
74                       base::Time::Now() - start_time);
75   UMA_HISTOGRAM_TIMES("ClearPluginData.time_at_shutdown",
76                       base::Time::Now() - remove_start_time_);
77   DCHECK(result) << "Error waiting for plugin process";
78 }
79 
ID()80 int PluginDataRemover::ID() {
81   // Generate a unique identifier for this PluginProcessHostClient.
82   return ChildProcessInfo::GenerateChildProcessUniqueId();
83 }
84 
OffTheRecord()85 bool PluginDataRemover::OffTheRecord() {
86   return false;
87 }
88 
SetPluginInfo(const webkit::npapi::WebPluginInfo & info)89 void PluginDataRemover::SetPluginInfo(
90     const webkit::npapi::WebPluginInfo& info) {
91 }
92 
OnChannelOpened(const IPC::ChannelHandle & handle)93 void PluginDataRemover::OnChannelOpened(const IPC::ChannelHandle& handle) {
94   ConnectToChannel(handle);
95   // Balancing the AddRef call in StartRemoving.
96   Release();
97 }
98 
ConnectToChannel(const IPC::ChannelHandle & handle)99 void PluginDataRemover::ConnectToChannel(const IPC::ChannelHandle& handle) {
100   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
101 
102   // If we timed out, don't bother connecting.
103   if (!is_removing_)
104     return;
105 
106   DCHECK(!channel_);
107   channel_ = new IPC::Channel(handle, IPC::Channel::MODE_CLIENT, this);
108   if (!channel_->Connect()) {
109     NOTREACHED() << "Couldn't connect to plugin";
110     SignalDone();
111     return;
112   }
113 
114   if (!channel_->Send(new PluginMsg_ClearSiteData(std::string(),
115                                                   kClearAllData,
116                                                   begin_time_))) {
117     NOTREACHED() << "Couldn't send ClearSiteData message";
118     SignalDone();
119     return;
120   }
121 }
122 
OnError()123 void PluginDataRemover::OnError() {
124   LOG(DFATAL) << "Couldn't open plugin channel";
125   SignalDone();
126   // Balancing the AddRef call in StartRemoving.
127   Release();
128 }
129 
OnClearSiteDataResult(bool success)130 void PluginDataRemover::OnClearSiteDataResult(bool success) {
131   LOG_IF(DFATAL, !success) << "ClearSiteData returned error";
132   UMA_HISTOGRAM_TIMES("ClearPluginData.time",
133                       base::Time::Now() - remove_start_time_);
134   SignalDone();
135 }
136 
OnTimeout()137 void PluginDataRemover::OnTimeout() {
138   LOG_IF(DFATAL, is_removing_) << "Timed out";
139   SignalDone();
140 }
141 
OnMessageReceived(const IPC::Message & msg)142 bool PluginDataRemover::OnMessageReceived(const IPC::Message& msg) {
143   IPC_BEGIN_MESSAGE_MAP(PluginDataRemover, msg)
144     IPC_MESSAGE_HANDLER(PluginHostMsg_ClearSiteDataResult,
145                         OnClearSiteDataResult)
146     IPC_MESSAGE_UNHANDLED_ERROR()
147   IPC_END_MESSAGE_MAP()
148 
149   return true;
150 }
151 
OnChannelError()152 void PluginDataRemover::OnChannelError() {
153   if (is_removing_) {
154     NOTREACHED() << "Channel error";
155     SignalDone();
156   }
157 }
158 
SignalDone()159 void PluginDataRemover::SignalDone() {
160   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
161   if (!is_removing_)
162     return;
163   is_removing_ = false;
164   event_->Signal();
165 }
166 
167 // static
IsSupported()168 bool PluginDataRemover::IsSupported() {
169   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
170   bool allow_wildcard = false;
171   webkit::npapi::WebPluginInfo plugin;
172   std::string mime_type;
173   if (!webkit::npapi::PluginList::Singleton()->GetPluginInfo(
174           GURL(), kFlashMimeType, allow_wildcard, &plugin, &mime_type)) {
175     return false;
176   }
177   scoped_ptr<Version> version(
178       webkit::npapi::PluginGroup::CreateVersionFromString(plugin.version));
179   scoped_ptr<Version> min_version(Version::GetVersionFromString(
180       CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
181           switches::kMinClearSiteDataFlashVersion)));
182   if (!min_version.get())
183     min_version.reset(Version::GetVersionFromString(kMinFlashVersion));
184   return webkit::npapi::IsPluginEnabled(plugin) &&
185          version.get() &&
186          min_version->CompareTo(*version) == -1;
187 }
188