summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsammc@chromium.org <sammc@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-10-30 04:45:56 +0000
committersammc@chromium.org <sammc@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-10-30 04:45:56 +0000
commit979574d0beda1f79337b1398c24d27d53351f517 (patch)
tree63d156d7b92f66885383c6b0db8af07e75cdbfb8
parenta418bf7985a2c936e96cb8c2b3e2a7c14d553f76 (diff)
downloadchromium_src-979574d0beda1f79337b1398c24d27d53351f517.zip
chromium_src-979574d0beda1f79337b1398c24d27d53351f517.tar.gz
chromium_src-979574d0beda1f79337b1398c24d27d53351f517.tar.bz2
Keep Chrome alive while packaged app background pages are running.
This will delay Chrome's shutdown until some time after the last app window closes. BUG=130457 Review URL: https://codereview.chromium.org/33993003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@231749 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--apps/app_keep_alive_service.cc68
-rw-r--r--apps/app_keep_alive_service.h38
-rw-r--r--apps/app_keep_alive_service_factory.cc47
-rw-r--r--apps/app_keep_alive_service_factory.h36
-rw-r--r--apps/app_keep_alive_service_unittest.cc121
-rw-r--r--apps/apps.gypi4
-rw-r--r--chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc2
-rw-r--r--chrome/chrome_tests_unit.gypi1
8 files changed, 317 insertions, 0 deletions
diff --git a/apps/app_keep_alive_service.cc b/apps/app_keep_alive_service.cc
new file mode 100644
index 0000000..825e0bb
--- /dev/null
+++ b/apps/app_keep_alive_service.cc
@@ -0,0 +1,68 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "apps/app_keep_alive_service.h"
+
+#include "apps/app_lifetime_monitor.h"
+#include "apps/app_lifetime_monitor_factory.h"
+#include "base/message_loop/message_loop.h"
+#include "chrome/browser/lifetime/application_lifetime.h"
+#include "chrome/browser/profiles/profile.h"
+
+namespace apps {
+
+AppKeepAliveService::AppKeepAliveService(content::BrowserContext* context)
+ : context_(context) {
+ AppLifetimeMonitor* app_lifetime_monitor =
+ AppLifetimeMonitorFactory::GetForProfile(static_cast<Profile*>(context));
+ app_lifetime_monitor->AddObserver(this);
+}
+
+AppKeepAliveService::~AppKeepAliveService() {}
+
+void AppKeepAliveService::Shutdown() {
+ AppLifetimeMonitor* app_lifetime_monitor =
+ AppLifetimeMonitorFactory::GetForProfile(static_cast<Profile*>(context_));
+ app_lifetime_monitor->RemoveObserver(this);
+ OnChromeTerminating();
+}
+
+void AppKeepAliveService::OnAppStart(Profile* profile,
+ const std::string& app_id) {
+ if (profile != context_)
+ return;
+
+ if (running_apps_.insert(app_id).second)
+ chrome::StartKeepAlive();
+}
+
+void AppKeepAliveService::OnAppStop(Profile* profile,
+ const std::string& app_id) {
+ if (profile != context_)
+ return;
+
+ if (running_apps_.erase(app_id))
+ chrome::EndKeepAlive();
+}
+
+void AppKeepAliveService::OnAppActivated(Profile* profile,
+ const std::string& app_id) {}
+
+void AppKeepAliveService::OnAppDeactivated(Profile* profile,
+ const std::string& app_id) {}
+
+void AppKeepAliveService::OnChromeTerminating() {
+ size_t keep_alives = running_apps_.size();
+ running_apps_.clear();
+
+ // In some tests, the message loop isn't running during shutdown and ending
+ // the last keep alive in that case CHECKs.
+ if (!base::MessageLoop::current() ||
+ base::MessageLoop::current()->is_running()) {
+ while (keep_alives--)
+ chrome::EndKeepAlive();
+ }
+}
+
+} // namespace apps
diff --git a/apps/app_keep_alive_service.h b/apps/app_keep_alive_service.h
new file mode 100644
index 0000000..563a953
--- /dev/null
+++ b/apps/app_keep_alive_service.h
@@ -0,0 +1,38 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef APPS_APP_KEEP_ALIVE_SERVICE_H_
+#define APPS_APP_KEEP_ALIVE_SERVICE_H_
+
+#include "apps/app_lifetime_monitor.h"
+#include "components/browser_context_keyed_service/browser_context_keyed_service.h"
+
+namespace apps {
+
+class AppKeepAliveService : public BrowserContextKeyedService,
+ public AppLifetimeMonitor::Observer {
+ public:
+ AppKeepAliveService(content::BrowserContext* context);
+ virtual ~AppKeepAliveService();
+ virtual void Shutdown() OVERRIDE;
+
+ // AppLifetimeMonitor::Observer:
+ virtual void OnAppStart(Profile* profile, const std::string& app_id) OVERRIDE;
+ virtual void OnAppStop(Profile* profile, const std::string& app_id) OVERRIDE;
+ virtual void OnAppActivated(Profile* profile,
+ const std::string& app_id) OVERRIDE;
+ virtual void OnAppDeactivated(Profile* profile,
+ const std::string& app_id) OVERRIDE;
+ virtual void OnChromeTerminating() OVERRIDE;
+
+ private:
+ content::BrowserContext* context_;
+ std::set<std::string> running_apps_;
+
+ DISALLOW_COPY_AND_ASSIGN(AppKeepAliveService);
+};
+
+} // namespace apps
+
+#endif // APPS_APP_KEEP_ALIVE_SERVICE_H_
diff --git a/apps/app_keep_alive_service_factory.cc b/apps/app_keep_alive_service_factory.cc
new file mode 100644
index 0000000..dc9e725
--- /dev/null
+++ b/apps/app_keep_alive_service_factory.cc
@@ -0,0 +1,47 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "apps/app_keep_alive_service_factory.h"
+
+#include "apps/app_keep_alive_service.h"
+#include "apps/app_lifetime_monitor_factory.h"
+#include "apps/shell_window_registry.h"
+#include "chrome/browser/profiles/incognito_helpers.h"
+#include "components/browser_context_keyed_service/browser_context_dependency_manager.h"
+
+namespace apps {
+
+// static
+AppKeepAliveServiceFactory* AppKeepAliveServiceFactory::GetInstance() {
+ return Singleton<AppKeepAliveServiceFactory>::get();
+}
+
+AppKeepAliveServiceFactory::AppKeepAliveServiceFactory()
+ : BrowserContextKeyedServiceFactory(
+ "AppKeepAliveService",
+ BrowserContextDependencyManager::GetInstance()) {
+ DependsOn(AppLifetimeMonitorFactory::GetInstance());
+}
+
+AppKeepAliveServiceFactory::~AppKeepAliveServiceFactory() {}
+
+BrowserContextKeyedService* AppKeepAliveServiceFactory::BuildServiceInstanceFor(
+ content::BrowserContext* context) const {
+ return new AppKeepAliveService(context);
+}
+
+bool AppKeepAliveServiceFactory::ServiceIsCreatedWithBrowserContext() const {
+ return true;
+}
+
+content::BrowserContext* AppKeepAliveServiceFactory::GetBrowserContextToUse(
+ content::BrowserContext* context) const {
+ return chrome::GetBrowserContextRedirectedInIncognito(context);
+}
+
+bool AppKeepAliveServiceFactory::ServiceIsNULLWhileTesting() const {
+ return true;
+}
+
+} // namespace apps
diff --git a/apps/app_keep_alive_service_factory.h b/apps/app_keep_alive_service_factory.h
new file mode 100644
index 0000000..32575d9
--- /dev/null
+++ b/apps/app_keep_alive_service_factory.h
@@ -0,0 +1,36 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef APPS_APP_KEEP_ALIVE_SERVICE_FACTORY_H_
+#define APPS_APP_KEEP_ALIVE_SERVICE_FACTORY_H_
+
+#include "base/memory/singleton.h"
+#include "components/browser_context_keyed_service/browser_context_keyed_service_factory.h"
+
+namespace apps {
+
+class AppKeepAliveService;
+
+class AppKeepAliveServiceFactory : public BrowserContextKeyedServiceFactory {
+ public:
+ static AppKeepAliveServiceFactory* GetInstance();
+
+ private:
+ friend struct DefaultSingletonTraits<AppKeepAliveServiceFactory>;
+
+ AppKeepAliveServiceFactory();
+ virtual ~AppKeepAliveServiceFactory();
+
+ // BrowserContextKeyedServiceFactory:
+ virtual BrowserContextKeyedService* BuildServiceInstanceFor(
+ content::BrowserContext* context) const OVERRIDE;
+ virtual bool ServiceIsCreatedWithBrowserContext() const OVERRIDE;
+ virtual content::BrowserContext* GetBrowserContextToUse(
+ content::BrowserContext* context) const OVERRIDE;
+ virtual bool ServiceIsNULLWhileTesting() const OVERRIDE;
+};
+
+} // namespace apps
+
+#endif // APPS_APP_KEEP_ALIVE_SERVICE_FACTORY_H_
diff --git a/apps/app_keep_alive_service_unittest.cc b/apps/app_keep_alive_service_unittest.cc
new file mode 100644
index 0000000..3478162
--- /dev/null
+++ b/apps/app_keep_alive_service_unittest.cc
@@ -0,0 +1,121 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "apps/app_keep_alive_service.h"
+#include "apps/app_keep_alive_service_factory.h"
+#include "chrome/browser/lifetime/application_lifetime.h"
+#include "chrome/test/base/testing_profile.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#if !defined(OS_ANDROID)
+
+class AppKeepAliveServiceUnitTest : public testing::Test {
+ protected:
+ virtual void SetUp() OVERRIDE {
+ testing::Test::SetUp();
+ service_.reset(new apps::AppKeepAliveService(&profile_));
+ }
+
+ virtual void TearDown() OVERRIDE {
+ while (chrome::WillKeepAlive())
+ chrome::EndKeepAlive();
+ testing::Test::TearDown();
+ }
+
+ TestingProfile profile_;
+ scoped_ptr<apps::AppKeepAliveService> service_;
+};
+
+TEST_F(AppKeepAliveServiceUnitTest, Basic) {
+ ASSERT_FALSE(chrome::WillKeepAlive());
+ service_->OnAppStart(&profile_, "foo");
+ EXPECT_TRUE(chrome::WillKeepAlive());
+ service_->OnAppStop(&profile_, "foo");
+ EXPECT_FALSE(chrome::WillKeepAlive());
+ service_->Shutdown();
+ EXPECT_FALSE(chrome::WillKeepAlive());
+}
+
+// Test that apps running in different profiles are ignored.
+TEST_F(AppKeepAliveServiceUnitTest, DifferentProfile) {
+ ASSERT_FALSE(chrome::WillKeepAlive());
+ service_->OnAppStart(NULL, "foo");
+ EXPECT_FALSE(chrome::WillKeepAlive());
+ service_->OnAppStart(&profile_, "foo");
+ EXPECT_TRUE(chrome::WillKeepAlive());
+ service_->OnAppStop(NULL, "foo");
+ EXPECT_TRUE(chrome::WillKeepAlive());
+ service_->OnAppStop(&profile_, "foo");
+ EXPECT_FALSE(chrome::WillKeepAlive());
+ service_->Shutdown();
+ EXPECT_FALSE(chrome::WillKeepAlive());
+}
+
+// Test that OnAppStop without a prior corresponding OnAppStart is ignored.
+TEST_F(AppKeepAliveServiceUnitTest, StopAppBeforeOpening) {
+ ASSERT_FALSE(chrome::WillKeepAlive());
+ service_->OnAppStop(&profile_, "foo");
+ ASSERT_FALSE(chrome::WillKeepAlive());
+ service_->OnAppStart(&profile_, "foo");
+ EXPECT_TRUE(chrome::WillKeepAlive());
+ service_->OnAppStop(&profile_, "foo");
+ EXPECT_FALSE(chrome::WillKeepAlive());
+ service_->Shutdown();
+ EXPECT_FALSE(chrome::WillKeepAlive());
+}
+
+// Test that OnAppStart for an app that has already started is ignored.
+TEST_F(AppKeepAliveServiceUnitTest, StartMoreThanOnce) {
+ ASSERT_FALSE(chrome::WillKeepAlive());
+ service_->OnAppStart(&profile_, "foo");
+ EXPECT_TRUE(chrome::WillKeepAlive());
+ service_->OnAppStart(&profile_, "foo");
+ EXPECT_TRUE(chrome::WillKeepAlive());
+ service_->OnAppStop(&profile_, "foo");
+ EXPECT_FALSE(chrome::WillKeepAlive());
+ service_->Shutdown();
+ EXPECT_FALSE(chrome::WillKeepAlive());
+}
+
+TEST_F(AppKeepAliveServiceUnitTest, MultipleApps) {
+ ASSERT_FALSE(chrome::WillKeepAlive());
+ service_->OnAppStart(&profile_, "foo");
+ EXPECT_TRUE(chrome::WillKeepAlive());
+ service_->OnAppStart(&profile_, "bar");
+ EXPECT_TRUE(chrome::WillKeepAlive());
+ service_->OnAppStop(&profile_, "foo");
+ EXPECT_TRUE(chrome::WillKeepAlive());
+ service_->OnAppStop(&profile_, "bar");
+ EXPECT_FALSE(chrome::WillKeepAlive());
+ service_->Shutdown();
+ EXPECT_FALSE(chrome::WillKeepAlive());
+}
+
+// Test that all keep alives are ended when OnChromeTerminating is called.
+TEST_F(AppKeepAliveServiceUnitTest, ChromeTerminateWithAppsStarted) {
+ ASSERT_FALSE(chrome::WillKeepAlive());
+ service_->OnAppStart(&profile_, "foo");
+ EXPECT_TRUE(chrome::WillKeepAlive());
+ service_->OnAppStart(&profile_, "bar");
+ EXPECT_TRUE(chrome::WillKeepAlive());
+ service_->OnChromeTerminating();
+ EXPECT_FALSE(chrome::WillKeepAlive());
+ service_->OnAppStop(&profile_, "foo");
+ service_->OnAppStop(&profile_, "bar");
+ EXPECT_FALSE(chrome::WillKeepAlive());
+ service_->Shutdown();
+ EXPECT_FALSE(chrome::WillKeepAlive());
+}
+
+// Test that all keep alives are ended when Shutdown is called.
+TEST_F(AppKeepAliveServiceUnitTest, ProfileShutdownWithAppsStarted) {
+ ASSERT_FALSE(chrome::WillKeepAlive());
+ service_->OnAppStart(&profile_, "foo");
+ EXPECT_TRUE(chrome::WillKeepAlive());
+ service_->OnAppStart(&profile_, "bar");
+ EXPECT_TRUE(chrome::WillKeepAlive());
+ service_->Shutdown();
+ EXPECT_FALSE(chrome::WillKeepAlive());
+}
+#endif
diff --git a/apps/apps.gypi b/apps/apps.gypi
index e956c46..ea177bd 100644
--- a/apps/apps.gypi
+++ b/apps/apps.gypi
@@ -23,6 +23,10 @@
'<(grit_out_dir)',
],
'sources': [
+ 'app_keep_alive_service.cc',
+ 'app_keep_alive_service.h',
+ 'app_keep_alive_service_factory.cc',
+ 'app_keep_alive_service_factory.h',
'app_lifetime_monitor.cc',
'app_lifetime_monitor.h',
'app_lifetime_monitor_factory.cc',
diff --git a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
index ac1c060..80b972a 100644
--- a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
+++ b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
@@ -4,6 +4,7 @@
#include "chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.h"
+#include "apps/app_keep_alive_service_factory.h"
#include "apps/app_load_service_factory.h"
#include "apps/app_restore_service_factory.h"
#include "apps/shell_window_geometry_cache.h"
@@ -216,6 +217,7 @@ EnsureBrowserContextKeyedServiceFactoriesBuilt() {
DownloadServiceFactory::GetInstance();
#if defined(ENABLE_EXTENSIONS)
AppShortcutManagerFactory::GetInstance();
+ apps::AppKeepAliveServiceFactory::GetInstance();
apps::AppLoadServiceFactory::GetInstance();
apps::AppRestoreServiceFactory::GetInstance();
apps::ShellWindowGeometryCache::Factory::GetInstance();
diff --git a/chrome/chrome_tests_unit.gypi b/chrome/chrome_tests_unit.gypi
index f0d3358..fc38f18 100644
--- a/chrome/chrome_tests_unit.gypi
+++ b/chrome/chrome_tests_unit.gypi
@@ -504,6 +504,7 @@
'win_use_external_manifest': 1,
},
'sources': [
+ '../apps/app_keep_alive_service_unittest.cc',
'../apps/app_shim/app_shim_host_mac_unittest.cc',
'../apps/saved_files_service_unittest.cc',
'../apps/app_shim/extension_app_shim_handler_mac_unittest.cc',