diff options
author | sammc@chromium.org <sammc@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-10-30 04:45:56 +0000 |
---|---|---|
committer | sammc@chromium.org <sammc@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-10-30 04:45:56 +0000 |
commit | 979574d0beda1f79337b1398c24d27d53351f517 (patch) | |
tree | 63d156d7b92f66885383c6b0db8af07e75cdbfb8 | |
parent | a418bf7985a2c936e96cb8c2b3e2a7c14d553f76 (diff) | |
download | chromium_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.cc | 68 | ||||
-rw-r--r-- | apps/app_keep_alive_service.h | 38 | ||||
-rw-r--r-- | apps/app_keep_alive_service_factory.cc | 47 | ||||
-rw-r--r-- | apps/app_keep_alive_service_factory.h | 36 | ||||
-rw-r--r-- | apps/app_keep_alive_service_unittest.cc | 121 | ||||
-rw-r--r-- | apps/apps.gypi | 4 | ||||
-rw-r--r-- | chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc | 2 | ||||
-rw-r--r-- | chrome/chrome_tests_unit.gypi | 1 |
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', |