| 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 46df9cf7875f2559cb2db24a613ec1b4fc1dbec2..f23cc9085e64534363c3ff47f1a0685cd95cff41 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"
|
| @@ -44,6 +46,13 @@ const int kGarbageCollectAppsInstallDelay = 15;
|
| // kMaxEphemeralAppsCount.
|
| const int kGarbageCollectAppsTriggerCount = 35;
|
|
|
| +// The number of seconds after an app has stopped running before it will be
|
| +// disabled.
|
| +const int kDefaultDisableAppDelay = 1;
|
| +
|
| +// The number of seconds after startup before disabling inactive ephemeral apps.
|
| +const int kDisableAppsOnStartupDelay = 5;
|
| +
|
| } // namespace
|
|
|
| const int EphemeralAppService::kAppInactiveThreshold = 10;
|
| @@ -58,17 +67,13 @@ EphemeralAppService* EphemeralAppService::Get(Profile* profile) {
|
| EphemeralAppService::EphemeralAppService(Profile* profile)
|
| : profile_(profile),
|
| extension_registry_observer_(this),
|
| - ephemeral_app_count_(-1) {
|
| - if (!CommandLine::ForCurrentProcess()->HasSwitch(
|
| - switches::kEnableEphemeralApps))
|
| - return;
|
| -
|
| - extension_registry_observer_.Add(ExtensionRegistry::Get(profile_));
|
| + app_lifetime_monitor_observer_(this),
|
| + ephemeral_app_count_(-1),
|
| + disable_idle_app_delay_(kDefaultDisableAppDelay),
|
| + weak_ptr_factory_(this) {
|
| registrar_.Add(this,
|
| extensions::NOTIFICATION_EXTENSIONS_READY_DEPRECATED,
|
| content::Source<Profile>(profile_));
|
| - registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED,
|
| - content::Source<Profile>(profile_));
|
| }
|
|
|
| EphemeralAppService::~EphemeralAppService() {
|
| @@ -119,11 +124,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();
|
| }
|
| @@ -139,8 +139,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(
|
| @@ -159,10 +161,46 @@ 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::DisableEphemeralApp,
|
| + weak_ptr_factory_.GetWeakPtr(),
|
| + app_id),
|
| + base::TimeDelta::FromSeconds(disable_idle_app_delay_));
|
| +}
|
| +
|
| +void EphemeralAppService::OnChromeTerminating() {
|
| + garbage_collect_apps_timer_.Stop();
|
| +
|
| + extension_registry_observer_.RemoveAll();
|
| + app_lifetime_monitor_observer_.RemoveAll();
|
| +}
|
| +
|
| void EphemeralAppService::Init() {
|
| InitEphemeralAppCount();
|
| +
|
| + // Start observing.
|
| + extension_registry_observer_.Add(ExtensionRegistry::Get(profile_));
|
| + app_lifetime_monitor_observer_.Add(
|
| + apps::AppLifetimeMonitorFactory::GetForProfile(profile_));
|
| +
|
| + // Execute startup clean up tasks (except during tests).
|
| + if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kTestType))
|
| + return;
|
| +
|
| TriggerGarbageCollect(
|
| base::TimeDelta::FromSeconds(kGarbageCollectAppsStartupDelay));
|
| +
|
| + base::MessageLoop::current()->PostDelayedTask(
|
| + FROM_HERE,
|
| + base::Bind(&EphemeralAppService::DisableEphemeralAppsOnStartup,
|
| + weak_ptr_factory_.GetWeakPtr()),
|
| + base::TimeDelta::FromSeconds(kDisableAppsOnStartupDelay));
|
| }
|
|
|
| void EphemeralAppService::InitEphemeralAppCount() {
|
| @@ -180,6 +218,76 @@ void EphemeralAppService::InitEphemeralAppCount() {
|
| }
|
| }
|
|
|
| +void EphemeralAppService::DisableEphemeralApp(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 and disable it 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::DisableEphemeralAppsOnStartup() {
|
| + ExtensionPrefs* prefs = ExtensionPrefs::Get(profile_);
|
| + DCHECK(prefs);
|
| + ExtensionService* service =
|
| + ExtensionSystem::Get(profile_)->extension_service();
|
| + DCHECK(service);
|
| +
|
| + // Ensure that all inactive ephemeral apps are disabled to prevent all
|
| + // background activity. This is done on startup to catch any apps that escaped
|
| + // being disabled 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()))
|
| + continue;
|
| +
|
| + // Only V2 apps are installed ephemerally. Remove other ephemeral app types
|
| + // that were cached before this policy was introduced.
|
| + if (!extension->is_platform_app()) {
|
| + service->UninstallExtension(
|
| + extension->id(),
|
| + extensions::UNINSTALL_REASON_ORPHANED_EPHEMERAL_EXTENSION,
|
| + base::Bind(&base::DoNothing),
|
| + NULL);
|
| + continue;
|
| + }
|
| +
|
| + if (!prefs->HasDisableReason(extension->id(),
|
| + Extension::DISABLE_INACTIVE_EPHEMERAL_APP) &&
|
| + !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(
|
|
|