OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/browser/plugin_data_remover_impl.h" | 5 #include "content/browser/plugin_data_remover_impl.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/metrics/histogram.h" | 8 #include "base/metrics/histogram.h" |
9 #include "base/synchronization/waitable_event.h" | 9 #include "base/synchronization/waitable_event.h" |
| 10 #include "base/utf_string_conversions.h" |
10 #include "base/version.h" | 11 #include "base/version.h" |
11 #include "content/browser/plugin_process_host.h" | 12 #include "content/browser/plugin_process_host.h" |
12 #include "content/browser/plugin_service_impl.h" | 13 #include "content/browser/plugin_service_impl.h" |
| 14 #include "content/browser/renderer_host/pepper_file_message_filter.h" |
13 #include "content/common/child_process_host_impl.h" | 15 #include "content/common/child_process_host_impl.h" |
14 #include "content/common/plugin_messages.h" | 16 #include "content/common/plugin_messages.h" |
| 17 #include "content/public/browser/browser_context.h" |
15 #include "content/public/browser/browser_thread.h" | 18 #include "content/public/browser/browser_thread.h" |
| 19 #include "content/public/common/pepper_plugin_info.h" |
| 20 #include "ppapi/proxy/ppapi_messages.h" |
16 #include "webkit/plugins/npapi/plugin_group.h" | 21 #include "webkit/plugins/npapi/plugin_group.h" |
17 | 22 |
18 using content::BrowserThread; | 23 namespace content { |
19 using content::ChildProcessHostImpl; | |
20 | 24 |
21 namespace { | 25 namespace { |
22 | 26 |
23 const char kFlashMimeType[] = "application/x-shockwave-flash"; | 27 const char kFlashMimeType[] = "application/x-shockwave-flash"; |
24 // The minimum Flash Player version that implements NPP_ClearSiteData. | 28 // The minimum Flash Player version that implements NPP_ClearSiteData. |
25 const char kMinFlashVersion[] = "10.3"; | 29 const char kMinFlashVersion[] = "10.3"; |
26 const int64 kRemovalTimeoutMs = 10000; | 30 const int64 kRemovalTimeoutMs = 10000; |
27 const uint64 kClearAllData = 0; | 31 const uint64 kClearAllData = 0; |
28 | 32 |
29 } // namespace | 33 } // namespace |
30 | 34 |
31 namespace content { | |
32 | |
33 // static | 35 // static |
34 PluginDataRemover* PluginDataRemover::Create( | 36 PluginDataRemover* PluginDataRemover::Create(BrowserContext* browser_context) { |
35 content::ResourceContext* resource_context) { | 37 return new PluginDataRemoverImpl(browser_context); |
36 return new PluginDataRemoverImpl(resource_context); | |
37 } | 38 } |
38 | 39 |
39 // static | 40 // static |
40 bool PluginDataRemover::IsSupported(webkit::WebPluginInfo* plugin) { | 41 bool PluginDataRemover::IsSupported(webkit::WebPluginInfo* plugin) { |
41 bool allow_wildcard = false; | 42 bool allow_wildcard = false; |
42 std::vector<webkit::WebPluginInfo> plugins; | 43 std::vector<webkit::WebPluginInfo> plugins; |
43 PluginService::GetInstance()->GetPluginInfoArray( | 44 PluginService::GetInstance()->GetPluginInfoArray( |
44 GURL(), kFlashMimeType, allow_wildcard, &plugins, NULL); | 45 GURL(), kFlashMimeType, allow_wildcard, &plugins, NULL); |
45 std::vector<webkit::WebPluginInfo>::iterator plugin_it = plugins.begin(); | 46 std::vector<webkit::WebPluginInfo>::iterator plugin_it = plugins.begin(); |
46 if (plugin_it == plugins.end()) | 47 if (plugin_it == plugins.end()) |
47 return false; | 48 return false; |
48 scoped_ptr<Version> version( | 49 scoped_ptr<Version> version( |
49 webkit::npapi::PluginGroup::CreateVersionFromString(plugin_it->version)); | 50 webkit::npapi::PluginGroup::CreateVersionFromString(plugin_it->version)); |
50 scoped_ptr<Version> min_version( | 51 scoped_ptr<Version> min_version( |
51 Version::GetVersionFromString(kMinFlashVersion)); | 52 Version::GetVersionFromString(kMinFlashVersion)); |
52 bool rv = version.get() && min_version->CompareTo(*version) == -1; | 53 bool rv = version.get() && min_version->CompareTo(*version) == -1; |
53 if (rv) | 54 if (rv) |
54 *plugin = *plugin_it; | 55 *plugin = *plugin_it; |
55 return rv; | 56 return rv; |
56 } | 57 } |
57 | 58 |
58 } | |
59 | |
60 class PluginDataRemoverImpl::Context | 59 class PluginDataRemoverImpl::Context |
61 : public PluginProcessHost::Client, | 60 : public PluginProcessHost::Client, |
| 61 public PpapiPluginProcessHost::BrokerClient, |
62 public IPC::Channel::Listener, | 62 public IPC::Channel::Listener, |
63 public base::RefCountedThreadSafe<Context, | 63 public base::RefCountedThreadSafe<Context, |
64 BrowserThread::DeleteOnIOThread> { | 64 BrowserThread::DeleteOnIOThread> { |
65 public: | 65 public: |
66 Context(base::Time begin_time, | 66 Context(base::Time begin_time, BrowserContext* browser_context) |
67 content::ResourceContext* resource_context) | |
68 : event_(new base::WaitableEvent(true, false)), | 67 : event_(new base::WaitableEvent(true, false)), |
69 begin_time_(begin_time), | 68 begin_time_(begin_time), |
70 is_removing_(false), | 69 is_removing_(false), |
71 resource_context_(resource_context), | 70 browser_context_path_(browser_context->GetPath()), |
| 71 resource_context_(browser_context->GetResourceContext()), |
72 channel_(NULL) { | 72 channel_(NULL) { |
| 73 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
73 } | 74 } |
74 | 75 |
75 virtual ~Context() { | 76 virtual ~Context() { |
76 } | 77 } |
77 | 78 |
78 void Init(const std::string& mime_type) { | 79 void Init(const std::string& mime_type) { |
79 BrowserThread::PostTask( | 80 BrowserThread::PostTask( |
80 BrowserThread::IO, | 81 BrowserThread::IO, |
81 FROM_HERE, | 82 FROM_HERE, |
82 base::Bind(&Context::InitOnIOThread, this, mime_type)); | 83 base::Bind(&Context::InitOnIOThread, this, mime_type)); |
83 BrowserThread::PostDelayedTask( | 84 BrowserThread::PostDelayedTask( |
84 BrowserThread::IO, | 85 BrowserThread::IO, |
85 FROM_HERE, | 86 FROM_HERE, |
86 base::Bind(&Context::OnTimeout, this), | 87 base::Bind(&Context::OnTimeout, this), |
87 base::TimeDelta::FromMilliseconds(kRemovalTimeoutMs)); | 88 base::TimeDelta::FromMilliseconds(kRemovalTimeoutMs)); |
88 } | 89 } |
89 | 90 |
90 // Initialize on the IO thread. | |
91 void InitOnIOThread(const std::string& mime_type) { | 91 void InitOnIOThread(const std::string& mime_type) { |
| 92 PluginServiceImpl* plugin_service = PluginServiceImpl::GetInstance(); |
| 93 |
| 94 // Get the plugin file path. |
| 95 std::vector<webkit::WebPluginInfo> plugins; |
| 96 plugin_service->GetPluginInfoArray( |
| 97 GURL(), mime_type, false, &plugins, NULL); |
| 98 FilePath plugin_path; |
| 99 if (!plugins.empty()) // May be empty for some tests. |
| 100 plugin_path = plugins[0].path; |
| 101 |
92 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 102 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
93 remove_start_time_ = base::Time::Now(); | 103 remove_start_time_ = base::Time::Now(); |
94 is_removing_ = true; | 104 is_removing_ = true; |
95 // Balanced in OnChannelOpened or OnError. Exactly one them will eventually | 105 // Balanced in On[Ppapi]ChannelOpened or OnError. Exactly one them will |
96 // be called, so we need to keep this object around until then. | 106 // eventually be called, so we need to keep this object around until then. |
97 AddRef(); | 107 AddRef(); |
98 PluginServiceImpl::GetInstance()->OpenChannelToNpapiPlugin( | 108 |
99 0, 0, GURL(), GURL(), mime_type, this); | 109 PepperPluginInfo* pepper_info = |
| 110 plugin_service->GetRegisteredPpapiPluginInfo(plugin_path); |
| 111 if (pepper_info) { |
| 112 // Use the broker since we run this function outside the sandbox. |
| 113 plugin_service->OpenChannelToPpapiBroker(plugin_path, this); |
| 114 } else { |
| 115 plugin_service->OpenChannelToNpapiPlugin( |
| 116 0, 0, GURL(), GURL(), mime_type, this); |
| 117 } |
100 } | 118 } |
101 | 119 |
102 // Called when a timeout happens in order not to block the client | 120 // Called when a timeout happens in order not to block the client |
103 // indefinitely. | 121 // indefinitely. |
104 void OnTimeout() { | 122 void OnTimeout() { |
105 LOG_IF(ERROR, is_removing_) << "Timed out"; | 123 LOG_IF(ERROR, is_removing_) << "Timed out"; |
106 SignalDone(); | 124 SignalDone(); |
107 } | 125 } |
108 | 126 |
109 // PluginProcessHost::Client methods. | 127 // PluginProcessHost::Client methods. |
110 virtual int ID() OVERRIDE { | 128 virtual int ID() OVERRIDE { |
111 // Generate a unique identifier for this PluginProcessHostClient. | 129 // Generate a unique identifier for this PluginProcessHostClient. |
112 return ChildProcessHostImpl::GenerateChildProcessUniqueId(); | 130 return ChildProcessHostImpl::GenerateChildProcessUniqueId(); |
113 } | 131 } |
114 | 132 |
115 virtual bool OffTheRecord() OVERRIDE { | 133 virtual bool OffTheRecord() OVERRIDE { |
116 return false; | 134 return false; |
117 } | 135 } |
118 | 136 |
119 virtual content::ResourceContext* GetResourceContext() OVERRIDE { | 137 virtual ResourceContext* GetResourceContext() OVERRIDE { |
120 return resource_context_; | 138 return resource_context_; |
121 } | 139 } |
122 | 140 |
123 virtual void SetPluginInfo(const webkit::WebPluginInfo& info) OVERRIDE { | 141 virtual void SetPluginInfo(const webkit::WebPluginInfo& info) OVERRIDE { |
124 } | 142 } |
125 | 143 |
126 virtual void OnFoundPluginProcessHost(PluginProcessHost* host) OVERRIDE { | 144 virtual void OnFoundPluginProcessHost(PluginProcessHost* host) OVERRIDE { |
127 } | 145 } |
128 | 146 |
129 virtual void OnSentPluginChannelRequest() OVERRIDE { | 147 virtual void OnSentPluginChannelRequest() OVERRIDE { |
130 } | 148 } |
131 | 149 |
132 virtual void OnChannelOpened(const IPC::ChannelHandle& handle) OVERRIDE { | 150 virtual void OnChannelOpened(const IPC::ChannelHandle& handle) OVERRIDE { |
133 ConnectToChannel(handle); | 151 ConnectToChannel(handle, false); |
134 // Balancing the AddRef call. | 152 // Balancing the AddRef call. |
135 Release(); | 153 Release(); |
136 } | 154 } |
137 | 155 |
138 virtual void OnError() OVERRIDE { | 156 virtual void OnError() OVERRIDE { |
139 LOG(ERROR) << "Couldn't open plugin channel"; | 157 LOG(ERROR) << "Couldn't open plugin channel"; |
140 SignalDone(); | 158 SignalDone(); |
141 // Balancing the AddRef call. | 159 // Balancing the AddRef call. |
142 Release(); | 160 Release(); |
143 } | 161 } |
144 | 162 |
| 163 // PpapiPluginProcessHost::BrokerClient implementation. |
| 164 virtual void GetPpapiChannelInfo(base::ProcessHandle* renderer_handle, |
| 165 int* renderer_id) OVERRIDE { |
| 166 *renderer_id = 0; |
| 167 } |
| 168 |
| 169 virtual void OnPpapiChannelOpened( |
| 170 base::ProcessHandle plugin_process_handle, |
| 171 const IPC::ChannelHandle& channel_handle) OVERRIDE { |
| 172 if (plugin_process_handle != base::kNullProcessHandle) |
| 173 ConnectToChannel(channel_handle, true); |
| 174 |
| 175 // Balancing the AddRef call. |
| 176 Release(); |
| 177 } |
| 178 |
145 // IPC::Channel::Listener methods. | 179 // IPC::Channel::Listener methods. |
146 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE { | 180 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE { |
147 IPC_BEGIN_MESSAGE_MAP(Context, message) | 181 IPC_BEGIN_MESSAGE_MAP(Context, message) |
148 IPC_MESSAGE_HANDLER(PluginHostMsg_ClearSiteDataResult, | 182 IPC_MESSAGE_HANDLER(PluginHostMsg_ClearSiteDataResult, |
149 OnClearSiteDataResult) | 183 OnClearSiteDataResult) |
| 184 IPC_MESSAGE_HANDLER(PpapiHostMsg_ClearSiteDataResult, |
| 185 OnClearSiteDataResult) |
150 IPC_MESSAGE_UNHANDLED_ERROR() | 186 IPC_MESSAGE_UNHANDLED_ERROR() |
151 IPC_END_MESSAGE_MAP() | 187 IPC_END_MESSAGE_MAP() |
152 | 188 |
153 return true; | 189 return true; |
154 } | 190 } |
155 | 191 |
156 virtual void OnChannelError() OVERRIDE { | 192 virtual void OnChannelError() OVERRIDE { |
157 if (is_removing_) { | 193 if (is_removing_) { |
158 NOTREACHED() << "Channel error"; | 194 NOTREACHED() << "Channel error"; |
159 SignalDone(); | 195 SignalDone(); |
160 } | 196 } |
161 } | 197 } |
162 | 198 |
163 base::WaitableEvent* event() { return event_.get(); } | 199 base::WaitableEvent* event() { return event_.get(); } |
164 | 200 |
165 private: | 201 private: |
166 // Connects the client side of a newly opened plug-in channel. | 202 // Connects the client side of a newly opened plug-in channel. |
167 void ConnectToChannel(const IPC::ChannelHandle& handle) { | 203 void ConnectToChannel(const IPC::ChannelHandle& handle, bool is_ppapi) { |
168 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 204 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
169 | 205 |
170 // If we timed out, don't bother connecting. | 206 // If we timed out, don't bother connecting. |
171 if (!is_removing_) | 207 if (!is_removing_) |
172 return; | 208 return; |
173 | 209 |
174 DCHECK(!channel_.get()); | 210 DCHECK(!channel_.get()); |
175 channel_.reset(new IPC::Channel(handle, IPC::Channel::MODE_CLIENT, this)); | 211 channel_.reset(new IPC::Channel(handle, IPC::Channel::MODE_CLIENT, this)); |
176 if (!channel_->Connect()) { | 212 if (!channel_->Connect()) { |
177 NOTREACHED() << "Couldn't connect to plugin"; | 213 NOTREACHED() << "Couldn't connect to plugin"; |
178 SignalDone(); | 214 SignalDone(); |
179 return; | 215 return; |
180 } | 216 } |
181 | 217 |
182 if (!channel_->Send(new PluginMsg_ClearSiteData(std::string(), | 218 uint64 max_age = begin_time_.is_null() ? |
183 kClearAllData, | 219 std::numeric_limits<uint64>::max() : |
184 begin_time_))) { | 220 (base::Time::Now() - begin_time_).InSeconds(); |
| 221 |
| 222 IPC::Message* msg; |
| 223 if (is_ppapi) { |
| 224 // Pass the path as 8-bit on all platforms. |
| 225 FilePath profile_path = |
| 226 PepperFileMessageFilter::GetDataDirName(browser_context_path_); |
| 227 #if defined(OS_WIN) |
| 228 std::string path_utf8 = UTF16ToUTF8(profile_path.value()); |
| 229 #else |
| 230 const std::string& path_utf8 = profile_path.value(); |
| 231 #endif |
| 232 msg = new PpapiMsg_ClearSiteData(profile_path, path_utf8, |
| 233 kClearAllData, max_age); |
| 234 } else { |
| 235 msg = new PluginMsg_ClearSiteData(std::string(), kClearAllData, max_age); |
| 236 } |
| 237 if (!channel_->Send(msg)) { |
185 NOTREACHED() << "Couldn't send ClearSiteData message"; | 238 NOTREACHED() << "Couldn't send ClearSiteData message"; |
186 SignalDone(); | 239 SignalDone(); |
187 return; | 240 return; |
188 } | 241 } |
189 } | 242 } |
190 | 243 |
191 // Handles the PluginHostMsg_ClearSiteDataResult message. | 244 // Handles the *HostMsg_ClearSiteDataResult message. |
192 void OnClearSiteDataResult(bool success) { | 245 void OnClearSiteDataResult(bool success) { |
193 LOG_IF(ERROR, !success) << "ClearSiteData returned error"; | 246 LOG_IF(ERROR, !success) << "ClearSiteData returned error"; |
194 UMA_HISTOGRAM_TIMES("ClearPluginData.time", | 247 UMA_HISTOGRAM_TIMES("ClearPluginData.time", |
195 base::Time::Now() - remove_start_time_); | 248 base::Time::Now() - remove_start_time_); |
196 SignalDone(); | 249 SignalDone(); |
197 } | 250 } |
198 | 251 |
199 // Signals that we are finished with removing data (successful or not). This | 252 // Signals that we are finished with removing data (successful or not). This |
200 // method is safe to call multiple times. | 253 // method is safe to call multiple times. |
201 void SignalDone() { | 254 void SignalDone() { |
202 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 255 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
203 if (!is_removing_) | 256 if (!is_removing_) |
204 return; | 257 return; |
205 is_removing_ = false; | 258 is_removing_ = false; |
206 event_->Signal(); | 259 event_->Signal(); |
207 } | 260 } |
208 | 261 |
209 scoped_ptr<base::WaitableEvent> event_; | 262 scoped_ptr<base::WaitableEvent> event_; |
210 // The point in time when we start removing data. | 263 // The point in time when we start removing data. |
211 base::Time remove_start_time_; | 264 base::Time remove_start_time_; |
212 // The point in time from which on we remove data. | 265 // The point in time from which on we remove data. |
213 base::Time begin_time_; | 266 base::Time begin_time_; |
214 bool is_removing_; | 267 bool is_removing_; |
215 | 268 |
216 // The resource context for the profile. | 269 // Path for the current profile. Must be retrieved on the UI thread from the |
217 content::ResourceContext* resource_context_; | 270 // browser context when we start so we can use it later on the I/O thread. |
| 271 FilePath browser_context_path_; |
| 272 |
| 273 // The resource context for the profile. Use only on the I/O thread. |
| 274 ResourceContext* resource_context_; |
218 | 275 |
219 // The channel is NULL until we have opened a connection to the plug-in | 276 // The channel is NULL until we have opened a connection to the plug-in |
220 // process. | 277 // process. |
221 scoped_ptr<IPC::Channel> channel_; | 278 scoped_ptr<IPC::Channel> channel_; |
222 }; | 279 }; |
223 | 280 |
224 | 281 |
225 PluginDataRemoverImpl::PluginDataRemoverImpl( | 282 PluginDataRemoverImpl::PluginDataRemoverImpl(BrowserContext* browser_context) |
226 content::ResourceContext* resource_context) | |
227 : mime_type_(kFlashMimeType), | 283 : mime_type_(kFlashMimeType), |
228 resource_context_(resource_context) { | 284 browser_context_(browser_context) { |
229 } | 285 } |
230 | 286 |
231 PluginDataRemoverImpl::~PluginDataRemoverImpl() { | 287 PluginDataRemoverImpl::~PluginDataRemoverImpl() { |
232 } | 288 } |
233 | 289 |
234 base::WaitableEvent* PluginDataRemoverImpl::StartRemoving( | 290 base::WaitableEvent* PluginDataRemoverImpl::StartRemoving( |
235 base::Time begin_time) { | 291 base::Time begin_time) { |
236 DCHECK(!context_.get()); | 292 DCHECK(!context_.get()); |
237 context_ = new Context(begin_time, resource_context_); | 293 context_ = new Context(begin_time, browser_context_); |
238 context_->Init(mime_type_); | 294 context_->Init(mime_type_); |
239 return context_->event(); | 295 return context_->event(); |
240 } | 296 } |
| 297 |
| 298 } // namespace content |
OLD | NEW |