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

Side by Side Diff: chrome/browser/extensions/extension_updater.cc

Issue 345023: Get rid of MessageLoop* caching in extensions code. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 11 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
OLDNEW
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2009 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 "chrome/browser/extensions/extension_updater.h" 5 #include "chrome/browser/extensions/extension_updater.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <set> 8 #include <set>
9 9
10 #include "base/logging.h" 10 #include "base/logging.h"
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
53 const int kStartupWaitSeconds = 60 * 5; 53 const int kStartupWaitSeconds = 60 * 5;
54 54
55 // For sanity checking on update frequency - enforced in release mode only. 55 // For sanity checking on update frequency - enforced in release mode only.
56 static const int kMinUpdateFrequencySeconds = 30; 56 static const int kMinUpdateFrequencySeconds = 30;
57 static const int kMaxUpdateFrequencySeconds = 60 * 60 * 24 * 7; // 7 days 57 static const int kMaxUpdateFrequencySeconds = 60 * 60 * 24 * 7; // 7 days
58 58
59 // A utility class to do file handling on the file I/O thread. 59 // A utility class to do file handling on the file I/O thread.
60 class ExtensionUpdaterFileHandler 60 class ExtensionUpdaterFileHandler
61 : public base::RefCountedThreadSafe<ExtensionUpdaterFileHandler> { 61 : public base::RefCountedThreadSafe<ExtensionUpdaterFileHandler> {
62 public: 62 public:
63 ExtensionUpdaterFileHandler(MessageLoop* updater_loop,
64 MessageLoop* file_io_loop)
65 : updater_loop_(updater_loop), file_io_loop_(file_io_loop) {}
66
67 // Writes crx file data into a tempfile, and calls back the updater. 63 // Writes crx file data into a tempfile, and calls back the updater.
68 void WriteTempFile(const std::string& extension_id, const std::string& data, 64 void WriteTempFile(const std::string& extension_id, const std::string& data,
69 scoped_refptr<ExtensionUpdater> updater) { 65 scoped_refptr<ExtensionUpdater> updater) {
70 // Make sure we're running in the right thread. 66 // Make sure we're running in the right thread.
71 DCHECK(MessageLoop::current() == file_io_loop_); 67 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
72 68
73 FilePath path; 69 FilePath path;
74 if (!file_util::CreateTemporaryFile(&path)) { 70 if (!file_util::CreateTemporaryFile(&path)) {
75 LOG(WARNING) << "Failed to create temporary file path"; 71 LOG(WARNING) << "Failed to create temporary file path";
76 return; 72 return;
77 } 73 }
78 if (file_util::WriteFile(path, data.c_str(), data.length()) != 74 if (file_util::WriteFile(path, data.c_str(), data.length()) !=
79 static_cast<int>(data.length())) { 75 static_cast<int>(data.length())) {
80 // TODO(asargent) - It would be nice to back off updating alltogether if 76 // TODO(asargent) - It would be nice to back off updating alltogether if
81 // the disk is full. (http://crbug.com/12763). 77 // the disk is full. (http://crbug.com/12763).
82 LOG(ERROR) << "Failed to write temporary file"; 78 LOG(ERROR) << "Failed to write temporary file";
83 file_util::Delete(path, false); 79 file_util::Delete(path, false);
84 return; 80 return;
85 } 81 }
86 82
87 // The ExtensionUpdater is now responsible for cleaning up the temp file 83 // The ExtensionUpdater is now responsible for cleaning up the temp file
88 // from disk. 84 // from disk.
89 updater_loop_->PostTask(FROM_HERE, NewRunnableMethod( 85 ChromeThread::PostTask(
90 updater.get(), &ExtensionUpdater::OnCRXFileWritten, extension_id, 86 ChromeThread::UI, FROM_HERE,
91 path)); 87 NewRunnableMethod(
88 updater.get(), &ExtensionUpdater::OnCRXFileWritten, extension_id,
89 path));
92 } 90 }
93 91
94 void DeleteFile(const FilePath& path) { 92 void DeleteFile(const FilePath& path) {
95 DCHECK(MessageLoop::current() == file_io_loop_); 93 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
96 if (!file_util::Delete(path, false)) { 94 if (!file_util::Delete(path, false)) {
97 LOG(WARNING) << "Failed to delete temp file " << path.value(); 95 LOG(WARNING) << "Failed to delete temp file " << path.value();
98 } 96 }
99 } 97 }
100
101 private:
102 // The MessageLoop we use to call back the ExtensionUpdater.
103 MessageLoop* updater_loop_;
104
105 // The MessageLoop we should be operating on for file operations.
106 MessageLoop* file_io_loop_;
107 }; 98 };
108 99
109 100
110 ExtensionUpdater::ExtensionUpdater(ExtensionUpdateService* service, 101 ExtensionUpdater::ExtensionUpdater(ExtensionUpdateService* service,
111 PrefService* prefs, 102 PrefService* prefs,
112 int frequency_seconds, 103 int frequency_seconds)
113 MessageLoop* file_io_loop,
114 MessageLoop* io_loop)
115 : service_(service), frequency_seconds_(frequency_seconds), 104 : service_(service), frequency_seconds_(frequency_seconds),
116 file_io_loop_(file_io_loop), io_loop_(io_loop), prefs_(prefs), 105 prefs_(prefs), file_handler_(new ExtensionUpdaterFileHandler()),
117 file_handler_(new ExtensionUpdaterFileHandler(MessageLoop::current(),
118 file_io_loop_)),
119 blacklist_checks_enabled_(true) { 106 blacklist_checks_enabled_(true) {
120 Init(); 107 Init();
121 } 108 }
122 109
123 void ExtensionUpdater::Init() { 110 void ExtensionUpdater::Init() {
124 // Unless we're in a unit test, expect that the file_io_loop_ is on the
125 // browser file thread.
126 if (g_browser_process->file_thread() != NULL) {
127 DCHECK(file_io_loop_ == g_browser_process->file_thread()->message_loop());
128 }
129
130 DCHECK_GE(frequency_seconds_, 5); 111 DCHECK_GE(frequency_seconds_, 5);
131 DCHECK(frequency_seconds_ <= kMaxUpdateFrequencySeconds); 112 DCHECK(frequency_seconds_ <= kMaxUpdateFrequencySeconds);
132 #ifdef NDEBUG 113 #ifdef NDEBUG
133 // In Release mode we enforce that update checks don't happen too often. 114 // In Release mode we enforce that update checks don't happen too often.
134 frequency_seconds_ = std::max(frequency_seconds_, kMinUpdateFrequencySeconds); 115 frequency_seconds_ = std::max(frequency_seconds_, kMinUpdateFrequencySeconds);
135 #endif 116 #endif
136 frequency_seconds_ = std::min(frequency_seconds_, kMaxUpdateFrequencySeconds); 117 frequency_seconds_ = std::min(frequency_seconds_, kMaxUpdateFrequencySeconds);
137 } 118 }
138 119
139 ExtensionUpdater::~ExtensionUpdater() {} 120 ExtensionUpdater::~ExtensionUpdater() {}
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
218 } else if (source == extension_fetcher_.get()) { 199 } else if (source == extension_fetcher_.get()) {
219 OnCRXFetchComplete(url, status, response_code, data); 200 OnCRXFetchComplete(url, status, response_code, data);
220 } else { 201 } else {
221 NOTREACHED(); 202 NOTREACHED();
222 } 203 }
223 } 204 }
224 205
225 // Utility class to handle doing xml parsing in a sandboxed utility process. 206 // Utility class to handle doing xml parsing in a sandboxed utility process.
226 class SafeManifestParser : public UtilityProcessHost::Client { 207 class SafeManifestParser : public UtilityProcessHost::Client {
227 public: 208 public:
228 SafeManifestParser(const std::string& xml, ExtensionUpdater* updater, 209 SafeManifestParser(const std::string& xml, ExtensionUpdater* updater)
229 MessageLoop* updater_loop, MessageLoop* io_loop) 210 : xml_(xml), updater_(updater) {
230 : xml_(xml), updater_loop_(updater_loop), io_loop_(io_loop),
231 updater_(updater) {
232 } 211 }
233 212
234 ~SafeManifestParser() {} 213 ~SafeManifestParser() {}
235 214
236 // Posts a task over to the IO loop to start the parsing of xml_ in a 215 // Posts a task over to the IO loop to start the parsing of xml_ in a
237 // utility process. 216 // utility process.
238 void Start() { 217 void Start() {
239 DCHECK(MessageLoop::current() == updater_loop_); 218 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
240 io_loop_->PostTask(FROM_HERE, 219 ChromeThread::PostTask(
241 NewRunnableMethod(this, &SafeManifestParser::ParseInSandbox, 220 ChromeThread::IO, FROM_HERE,
221 NewRunnableMethod(
222 this, &SafeManifestParser::ParseInSandbox,
242 g_browser_process->resource_dispatcher_host())); 223 g_browser_process->resource_dispatcher_host()));
243 } 224 }
244 225
245 // Creates the sandboxed utility process and tells it to start parsing. 226 // Creates the sandboxed utility process and tells it to start parsing.
246 void ParseInSandbox(ResourceDispatcherHost* rdh) { 227 void ParseInSandbox(ResourceDispatcherHost* rdh) {
247 DCHECK(MessageLoop::current() == io_loop_); 228 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
248 229
249 // TODO(asargent) we shouldn't need to do this branch here - instead 230 // TODO(asargent) we shouldn't need to do this branch here - instead
250 // UtilityProcessHost should handle it for us. (http://crbug.com/19192) 231 // UtilityProcessHost should handle it for us. (http://crbug.com/19192)
251 bool use_utility_process = rdh && 232 bool use_utility_process = rdh &&
252 !CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess); 233 !CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess);
253 234
254 #if defined(OS_POSIX) 235 #if defined(OS_POSIX)
255 // TODO(port): Don't use a utility process on linux (crbug.com/22703) or 236 // TODO(port): Don't use a utility process on linux (crbug.com/22703) or
256 // MacOS (crbug.com/8102) until problems related to autoupdate are fixed. 237 // MacOS (crbug.com/8102) until problems related to autoupdate are fixed.
257 use_utility_process = false; 238 use_utility_process = false;
258 #endif 239 #endif
259 240
260 if (use_utility_process) { 241 if (use_utility_process) {
261 UtilityProcessHost* host = new UtilityProcessHost( 242 UtilityProcessHost* host = new UtilityProcessHost(
262 rdh, this, updater_loop_); 243 rdh, this, ChromeThread::UI);
263 host->StartUpdateManifestParse(xml_); 244 host->StartUpdateManifestParse(xml_);
264 } else { 245 } else {
265 UpdateManifest manifest; 246 UpdateManifest manifest;
266 if (manifest.Parse(xml_)) { 247 if (manifest.Parse(xml_)) {
267 updater_loop_->PostTask(FROM_HERE, NewRunnableMethod(this, 248 ChromeThread::PostTask(
268 &SafeManifestParser::OnParseUpdateManifestSucceeded, 249 ChromeThread::UI, FROM_HERE,
269 manifest.results())); 250 NewRunnableMethod(
251 this, &SafeManifestParser::OnParseUpdateManifestSucceeded,
252 manifest.results()));
270 } else { 253 } else {
271 updater_loop_->PostTask(FROM_HERE, NewRunnableMethod(this, 254 ChromeThread::PostTask(
272 &SafeManifestParser::OnParseUpdateManifestFailed, 255 ChromeThread::UI, FROM_HERE,
273 manifest.errors())); 256 NewRunnableMethod(
257 this, &SafeManifestParser::OnParseUpdateManifestFailed,
258 manifest.errors()));
274 } 259 }
275 } 260 }
276 } 261 }
277 262
278 // Callback from the utility process when parsing succeeded. 263 // Callback from the utility process when parsing succeeded.
279 virtual void OnParseUpdateManifestSucceeded( 264 virtual void OnParseUpdateManifestSucceeded(
280 const UpdateManifest::ResultList& list) { 265 const UpdateManifest::ResultList& list) {
281 DCHECK(MessageLoop::current() == updater_loop_); 266 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
282 updater_->HandleManifestResults(list); 267 updater_->HandleManifestResults(list);
283 } 268 }
284 269
285 // Callback from the utility process when parsing failed. 270 // Callback from the utility process when parsing failed.
286 virtual void OnParseUpdateManifestFailed(const std::string& error_message) { 271 virtual void OnParseUpdateManifestFailed(const std::string& error_message) {
287 DCHECK(MessageLoop::current() == updater_loop_); 272 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
288 LOG(WARNING) << "Error parsing update manifest:\n" << error_message; 273 LOG(WARNING) << "Error parsing update manifest:\n" << error_message;
289 } 274 }
290 275
291 private: 276 private:
292 const std::string& xml_; 277 const std::string& xml_;
293 278
294 // The MessageLoop we use to call back the ExtensionUpdater.
295 MessageLoop* updater_loop_;
296
297 // The MessageLoop where we create the utility process.
298 MessageLoop* io_loop_;
299
300 scoped_refptr<ExtensionUpdater> updater_; 279 scoped_refptr<ExtensionUpdater> updater_;
301 }; 280 };
302 281
303 282
304 void ExtensionUpdater::OnManifestFetchComplete(const GURL& url, 283 void ExtensionUpdater::OnManifestFetchComplete(const GURL& url,
305 const URLRequestStatus& status, 284 const URLRequestStatus& status,
306 int response_code, 285 int response_code,
307 const std::string& data) { 286 const std::string& data) {
308 // We want to try parsing the manifest, and if it indicates updates are 287 // We want to try parsing the manifest, and if it indicates updates are
309 // available, we want to fire off requests to fetch those updates. 288 // available, we want to fire off requests to fetch those updates.
310 if (status.status() == URLRequestStatus::SUCCESS && response_code == 200) { 289 if (status.status() == URLRequestStatus::SUCCESS && response_code == 200) {
311 scoped_refptr<SafeManifestParser> safe_parser = 290 scoped_refptr<SafeManifestParser> safe_parser =
312 new SafeManifestParser(data, this, MessageLoop::current(), io_loop_); 291 new SafeManifestParser(data, this);
313 safe_parser->Start(); 292 safe_parser->Start();
314 } else { 293 } else {
315 // TODO(asargent) Do exponential backoff here. (http://crbug.com/12546). 294 // TODO(asargent) Do exponential backoff here. (http://crbug.com/12546).
316 LOG(INFO) << "Failed to fetch manifst '" << url.possibly_invalid_spec() << 295 LOG(INFO) << "Failed to fetch manifst '" << url.possibly_invalid_spec() <<
317 "' response code:" << response_code; 296 "' response code:" << response_code;
318 } 297 }
319 manifest_fetcher_.reset(); 298 manifest_fetcher_.reset();
320 299
321 // If we have any pending manifest requests, fire off the next one. 300 // If we have any pending manifest requests, fire off the next one.
322 if (!manifests_pending_.empty()) { 301 if (!manifests_pending_.empty()) {
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
368 LOG(ERROR) << "Called with unexpected url:'" << url.spec() 347 LOG(ERROR) << "Called with unexpected url:'" << url.spec()
369 << "' expected:'" << current_extension_fetch_.url.spec() << "'"; 348 << "' expected:'" << current_extension_fetch_.url.spec() << "'";
370 NOTREACHED(); 349 NOTREACHED();
371 } else if (status.status() == URLRequestStatus::SUCCESS && 350 } else if (status.status() == URLRequestStatus::SUCCESS &&
372 response_code == 200) { 351 response_code == 200) {
373 if (current_extension_fetch_.id == kBlacklistAppID) { 352 if (current_extension_fetch_.id == kBlacklistAppID) {
374 ProcessBlacklist(data); 353 ProcessBlacklist(data);
375 } else { 354 } else {
376 // Successfully fetched - now write crx to a file so we can have the 355 // Successfully fetched - now write crx to a file so we can have the
377 // ExtensionsService install it. 356 // ExtensionsService install it.
378 file_io_loop_->PostTask(FROM_HERE, NewRunnableMethod( 357 ChromeThread::PostTask(
379 file_handler_.get(), &ExtensionUpdaterFileHandler::WriteTempFile, 358 ChromeThread::FILE, FROM_HERE,
380 current_extension_fetch_.id, data, this)); 359 NewRunnableMethod(
360 file_handler_.get(), &ExtensionUpdaterFileHandler::WriteTempFile,
361 current_extension_fetch_.id, data, this));
381 } 362 }
382 } else { 363 } else {
383 // TODO(asargent) do things like exponential backoff, handling 364 // TODO(asargent) do things like exponential backoff, handling
384 // 503 Service Unavailable / Retry-After headers, etc. here. 365 // 503 Service Unavailable / Retry-After headers, etc. here.
385 // (http://crbug.com/12546). 366 // (http://crbug.com/12546).
386 LOG(INFO) << "Failed to fetch extension '" << 367 LOG(INFO) << "Failed to fetch extension '" <<
387 url.possibly_invalid_spec() << "' response code:" << response_code; 368 url.possibly_invalid_spec() << "' response code:" << response_code;
388 } 369 }
389 extension_fetcher_.reset(); 370 extension_fetcher_.reset();
390 current_extension_fetch_ = ExtensionFetch(); 371 current_extension_fetch_ = ExtensionFetch();
391 372
392 // If there are any pending downloads left, start one. 373 // If there are any pending downloads left, start one.
393 if (extensions_pending_.size() > 0) { 374 if (extensions_pending_.size() > 0) {
394 ExtensionFetch next = extensions_pending_.front(); 375 ExtensionFetch next = extensions_pending_.front();
395 extensions_pending_.pop_front(); 376 extensions_pending_.pop_front();
396 FetchUpdatedExtension(next.id, next.url, next.package_hash, next.version); 377 FetchUpdatedExtension(next.id, next.url, next.package_hash, next.version);
397 } 378 }
398 } 379 }
399 380
400 void ExtensionUpdater::OnCRXFileWritten(const std::string& id, 381 void ExtensionUpdater::OnCRXFileWritten(const std::string& id,
401 const FilePath& path) { 382 const FilePath& path) {
402 service_->UpdateExtension(id, path); 383 service_->UpdateExtension(id, path);
403 } 384 }
404 385
405 void ExtensionUpdater::OnExtensionInstallFinished(const FilePath& path, 386 void ExtensionUpdater::OnExtensionInstallFinished(const FilePath& path,
406 Extension* extension) { 387 Extension* extension) {
407 // Have the file_handler_ delete the temp file on the file I/O thread. 388 // Have the file_handler_ delete the temp file on the file I/O thread.
408 file_io_loop_->PostTask(FROM_HERE, NewRunnableMethod( 389 ChromeThread::PostTask(
409 file_handler_.get(), &ExtensionUpdaterFileHandler::DeleteFile, path)); 390 ChromeThread::FILE, FROM_HERE,
391 NewRunnableMethod(
392 file_handler_.get(), &ExtensionUpdaterFileHandler::DeleteFile, path));
410 } 393 }
411 394
412 395
413 // Helper function for building up request parameters in update check urls. It 396 // Helper function for building up request parameters in update check urls. It
414 // appends information about one extension to a request parameter string. The 397 // appends information about one extension to a request parameter string. The
415 // format for request parameters in update checks is: 398 // format for request parameters in update checks is:
416 // 399 //
417 // ?x=EXT1_INFO&x=EXT2_INFO 400 // ?x=EXT1_INFO&x=EXT2_INFO
418 // 401 //
419 // where EXT1_INFO and EXT2_INFO are url-encoded strings of the form: 402 // where EXT1_INFO and EXT2_INFO are url-encoded strings of the form:
(...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after
637 extension_fetcher_.reset( 620 extension_fetcher_.reset(
638 URLFetcher::Create(kExtensionFetcherId, url, URLFetcher::GET, this)); 621 URLFetcher::Create(kExtensionFetcherId, url, URLFetcher::GET, this));
639 extension_fetcher_->set_request_context( 622 extension_fetcher_->set_request_context(
640 Profile::GetDefaultRequestContext()); 623 Profile::GetDefaultRequestContext());
641 extension_fetcher_->set_load_flags(net::LOAD_DO_NOT_SEND_COOKIES | 624 extension_fetcher_->set_load_flags(net::LOAD_DO_NOT_SEND_COOKIES |
642 net::LOAD_DO_NOT_SAVE_COOKIES); 625 net::LOAD_DO_NOT_SAVE_COOKIES);
643 extension_fetcher_->Start(); 626 extension_fetcher_->Start();
644 current_extension_fetch_ = ExtensionFetch(id, url, hash, version); 627 current_extension_fetch_ = ExtensionFetch(id, url, hash, version);
645 } 628 }
646 } 629 }
OLDNEW
« no previous file with comments | « chrome/browser/extensions/extension_updater.h ('k') | chrome/browser/extensions/extension_updater_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698