| Index: chrome/browser/apps/ephemeral_app_service.cc
|
| diff --git a/chrome/browser/apps/ephemeral_app_service.cc b/chrome/browser/apps/ephemeral_app_service.cc
|
| index 067de9cc7067b990e3fd5b764774ab13a0f68a0e..9793539048a4d5794a1f405086ec37c59bc292f0 100644
|
| --- a/chrome/browser/apps/ephemeral_app_service.cc
|
| +++ b/chrome/browser/apps/ephemeral_app_service.cc
|
| @@ -4,7 +4,9 @@
|
|
|
| #include "chrome/browser/apps/ephemeral_app_service.h"
|
|
|
| +#include "apps/app_lifetime_monitor_factory.h"
|
| #include "base/command_line.h"
|
| +#include "base/message_loop/message_loop.h"
|
| #include "chrome/browser/apps/ephemeral_app_service_factory.h"
|
| #include "chrome/browser/chrome_notification_types.h"
|
| #include "chrome/browser/extensions/extension_service.h"
|
| @@ -23,6 +25,7 @@
|
|
|
| using extensions::Extension;
|
| using extensions::ExtensionPrefs;
|
| +using extensions::ExtensionRegistry;
|
| using extensions::ExtensionSet;
|
| using extensions::ExtensionSystem;
|
|
|
| @@ -41,6 +44,13 @@ const int kGarbageCollectAppsInstallDelay = 15;
|
| // kMaxEphemeralAppsCount.
|
| const int kGarbageCollectAppsTriggerCount = 35;
|
|
|
| +// The number of seconds after an app has stopped running before it will be
|
| +// unloaded and disabled.
|
| +const int kDefaultUnloadAppDelay = 1;
|
| +
|
| +// The number of seconds after startup before unloading inactive ephemeral apps.
|
| +const int kUnloadAppsOnStartupDelay = 5;
|
| +
|
| } // namespace
|
|
|
| const int EphemeralAppService::kAppInactiveThreshold = 10;
|
| @@ -55,17 +65,16 @@ EphemeralAppService* EphemeralAppService::Get(Profile* profile) {
|
| EphemeralAppService::EphemeralAppService(Profile* profile)
|
| : profile_(profile),
|
| extension_registry_observer_(this),
|
| - ephemeral_app_count_(-1) {
|
| + ephemeral_app_count_(-1),
|
| + unload_idle_app_delay_(kDefaultUnloadAppDelay),
|
| + weak_ptr_factory_(this) {
|
| if (!CommandLine::ForCurrentProcess()->HasSwitch(
|
| switches::kEnableEphemeralApps))
|
| return;
|
|
|
| - extension_registry_observer_.Add(
|
| - extensions::ExtensionRegistry::Get(profile_));
|
| + extension_registry_observer_.Add(ExtensionRegistry::Get(profile_));
|
| registrar_.Add(this, chrome::NOTIFICATION_EXTENSIONS_READY,
|
| content::Source<Profile>(profile_));
|
| - registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED,
|
| - content::Source<Profile>(profile_));
|
| }
|
|
|
| EphemeralAppService::~EphemeralAppService() {
|
| @@ -80,11 +89,6 @@ void EphemeralAppService::Observe(
|
| Init();
|
| break;
|
| }
|
| - case chrome::NOTIFICATION_PROFILE_DESTROYED: {
|
| - // Ideally we need to know when the extension system is shutting down.
|
| - garbage_collect_apps_timer_.Stop();
|
| - break;
|
| - }
|
| default:
|
| NOTREACHED();
|
| }
|
| @@ -100,8 +104,10 @@ void EphemeralAppService::OnExtensionWillBeInstalled(
|
| // An ephemeral app was just promoted to a regular installed app.
|
| --ephemeral_app_count_;
|
| DCHECK_GE(ephemeral_app_count_, 0);
|
| + HandleEphemeralAppPromoted(extension);
|
| } else if (!is_update &&
|
| extensions::util::IsEphemeralApp(extension->id(), profile_)) {
|
| + // A new ephemeral app was launched.
|
| ++ephemeral_app_count_;
|
| if (ephemeral_app_count_ >= kGarbageCollectAppsTriggerCount) {
|
| TriggerGarbageCollect(
|
| @@ -119,16 +125,51 @@ void EphemeralAppService::OnExtensionUninstalled(
|
| }
|
| }
|
|
|
| +void EphemeralAppService::OnAppStop(Profile* profile,
|
| + const std::string& app_id) {
|
| + if (!extensions::util::IsEphemeralApp(app_id, profile_))
|
| + return;
|
| +
|
| + base::MessageLoop::current()->PostDelayedTask(
|
| + FROM_HERE,
|
| + base::Bind(&EphemeralAppService::UnloadEphemeralApp,
|
| + weak_ptr_factory_.GetWeakPtr(),
|
| + app_id),
|
| + base::TimeDelta::FromSeconds(unload_idle_app_delay_));
|
| +}
|
| +
|
| +void EphemeralAppService::OnChromeTerminating() {
|
| + garbage_collect_apps_timer_.Stop();
|
| +
|
| + extension_registry_observer_.RemoveAll();
|
| +
|
| + apps::AppLifetimeMonitor* lifetime_monitor =
|
| + apps::AppLifetimeMonitorFactory::GetForProfile(profile_);
|
| + DCHECK(lifetime_monitor);
|
| + lifetime_monitor->RemoveObserver(this);
|
| +}
|
| +
|
| void EphemeralAppService::Init() {
|
| InitEphemeralAppCount();
|
| +
|
| + apps::AppLifetimeMonitor* lifetime_monitor =
|
| + apps::AppLifetimeMonitorFactory::GetForProfile(profile_);
|
| + DCHECK(lifetime_monitor);
|
| + lifetime_monitor->AddObserver(this);
|
| +
|
| TriggerGarbageCollect(
|
| base::TimeDelta::FromSeconds(kGarbageCollectAppsStartupDelay));
|
| +
|
| + base::MessageLoop::current()->PostDelayedTask(
|
| + FROM_HERE,
|
| + base::Bind(&EphemeralAppService::UnloadEphemeralAppsOnStartup,
|
| + weak_ptr_factory_.GetWeakPtr()),
|
| + base::TimeDelta::FromSeconds(kUnloadAppsOnStartupDelay));
|
| }
|
|
|
| void EphemeralAppService::InitEphemeralAppCount() {
|
| scoped_ptr<ExtensionSet> extensions =
|
| - extensions::ExtensionRegistry::Get(profile_)
|
| - ->GenerateInstalledExtensionsSet();
|
| + ExtensionRegistry::Get(profile_)->GenerateInstalledExtensionsSet();
|
| ExtensionPrefs* prefs = ExtensionPrefs::Get(profile_);
|
| DCHECK(prefs);
|
|
|
| @@ -141,6 +182,62 @@ void EphemeralAppService::InitEphemeralAppCount() {
|
| }
|
| }
|
|
|
| +void EphemeralAppService::UnloadEphemeralApp(const std::string& app_id) {
|
| + if (!extensions::util::IsEphemeralApp(app_id, profile_) ||
|
| + !extensions::util::IsExtensionIdle(app_id, profile_)) {
|
| + return;
|
| + }
|
| +
|
| + // After an ephemeral app has stopped running, unload it from extension
|
| + // system to prevent all background activity.
|
| + ExtensionService* service =
|
| + ExtensionSystem::Get(profile_)->extension_service();
|
| + DCHECK(service);
|
| + service->DisableExtension(app_id, Extension::DISABLE_INACTIVE_EPHEMERAL_APP);
|
| +}
|
| +
|
| +void EphemeralAppService::UnloadEphemeralAppsOnStartup() {
|
| + ExtensionPrefs* prefs = ExtensionPrefs::Get(profile_);
|
| + DCHECK(prefs);
|
| + ExtensionService* service =
|
| + ExtensionSystem::Get(profile_)->extension_service();
|
| + DCHECK(service);
|
| +
|
| + // Ensure that all inactive ephemeral apps are unloaded from extension system
|
| + // to prevent all background activity. This is done on startup to catch any
|
| + // apps that escaped unloading on shutdown.
|
| + scoped_ptr<ExtensionSet> extensions =
|
| + ExtensionRegistry::Get(profile_)->GenerateInstalledExtensionsSet();
|
| + for (ExtensionSet::const_iterator it = extensions->begin();
|
| + it != extensions->end();
|
| + ++it) {
|
| + const Extension* extension = *it;
|
| + if (prefs->IsEphemeralApp(extension->id()) &&
|
| + !prefs->IsExtensionDisabled(extension->id()) &&
|
| + !prefs->IsExtensionRunning(extension->id()) &&
|
| + extensions::util::IsExtensionIdle(extension->id(), profile_)) {
|
| + service->DisableExtension(extension->id(),
|
| + Extension::DISABLE_INACTIVE_EPHEMERAL_APP);
|
| + }
|
| + }
|
| +}
|
| +
|
| +void EphemeralAppService::HandleEphemeralAppPromoted(const Extension* app) {
|
| + // When ephemeral apps are promoted to regular install apps, remove the
|
| + // DISABLE_INACTIVE_EPHEMERAL_APP reason and enable the app if there are no
|
| + // other reasons.
|
| + ExtensionPrefs* prefs = ExtensionPrefs::Get(profile_);
|
| + DCHECK(prefs);
|
| +
|
| + int disable_reasons = prefs->GetDisableReasons(app->id());
|
| + if (disable_reasons & Extension::DISABLE_INACTIVE_EPHEMERAL_APP) {
|
| + prefs->RemoveDisableReason(app->id(),
|
| + Extension::DISABLE_INACTIVE_EPHEMERAL_APP);
|
| + if (disable_reasons == Extension::DISABLE_INACTIVE_EPHEMERAL_APP)
|
| + prefs->SetExtensionState(app->id(), Extension::ENABLED);
|
| + }
|
| +}
|
| +
|
| void EphemeralAppService::TriggerGarbageCollect(const base::TimeDelta& delay) {
|
| if (!garbage_collect_apps_timer_.IsRunning()) {
|
| garbage_collect_apps_timer_.Start(
|
| @@ -153,8 +250,7 @@ void EphemeralAppService::TriggerGarbageCollect(const base::TimeDelta& delay) {
|
|
|
| void EphemeralAppService::GarbageCollectApps() {
|
| scoped_ptr<ExtensionSet> extensions =
|
| - extensions::ExtensionRegistry::Get(profile_)
|
| - ->GenerateInstalledExtensionsSet();
|
| + ExtensionRegistry::Get(profile_)->GenerateInstalledExtensionsSet();
|
| ExtensionPrefs* prefs = ExtensionPrefs::Get(profile_);
|
| DCHECK(prefs);
|
|
|
|
|