chrome/browser/extensions: Remove use of MessageLoopProxy and deprecated MessageLoop...
[chromium-blink-merge.git] / content / browser / plugin_data_remover_impl.cc
blob36cc23fe47f99d89a3df1f503af02167cdf2c3f1
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"
7 #include <limits>
9 #include "base/bind.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"
26 namespace content {
28 namespace {
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;
35 } // namespace
37 // static
38 PluginDataRemover* PluginDataRemover::Create(BrowserContext* browser_context) {
39 return new PluginDataRemoverImpl(browser_context);
42 // static
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) {
52 Version version;
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,
62 public IPC::Listener,
63 public base::RefCountedThreadSafe<Context,
64 BrowserThread::DeleteOnIOThread> {
65 public:
66 Context(base::Time begin_time, BrowserContext* browser_context)
67 : event_(new base::WaitableEvent(true, false)),
68 begin_time_(begin_time),
69 is_removing_(false),
70 browser_context_path_(browser_context->GetPath()),
71 resource_context_(browser_context->GetResourceContext()) {
72 DCHECK_CURRENTLY_ON(BrowserThread::UI);
75 void Init(const std::string& mime_type) {
76 BrowserThread::PostTask(
77 BrowserThread::IO,
78 FROM_HERE,
79 base::Bind(&Context::InitOnIOThread, this, mime_type));
80 BrowserThread::PostDelayedTask(
81 BrowserThread::IO,
82 FROM_HERE,
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);
95 if (plugins.empty()) {
96 // May be empty for some tests and on the CrOS login OOBE screen.
97 event_->Signal();
98 return;
101 base::FilePath plugin_path = plugins[0].path;
103 DCHECK_CURRENTLY_ON(BrowserThread::IO);
104 remove_start_time_ = base::Time::Now();
105 is_removing_ = true;
106 // Balanced in On[Ppapi]ChannelOpened or OnError. Exactly one them will
107 // eventually be called, so we need to keep this object around until then.
108 AddRef();
110 PepperPluginInfo* pepper_info =
111 plugin_service->GetRegisteredPpapiPluginInfo(plugin_path);
112 if (pepper_info) {
113 plugin_name_ = pepper_info->name;
114 // Use the broker since we run this function outside the sandbox.
115 plugin_service->OpenChannelToPpapiBroker(0, plugin_path, this);
116 } else {
117 plugin_service->OpenChannelToNpapiPlugin(
118 0, 0, GURL(), GURL(), mime_type, this);
122 // Called when a timeout happens in order not to block the client
123 // indefinitely.
124 void OnTimeout() {
125 LOG_IF(ERROR, is_removing_) << "Timed out";
126 SignalDone();
129 // PluginProcessHost::Client methods.
130 int ID() override {
131 // Generate a unique identifier for this PluginProcessHostClient.
132 return ChildProcessHostImpl::GenerateChildProcessUniqueId();
135 bool OffTheRecord() override { return false; }
137 ResourceContext* GetResourceContext() override { return resource_context_; }
139 void SetPluginInfo(const WebPluginInfo& info) override {}
141 void OnFoundPluginProcessHost(PluginProcessHost* host) override {}
143 void OnSentPluginChannelRequest() override {}
145 void OnChannelOpened(const IPC::ChannelHandle& handle) override {
146 ConnectToChannel(handle, false);
147 // Balancing the AddRef call.
148 Release();
151 void OnError() override {
152 LOG(ERROR) << "Couldn't open plugin channel";
153 SignalDone();
154 // Balancing the AddRef call.
155 Release();
158 // PpapiPluginProcessHost::BrokerClient implementation.
159 void GetPpapiChannelInfo(base::ProcessHandle* renderer_handle,
160 int* renderer_id) override {
161 *renderer_handle = base::kNullProcessHandle;
162 *renderer_id = 0;
165 void OnPpapiChannelOpened(const IPC::ChannelHandle& channel_handle,
166 base::ProcessId /* peer_pid */,
167 int /* child_id */) override {
168 if (!channel_handle.name.empty())
169 ConnectToChannel(channel_handle, true);
171 // Balancing the AddRef call.
172 Release();
175 // IPC::Listener methods.
176 bool OnMessageReceived(const IPC::Message& message) override {
177 IPC_BEGIN_MESSAGE_MAP(Context, message)
178 IPC_MESSAGE_HANDLER(PluginProcessHostMsg_ClearSiteDataResult,
179 OnClearSiteDataResult)
180 IPC_MESSAGE_HANDLER(PpapiHostMsg_ClearSiteDataResult,
181 OnPpapiClearSiteDataResult)
182 IPC_MESSAGE_UNHANDLED_ERROR()
183 IPC_END_MESSAGE_MAP()
185 return true;
188 void OnChannelError() override {
189 if (is_removing_) {
190 NOTREACHED() << "Channel error";
191 SignalDone();
195 base::WaitableEvent* event() { return event_.get(); }
197 private:
198 friend struct BrowserThread::DeleteOnThread<BrowserThread::IO>;
199 friend class base::DeleteHelper<Context>;
200 ~Context() override {}
202 IPC::Message* CreatePpapiClearSiteDataMsg(uint64 max_age) {
203 base::FilePath profile_path =
204 PepperFlashFileMessageFilter::GetDataDirName(browser_context_path_);
205 // TODO(vtl): This "duplicates" logic in webkit/plugins/ppapi/file_path.cc
206 // (which prepends the plugin name to the relative part of the path
207 // instead, with the absolute, profile-dependent part being enforced by
208 // the browser).
209 #if defined(OS_WIN)
210 base::FilePath plugin_data_path =
211 profile_path.Append(base::FilePath(base::UTF8ToUTF16(plugin_name_)));
212 #else
213 base::FilePath plugin_data_path =
214 profile_path.Append(base::FilePath(plugin_name_));
215 #endif // defined(OS_WIN)
216 return new PpapiMsg_ClearSiteData(0u, plugin_data_path, std::string(),
217 kClearAllData, max_age);
220 // Connects the client side of a newly opened plugin channel.
221 void ConnectToChannel(const IPC::ChannelHandle& handle, bool is_ppapi) {
222 DCHECK_CURRENTLY_ON(BrowserThread::IO);
224 // If we timed out, don't bother connecting.
225 if (!is_removing_)
226 return;
228 DCHECK(!channel_.get());
229 channel_ = IPC::Channel::CreateClient(handle, this);
230 if (!channel_->Connect()) {
231 NOTREACHED() << "Couldn't connect to plugin";
232 SignalDone();
233 return;
236 uint64 max_age = begin_time_.is_null() ?
237 std::numeric_limits<uint64>::max() :
238 (base::Time::Now() - begin_time_).InSeconds();
240 IPC::Message* msg;
241 if (is_ppapi) {
242 msg = CreatePpapiClearSiteDataMsg(max_age);
243 } else {
244 msg = new PluginProcessMsg_ClearSiteData(
245 std::string(), kClearAllData, max_age);
247 if (!channel_->Send(msg)) {
248 NOTREACHED() << "Couldn't send ClearSiteData message";
249 SignalDone();
250 return;
254 // Handles the PpapiHostMsg_ClearSiteDataResult message by delegating to the
255 // PluginProcessHostMsg_ClearSiteDataResult handler.
256 void OnPpapiClearSiteDataResult(uint32 request_id, bool success) {
257 DCHECK_EQ(0u, request_id);
258 OnClearSiteDataResult(success);
261 // Handles the PluginProcessHostMsg_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_);
266 SignalDone();
269 // Signals that we are finished with removing data (successful or not). This
270 // method is safe to call multiple times.
271 void SignalDone() {
272 DCHECK_CURRENTLY_ON(BrowserThread::IO);
273 if (!is_removing_)
274 return;
275 is_removing_ = false;
276 event_->Signal();
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_;
284 bool is_removing_;
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 base::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 plugin
297 // process.
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