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

Unified Diff: chrome/browser/apps/ephemeral_app_service.cc

Issue 344543006: Disable ephemeral apps after they stop running (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase Created 6 years, 5 months 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 side-by-side diff with in-line comments
Download patch
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 0fbc007979c111fb2cb324f58864676ce208b571..f0f3703ea2e5dc03b2d65141cc92dcc02012262b 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"
@@ -43,6 +45,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;
@@ -57,16 +66,11 @@ 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_));
+ ephemeral_app_count_(-1),
+ unload_idle_app_delay_(kDefaultUnloadAppDelay),
+ weak_ptr_factory_(this) {
registrar_.Add(this, chrome::NOTIFICATION_EXTENSIONS_READY,
content::Source<Profile>(profile_));
- registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED,
- content::Source<Profile>(profile_));
}
EphemeralAppService::~EphemeralAppService() {
@@ -116,11 +120,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();
}
@@ -136,8 +135,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(
@@ -156,10 +157,53 @@ 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();
+
+ // Start observing.
+ extension_registry_observer_.Add(ExtensionRegistry::Get(profile_));
+
+ apps::AppLifetimeMonitor* lifetime_monitor =
+ apps::AppLifetimeMonitorFactory::GetForProfile(profile_);
+ DCHECK(lifetime_monitor);
+ lifetime_monitor->AddObserver(this);
+
+ // 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::UnloadEphemeralAppsOnStartup,
+ weak_ptr_factory_.GetWeakPtr()),
+ base::TimeDelta::FromSeconds(kUnloadAppsOnStartupDelay));
}
void EphemeralAppService::InitEphemeralAppCount() {
@@ -177,6 +221,73 @@ 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()))
+ 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,
+ NULL);
+ }
+
+ if (!prefs->IsExtensionDisabled(extension->id()) &&
benwells 2014/07/29 08:58:42 Does this mean if an ephemeral app is disabled for
tmdiep 2014/08/04 06:22:53 Good catch. If the app happened to be disabled for
+ !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(
« no previous file with comments | « chrome/browser/apps/ephemeral_app_service.h ('k') | chrome/browser/apps/ephemeral_app_service_browsertest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698