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 "chrome/browser/background/background_contents_service.h" | 5 #include "chrome/browser/background/background_contents_service.h" |
6 | 6 |
7 #include <utility> | 7 #include <utility> |
8 | 8 |
9 #include "apps/app_load_service.h" | 9 #include "apps/app_load_service.h" |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
(...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
273 -1, // Entry lifetime: -1 to never discard. | 273 -1, // Entry lifetime: -1 to never discard. |
274 false, // Whether to always use initial delay. No-op as there are | 274 false, // Whether to always use initial delay. No-op as there are |
275 // no initial errors to ignore. | 275 // no initial errors to ignore. |
276 }; | 276 }; |
277 | 277 |
278 int BackgroundContentsService::restart_delay_in_ms_ = 3000; // 3 seconds. | 278 int BackgroundContentsService::restart_delay_in_ms_ = 3000; // 3 seconds. |
279 | 279 |
280 BackgroundContentsService::BackgroundContentsService( | 280 BackgroundContentsService::BackgroundContentsService( |
281 Profile* profile, | 281 Profile* profile, |
282 const base::CommandLine* command_line) | 282 const base::CommandLine* command_line) |
283 : prefs_(NULL), extension_registry_observer_(this) { | 283 : prefs_(NULL), |
| 284 extension_registry_observer_(this), |
| 285 weak_ptr_factory_(this) { |
284 // Don't load/store preferences if the parent profile is incognito. | 286 // Don't load/store preferences if the parent profile is incognito. |
285 if (!profile->IsOffTheRecord()) | 287 if (!profile->IsOffTheRecord()) |
286 prefs_ = profile->GetPrefs(); | 288 prefs_ = profile->GetPrefs(); |
287 | 289 |
288 // Listen for events to tell us when to load/unload persisted background | 290 // Listen for events to tell us when to load/unload persisted background |
289 // contents. | 291 // contents. |
290 StartObserving(profile); | 292 StartObserving(profile); |
291 } | 293 } |
292 | 294 |
293 BackgroundContentsService::~BackgroundContentsService() { | 295 BackgroundContentsService::~BackgroundContentsService() { |
(...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
471 // Now load the manifest-specified background page. If service isn't | 473 // Now load the manifest-specified background page. If service isn't |
472 // ready, then the background page will be loaded from the | 474 // ready, then the background page will be loaded from the |
473 // EXTENSIONS_READY callback. | 475 // EXTENSIONS_READY callback. |
474 LoadBackgroundContents(profile, | 476 LoadBackgroundContents(profile, |
475 BackgroundInfo::GetBackgroundURL(extension), | 477 BackgroundInfo::GetBackgroundURL(extension), |
476 "background", | 478 "background", |
477 base::UTF8ToUTF16(extension->id())); | 479 base::UTF8ToUTF16(extension->id())); |
478 } | 480 } |
479 } | 481 } |
480 | 482 |
| 483 // If there is an existing BackoffEntry for the extension, clear it if |
| 484 // the component extension stays loaded for 60 seconds. This avoids the |
| 485 // situation of effectively disabling an extension for the entire browser |
| 486 // session if there was a periodic crash (sometimes caused by another source). |
| 487 if (extensions::Manifest::IsComponentLocation(extension->location())) { |
| 488 ComponentExtensionBackoffEntryMap::const_iterator it = |
| 489 component_backoff_map_.find(extension->id()); |
| 490 if (it != component_backoff_map_.end()) { |
| 491 net::BackoffEntry* entry = component_backoff_map_[extension->id()].get(); |
| 492 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(FROM_HERE, |
| 493 base::Bind(&BackgroundContentsService::MaybeClearBackoffEntry, |
| 494 weak_ptr_factory_.GetWeakPtr(), extension->id(), |
| 495 entry->failure_count()), |
| 496 base::TimeDelta::FromSeconds(60)); |
| 497 } |
| 498 } |
| 499 |
481 // Close the crash notification balloon for the app/extension, if any. | 500 // Close the crash notification balloon for the app/extension, if any. |
482 ScheduleCloseBalloon(extension->id(), profile); | 501 ScheduleCloseBalloon(extension->id(), profile); |
483 SendChangeNotification(profile); | 502 SendChangeNotification(profile); |
484 } | 503 } |
485 | 504 |
486 void BackgroundContentsService::OnExtensionUnloaded( | 505 void BackgroundContentsService::OnExtensionUnloaded( |
487 content::BrowserContext* browser_context, | 506 content::BrowserContext* browser_context, |
488 const extensions::Extension* extension, | 507 const extensions::Extension* extension, |
489 extensions::UnloadedExtensionInfo::Reason reason) { | 508 extensions::UnloadedExtensionInfo::Reason reason) { |
490 switch (reason) { | 509 switch (reason) { |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
533 } | 552 } |
534 | 553 |
535 void BackgroundContentsService::RestartForceInstalledExtensionOnCrash( | 554 void BackgroundContentsService::RestartForceInstalledExtensionOnCrash( |
536 const Extension* extension, | 555 const Extension* extension, |
537 Profile* profile) { | 556 Profile* profile) { |
538 int restart_delay = restart_delay_in_ms_; | 557 int restart_delay = restart_delay_in_ms_; |
539 | 558 |
540 // If the extension was a component extension, use exponential backoff when | 559 // If the extension was a component extension, use exponential backoff when |
541 // attempting to reload. | 560 // attempting to reload. |
542 if (extensions::Manifest::IsComponentLocation(extension->location())) { | 561 if (extensions::Manifest::IsComponentLocation(extension->location())) { |
543 ExtensionBackoffEntryMap::const_iterator it = | 562 ComponentExtensionBackoffEntryMap::const_iterator it = |
544 backoff_map_.find(extension->id()); | 563 component_backoff_map_.find(extension->id()); |
545 | 564 |
546 // Create a BackoffEntry if this is the first time we try to reload this | 565 // Create a BackoffEntry if this is the first time we try to reload this |
547 // particular extension. | 566 // particular extension. |
548 if (it == backoff_map_.end()) { | 567 if (it == component_backoff_map_.end()) { |
549 std::unique_ptr<net::BackoffEntry> backoff_entry( | 568 std::unique_ptr<net::BackoffEntry> backoff_entry( |
550 new net::BackoffEntry(&kExtensionReloadBackoffPolicy)); | 569 new net::BackoffEntry(&kExtensionReloadBackoffPolicy)); |
551 backoff_map_.insert( | 570 component_backoff_map_.insert( |
552 std::pair<extensions::ExtensionId, | 571 std::pair<extensions::ExtensionId, |
553 std::unique_ptr<net::BackoffEntry>>( | 572 std::unique_ptr<net::BackoffEntry>>( |
554 extension->id(), std::move(backoff_entry))); | 573 extension->id(), std::move(backoff_entry))); |
555 } | 574 } |
556 | 575 |
557 net::BackoffEntry* entry = backoff_map_[extension->id()].get(); | 576 net::BackoffEntry* entry = component_backoff_map_[extension->id()].get(); |
558 entry->InformOfRequest(false); | 577 entry->InformOfRequest(false); |
559 restart_delay = entry->GetTimeUntilRelease().InMilliseconds(); | 578 restart_delay = entry->GetTimeUntilRelease().InMilliseconds(); |
560 } | 579 } |
561 | 580 |
562 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( | 581 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( |
563 FROM_HERE, base::Bind(&ReloadExtension, extension->id(), profile), | 582 FROM_HERE, base::Bind(&ReloadExtension, extension->id(), profile), |
564 base::TimeDelta::FromMilliseconds(restart_delay)); | 583 base::TimeDelta::FromMilliseconds(restart_delay)); |
565 } | 584 } |
566 | 585 |
567 // Loads all background contents whose urls have been stored in prefs. | 586 // Loads all background contents whose urls have been stored in prefs. |
(...skipping 29 matching lines...) Expand all Loading... |
597 } | 616 } |
598 } | 617 } |
599 | 618 |
600 void BackgroundContentsService::SendChangeNotification(Profile* profile) { | 619 void BackgroundContentsService::SendChangeNotification(Profile* profile) { |
601 content::NotificationService::current()->Notify( | 620 content::NotificationService::current()->Notify( |
602 chrome::NOTIFICATION_BACKGROUND_CONTENTS_SERVICE_CHANGED, | 621 chrome::NOTIFICATION_BACKGROUND_CONTENTS_SERVICE_CHANGED, |
603 content::Source<Profile>(profile), | 622 content::Source<Profile>(profile), |
604 content::Details<BackgroundContentsService>(this)); | 623 content::Details<BackgroundContentsService>(this)); |
605 } | 624 } |
606 | 625 |
| 626 void BackgroundContentsService::MaybeClearBackoffEntry( |
| 627 const std::string extension_id, |
| 628 int expected_failure_count) { |
| 629 ComponentExtensionBackoffEntryMap::const_iterator it = |
| 630 component_backoff_map_.find(extension_id); |
| 631 if (it == component_backoff_map_.end()) |
| 632 return; |
| 633 |
| 634 net::BackoffEntry* entry = component_backoff_map_[extension_id].get(); |
| 635 |
| 636 // Only remove the BackoffEntry if there has has been no failure for |
| 637 // |extension_id| since loading. |
| 638 if (entry->failure_count() == expected_failure_count) |
| 639 component_backoff_map_.erase(it); |
| 640 } |
| 641 |
607 void BackgroundContentsService::LoadBackgroundContentsForExtension( | 642 void BackgroundContentsService::LoadBackgroundContentsForExtension( |
608 Profile* profile, | 643 Profile* profile, |
609 const std::string& extension_id) { | 644 const std::string& extension_id) { |
610 // First look if the manifest specifies a background page. | 645 // First look if the manifest specifies a background page. |
611 const Extension* extension = | 646 const Extension* extension = |
612 extensions::ExtensionSystem::Get(profile)->extension_service()-> | 647 extensions::ExtensionSystem::Get(profile)->extension_service()-> |
613 GetExtensionById(extension_id, false); | 648 GetExtensionById(extension_id, false); |
614 DCHECK(!extension || extension->is_hosted_app()); | 649 DCHECK(!extension || extension->is_hosted_app()); |
615 if (extension && BackgroundInfo::HasBackgroundPage(extension)) { | 650 if (extension && BackgroundInfo::HasBackgroundPage(extension)) { |
616 LoadBackgroundContents(profile, | 651 LoadBackgroundContents(profile, |
(...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
823 const gfx::Rect& initial_rect, | 858 const gfx::Rect& initial_rect, |
824 bool user_gesture, | 859 bool user_gesture, |
825 bool* was_blocked) { | 860 bool* was_blocked) { |
826 Browser* browser = chrome::FindLastActiveWithProfile( | 861 Browser* browser = chrome::FindLastActiveWithProfile( |
827 Profile::FromBrowserContext(new_contents->GetBrowserContext())); | 862 Profile::FromBrowserContext(new_contents->GetBrowserContext())); |
828 if (browser) { | 863 if (browser) { |
829 chrome::AddWebContents(browser, NULL, new_contents, disposition, | 864 chrome::AddWebContents(browser, NULL, new_contents, disposition, |
830 initial_rect, user_gesture, was_blocked); | 865 initial_rect, user_gesture, was_blocked); |
831 } | 866 } |
832 } | 867 } |
OLD | NEW |