Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(83)

Side by Side Diff: content/browser/plugin_data_remover_impl.cc

Issue 8603012: Fix race in PluginDataRemoverImpl going away while it's still being used on the IO thread... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Move Context class to cc file Created 9 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « content/browser/plugin_data_remover_impl.h ('k') | content/browser/plugin_service.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 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 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/version.h" 10 #include "base/version.h"
11 #include "content/browser/plugin_process_host.h"
11 #include "content/browser/plugin_service.h" 12 #include "content/browser/plugin_service.h"
12 #include "content/common/plugin_messages.h" 13 #include "content/common/plugin_messages.h"
13 #include "content/public/browser/browser_thread.h" 14 #include "content/public/browser/browser_thread.h"
14 #include "webkit/plugins/npapi/plugin_group.h" 15 #include "webkit/plugins/npapi/plugin_group.h"
15 16
16 using content::BrowserThread; 17 using content::BrowserThread;
17 18
18 namespace { 19 namespace {
19 20
20 const char kFlashMimeType[] = "application/x-shockwave-flash"; 21 const char kFlashMimeType[] = "application/x-shockwave-flash";
(...skipping 26 matching lines...) Expand all
47 scoped_ptr<Version> min_version( 48 scoped_ptr<Version> min_version(
48 Version::GetVersionFromString(kMinFlashVersion)); 49 Version::GetVersionFromString(kMinFlashVersion));
49 bool rv = version.get() && min_version->CompareTo(*version) == -1; 50 bool rv = version.get() && min_version->CompareTo(*version) == -1;
50 if (rv) 51 if (rv)
51 *plugin = *plugin_it; 52 *plugin = *plugin_it;
52 return rv; 53 return rv;
53 } 54 }
54 55
55 } 56 }
56 57
58 class PluginDataRemoverImpl::Context
59 : public PluginProcessHost::Client,
60 public IPC::Channel::Listener,
61 public base::RefCountedThreadSafe<Context> {
62 public:
63 Context(const std::string& mime_type,
64 base::Time begin_time,
65 const content::ResourceContext& resource_context)
66 : event_(new base::WaitableEvent(true, false)),
67 begin_time_(begin_time),
68 is_removing_(false),
69 resource_context_(resource_context),
70 channel_(NULL) {
71 // Balanced in OnChannelOpened or OnError. Exactly one them will eventually
72 // be called, so we need to keep this object around until then.
73 AddRef();
74 remove_start_time_ = base::Time::Now();
75 BrowserThread::PostTask(
76 BrowserThread::IO,
77 FROM_HERE,
78 base::Bind(&Context::Init, this, mime_type));
79
80 BrowserThread::PostDelayedTask(
81 BrowserThread::IO,
82 FROM_HERE,
83 base::Bind(&Context::OnTimeout, this),
84 kRemovalTimeoutMs);
85 }
86
87 virtual ~Context() {
88 if (channel_)
89 BrowserThread::DeleteSoon(BrowserThread::IO, FROM_HERE, channel_);
90 }
91
92 // PluginProcessHost::Client methods.
93 virtual int ID() OVERRIDE {
94 // Generate a unique identifier for this PluginProcessHostClient.
95 return ChildProcessInfo::GenerateChildProcessUniqueId();
96 }
97
98 virtual bool OffTheRecord() OVERRIDE {
99 return false;
100 }
101
102 virtual const content::ResourceContext& GetResourceContext() OVERRIDE {
103 return resource_context_;
104 }
105
106 virtual void SetPluginInfo(const webkit::WebPluginInfo& info) OVERRIDE {
107 }
108
109 virtual void OnFoundPluginProcessHost(PluginProcessHost* host) OVERRIDE {
110 }
111
112 virtual void OnSentPluginChannelRequest() OVERRIDE {
113 }
114
115 virtual void OnChannelOpened(const IPC::ChannelHandle& handle) OVERRIDE {
116 ConnectToChannel(handle);
117 // Balancing the AddRef call.
118 Release();
119 }
120
121 virtual void OnError() OVERRIDE {
122 LOG(DFATAL) << "Couldn't open plugin channel";
123 SignalDone();
124 // Balancing the AddRef call.
125 Release();
126 }
127
128 // IPC::Channel::Listener methods.
129 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
130 IPC_BEGIN_MESSAGE_MAP(Context, message)
131 IPC_MESSAGE_HANDLER(PluginHostMsg_ClearSiteDataResult,
132 OnClearSiteDataResult)
133 IPC_MESSAGE_UNHANDLED_ERROR()
134 IPC_END_MESSAGE_MAP()
135
136 return true;
137 }
138
139 virtual void OnChannelError() OVERRIDE {
140 if (is_removing_) {
141 NOTREACHED() << "Channel error";
142 SignalDone();
143 }
144 }
145
146
147 base::WaitableEvent* event() { return event_.get(); }
148
149 private:
150 // Initialize on the IO thread.
151 void Init(const std::string& mime_type) {
152 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
153 is_removing_ = true;
154 PluginService::GetInstance()->OpenChannelToNpapiPlugin(
155 0, 0, GURL(), GURL(), mime_type, this);
156 }
157
158 // Connects the client side of a newly opened plug-in channel.
159 void ConnectToChannel(const IPC::ChannelHandle& handle) {
160 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
161
162 // If we timed out, don't bother connecting.
163 if (!is_removing_)
164 return;
165
166 DCHECK(!channel_);
167 channel_ = new IPC::Channel(handle, IPC::Channel::MODE_CLIENT, this);
168 if (!channel_->Connect()) {
169 NOTREACHED() << "Couldn't connect to plugin";
170 SignalDone();
171 return;
172 }
173
174 if (!channel_->Send(new PluginMsg_ClearSiteData(std::string(),
175 kClearAllData,
176 begin_time_))) {
177 NOTREACHED() << "Couldn't send ClearSiteData message";
178 SignalDone();
179 return;
180 }
181 }
182
183 // Handles the PluginHostMsg_ClearSiteDataResult message.
184 void OnClearSiteDataResult(bool success) {
185 LOG_IF(ERROR, !success) << "ClearSiteData returned error";
186 UMA_HISTOGRAM_TIMES("ClearPluginData.time",
187 base::Time::Now() - remove_start_time_);
188 SignalDone();
189 }
190
191 // Called when a timeout happens in order not to block the client
192 // indefinitely.
193 void OnTimeout() {
194 LOG_IF(ERROR, is_removing_) << "Timed out";
195 SignalDone();
196 }
197
198 // Signals that we are finished with removing data (successful or not). This
199 // method is safe to call multiple times.
200 void SignalDone() {
201 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
202 if (!is_removing_)
203 return;
204 is_removing_ = false;
205 event_->Signal();
206 }
207
208 scoped_ptr<base::WaitableEvent> event_;
209 // The point in time when we start removing data.
210 base::Time remove_start_time_;
211 // The point in time from which on we remove data.
212 base::Time begin_time_;
213 bool is_removing_;
214
215 // The resource context for the profile.
216 const content::ResourceContext& resource_context_;
217
218 // We own the channel, but it's used on the IO thread, so it needs to be
219 // deleted there. It's NULL until we have opened a connection to the plug-in
220 // process.
221 IPC::Channel* channel_;
222 };
223
224
57 PluginDataRemoverImpl::PluginDataRemoverImpl( 225 PluginDataRemoverImpl::PluginDataRemoverImpl(
58 const content::ResourceContext& resource_context) 226 const content::ResourceContext& resource_context)
59 : mime_type_(kFlashMimeType), 227 : mime_type_(kFlashMimeType),
60 is_starting_process_(false), 228 resource_context_(resource_context) {
61 is_removing_(false),
62 context_(resource_context),
63 event_(new base::WaitableEvent(true, false)),
64 channel_(NULL),
65 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) {
66 } 229 }
67 230
68 PluginDataRemoverImpl::~PluginDataRemoverImpl() { 231 PluginDataRemoverImpl::~PluginDataRemoverImpl() {
69 if (is_starting_process_)
70 PluginService::GetInstance()->CancelOpenChannelToNpapiPlugin(this);
71 DCHECK(!is_removing_);
72 if (channel_)
73 BrowserThread::DeleteSoon(BrowserThread::IO, FROM_HERE, channel_);
74 } 232 }
75 233
76 base::WaitableEvent* PluginDataRemoverImpl::StartRemoving( 234 base::WaitableEvent* PluginDataRemoverImpl::StartRemoving(
77 base::Time begin_time) { 235 base::Time begin_time) {
78 DCHECK(!is_removing_); 236 DCHECK(!context_.get());
79 remove_start_time_ = base::Time::Now(); 237 context_ = new Context(mime_type_, begin_time, resource_context_);
80 begin_time_ = begin_time; 238 return context_->event();
81
82 is_starting_process_ = true;
83 is_removing_ = true;
84 PluginService::GetInstance()->OpenChannelToNpapiPlugin(
85 0, 0, GURL(), GURL(), mime_type_, this);
86
87 BrowserThread::PostDelayedTask(
88 BrowserThread::IO,
89 FROM_HERE,
90 base::Bind(&PluginDataRemoverImpl::OnTimeout, weak_factory_.GetWeakPtr()),
91 kRemovalTimeoutMs);
92
93 return event_.get();
94 } 239 }
95
96 int PluginDataRemoverImpl::ID() {
97 // Generate a unique identifier for this PluginProcessHostClient.
98 return ChildProcessInfo::GenerateChildProcessUniqueId();
99 }
100
101 bool PluginDataRemoverImpl::OffTheRecord() {
102 return false;
103 }
104
105 const content::ResourceContext& PluginDataRemoverImpl::GetResourceContext() {
106 return context_;
107 }
108
109 void PluginDataRemoverImpl::SetPluginInfo(
110 const webkit::WebPluginInfo& info) {
111 }
112
113 void PluginDataRemoverImpl::OnFoundPluginProcessHost(
114 PluginProcessHost* host) {
115 }
116
117 void PluginDataRemoverImpl::OnSentPluginChannelRequest() {
118 }
119
120 void PluginDataRemoverImpl::OnChannelOpened(const IPC::ChannelHandle& handle) {
121 is_starting_process_ = false;
122 ConnectToChannel(handle);
123 }
124
125 void PluginDataRemoverImpl::ConnectToChannel(const IPC::ChannelHandle& handle) {
126 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
127
128 // If we timed out, don't bother connecting.
129 if (!is_removing_)
130 return;
131
132 DCHECK(!channel_);
133 channel_ = new IPC::Channel(handle, IPC::Channel::MODE_CLIENT, this);
134 if (!channel_->Connect()) {
135 NOTREACHED() << "Couldn't connect to plugin";
136 SignalDone();
137 return;
138 }
139
140 if (!channel_->Send(new PluginMsg_ClearSiteData(std::string(),
141 kClearAllData,
142 begin_time_))) {
143 NOTREACHED() << "Couldn't send ClearSiteData message";
144 SignalDone();
145 return;
146 }
147 }
148
149 void PluginDataRemoverImpl::OnError() {
150 LOG(DFATAL) << "Couldn't open plugin channel";
151 SignalDone();
152 }
153
154 void PluginDataRemoverImpl::OnClearSiteDataResult(bool success) {
155 LOG_IF(ERROR, !success) << "ClearSiteData returned error";
156 UMA_HISTOGRAM_TIMES("ClearPluginData.time",
157 base::Time::Now() - remove_start_time_);
158 SignalDone();
159 }
160
161 void PluginDataRemoverImpl::OnTimeout() {
162 LOG_IF(ERROR, is_removing_) << "Timed out";
163 SignalDone();
164 }
165
166 bool PluginDataRemoverImpl::OnMessageReceived(const IPC::Message& msg) {
167 IPC_BEGIN_MESSAGE_MAP(PluginDataRemoverImpl, msg)
168 IPC_MESSAGE_HANDLER(PluginHostMsg_ClearSiteDataResult,
169 OnClearSiteDataResult)
170 IPC_MESSAGE_UNHANDLED_ERROR()
171 IPC_END_MESSAGE_MAP()
172
173 return true;
174 }
175
176 void PluginDataRemoverImpl::OnChannelError() {
177 is_starting_process_ = false;
178 if (is_removing_) {
179 NOTREACHED() << "Channel error";
180 SignalDone();
181 }
182 }
183
184 void PluginDataRemoverImpl::SignalDone() {
185 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
186 if (!is_removing_)
187 return;
188 is_removing_ = false;
189 event_->Signal();
190 }
OLDNEW
« no previous file with comments | « content/browser/plugin_data_remover_impl.h ('k') | content/browser/plugin_service.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698