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 if (plugins.empty()) { | |
99 NOTREACHED(); | |
100 return; | |
101 } | |
102 FilePath plugin_path = plugins[0].path; | |
103 | |
92 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 104 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
93 remove_start_time_ = base::Time::Now(); | 105 remove_start_time_ = base::Time::Now(); |
94 is_removing_ = true; | 106 is_removing_ = true; |
95 // Balanced in OnChannelOpened or OnError. Exactly one them will eventually | 107 // Balanced in OnChannelOpened or OnError. Exactly one them will eventually |
viettrungluu
2012/04/11 02:48:10
Now there are two OnChannelOpened's!
| |
96 // be called, so we need to keep this object around until then. | 108 // be called, so we need to keep this object around until then. |
97 AddRef(); | 109 AddRef(); |
98 PluginServiceImpl::GetInstance()->OpenChannelToNpapiPlugin( | 110 |
99 0, 0, GURL(), GURL(), mime_type, this); | 111 PepperPluginInfo* pepper_info = |
112 plugin_service->GetRegisteredPpapiPluginInfo(plugin_path); | |
113 if (pepper_info) { | |
114 // Use the broker since we run this function outside the sandbox. | |
115 plugin_service->OpenChannelToPpapiBroker(plugin_path, this); | |
116 } else { | |
117 plugin_service->OpenChannelToNpapiPlugin( | |
118 0, 0, GURL(), GURL(), mime_type, this); | |
119 } | |
100 } | 120 } |
101 | 121 |
102 // Called when a timeout happens in order not to block the client | 122 // Called when a timeout happens in order not to block the client |
103 // indefinitely. | 123 // indefinitely. |
104 void OnTimeout() { | 124 void OnTimeout() { |
105 LOG_IF(ERROR, is_removing_) << "Timed out"; | 125 LOG_IF(ERROR, is_removing_) << "Timed out"; |
106 SignalDone(); | 126 SignalDone(); |
107 } | 127 } |
108 | 128 |
109 // PluginProcessHost::Client methods. | 129 // PluginProcessHost::Client methods. |
110 virtual int ID() OVERRIDE { | 130 virtual int ID() OVERRIDE { |
111 // Generate a unique identifier for this PluginProcessHostClient. | 131 // Generate a unique identifier for this PluginProcessHostClient. |
112 return ChildProcessHostImpl::GenerateChildProcessUniqueId(); | 132 return ChildProcessHostImpl::GenerateChildProcessUniqueId(); |
113 } | 133 } |
114 | 134 |
115 virtual bool OffTheRecord() OVERRIDE { | 135 virtual bool OffTheRecord() OVERRIDE { |
116 return false; | 136 return false; |
117 } | 137 } |
118 | 138 |
119 virtual content::ResourceContext* GetResourceContext() OVERRIDE { | 139 virtual ResourceContext* GetResourceContext() OVERRIDE { |
120 return resource_context_; | 140 return resource_context_; |
121 } | 141 } |
122 | 142 |
123 virtual void SetPluginInfo(const webkit::WebPluginInfo& info) OVERRIDE { | 143 virtual void SetPluginInfo(const webkit::WebPluginInfo& info) OVERRIDE { |
124 } | 144 } |
125 | 145 |
126 virtual void OnFoundPluginProcessHost(PluginProcessHost* host) OVERRIDE { | 146 virtual void OnFoundPluginProcessHost(PluginProcessHost* host) OVERRIDE { |
127 } | 147 } |
128 | 148 |
129 virtual void OnSentPluginChannelRequest() OVERRIDE { | 149 virtual void OnSentPluginChannelRequest() OVERRIDE { |
130 } | 150 } |
131 | 151 |
132 virtual void OnChannelOpened(const IPC::ChannelHandle& handle) OVERRIDE { | 152 virtual void OnChannelOpened(const IPC::ChannelHandle& handle) OVERRIDE { |
133 ConnectToChannel(handle); | 153 ConnectToChannel(handle, false); |
134 // Balancing the AddRef call. | 154 // Balancing the AddRef call. |
135 Release(); | 155 Release(); |
136 } | 156 } |
137 | 157 |
138 virtual void OnError() OVERRIDE { | 158 virtual void OnError() OVERRIDE { |
139 LOG(ERROR) << "Couldn't open plugin channel"; | 159 LOG(ERROR) << "Couldn't open plugin channel"; |
140 SignalDone(); | 160 SignalDone(); |
141 // Balancing the AddRef call. | 161 // Balancing the AddRef call. |
142 Release(); | 162 Release(); |
143 } | 163 } |
144 | 164 |
165 // PpapiPluginProcessHost::BrokerClient implementation. | |
166 virtual void GetChannelInfo(base::ProcessHandle* renderer_handle, | |
167 int* renderer_id) OVERRIDE { | |
168 *renderer_id = 0; | |
169 } | |
170 | |
171 virtual void OnChannelOpened( | |
viettrungluu
2012/04/11 02:48:10
Having two very similar |OnChannelOpened()|s is re
| |
172 base::ProcessHandle plugin_process_handle, | |
173 const IPC::ChannelHandle& channel_handle) OVERRIDE { | |
174 ConnectToChannel(channel_handle, true); | |
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 |