summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbenwells@chromium.org <benwells@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-12-01 07:16:45 +0000
committerbenwells@chromium.org <benwells@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-12-01 07:16:45 +0000
commit99bfb2040b313f6f1703db227678913135acf80e (patch)
treebf9d89e43e02182748a544946e2139631474a735
parentc3c36c3f276fead96ee34bbcc46d41c8bc3c9acd (diff)
downloadchromium_src-99bfb2040b313f6f1703db227678913135acf80e.zip
chromium_src-99bfb2040b313f6f1703db227678913135acf80e.tar.gz
chromium_src-99bfb2040b313f6f1703db227678913135acf80e.tar.bz2
Keep browser process alive while there are platform apps with background pages running. This does not happen on Android or ChromeOS builds: Android does not support browser process keep alive, and ChromeOS does not need or like it.
This change prevents platform apps getting killed unceremoniously while they have background pages active. This also delays the process being shutdown after closing the last platform app window, as background pages are kept alive for 15 seconds after their last activity is completed. This change re-lands r165772 which caused problems on Google branded ChromeOS. This version does not add keep alives for ChromeOS and was tested on the ChromeOS try bots. TBR=davemoore@chromium.org for the ash launcher test change. BUG=155457 TEST=Make sure platform apps can be used from the launcher without chrome windows open; make sure Chrome shuts down properly in all cases. Committed: http://src.chromium.org/viewvc/chrome?view=rev&revision=165772 Review URL: https://chromiumcodereview.appspot.com/11117011 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@170660 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/chromeos/extensions/external_filesystem_apitest.cc1
-rw-r--r--chrome/browser/extensions/api/app_window/app_window_apitest.cc4
-rw-r--r--chrome/browser/extensions/api/bluetooth/bluetooth_apitest.cc14
-rw-r--r--chrome/browser/extensions/api/dns/dns_apitest.cc2
-rw-r--r--chrome/browser/extensions/api/identity/identity_apitest.cc13
-rw-r--r--chrome/browser/extensions/api/media_galleries/media_galleries_apitest.cc10
-rw-r--r--chrome/browser/extensions/api/media_galleries_private/media_galleries_private_apitest.cc74
-rw-r--r--chrome/browser/extensions/api/push_messaging/push_messaging_apitest.cc4
-rw-r--r--chrome/browser/extensions/api/serial/serial_apitest.cc4
-rw-r--r--chrome/browser/extensions/api/socket/socket_apitest.cc5
-rw-r--r--chrome/browser/extensions/api/sync_file_system/sync_file_system_apitest.cc10
-rw-r--r--chrome/browser/extensions/api/system_indicator/system_indicator_apitest.cc2
-rw-r--r--chrome/browser/extensions/api/system_info_cpu/system_info_cpu_apitest.cc2
-rw-r--r--chrome/browser/extensions/api/system_info_memory/system_info_memory_apitest.cc2
-rw-r--r--chrome/browser/extensions/api/usb/usb_apitest.cc8
-rw-r--r--chrome/browser/extensions/extension_apitest.cc7
-rw-r--r--chrome/browser/extensions/extension_apitest.h8
-rw-r--r--chrome/browser/extensions/extension_browsertest.cc40
-rw-r--r--chrome/browser/extensions/extension_browsertest.h8
-rw-r--r--chrome/browser/extensions/extension_host.cc17
-rw-r--r--chrome/browser/extensions/extension_host.h9
-rw-r--r--chrome/browser/extensions/platform_app_browsertest.cc83
-rw-r--r--chrome/browser/extensions/platform_app_browsertest_util.cc54
-rw-r--r--chrome/browser/extensions/platform_app_browsertest_util.h15
-rw-r--r--chrome/browser/extensions/platform_app_service.cc45
-rw-r--r--chrome/browser/extensions/platform_app_service.h35
-rw-r--r--chrome/browser/extensions/platform_app_service_factory.cc47
-rw-r--r--chrome/browser/extensions/platform_app_service_factory.h36
-rw-r--r--chrome/browser/extensions/web_view_browsertest.cc10
-rw-r--r--chrome/browser/profiles/profile_dependency_manager.cc2
-rw-r--r--chrome/browser/sync/test/integration/apps_helper.cc25
-rw-r--r--chrome/browser/sync/test/integration/apps_helper.h4
-rw-r--r--chrome/browser/sync/test/integration/single_client_apps_sync_test.cc17
-rw-r--r--chrome/browser/sync/test/integration/two_client_apps_sync_test.cc13
-rw-r--r--chrome/browser/ui/ash/launcher/chrome_launcher_controller_browsertest.cc29
-rw-r--r--chrome/chrome_browser_extensions.gypi4
-rw-r--r--chrome/test/data/extensions/api_test/media_galleries_private/attachdetach/test.js2
-rw-r--r--chrome/test/data/extensions/platform_apps/geometry/test.js2
-rw-r--r--chrome/test/data/extensions/platform_apps/open_link/main.js2
-rw-r--r--chrome/test/data/extensions/platform_apps/windows_api_bounds/background.js1
40 files changed, 523 insertions, 147 deletions
diff --git a/chrome/browser/chromeos/extensions/external_filesystem_apitest.cc b/chrome/browser/chromeos/extensions/external_filesystem_apitest.cc
index 0efa08e..927955b 100644
--- a/chrome/browser/chromeos/extensions/external_filesystem_apitest.cc
+++ b/chrome/browser/chromeos/extensions/external_filesystem_apitest.cc
@@ -344,6 +344,7 @@ IN_PROC_BROWSER_TEST_F(FileSystemExtensionApiTest, FileBrowserWebIntentTest) {
// The webintent_handler sends chrome.test.succeed() on successful receipt
// of the incoming Web Intent.
ASSERT_TRUE(catcher.GetNextResult()) << message_;
+ CloseShellWindowsAndWaitForAppToExit();
}
IN_PROC_BROWSER_TEST_F(FileSystemExtensionApiTest, FileBrowserTestWrite) {
diff --git a/chrome/browser/extensions/api/app_window/app_window_apitest.cc b/chrome/browser/extensions/api/app_window/app_window_apitest.cc
index 5307888..d514e4d 100644
--- a/chrome/browser/extensions/api/app_window/app_window_apitest.cc
+++ b/chrome/browser/extensions/api/app_window/app_window_apitest.cc
@@ -35,6 +35,8 @@ IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, WindowsApiBounds) {
ready_listener.Reply(base::IntToString(slop));
ASSERT_TRUE(success_listener.WaitUntilSatisfied());
+
+ CloseShellWindowsAndWaitForAppToExit();
}
// TODO(asargent) - Fix onMinimzed event on OSX (crbug.com/162793) and figure
@@ -44,7 +46,7 @@ IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, WindowsApiBounds) {
IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, WindowsApiProperties) {
EXPECT_TRUE(
- RunExtensionTest("platform_apps/windows_api_properties")) << message_;
+ RunPlatformAppTest("platform_apps/windows_api_properties")) << message_;
}
#endif // defined(TOOLKIT_VIEWS)
diff --git a/chrome/browser/extensions/api/bluetooth/bluetooth_apitest.cc b/chrome/browser/extensions/api/bluetooth/bluetooth_apitest.cc
index 15fa7c6..d646d6d 100644
--- a/chrome/browser/extensions/api/bluetooth/bluetooth_apitest.cc
+++ b/chrome/browser/extensions/api/bluetooth/bluetooth_apitest.cc
@@ -330,6 +330,7 @@ IN_PROC_BROWSER_TEST_F(BluetoothApiTest, DiscoveryCallback) {
discovery_stopped.Reply("go");
EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
+ CloseShellWindowsAndWaitForAppToExit();
}
IN_PROC_BROWSER_TEST_F(BluetoothApiTest, DiscoveryInProgress) {
@@ -360,6 +361,7 @@ IN_PROC_BROWSER_TEST_F(BluetoothApiTest, DiscoveryInProgress) {
discovery_stopped.Reply("go");
EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
+ CloseShellWindowsAndWaitForAppToExit();
}
IN_PROC_BROWSER_TEST_F(BluetoothApiTest, Events) {
@@ -381,6 +383,7 @@ IN_PROC_BROWSER_TEST_F(BluetoothApiTest, Events) {
listener.Reply("go");
EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
+ CloseShellWindowsAndWaitForAppToExit();
}
IN_PROC_BROWSER_TEST_F(BluetoothApiTest, GetDevices) {
@@ -414,6 +417,7 @@ IN_PROC_BROWSER_TEST_F(BluetoothApiTest, GetDevices) {
listener.Reply("go");
EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
+ CloseShellWindowsAndWaitForAppToExit();
}
IN_PROC_BROWSER_TEST_F(BluetoothApiTest, GetDevicesConcurrently) {
@@ -425,9 +429,10 @@ IN_PROC_BROWSER_TEST_F(BluetoothApiTest, GetDevicesConcurrently) {
// Save the callback to delay execution so that we can force the calls to
// happen concurrently. This will be called after the listener is satisfied.
- BluetoothDevice::ProvidesServiceCallback callback;
+ BluetoothDevice::ProvidesServiceCallback* callback =
+ new BluetoothDevice::ProvidesServiceCallback;
EXPECT_CALL(*device1_, ProvidesServiceWithName(testing::_, testing::_))
- .WillOnce(testing::SaveArg<1>(&callback));
+ .WillOnce(testing::SaveArg<1>(callback));
EXPECT_CALL(*mock_adapter_, GetDevices())
.WillOnce(testing::Return(devices));
@@ -438,10 +443,12 @@ IN_PROC_BROWSER_TEST_F(BluetoothApiTest, GetDevicesConcurrently) {
test_data_dir_.AppendASCII("bluetooth/get_devices_concurrently")));
EXPECT_TRUE(listener.WaitUntilSatisfied());
- callback.Run(false);
+ callback->Run(false);
+ delete callback;
listener.Reply("go");
EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
+ CloseShellWindowsAndWaitForAppToExit();
}
IN_PROC_BROWSER_TEST_F(BluetoothApiTest, GetDevicesError) {
@@ -457,4 +464,5 @@ IN_PROC_BROWSER_TEST_F(BluetoothApiTest, GetDevicesError) {
listener.Reply("go");
EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
+ CloseShellWindowsAndWaitForAppToExit();
}
diff --git a/chrome/browser/extensions/api/dns/dns_apitest.cc b/chrome/browser/extensions/api/dns/dns_apitest.cc
index a4c5ad0..b792127 100644
--- a/chrome/browser/extensions/api/dns/dns_apitest.cc
+++ b/chrome/browser/extensions/api/dns/dns_apitest.cc
@@ -101,5 +101,5 @@ IN_PROC_BROWSER_TEST_F(DnsApiTest, DnsResolveHostname) {
}
IN_PROC_BROWSER_TEST_F(DnsApiTest, DnsExtension) {
- ASSERT_TRUE(RunExtensionTest("dns/api")) << message_;
+ ASSERT_TRUE(RunPlatformAppTest("dns/api")) << message_;
}
diff --git a/chrome/browser/extensions/api/identity/identity_apitest.cc b/chrome/browser/extensions/api/identity/identity_apitest.cc
index e5d05bb..7f49ae4 100644
--- a/chrome/browser/extensions/api/identity/identity_apitest.cc
+++ b/chrome/browser/extensions/api/identity/identity_apitest.cc
@@ -177,6 +177,7 @@ IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
EXPECT_EQ(std::string(errors::kInvalidClientId), error);
EXPECT_FALSE(func->login_ui_shown());
EXPECT_FALSE(func->install_ui_shown());
+ CloseShellWindowsAndWaitForAppToExit();
}
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
@@ -188,6 +189,7 @@ IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
EXPECT_EQ(std::string(errors::kInvalidScopes), error);
EXPECT_FALSE(func->login_ui_shown());
EXPECT_FALSE(func->install_ui_shown());
+ CloseShellWindowsAndWaitForAppToExit();
}
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
@@ -200,6 +202,7 @@ IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
EXPECT_EQ(std::string(errors::kUserNotSignedIn), error);
EXPECT_FALSE(func->login_ui_shown());
EXPECT_FALSE(func->install_ui_shown());
+ CloseShellWindowsAndWaitForAppToExit();
}
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
@@ -217,6 +220,7 @@ IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
EXPECT_TRUE(StartsWithASCII(error, errors::kAuthFailure, false));
EXPECT_FALSE(func->login_ui_shown());
EXPECT_FALSE(func->install_ui_shown());
+ CloseShellWindowsAndWaitForAppToExit();
}
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
@@ -236,6 +240,7 @@ IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
EXPECT_EQ(std::string(kAccessToken), access_token);
EXPECT_FALSE(func->login_ui_shown());
EXPECT_FALSE(func->install_ui_shown());
+ CloseShellWindowsAndWaitForAppToExit();
}
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
@@ -248,6 +253,7 @@ IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
EXPECT_EQ(std::string(errors::kUserNotSignedIn), error);
EXPECT_TRUE(func->login_ui_shown());
EXPECT_FALSE(func->install_ui_shown());
+ CloseShellWindowsAndWaitForAppToExit();
}
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
@@ -265,6 +271,7 @@ IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
EXPECT_TRUE(StartsWithASCII(error, errors::kAuthFailure, false));
EXPECT_TRUE(func->login_ui_shown());
EXPECT_FALSE(func->install_ui_shown());
+ CloseShellWindowsAndWaitForAppToExit();
}
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
@@ -284,6 +291,7 @@ IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
EXPECT_EQ(std::string(kAccessToken), access_token);
EXPECT_TRUE(func->login_ui_shown());
EXPECT_FALSE(func->install_ui_shown());
+ CloseShellWindowsAndWaitForAppToExit();
}
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
@@ -302,6 +310,7 @@ IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
EXPECT_EQ(std::string(errors::kUserRejected), error);
EXPECT_TRUE(func->login_ui_shown());
EXPECT_TRUE(func->install_ui_shown());
+ CloseShellWindowsAndWaitForAppToExit();
}
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
@@ -326,6 +335,7 @@ IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
EXPECT_TRUE(StartsWithASCII(error, errors::kAuthFailure, false));
EXPECT_TRUE(func->login_ui_shown());
EXPECT_TRUE(func->install_ui_shown());
+ CloseShellWindowsAndWaitForAppToExit();
}
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
@@ -352,6 +362,7 @@ IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
EXPECT_EQ(std::string(kAccessToken), access_token);
EXPECT_TRUE(func->login_ui_shown());
EXPECT_TRUE(func->install_ui_shown());
+ CloseShellWindowsAndWaitForAppToExit();
}
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
@@ -370,6 +381,7 @@ IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
EXPECT_EQ(std::string(errors::kUserRejected), error);
EXPECT_FALSE(func->login_ui_shown());
EXPECT_TRUE(func->install_ui_shown());
+ CloseShellWindowsAndWaitForAppToExit();
}
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
@@ -396,6 +408,7 @@ IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
EXPECT_EQ(std::string(kAccessToken), access_token);
EXPECT_FALSE(func->login_ui_shown());
EXPECT_TRUE(func->install_ui_shown());
+ CloseShellWindowsAndWaitForAppToExit();
}
class LaunchWebAuthFlowFunctionTest : public ExtensionBrowserTest {
diff --git a/chrome/browser/extensions/api/media_galleries/media_galleries_apitest.cc b/chrome/browser/extensions/api/media_galleries/media_galleries_apitest.cc
index d1a5e64..3316e9d 100644
--- a/chrome/browser/extensions/api/media_galleries/media_galleries_apitest.cc
+++ b/chrome/browser/extensions/api/media_galleries/media_galleries_apitest.cc
@@ -57,17 +57,19 @@ IN_PROC_BROWSER_TEST_F(PlatformAppMediaGalleriesBrowserTest, NoGalleries) {
IN_PROC_BROWSER_TEST_F(PlatformAppMediaGalleriesBrowserTest,
MediaGalleriesRead) {
chrome::EnsureMediaDirectoriesExists media_directories;
- ASSERT_TRUE(RunPlatformAppTest("api_test/media_galleries/read_access"))
- << message_;
+ ASSERT_TRUE(RunPlatformAppTestReturnImmediately(
+ "api_test/media_galleries/read_access")) << message_;
RunSecondTestPhase(media_directories.num_galleries());
+ CloseShellWindowsAndWaitForAppToExit();
}
IN_PROC_BROWSER_TEST_F(PlatformAppMediaGalleriesBrowserTest,
MediaGalleriesNoAccess) {
chrome::EnsureMediaDirectoriesExists media_directories;
- ASSERT_TRUE(RunPlatformAppTest("api_test/media_galleries/no_access"))
- << message_;
+ ASSERT_TRUE(RunPlatformAppTestReturnImmediately(
+ "api_test/media_galleries/no_access")) << message_;
RunSecondTestPhase(media_directories.num_galleries());
+ CloseShellWindowsAndWaitForAppToExit();
}
IN_PROC_BROWSER_TEST_F(ExperimentalMediaGalleriesApiTest,
diff --git a/chrome/browser/extensions/api/media_galleries_private/media_galleries_private_apitest.cc b/chrome/browser/extensions/api/media_galleries_private/media_galleries_private_apitest.cc
index 05dffbe..51ccbd2 100644
--- a/chrome/browser/extensions/api/media_galleries_private/media_galleries_private_apitest.cc
+++ b/chrome/browser/extensions/api/media_galleries_private/media_galleries_private_apitest.cc
@@ -80,20 +80,27 @@ class MediaGalleriesPrivateApiTest : public ExtensionApiTest {
EXPECT_TRUE(listener.WaitUntilSatisfied());
}
- void AttachDetach() {
- Attach();
- Detach();
- }
-
- void Attach() {
+ void Attach(bool listening) {
+ const std::string expect_attach_msg =
+ base::StringPrintf("%s,%s", kAttachTestOk, kDeviceName);
+ ExtensionTestMessageListener attach_finished_listener(
+ expect_attach_msg,
+ false /* no reply */);
base::SystemMonitor::Get()->ProcessRemovableStorageAttached(
device_id_, ASCIIToUTF16(kDeviceName), kDevicePath);
WaitForDeviceEvents();
+ if (listening)
+ EXPECT_TRUE(attach_finished_listener.WaitUntilSatisfied());
}
- void Detach() {
+ void Detach(bool listening) {
+ ExtensionTestMessageListener detach_finished_listener(
+ kDetachTestOk,
+ false /* no reply */);
base::SystemMonitor::Get()->ProcessRemovableStorageDetached(device_id_);
WaitForDeviceEvents();
+ if (listening)
+ EXPECT_TRUE(detach_finished_listener.WaitUntilSatisfied());
}
private:
@@ -119,49 +126,41 @@ IN_PROC_BROWSER_TEST_F(MediaGalleriesPrivateApiTest, DeviceAttachDetachEvents) {
ASSERT_TRUE(host);
// No listeners, attach and detach a couple times.
- AttachDetach();
- AttachDetach();
+ Attach(false);
+ Detach(false);
+ Attach(false);
+ Detach(false);
// Add attach listener.
ChangeListener(host, kAddAttachListenerCmd, kAddAttachListenerOk);
// Attach / detach
- const std::string expect_attach_msg =
- base::StringPrintf("%s,%s", kAttachTestOk, kDeviceName);
- ExtensionTestMessageListener attach_finished_listener(expect_attach_msg,
- false /* no reply */);
- Attach();
- EXPECT_TRUE(attach_finished_listener.WaitUntilSatisfied());
- Detach();
+ Attach(true);
+ Detach(false);
// Attach / detach
- Attach();
- EXPECT_TRUE(attach_finished_listener.WaitUntilSatisfied());
- // Detach
- Detach();
+ Attach(true);
+ Detach(false);
// Remove attach listener.
ChangeListener(host, kRemoveAttachListenerCmd, kRemoveAttachListenerOk);
// No listeners, attach and detach a couple times.
- AttachDetach();
- AttachDetach();
+ Attach(false);
+ Detach(false);
+ Attach(false);
+ Detach(false);
// Add detach listener.
ChangeListener(host, kAddDummyDetachListenerCmd, kAddDummyDetachListenerOk);
// Attach / detach
- Attach();
-
- ExtensionTestMessageListener detach_finished_listener(kDetachTestOk,
- false /* no reply */);
- Detach();
- EXPECT_TRUE(detach_finished_listener.WaitUntilSatisfied());
+ Attach(false);
+ Detach(true);
// Attach / detach
- Attach();
- Detach();
- EXPECT_TRUE(detach_finished_listener.WaitUntilSatisfied());
+ Attach(false);
+ Detach(true);
// Switch ok dummy detach listener for the regular one.
ChangeListener(host, kRemoveDummyDetachListenerCmd,
@@ -171,13 +170,10 @@ IN_PROC_BROWSER_TEST_F(MediaGalleriesPrivateApiTest, DeviceAttachDetachEvents) {
// Add attach listener.
ChangeListener(host, kAddAttachListenerCmd, kAddAttachListenerOk);
- Attach();
- EXPECT_TRUE(attach_finished_listener.WaitUntilSatisfied());
- Detach();
- EXPECT_TRUE(detach_finished_listener.WaitUntilSatisfied());
+ Attach(true);
+ Detach(true);
- Attach();
- EXPECT_TRUE(attach_finished_listener.WaitUntilSatisfied());
- Detach();
- EXPECT_TRUE(detach_finished_listener.WaitUntilSatisfied());
+ Attach(true);
+ Detach(true);
+ CloseShellWindowsAndWaitForAppToExit();
}
diff --git a/chrome/browser/extensions/api/push_messaging/push_messaging_apitest.cc b/chrome/browser/extensions/api/push_messaging/push_messaging_apitest.cc
index c881e88..fe81014c 100644
--- a/chrome/browser/extensions/api/push_messaging/push_messaging_apitest.cc
+++ b/chrome/browser/extensions/api/push_messaging/push_messaging_apitest.cc
@@ -52,7 +52,7 @@ class PushMessagingApiTest : public ExtensionApiTest {
IN_PROC_BROWSER_TEST_F(PushMessagingApiTest, EventDispatch) {
ResultCatcher catcher;
catcher.RestrictToProfile(browser()->profile());
- ExtensionTestMessageListener ready("ready", true);
+ ExtensionTestMessageListener ready("ready", false);
const extensions::Extension* extension =
LoadExtension(test_data_dir_.AppendASCII("push_messaging"));
@@ -71,7 +71,7 @@ IN_PROC_BROWSER_TEST_F(PushMessagingApiTest, EventDispatch) {
IN_PROC_BROWSER_TEST_F(PushMessagingApiTest, ReceivesPush) {
ResultCatcher catcher;
catcher.RestrictToProfile(browser()->profile());
- ExtensionTestMessageListener ready("ready", true);
+ ExtensionTestMessageListener ready("ready", false);
const extensions::Extension* extension =
LoadExtension(test_data_dir_.AppendASCII("push_messaging"));
diff --git a/chrome/browser/extensions/api/serial/serial_apitest.cc b/chrome/browser/extensions/api/serial/serial_apitest.cc
index 6495184..f37ae67 100644
--- a/chrome/browser/extensions/api/serial/serial_apitest.cc
+++ b/chrome/browser/extensions/api/serial/serial_apitest.cc
@@ -178,12 +178,12 @@ IN_PROC_BROWSER_TEST_F(SerialApiTest, SerialFakeHardware) {
FakeSerialOpenFunctionFactory));
#endif
- ASSERT_TRUE(RunExtensionTest("serial/api")) << message_;
+ ASSERT_TRUE(RunPlatformAppTest("serial/api")) << message_;
}
IN_PROC_BROWSER_TEST_F(SerialApiTest, SerialRealHardware) {
ResultCatcher catcher;
catcher.RestrictToProfile(browser()->profile());
- ASSERT_TRUE(RunExtensionTest("serial/real_hardware")) << message_;
+ ASSERT_TRUE(RunPlatformAppTest("serial/real_hardware")) << message_;
}
diff --git a/chrome/browser/extensions/api/socket/socket_apitest.cc b/chrome/browser/extensions/api/socket/socket_apitest.cc
index 93bd3c8..d279717 100644
--- a/chrome/browser/extensions/api/socket/socket_apitest.cc
+++ b/chrome/browser/extensions/api/socket/socket_apitest.cc
@@ -145,6 +145,7 @@ IN_PROC_BROWSER_TEST_F(SocketApiTest, SocketUDPExtension) {
base::StringPrintf("udp:%s:%d", host_port_pair.host().c_str(), port));
EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
+ CloseShellWindowsAndWaitForAppToExit();
}
IN_PROC_BROWSER_TEST_F(SocketApiTest, SocketTCPExtension) {
@@ -172,6 +173,7 @@ IN_PROC_BROWSER_TEST_F(SocketApiTest, SocketTCPExtension) {
base::StringPrintf("tcp:%s:%d", host_port_pair.host().c_str(), port));
EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
+ CloseShellWindowsAndWaitForAppToExit();
}
IN_PROC_BROWSER_TEST_F(SocketApiTest, SocketTCPServerExtension) {
@@ -184,9 +186,12 @@ IN_PROC_BROWSER_TEST_F(SocketApiTest, SocketTCPServerExtension) {
base::StringPrintf("tcp_server:%s:%d", kHostname.c_str(), kPort));
EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
+ CloseShellWindowsAndWaitForAppToExit();
}
IN_PROC_BROWSER_TEST_F(SocketApiTest, SocketTCPServerUnbindOnUnload) {
ASSERT_TRUE(RunExtensionTest("socket/unload")) << message_;
+ CloseShellWindowsAndWaitForAppToExit();
ASSERT_TRUE(RunExtensionTest("socket/unload")) << message_;
+ CloseShellWindowsAndWaitForAppToExit();
}
diff --git a/chrome/browser/extensions/api/sync_file_system/sync_file_system_apitest.cc b/chrome/browser/extensions/api/sync_file_system/sync_file_system_apitest.cc
index b5bc79c..35ee945 100644
--- a/chrome/browser/extensions/api/sync_file_system/sync_file_system_apitest.cc
+++ b/chrome/browser/extensions/api/sync_file_system/sync_file_system_apitest.cc
@@ -58,20 +58,18 @@ class SyncFileSystemApiTest : public ExtensionApiTest {
} // namespace
// TODO(calvinlo): Add Chrome OS support for syncable file system
-#if !defined(OS_CHROMEOS)
-
-// TODO(calvinlo): Add Chrome OS support for syncable file system
// (http://crbug.com/160693)
#if !defined(OS_CHROMEOS)
-// TODO(benwells): Re-enable this test.
+// TODO(calvinlo): Re-enable this test.
+// (http://crbug.com/162811)
IN_PROC_BROWSER_TEST_F(SyncFileSystemApiTest, DISABLED_DeleteFileSystem) {
ASSERT_TRUE(RunPlatformAppTest("sync_file_system/delete_file_system"))
<< message_;
}
IN_PROC_BROWSER_TEST_F(SyncFileSystemApiTest, GetUsageAndQuota) {
- ASSERT_TRUE(RunExtensionTest("sync_file_system/get_usage_and_quota"))
+ ASSERT_TRUE(RunPlatformAppTest("sync_file_system/get_usage_and_quota"))
<< message_;
}
@@ -89,7 +87,5 @@ IN_PROC_BROWSER_TEST_F(SyncFileSystemApiTest, WriteFileThenGetUsage) {
#endif // !defined(OS_CHROMEOS)
-#endif // !defined(OS_CHROMEOS)
-
} // namespace chrome
diff --git a/chrome/browser/extensions/api/system_indicator/system_indicator_apitest.cc b/chrome/browser/extensions/api/system_indicator/system_indicator_apitest.cc
index 446a576..3fb2a00 100644
--- a/chrome/browser/extensions/api/system_indicator/system_indicator_apitest.cc
+++ b/chrome/browser/extensions/api/system_indicator/system_indicator_apitest.cc
@@ -5,5 +5,5 @@
#include "chrome/browser/extensions/extension_apitest.h"
IN_PROC_BROWSER_TEST_F(ExtensionApiTest, SystemIndicator) {
- ASSERT_TRUE(RunExtensionTest("system_indicator/basics")) << message_;
+ ASSERT_TRUE(RunPlatformAppTest("system_indicator/basics")) << message_;
}
diff --git a/chrome/browser/extensions/api/system_info_cpu/system_info_cpu_apitest.cc b/chrome/browser/extensions/api/system_info_cpu/system_info_cpu_apitest.cc
index 21f4e17..3bc41d1 100644
--- a/chrome/browser/extensions/api/system_info_cpu/system_info_cpu_apitest.cc
+++ b/chrome/browser/extensions/api/system_info_cpu/system_info_cpu_apitest.cc
@@ -78,7 +78,7 @@ IN_PROC_BROWSER_TEST_F(SystemInfoCpuApiTest, Cpu) {
CpuInfoProvider* provider = new MockCpuInfoProviderImpl();
// The provider is owned by the single CpuInfoProvider instance.
CpuInfoProvider::InitializeForTesting(provider);
- ASSERT_TRUE(RunExtensionTest("systeminfo/cpu")) << message_;
+ ASSERT_TRUE(RunPlatformAppTest("systeminfo/cpu")) << message_;
}
} // namespace extensions
diff --git a/chrome/browser/extensions/api/system_info_memory/system_info_memory_apitest.cc b/chrome/browser/extensions/api/system_info_memory/system_info_memory_apitest.cc
index 4ffb578..dcf94ab 100644
--- a/chrome/browser/extensions/api/system_info_memory/system_info_memory_apitest.cc
+++ b/chrome/browser/extensions/api/system_info_memory/system_info_memory_apitest.cc
@@ -49,7 +49,7 @@ IN_PROC_BROWSER_TEST_F(SystemInfoMemoryApiTest, Memory) {
MemoryInfoProvider* provider = new MockMemoryInfoProviderImpl();
// The provider is owned by the single MemoryInfoProvider instance.
MemoryInfoProvider::InitializeForTesting(provider);
- ASSERT_TRUE(RunExtensionTest("systeminfo/memory")) << message_;
+ ASSERT_TRUE(RunPlatformAppTest("systeminfo/memory")) << message_;
}
} // namespace extensions
diff --git a/chrome/browser/extensions/api/usb/usb_apitest.cc b/chrome/browser/extensions/api/usb/usb_apitest.cc
index c7c382f..3729efa 100644
--- a/chrome/browser/extensions/api/usb/usb_apitest.cc
+++ b/chrome/browser/extensions/api/usb/usb_apitest.cc
@@ -81,7 +81,7 @@ class UsbApiTest : public ExtensionApiTest {
IN_PROC_BROWSER_TEST_F(UsbApiTest, DeviceHandling) {
EXPECT_CALL(*mock_device_, Close(_)).Times(1);
- ASSERT_TRUE(RunExtensionTest("usb/device_handling"));
+ ASSERT_TRUE(RunPlatformAppTest("usb/device_handling"));
}
IN_PROC_BROWSER_TEST_F(UsbApiTest, TransferEvent) {
@@ -99,14 +99,14 @@ IN_PROC_BROWSER_TEST_F(UsbApiTest, TransferEvent) {
IsochronousTransfer(UsbDevice::OUTBOUND, 3, _, 1, 1, 1, _, _))
.WillOnce(InvokeUsbTransferCallback<7>(USB_TRANSFER_COMPLETED));
EXPECT_CALL(*mock_device_, Close(_)).Times(AnyNumber());
- ASSERT_TRUE(RunExtensionTest("usb/transfer_event"));
+ ASSERT_TRUE(RunPlatformAppTest("usb/transfer_event"));
}
IN_PROC_BROWSER_TEST_F(UsbApiTest, ZeroLengthTransfer) {
EXPECT_CALL(*mock_device_, BulkTransfer(_, _, _, 0, _, _))
.WillOnce(InvokeUsbTransferCallback<5>(USB_TRANSFER_COMPLETED));
EXPECT_CALL(*mock_device_, Close(_)).Times(AnyNumber());
- ASSERT_TRUE(RunExtensionTest("usb/zero_length_transfer"));
+ ASSERT_TRUE(RunPlatformAppTest("usb/zero_length_transfer"));
}
IN_PROC_BROWSER_TEST_F(UsbApiTest, TransferFailure) {
@@ -115,5 +115,5 @@ IN_PROC_BROWSER_TEST_F(UsbApiTest, TransferFailure) {
.WillOnce(InvokeUsbTransferCallback<5>(USB_TRANSFER_ERROR))
.WillOnce(InvokeUsbTransferCallback<5>(USB_TRANSFER_TIMEOUT));
EXPECT_CALL(*mock_device_, Close(_)).Times(AnyNumber());
- ASSERT_TRUE(RunExtensionTest("usb/transfer_failure"));
+ ASSERT_TRUE(RunPlatformAppTest("usb/transfer_failure"));
}
diff --git a/chrome/browser/extensions/extension_apitest.cc b/chrome/browser/extensions/extension_apitest.cc
index 9ab6a72..c09e185 100644
--- a/chrome/browser/extensions/extension_apitest.cc
+++ b/chrome/browser/extensions/extension_apitest.cc
@@ -174,6 +174,13 @@ bool ExtensionApiTest::RunPageTest(const std::string& page_url,
}
bool ExtensionApiTest::RunPlatformAppTest(const char* extension_name) {
+ bool res = RunPlatformAppTestReturnImmediately(extension_name);
+ CloseShellWindowsAndWaitForAppToExit();
+ return res;
+}
+
+bool ExtensionApiTest::RunPlatformAppTestReturnImmediately(
+ const char* extension_name) {
return RunExtensionTestImpl(extension_name, "", kFlagLaunchPlatformApp);
}
diff --git a/chrome/browser/extensions/extension_apitest.h b/chrome/browser/extensions/extension_apitest.h
index 143f9fd..2c5343f 100644
--- a/chrome/browser/extensions/extension_apitest.h
+++ b/chrome/browser/extensions/extension_apitest.h
@@ -148,9 +148,15 @@ class ExtensionApiTest : public ExtensionBrowserTest {
bool RunPageTest(const std::string& page_url, int flags);
// Similar to RunExtensionTest, except used for running tests in platform app
- // shell windows.
+ // shell windows. After running the test will close all shell windows and wait
+ // for the background page to be unloaded.
bool RunPlatformAppTest(const char* extension_name);
+ // Similar to RunPlatformAppTest, except after running the test returns
+ // without closing shell windows or waiting for the background page to be
+ // unloaded.
+ bool RunPlatformAppTestReturnImmediately(const char* extension_name);
+
// Start the test server, and store details of its state. Those details
// will be available to javascript tests using chrome.test.getConfig().
bool StartTestServer();
diff --git a/chrome/browser/extensions/extension_browsertest.cc b/chrome/browser/extensions/extension_browsertest.cc
index 0933e74..c52a101 100644
--- a/chrome/browser/extensions/extension_browsertest.cc
+++ b/chrome/browser/extensions/extension_browsertest.cc
@@ -23,10 +23,12 @@
#include "chrome/browser/extensions/extension_install_prompt.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_system.h"
+#include "chrome/browser/extensions/shell_window_registry.h"
#include "chrome/browser/extensions/unpacked_installer.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_window.h"
+#include "chrome/browser/ui/extensions/shell_window.h"
#include "chrome/browser/ui/omnibox/location_bar.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/common/chrome_notification_types.h"
@@ -45,6 +47,7 @@
using extensions::Extension;
using extensions::ExtensionCreator;
using extensions::FeatureSwitch;
+using extensions::ShellWindowRegistry;
ExtensionBrowserTest::ExtensionBrowserTest()
: loaded_(false),
@@ -75,6 +78,10 @@ void ExtensionBrowserTest::SetUpCommandLine(CommandLine* command_line) {
"TestUser@gmail.com");
command_line->AppendSwitchASCII(switches::kLoginProfile, "user");
#endif
+
+ // Make event pages get suspended quicker.
+ command_line->AppendSwitchASCII(switches::kEventPageIdleTime, "1");
+ command_line->AppendSwitchASCII(switches::kEventPageUnloadingTime, "1");
}
const Extension* ExtensionBrowserTest::LoadExtensionWithFlags(
@@ -543,6 +550,39 @@ bool ExtensionBrowserTest::WaitForCrxInstallerDone() {
return crx_installers_done_observed_ == (before + 1);
}
+void ExtensionBrowserTest::CloseShellWindow(ShellWindow* window) {
+ content::WindowedNotificationObserver destroyed_observer(
+ content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
+ content::NotificationService::AllSources());
+ window->GetBaseWindow()->Close();
+ destroyed_observer.Wait();
+}
+
+void ExtensionBrowserTest::CloseShellWindowsAndWaitForAppToExit() {
+ ExtensionProcessManager* manager =
+ extensions::ExtensionSystem::Get(browser()->profile())->process_manager();
+ // If there are no background hosts active, the app must have already exited.
+ // This can happen if no windows were opened.
+ if (manager->background_hosts().empty())
+ return;
+
+ content::WindowedNotificationObserver destroyed_observer(
+ chrome::NOTIFICATION_EXTENSION_HOST_DESTROYED,
+ content::NotificationService::AllSources());
+
+ // Close all the windows.
+ ShellWindowRegistry* app_registry =
+ ShellWindowRegistry::Get(browser()->profile());
+ ShellWindowRegistry::const_iterator iter;
+ ShellWindowRegistry::ShellWindowSet shell_windows =
+ app_registry->shell_windows();
+ for (iter = shell_windows.begin(); iter != shell_windows.end(); ++iter)
+ CloseShellWindow(*iter);
+
+ // Now wait for the lazy background page of the platform app to be unloaded.
+ destroyed_observer.Wait();
+}
+
void ExtensionBrowserTest::OpenWindow(content::WebContents* contents,
const GURL& url,
bool newtab_process_should_equal_opener,
diff --git a/chrome/browser/extensions/extension_browsertest.h b/chrome/browser/extensions/extension_browsertest.h
index b1e82a0..7affc49 100644
--- a/chrome/browser/extensions/extension_browsertest.h
+++ b/chrome/browser/extensions/extension_browsertest.h
@@ -22,6 +22,7 @@
#include "content/public/browser/web_contents.h"
class ExtensionProcessManager;
+class ShellWindow;
// Base class for extension browser tests. Provides utilities for loading,
// unloading, and installing extensions.
@@ -169,6 +170,13 @@ class ExtensionBrowserTest : virtual public InProcessBrowserTest,
// Wait for the crx installer to be done. Returns true if it really is done.
bool WaitForCrxInstallerDone();
+ // Closes |window| and waits until it's gone.
+ void CloseShellWindow(ShellWindow* window);
+
+ // Close any Shell Windows and wait for the app's background page to be
+ // unloaded.
+ void CloseShellWindowsAndWaitForAppToExit();
+
// Simulates a page calling window.open on an URL and waits for the
// navigation.
void OpenWindow(content::WebContents* contents,
diff --git a/chrome/browser/extensions/extension_host.cc b/chrome/browser/extensions/extension_host.cc
index f46e888..f72319a 100644
--- a/chrome/browser/extensions/extension_host.cc
+++ b/chrome/browser/extensions/extension_host.cc
@@ -22,6 +22,7 @@
#include "chrome/browser/extensions/window_controller.h"
#include "chrome/browser/file_select_helper.h"
#include "chrome/browser/intents/web_intents_util.h"
+#include "chrome/browser/lifetime/application_lifetime.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/app_modal_dialogs/javascript_dialog_creator.h"
#include "chrome/browser/ui/browser.h"
@@ -137,6 +138,7 @@ ExtensionHost::ExtensionHost(const Extension* extension,
render_view_host_(NULL),
did_stop_loading_(false),
document_element_available_(false),
+ keeping_browser_process_alive_(false),
initial_url_(url),
ALLOW_THIS_IN_INITIALIZER_LIST(
extension_function_dispatcher_(profile_, this)),
@@ -169,6 +171,11 @@ ExtensionHost::~ExtensionHost() {
content::Source<Profile>(profile_),
content::Details<ExtensionHost>(this));
ProcessCreationQueue::GetInstance()->Remove(this);
+
+#if !defined(OS_ANDROID)
+ if (keeping_browser_process_alive_)
+ browser::EndKeepAlive();
+#endif
}
void ExtensionHost::CreateView(Browser* browser) {
@@ -460,6 +467,16 @@ void ExtensionHost::DidCloseJavaScriptDialog() {
pm->DecrementLazyKeepaliveCount(extension());
}
+void ExtensionHost::SetKeepsBrowserProcessAlive() {
+ if (keeping_browser_process_alive_)
+ return;
+
+#if !defined(OS_ANDROID)
+ keeping_browser_process_alive_ = true;
+ browser::StartKeepAlive();
+#endif
+}
+
WebContents* ExtensionHost::OpenURLFromTab(WebContents* source,
const OpenURLParams& params) {
// Whitelist the dispositions we will allow to be opened.
diff --git a/chrome/browser/extensions/extension_host.h b/chrome/browser/extensions/extension_host.h
index 9c0e247..0e5bdbc 100644
--- a/chrome/browser/extensions/extension_host.h
+++ b/chrome/browser/extensions/extension_host.h
@@ -129,6 +129,12 @@ class ExtensionHost : public content::WebContentsDelegate,
void WillRunJavaScriptDialog();
void DidCloseJavaScriptDialog();
+ // This is called on hosts which need to keep the browser process alive. This
+ // function will add a browser process keep-alive, if it hasn't already been
+ // added. Hosts which have had this called will remove the keep-alive when
+ // they are destroyed.
+ void SetKeepsBrowserProcessAlive();
+
// content::WebContentsObserver
virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
virtual void RenderViewCreated(
@@ -245,6 +251,9 @@ class ExtensionHost : public content::WebContentsDelegate,
// True if the main frame has finished parsing.
bool document_element_available_;
+ // If true, the browser process has had a keep-alive added for this host.
+ bool keeping_browser_process_alive_;
+
// The original URL of the page being hosted.
GURL initial_url_;
diff --git a/chrome/browser/extensions/platform_app_browsertest.cc b/chrome/browser/extensions/platform_app_browsertest.cc
index 84e8b4b..2d9016e 100644
--- a/chrome/browser/extensions/platform_app_browsertest.cc
+++ b/chrome/browser/extensions/platform_app_browsertest.cc
@@ -20,10 +20,12 @@
#include "chrome/browser/extensions/platform_app_browsertest_util.h"
#include "chrome/browser/extensions/platform_app_launcher.h"
#include "chrome/browser/extensions/shell_window_registry.h"
+#include "chrome/browser/lifetime/application_lifetime.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/tab_contents/render_view_context_menu.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_tabstrip.h"
+#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/constrained_window_tab_helper.h"
#include "chrome/browser/ui/extensions/application_launch.h"
#include "chrome/browser/ui/extensions/shell_window.h"
@@ -146,6 +148,8 @@ const char kTestFilePath[] = "platform_apps/launch_files/test.txt";
} // namespace
+// TODO(benwells): Break up this file into some sensible smaller files.
+
// Tests that CreateShellWindow doesn't crash if you close it straight away.
// LauncherPlatformAppBrowserTest relies on this behaviour, but is only run for
// ash, so we test that it works here.
@@ -153,6 +157,7 @@ IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, CreateAndCloseShellWindow) {
const Extension* extension = LoadAndLaunchPlatformApp("minimal");
ShellWindow* window = CreateShellWindow(extension);
CloseShellWindow(window);
+ CloseShellWindowsAndWaitForAppToExit();
}
// Tests that platform apps can be launched in incognito mode without crashing.
@@ -177,6 +182,16 @@ IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, MAYBE_LaunchAppIncognito) {
NEW_WINDOW));
ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
+ CloseShellWindowsAndWaitForAppToExit();
+}
+
+// Tests that the browser process is kept alive by the platform app's background
+// page.
+IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, AppEventPageKeepsBrowserAlive) {
+ LoadAndLaunchPlatformApp("minimal");
+ browser()->window()->Close();
+ ASSERT_TRUE(browser::WillKeepAlive());
+ CloseShellWindowsAndWaitForAppToExit();
}
// Tests that platform apps received the "launch" event when launched.
@@ -211,6 +226,7 @@ IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchReply) {
web_contents);
ASSERT_TRUE(handler.WaitUntilReply());
+ CloseShellWindowsAndWaitForAppToExit();
}
// Tests that platform apps cannot use certain disabled window properties, but
@@ -221,11 +237,8 @@ IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, DisabledWindowProperties) {
}
IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, EmptyContextMenu) {
- ExtensionTestMessageListener launched_listener("Launched", false);
LoadAndLaunchPlatformApp("minimal");
- ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
-
// The empty app doesn't add any context menu items, so its menu should
// only include the developer tools.
WebContents* web_contents = GetFirstShellWindowWebContents();
@@ -241,16 +254,12 @@ IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, EmptyContextMenu) {
ASSERT_TRUE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_RELOAD_PACKAGED_APP));
ASSERT_FALSE(menu->HasCommandWithId(IDC_BACK));
ASSERT_FALSE(menu->HasCommandWithId(IDC_SAVE_PAGE));
+ CloseShellWindowsAndWaitForAppToExit();
}
IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, AppWithContextMenu) {
- ExtensionTestMessageListener launched_listener("Launched", false);
LoadAndLaunchPlatformApp("context_menu");
- // Wait for the extension to tell us it's initialized its context menus and
- // launched a window.
- ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
-
// The context_menu app has two context menu items. These, along with a
// separator and the developer tools, is all that should be in the menu.
WebContents* web_contents = GetFirstShellWindowWebContents();
@@ -269,16 +278,12 @@ IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, AppWithContextMenu) {
ASSERT_FALSE(menu->HasCommandWithId(IDC_BACK));
ASSERT_FALSE(menu->HasCommandWithId(IDC_SAVE_PAGE));
ASSERT_FALSE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_UNDO));
+ CloseShellWindowsAndWaitForAppToExit();
}
IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, InstalledAppWithContextMenu) {
- ExtensionTestMessageListener launched_listener("Launched", false);
InstallAndLaunchPlatformApp("context_menu");
- // Wait for the extension to tell us it's initialized its context menus and
- // launched a window.
- ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
-
// The context_menu app has two context menu items. For an installed app
// these are all that should be in the menu.
WebContents* web_contents = GetFirstShellWindowWebContents();
@@ -297,16 +302,12 @@ IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, InstalledAppWithContextMenu) {
ASSERT_FALSE(menu->HasCommandWithId(IDC_BACK));
ASSERT_FALSE(menu->HasCommandWithId(IDC_SAVE_PAGE));
ASSERT_FALSE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_UNDO));
+ CloseShellWindowsAndWaitForAppToExit();
}
IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, AppWithContextMenuTextField) {
- ExtensionTestMessageListener launched_listener("Launched", false);
LoadAndLaunchPlatformApp("context_menu");
- // Wait for the extension to tell us it's initialized its context menus and
- // launched a window.
- ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
-
// The context_menu app has one context menu item. This, along with a
// separator and the developer tools, is all that should be in the menu.
WebContents* web_contents = GetFirstShellWindowWebContents();
@@ -326,16 +327,12 @@ IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, AppWithContextMenuTextField) {
ASSERT_TRUE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_COPY));
ASSERT_FALSE(menu->HasCommandWithId(IDC_BACK));
ASSERT_FALSE(menu->HasCommandWithId(IDC_SAVE_PAGE));
+ CloseShellWindowsAndWaitForAppToExit();
}
IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, AppWithContextMenuSelection) {
- ExtensionTestMessageListener launched_listener("Launched", false);
LoadAndLaunchPlatformApp("context_menu");
- // Wait for the extension to tell us it's initialized its context menus and
- // launched a window.
- ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
-
// The context_menu app has one context menu item. This, along with a
// separator and the developer tools, is all that should be in the menu.
WebContents* web_contents = GetFirstShellWindowWebContents();
@@ -355,16 +352,12 @@ IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, AppWithContextMenuSelection) {
ASSERT_TRUE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_COPY));
ASSERT_FALSE(menu->HasCommandWithId(IDC_BACK));
ASSERT_FALSE(menu->HasCommandWithId(IDC_SAVE_PAGE));
+ CloseShellWindowsAndWaitForAppToExit();
}
IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, AppWithContextMenuClicked) {
- ExtensionTestMessageListener launched_listener("Launched", false);
LoadAndLaunchPlatformApp("context_menu_click");
- // Wait for the extension to tell us it's initialized its context menus and
- // launched a window.
- ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
-
// Test that the menu item shows up
WebContents* web_contents = GetFirstShellWindowWebContents();
ASSERT_TRUE(web_contents);
@@ -382,13 +375,15 @@ IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, AppWithContextMenuClicked) {
menu->ExecuteCommand(IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST);
ASSERT_TRUE(onclicked_listener.WaitUntilSatisfied());
+ CloseShellWindowsAndWaitForAppToExit();
}
IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, DisallowNavigation) {
TabsAddedNotificationObserver observer(2);
ASSERT_TRUE(StartTestServer());
- ASSERT_TRUE(RunPlatformAppTest("platform_apps/navigation")) << message_;
+ ASSERT_TRUE(RunPlatformAppTestReturnImmediately("platform_apps/navigation"))
+ << message_;
observer.Wait();
ASSERT_EQ(2U, observer.tabs().size());
@@ -396,6 +391,8 @@ IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, DisallowNavigation) {
observer.tabs()[0]->GetURL().spec());
EXPECT_EQ("http://chromium.org/",
observer.tabs()[1]->GetURL().spec());
+ browser()->window()->Close();
+ CloseShellWindowsAndWaitForAppToExit();
}
IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, Iframes) {
@@ -465,9 +462,7 @@ IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, ExtensionWindowingApis) {
ASSERT_EQ(0U, GetShellWindowCount());
// Launch a platform app that shows a window.
- ExtensionTestMessageListener launched_listener("Launched", false);
LoadAndLaunchPlatformApp("minimal");
- ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
ASSERT_EQ(1U, GetShellWindowCount());
ShellWindowRegistry::ShellWindowSet shell_windows =
ShellWindowRegistry::Get(browser()->profile())->shell_windows();
@@ -484,13 +479,12 @@ IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, ExtensionWindowingApis) {
// to get a list of all the shell windows, so we can test this.
// Launch another platform app that also shows a window.
- ExtensionTestMessageListener launched_listener2("Launched", false);
LoadAndLaunchPlatformApp("context_menu");
- ASSERT_TRUE(launched_listener2.WaitUntilSatisfied());
// There are two total shell windows, but each app can only see its own.
ASSERT_EQ(2U, GetShellWindowCount());
// TODO(jeremya): as above, this requires more extension functions.
+ CloseShellWindowsAndWaitForAppToExit();
}
// ChromeOS does not support passing arguments on the command line, so the tests
@@ -535,6 +529,7 @@ IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchWithRelativeFile) {
message_ = catcher.message();
ASSERT_TRUE(0);
}
+ CloseShellWindowsAndWaitForAppToExit();
}
// Tests that no launch data is sent through if the file is of the wrong MIME
@@ -601,6 +596,8 @@ IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, OpenLink) {
LoadAndLaunchPlatformApp("open_link");
observer.Wait();
ASSERT_EQ(2, browser()->tab_count());
+ browser()->window()->Close();
+ CloseShellWindowsAndWaitForAppToExit();
}
IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, MutationEventsDisabled) {
@@ -672,6 +669,8 @@ IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest,
// Wait for javascript to verify that the second window got the updated
// coordinates, ignoring the default coordinates passed to the create method.
ASSERT_TRUE(done2_listener.WaitUntilSatisfied());
+
+ CloseShellWindowsAndWaitForAppToExit();
}
// Tests that a running app is recorded in the preferences as such.
@@ -703,6 +702,7 @@ IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, RunningAppsAreRecorded) {
AppRestoreServiceFactory::GetForProfile(browser()->profile())->
HandleStartup(true);
restart_listener.WaitUntilSatisfied();
+ CloseShellWindowsAndWaitForAppToExit();
}
namespace {
@@ -720,10 +720,8 @@ class PlatformAppDevToolsBrowserTest : public PlatformAppBrowserTest {
void PlatformAppDevToolsBrowserTest::RunTestWithDevTools(
const char* name, int test_flags) {
using content::DevToolsAgentHostRegistry;
- ExtensionTestMessageListener launched_listener("Launched", false);
const Extension* extension = LoadAndLaunchPlatformApp(name);
ASSERT_TRUE(extension);
- ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
ShellWindow* window = GetFirstShellWindow();
ASSERT_TRUE(window);
ASSERT_EQ(window->window_key().empty(), (test_flags & HAS_ID) == 0);
@@ -761,6 +759,7 @@ void PlatformAppDevToolsBrowserTest::RunTestWithDevTools(
ASSERT_TRUE(rvh);
ASSERT_TRUE(DevToolsAgentHostRegistry::HasDevToolsAgentHost(rvh));
}
+ CloseShellWindowsAndWaitForAppToExit();
}
} // namespace
@@ -802,14 +801,19 @@ IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, MAYBE_ConstrainedWindowRequest) {
ExtensionTestMessageListener listener("PermissionRequestDone", false);
constrained_window_tab_helper->CloseConstrainedWindows();
ASSERT_TRUE(listener.WaitUntilSatisfied());
+
+ CloseShellWindowsAndWaitForAppToExit();
}
// Tests that an app calling chrome.runtime.reload will reload the app and
// relaunch it if it was running.
IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, ReloadRelaunches) {
ExtensionTestMessageListener launched_listener("Launched", true);
- const Extension* extension = LoadAndLaunchPlatformApp("reload");
+ const Extension* extension = LoadPlatformApp("reload");
ASSERT_TRUE(extension);
+ application_launch::OpenApplication(application_launch::LaunchParams(
+ browser()->profile(), extension, extension_misc::LAUNCH_NONE,
+ NEW_WINDOW));
ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
ASSERT_TRUE(GetFirstShellWindow());
@@ -818,6 +822,7 @@ IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, ReloadRelaunches) {
launched_listener.Reply("reload");
ASSERT_TRUE(launched_listener2.WaitUntilSatisfied());
ASSERT_TRUE(GetFirstShellWindow());
+ CloseShellWindowsAndWaitForAppToExit();
}
namespace {
@@ -879,6 +884,8 @@ IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest,
NEW_WINDOW));
ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
+
+ CloseShellWindowsAndWaitForAppToExit();
}
// Component App Test 2 of 3: ensure an installed component app can be launched
@@ -921,6 +928,8 @@ IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest,
extension_prefs->pref_service()->RegisterStringPref(
pref_path.c_str(), std::string(), PrefServiceBase::UNSYNCABLE_PREF);
extension_prefs->pref_service()->Set(pref_path.c_str(), old_version);
+
+ CloseShellWindowsAndWaitForAppToExit();
}
// Component App Test 3 of 3: simulate a component extension upgrade that
@@ -944,6 +953,8 @@ IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, ComponentAppBackgroundPage) {
NEW_WINDOW));
ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
+
+ CloseShellWindowsAndWaitForAppToExit();
}
} // namespace extensions
diff --git a/chrome/browser/extensions/platform_app_browsertest_util.cc b/chrome/browser/extensions/platform_app_browsertest_util.cc
index 5b26f9b..2f42da2 100644
--- a/chrome/browser/extensions/platform_app_browsertest_util.cc
+++ b/chrome/browser/extensions/platform_app_browsertest_util.cc
@@ -8,10 +8,12 @@
#include "base/stringprintf.h"
#include "chrome/browser/extensions/api/tabs/tabs.h"
#include "chrome/browser/extensions/extension_function_test_utils.h"
+#include "chrome/browser/extensions/extension_test_message_listener.h"
#include "chrome/browser/extensions/shell_window_registry.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/extensions/application_launch.h"
#include "chrome/browser/ui/extensions/shell_window.h"
+#include "chrome/common/chrome_notification_types.h"
#include "chrome/common/chrome_switches.h"
#include "content/public/browser/notification_service.h"
#include "content/public/test/test_utils.h"
@@ -25,46 +27,49 @@ namespace extensions {
void PlatformAppBrowserTest::SetUpCommandLine(CommandLine* command_line) {
// Skips ExtensionApiTest::SetUpCommandLine.
ExtensionBrowserTest::SetUpCommandLine(command_line);
-
- // Make event pages get suspended quicker.
- command_line->AppendSwitchASCII(switches::kEventPageIdleTime, "1");
- command_line->AppendSwitchASCII(switches::kEventPageUnloadingTime, "1");
}
-const Extension* PlatformAppBrowserTest::LoadAndLaunchPlatformApp(
- const char* name) {
- content::WindowedNotificationObserver app_loaded_observer(
- content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
- content::NotificationService::AllSources());
-
+const Extension* PlatformAppBrowserTest::LoadPlatformApp(const char* name) {
const Extension* extension = LoadExtension(
test_data_dir_.AppendASCII("platform_apps").AppendASCII(name));
EXPECT_TRUE(extension);
+ return extension;
+}
+
+const Extension* PlatformAppBrowserTest::InstallPlatformApp(
+ const char* name) {
+ const Extension* extension = InstallExtension(
+ test_data_dir_.AppendASCII("platform_apps").AppendASCII(name), 1);
+ EXPECT_TRUE(extension);
+
+ return extension;
+}
+
+const Extension* PlatformAppBrowserTest::LoadAndLaunchPlatformApp(
+ const char* name) {
+ ExtensionTestMessageListener launched_listener("Launched", false);
+
+ const Extension* extension = LoadPlatformApp(name);
application_launch::OpenApplication(application_launch::LaunchParams(
browser()->profile(), extension, extension_misc::LAUNCH_NONE,
NEW_WINDOW));
- app_loaded_observer.Wait();
+ launched_listener.WaitUntilSatisfied();
return extension;
}
const Extension* PlatformAppBrowserTest::InstallAndLaunchPlatformApp(
const char* name) {
- content::WindowedNotificationObserver app_loaded_observer(
- content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
- content::NotificationService::AllSources());
-
- const Extension* extension = InstallExtension(
- test_data_dir_.AppendASCII("platform_apps").AppendASCII(name), 1);
- EXPECT_TRUE(extension);
+ ExtensionTestMessageListener launched_listener("Launched", false);
+ const Extension* extension = InstallPlatformApp(name);
application_launch::OpenApplication(application_launch::LaunchParams(
browser()->profile(), extension, extension_misc::LAUNCH_NONE,
NEW_WINDOW));
- app_loaded_observer.Wait();
+ launched_listener.WaitUntilSatisfied();
return extension;
}
@@ -83,9 +88,8 @@ ShellWindow* PlatformAppBrowserTest::GetFirstShellWindow() {
ShellWindowRegistry::const_iterator iter;
ShellWindowRegistry::ShellWindowSet shell_windows =
app_registry->shell_windows();
- for (iter = shell_windows.begin(); iter != shell_windows.end(); ++iter) {
+ for (iter = shell_windows.begin(); iter != shell_windows.end(); ++iter)
return *iter;
- }
return NULL;
}
@@ -143,12 +147,4 @@ ShellWindow* PlatformAppBrowserTest::CreateShellWindow(
browser()->profile(), extension, GURL(""), params);
}
-void PlatformAppBrowserTest::CloseShellWindow(ShellWindow* window) {
- content::WindowedNotificationObserver destroyed_observer(
- content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
- content::NotificationService::AllSources());
- window->GetBaseWindow()->Close();
- destroyed_observer.Wait();
-}
-
} // namespace extensions
diff --git a/chrome/browser/extensions/platform_app_browsertest_util.h b/chrome/browser/extensions/platform_app_browsertest_util.h
index 3d3a2a7..88c9258 100644
--- a/chrome/browser/extensions/platform_app_browsertest_util.h
+++ b/chrome/browser/extensions/platform_app_browsertest_util.h
@@ -19,11 +19,23 @@ class ShellWindow;
namespace extensions {
class Extension;
+// TODO(benwells): Clean up this test hierarchy.
+// - rename this to PlatformAppApiTest
+// - remove the existing PlatformAppApiTest
+// - Move the CloseWindow* functions from ExtensionBrowserTest to here
+// - Move the RunPlatformAppTest functions from ExtensionApiTest to here
+// - Make all platform app tests use this class.
class PlatformAppBrowserTest : public ExtensionApiTest {
public:
virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE;
protected:
+ // Loads the app named |name| out of the platform_apps subdirectory.
+ const Extension* LoadPlatformApp(const char* name);
+
+ // Installs the app named |name| out of the platform_apps subdirectory.
+ const Extension* InstallPlatformApp(const char* name);
+
// Runs the app named |name| out of the platform_apps subdirectory. Waits
// until it is launched.
const Extension* LoadAndLaunchPlatformApp(const char* name);
@@ -63,9 +75,6 @@ class PlatformAppBrowserTest : public ExtensionApiTest {
// Creates an empty shell window for |extension|.
ShellWindow* CreateShellWindow(const Extension* extension);
-
- // Closes |window| and waits until it's gone.
- void CloseShellWindow(ShellWindow* window);
};
}
diff --git a/chrome/browser/extensions/platform_app_service.cc b/chrome/browser/extensions/platform_app_service.cc
new file mode 100644
index 0000000..8874ed0
--- /dev/null
+++ b/chrome/browser/extensions/platform_app_service.cc
@@ -0,0 +1,45 @@
+// Copyright (c) 2012 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 "chrome/browser/extensions/platform_app_service.h"
+
+#include "chrome/browser/extensions/extension_host.h"
+#include "chrome/common/chrome_notification_types.h"
+#include "chrome/common/extensions/extension.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/notification_details.h"
+#include "content/public/browser/notification_service.h"
+#include "content/public/browser/notification_types.h"
+
+namespace extensions {
+
+PlatformAppService::PlatformAppService(Profile* profile) {
+#if !defined(OS_CHROMEOS)
+ registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_HOST_CREATED,
+ content::Source<content::BrowserContext>(profile));
+#endif
+}
+
+PlatformAppService::~PlatformAppService() {}
+
+void PlatformAppService::Observe(int type,
+ const content::NotificationSource& source,
+ const content::NotificationDetails& details) {
+ switch (type) {
+ case chrome::NOTIFICATION_EXTENSION_HOST_CREATED: {
+// This code causes problems at logout for ChromeOS, and is not necessary anyway
+// as the browser process lifetime is defined by the session.
+#if !defined(OS_CHROMEOS)
+ ExtensionHost* host = content::Details<ExtensionHost>(details).ptr();
+ if (host->extension()->is_platform_app())
+ host->SetKeepsBrowserProcessAlive();
+#endif
+ break;
+ }
+ default:
+ NOTREACHED();
+ }
+}
+
+} // namespace extensions
diff --git a/chrome/browser/extensions/platform_app_service.h b/chrome/browser/extensions/platform_app_service.h
new file mode 100644
index 0000000..28a578d
--- /dev/null
+++ b/chrome/browser/extensions/platform_app_service.h
@@ -0,0 +1,35 @@
+// Copyright (c) 2012 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 CHROME_BROWSER_EXTENSIONS_PLATFORM_APP_SERVICE_H_
+#define CHROME_BROWSER_EXTENSIONS_PLATFORM_APP_SERVICE_H_
+
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_keyed_service.h"
+#include "content/public/browser/notification_observer.h"
+#include "content/public/browser/notification_registrar.h"
+
+namespace extensions {
+
+// The PlatformAppService provides services for platform apps, such as
+// keeping the browser process alive while they are running.
+// TODO(benwells): Merge functionality of ShellWindowRegistry into this class.
+class PlatformAppService : public ProfileKeyedService,
+ public content::NotificationObserver {
+ public:
+ explicit PlatformAppService(Profile* profile);
+ virtual ~PlatformAppService();
+
+ private:
+ // content::NotificationObserver:
+ virtual void Observe(int type,
+ const content::NotificationSource& source,
+ const content::NotificationDetails& details) OVERRIDE;
+
+ content::NotificationRegistrar registrar_;
+};
+
+} // namespace extensions
+
+#endif // CHROME_BROWSER_EXTENSIONS_PLATFORM_APP_SERVICE_H_
diff --git a/chrome/browser/extensions/platform_app_service_factory.cc b/chrome/browser/extensions/platform_app_service_factory.cc
new file mode 100644
index 0000000..c4fa6d1
--- /dev/null
+++ b/chrome/browser/extensions/platform_app_service_factory.cc
@@ -0,0 +1,47 @@
+// Copyright (c) 2012 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 "chrome/browser/extensions/platform_app_service_factory.h"
+
+#include "chrome/browser/profiles/profile_dependency_manager.h"
+
+namespace extensions {
+
+// static
+PlatformAppService* PlatformAppServiceFactory::GetForProfile(
+ Profile* profile) {
+ return static_cast<PlatformAppService*>(
+ GetInstance()->GetServiceForProfile(profile, true));
+}
+
+PlatformAppServiceFactory* PlatformAppServiceFactory::GetInstance() {
+ return Singleton<PlatformAppServiceFactory>::get();
+}
+
+PlatformAppServiceFactory::PlatformAppServiceFactory()
+ : ProfileKeyedServiceFactory("PlatformAppService",
+ ProfileDependencyManager::GetInstance()) {
+}
+
+PlatformAppServiceFactory::~PlatformAppServiceFactory() {
+}
+
+ProfileKeyedService* PlatformAppServiceFactory::BuildServiceInstanceFor(
+ Profile* profile) const {
+ return new PlatformAppService(profile);
+}
+
+bool PlatformAppServiceFactory::ServiceHasOwnInstanceInIncognito() const {
+ return true;
+}
+
+bool PlatformAppServiceFactory::ServiceIsCreatedWithProfile() const {
+ return true;
+}
+
+bool PlatformAppServiceFactory::ServiceIsNULLWhileTesting() const {
+ return false;
+}
+
+} // namespace extensions
diff --git a/chrome/browser/extensions/platform_app_service_factory.h b/chrome/browser/extensions/platform_app_service_factory.h
new file mode 100644
index 0000000..82412e9
--- /dev/null
+++ b/chrome/browser/extensions/platform_app_service_factory.h
@@ -0,0 +1,36 @@
+// Copyright (c) 2012 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 CHROME_BROWSER_EXTENSIONS_PLATFORM_APP_SERVICE_FACTORY_H_
+#define CHROME_BROWSER_EXTENSIONS_PLATFORM_APP_SERVICE_FACTORY_H_
+
+#include "base/memory/singleton.h"
+#include "chrome/browser/extensions/platform_app_service.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_keyed_service_factory.h"
+
+namespace extensions {
+
+class PlatformAppServiceFactory : public ProfileKeyedServiceFactory {
+ public:
+ static PlatformAppService* GetForProfile(Profile* profile);
+
+ static PlatformAppServiceFactory* GetInstance();
+ private:
+ friend struct DefaultSingletonTraits<PlatformAppServiceFactory>;
+
+ PlatformAppServiceFactory();
+ virtual ~PlatformAppServiceFactory();
+
+ // ProfileKeyedServiceFactory
+ virtual ProfileKeyedService* BuildServiceInstanceFor(
+ Profile* profile) const OVERRIDE;
+ virtual bool ServiceHasOwnInstanceInIncognito() const OVERRIDE;
+ virtual bool ServiceIsCreatedWithProfile() const OVERRIDE;
+ virtual bool ServiceIsNULLWhileTesting() const OVERRIDE;
+};
+
+} // namespace extensions
+
+#endif // CHROME_BROWSER_EXTENSIONS_PLATFORM_APP_SERVICE_FACTORY_H_
diff --git a/chrome/browser/extensions/web_view_browsertest.cc b/chrome/browser/extensions/web_view_browsertest.cc
index 158fc3e..5c90088 100644
--- a/chrome/browser/extensions/web_view_browsertest.cc
+++ b/chrome/browser/extensions/web_view_browsertest.cc
@@ -282,6 +282,8 @@ IN_PROC_BROWSER_TEST_F(WebViewTest, CookieIsolation) {
named_partition_contents1,
&cookie_size, &cookie_value);
EXPECT_EQ("", cookie_value);
+
+ CloseShellWindowsAndWaitForAppToExit();
}
// This tests that in-memory storage partitions are reset on browser restart,
@@ -372,6 +374,8 @@ IN_PROC_BROWSER_TEST_F(WebViewTest, PRE_StoragePersistence) {
persistent_partition_contents3,
&cookie_size, &cookie_value);
EXPECT_EQ("persist2=true", cookie_value);
+
+ CloseShellWindowsAndWaitForAppToExit();
}
// This is the post-reset portion of the StoragePersistence test. See
@@ -433,6 +437,8 @@ IN_PROC_BROWSER_TEST_F(WebViewTest, StoragePersistence) {
persistent_partition_contents3,
&cookie_size, &cookie_value);
EXPECT_EQ("persist2=true", cookie_value);
+
+ CloseShellWindowsAndWaitForAppToExit();
}
// This tests DOM storage isolation for packaged apps with webview tags. It
@@ -521,6 +527,8 @@ IN_PROC_BROWSER_TEST_F(WebViewTest, DOMStorageIsolation) {
default_tag_contents1->GetRenderViewHost(), std::wstring(),
get_session_storage.c_str(), &output));
EXPECT_STREQ("badval", output.c_str());
+
+ CloseShellWindowsAndWaitForAppToExit();
}
// This tests IndexedDB isolation for packaged apps with webview tags. It loads
@@ -607,4 +615,6 @@ IN_PROC_BROWSER_TEST_F(WebViewTest, IndexedDBIsolation) {
ExecuteScriptWaitForTitle(chrome::GetWebContentsAt(browser(), 0),
script, "db not found");
ExecuteScriptWaitForTitle(default_tag_contents1, script, "db not found");
+
+ CloseShellWindowsAndWaitForAppToExit();
}
diff --git a/chrome/browser/profiles/profile_dependency_manager.cc b/chrome/browser/profiles/profile_dependency_manager.cc
index 282d5a8..9488ff6 100644
--- a/chrome/browser/profiles/profile_dependency_manager.cc
+++ b/chrome/browser/profiles/profile_dependency_manager.cc
@@ -23,6 +23,7 @@
#include "chrome/browser/extensions/api/tab_capture/tab_capture_registry_factory.h"
#include "chrome/browser/extensions/app_restore_service_factory.h"
#include "chrome/browser/extensions/extension_system_factory.h"
+#include "chrome/browser/extensions/platform_app_service_factory.h"
#include "chrome/browser/favicon/favicon_service_factory.h"
#include "chrome/browser/google/google_url_tracker_factory.h"
#include "chrome/browser/history/history_service_factory.h"
@@ -225,6 +226,7 @@ void ProfileDependencyManager::AssertFactoriesBuilt() {
extensions::CommandServiceFactory::GetInstance();
extensions::ExtensionSystemFactory::GetInstance();
extensions::IdleManagerFactory::GetInstance();
+ extensions::PlatformAppServiceFactory::GetInstance();
extensions::ProcessesAPIFactory::GetInstance();
extensions::SuggestedLinksRegistryFactory::GetInstance();
extensions::TabCaptureRegistryFactory::GetInstance();
diff --git a/chrome/browser/sync/test/integration/apps_helper.cc b/chrome/browser/sync/test/integration/apps_helper.cc
index fe9a379..77c83c9 100644
--- a/chrome/browser/sync/test/integration/apps_helper.cc
+++ b/chrome/browser/sync/test/integration/apps_helper.cc
@@ -6,11 +6,14 @@
#include "base/logging.h"
#include "base/string_number_conversions.h"
+#include "chrome/browser/extensions/extension_process_manager.h"
+#include "chrome/browser/extensions/extension_system.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sync/test/integration/sync_app_helper.h"
#include "chrome/browser/sync/test/integration/sync_datatype_helper.h"
#include "chrome/browser/sync/test/integration/sync_extension_helper.h"
#include "chrome/common/extensions/extension.h"
+#include "content/public/test/test_utils.h"
using sync_datatype_helper::test;
@@ -20,6 +23,19 @@ std::string CreateFakeAppName(int index) {
return "fakeapp" + base::IntToString(index);
}
+void WaitForPlatformAppsToUnloadForProfile(Profile* profile) {
+ // Note this will hang if there are extensions with persistent background
+ // pages loaded.
+ ExtensionProcessManager* pm =
+ extensions::ExtensionSystem::Get(profile)->process_manager();
+ while (!pm->background_hosts().empty()) {
+ content::WindowedNotificationObserver destroyed_observer(
+ chrome::NOTIFICATION_EXTENSION_HOST_DESTROYED,
+ content::NotificationService::AllSources());
+ destroyed_observer.Wait();
+ }
+}
+
} // namespace
namespace apps_helper {
@@ -126,4 +142,13 @@ void FixNTPOrdinalCollisions(Profile* profile) {
SyncAppHelper::GetInstance()->FixNTPOrdinalCollisions(profile);
}
+void WaitForPlatformAppsToUnload() {
+ // First run any pending tasks to allow any about to load background
+ // pages to load.
+ MessageLoop::current()->RunUntilIdle();
+ for (int i = 0; i < test()->num_clients(); ++i)
+ WaitForPlatformAppsToUnloadForProfile(test()->GetProfile(i));
+ WaitForPlatformAppsToUnloadForProfile(test()->verifier());
+}
+
} // namespace apps_helper
diff --git a/chrome/browser/sync/test/integration/apps_helper.h b/chrome/browser/sync/test/integration/apps_helper.h
index 70d3ec4..e54a430 100644
--- a/chrome/browser/sync/test/integration/apps_helper.h
+++ b/chrome/browser/sync/test/integration/apps_helper.h
@@ -84,6 +84,10 @@ void CopyNTPOrdinals(Profile* source, Profile* destination, int index);
// Fix any NTP icon collisions that are currently in |profile|.
void FixNTPOrdinalCollisions(Profile* profile);
+// Wait until there are no lazy background pages loaded.
+// This needs to be done before exiting tests which installed platform apps.
+void WaitForPlatformAppsToUnload();
+
} // namespace apps_helper
#endif // CHROME_BROWSER_SYNC_TEST_INTEGRATION_APPS_HELPER_H_
diff --git a/chrome/browser/sync/test/integration/single_client_apps_sync_test.cc b/chrome/browser/sync/test/integration/single_client_apps_sync_test.cc
index 320b4a2..d3139ca 100644
--- a/chrome/browser/sync/test/integration/single_client_apps_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_apps_sync_test.cc
@@ -3,13 +3,16 @@
// found in the LICENSE file.
#include "base/basictypes.h"
+#include "base/command_line.h"
#include "chrome/browser/sync/profile_sync_service_harness.h"
#include "chrome/browser/sync/test/integration/apps_helper.h"
#include "chrome/browser/sync/test/integration/sync_test.h"
+#include "chrome/common/chrome_switches.h"
using apps_helper::AllProfilesHaveSameAppsAsVerifier;
using apps_helper::InstallApp;
using apps_helper::InstallPlatformApp;
+using apps_helper::WaitForPlatformAppsToUnload;
class SingleClientAppsSyncTest : public SyncTest {
public:
@@ -17,6 +20,14 @@ class SingleClientAppsSyncTest : public SyncTest {
virtual ~SingleClientAppsSyncTest() {}
+ protected:
+ virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
+ SyncTest::SetUpCommandLine(command_line);
+ // Make event pages get suspended quicker.
+ command_line->AppendSwitchASCII(switches::kEventPageIdleTime, "1");
+ command_line->AppendSwitchASCII(switches::kEventPageUnloadingTime, "1");
+ }
+
private:
DISALLOW_COPY_AND_ASSIGN(SingleClientAppsSyncTest);
};
@@ -53,6 +64,8 @@ IN_PROC_BROWSER_TEST_F(SingleClientAppsSyncTest, StartWithSomePlatformApps) {
ASSERT_TRUE(SetupSync());
ASSERT_TRUE(AllProfilesHaveSameAppsAsVerifier());
+
+ WaitForPlatformAppsToUnload();
}
IN_PROC_BROWSER_TEST_F(SingleClientAppsSyncTest, InstallSomeLegacyApps) {
@@ -83,6 +96,8 @@ IN_PROC_BROWSER_TEST_F(SingleClientAppsSyncTest, InstallSomePlatformApps) {
"Waiting for app changes."));
ASSERT_TRUE(AllProfilesHaveSameAppsAsVerifier());
+
+ WaitForPlatformAppsToUnload();
}
IN_PROC_BROWSER_TEST_F(SingleClientAppsSyncTest, InstallSomeApps) {
@@ -106,4 +121,6 @@ IN_PROC_BROWSER_TEST_F(SingleClientAppsSyncTest, InstallSomeApps) {
"Waiting for app changes."));
ASSERT_TRUE(AllProfilesHaveSameAppsAsVerifier());
+
+ WaitForPlatformAppsToUnload();
}
diff --git a/chrome/browser/sync/test/integration/two_client_apps_sync_test.cc b/chrome/browser/sync/test/integration/two_client_apps_sync_test.cc
index 475759a..83b72ac 100644
--- a/chrome/browser/sync/test/integration/two_client_apps_sync_test.cc
+++ b/chrome/browser/sync/test/integration/two_client_apps_sync_test.cc
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "base/basictypes.h"
+#include "base/command_line.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_sorting.h"
#include "chrome/browser/profiles/profile.h"
@@ -10,6 +11,7 @@
#include "chrome/browser/sync/test/integration/apps_helper.h"
#include "chrome/browser/sync/test/integration/sync_app_helper.h"
#include "chrome/browser/sync/test/integration/sync_test.h"
+#include "chrome/common/chrome_switches.h"
#include "chrome/common/extensions/extension_constants.h"
#include "sync/api/string_ordinal.h"
@@ -28,6 +30,7 @@ using apps_helper::InstallPlatformApp;
using apps_helper::SetAppLaunchOrdinalForApp;
using apps_helper::SetPageOrdinalForApp;
using apps_helper::UninstallApp;
+using apps_helper::WaitForPlatformAppsToUnload;
class TwoClientAppsSyncTest : public SyncTest {
public:
@@ -35,6 +38,14 @@ class TwoClientAppsSyncTest : public SyncTest {
virtual ~TwoClientAppsSyncTest() {}
+ protected:
+ virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
+ SyncTest::SetUpCommandLine(command_line);
+ // Make event pages get suspended quicker.
+ command_line->AppendSwitchASCII(switches::kEventPageIdleTime, "1");
+ command_line->AppendSwitchASCII(switches::kEventPageUnloadingTime, "1");
+ }
+
private:
DISALLOW_COPY_AND_ASSIGN(TwoClientAppsSyncTest);
};
@@ -108,6 +119,8 @@ IN_PROC_BROWSER_TEST_F(TwoClientAppsSyncTest, StartWithDifferentApps) {
InstallAppsPendingForSync(GetProfile(1));
ASSERT_TRUE(AllProfilesHaveSameAppsAsVerifier());
+
+ WaitForPlatformAppsToUnload();
}
// Install some apps on both clients, then sync. Then install some apps on only
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_browsertest.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_browsertest.cc
index a9b8d26..c6c2a91 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_browsertest.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_browsertest.cc
@@ -127,7 +127,7 @@ class LauncherAppBrowserTest : public ExtensionBrowserTest {
IN_PROC_BROWSER_TEST_F(LauncherPlatformAppBrowserTest, LaunchUnpinned) {
ash::Launcher* launcher = ash::Launcher::ForPrimaryDisplay();
int item_count = launcher->model()->item_count();
- const Extension* extension = LoadAndLaunchPlatformApp("launch");
+ const Extension* extension = LoadPlatformApp("launch");
ShellWindow* window = CreateShellWindow(extension);
++item_count;
ASSERT_EQ(item_count, launcher->model()->item_count());
@@ -138,6 +138,7 @@ IN_PROC_BROWSER_TEST_F(LauncherPlatformAppBrowserTest, LaunchUnpinned) {
CloseShellWindow(window);
--item_count;
EXPECT_EQ(item_count, launcher->model()->item_count());
+ CloseShellWindowsAndWaitForAppToExit();
}
// Test that we can launch a platform app that already has a shortcut.
@@ -145,7 +146,7 @@ IN_PROC_BROWSER_TEST_F(LauncherPlatformAppBrowserTest, LaunchPinned) {
int item_count = launcher_->model()->item_count();
// First get app_id.
- const Extension* extension = LoadAndLaunchPlatformApp("launch");
+ const Extension* extension = LoadPlatformApp("launch");
const std::string app_id = extension->id();
// Then create a shortcut.
@@ -170,12 +171,13 @@ IN_PROC_BROWSER_TEST_F(LauncherPlatformAppBrowserTest, LaunchPinned) {
item = *launcher_->model()->ItemByID(shortcut_id);
EXPECT_EQ(ash::TYPE_APP_SHORTCUT, item.type);
EXPECT_EQ(ash::STATUS_CLOSED, item.status);
+ CloseShellWindowsAndWaitForAppToExit();
}
IN_PROC_BROWSER_TEST_F(LauncherPlatformAppBrowserTest, PinRunning) {
// Run.
int item_count = launcher_->model()->item_count();
- const Extension* extension = LoadAndLaunchPlatformApp("launch");
+ const Extension* extension = LoadPlatformApp("launch");
ShellWindow* window = CreateShellWindow(extension);
++item_count;
ASSERT_EQ(item_count, launcher_->model()->item_count());
@@ -209,13 +211,14 @@ IN_PROC_BROWSER_TEST_F(LauncherPlatformAppBrowserTest, PinRunning) {
// Then close it, make sure the item remains.
CloseShellWindow(window);
ASSERT_EQ(item_count, launcher_->model()->item_count());
+ CloseShellWindowsAndWaitForAppToExit();
}
IN_PROC_BROWSER_TEST_F(LauncherPlatformAppBrowserTest, UnpinRunning) {
int item_count = launcher_->model()->item_count();
// First get app_id.
- const Extension* extension = LoadAndLaunchPlatformApp("launch");
+ const Extension* extension = LoadPlatformApp("launch");
const std::string app_id = extension->id();
// Then create a shortcut.
@@ -256,6 +259,7 @@ IN_PROC_BROWSER_TEST_F(LauncherPlatformAppBrowserTest, UnpinRunning) {
CloseShellWindow(window);
--item_count;
ASSERT_EQ(item_count, launcher_->model()->item_count());
+ CloseShellWindowsAndWaitForAppToExit();
}
// Test that we can launch a platform app with more than one window.
@@ -263,7 +267,7 @@ IN_PROC_BROWSER_TEST_F(LauncherPlatformAppBrowserTest, MultipleWindows) {
int item_count = launcher_->model()->item_count();
// First run app.
- const Extension* extension = LoadAndLaunchPlatformApp("launch");
+ const Extension* extension = LoadPlatformApp("launch");
ShellWindow* window1 = CreateShellWindow(extension);
++item_count;
ASSERT_EQ(item_count, launcher_->model()->item_count());
@@ -292,6 +296,7 @@ IN_PROC_BROWSER_TEST_F(LauncherPlatformAppBrowserTest, MultipleWindows) {
// Confirm item is removed.
--item_count;
ASSERT_EQ(item_count, launcher_->model()->item_count());
+ CloseShellWindowsAndWaitForAppToExit();
}
// Times out on ChromeOS: http://crbug.com/159394
@@ -304,7 +309,7 @@ IN_PROC_BROWSER_TEST_F(LauncherPlatformAppBrowserTest, MAYBE_MultipleApps) {
int item_count = launcher_->model()->item_count();
// First run app.
- const Extension* extension1 = LoadAndLaunchPlatformApp("launch");
+ const Extension* extension1 = LoadPlatformApp("launch");
ShellWindow* window1 = CreateShellWindow(extension1);
++item_count;
ASSERT_EQ(item_count, launcher_->model()->item_count());
@@ -315,7 +320,7 @@ IN_PROC_BROWSER_TEST_F(LauncherPlatformAppBrowserTest, MAYBE_MultipleApps) {
EXPECT_EQ(ash::STATUS_ACTIVE, item1.status);
// Then run second app.
- const Extension* extension2 = LoadAndLaunchPlatformApp("launch_2");
+ const Extension* extension2 = LoadPlatformApp("launch_2");
ShellWindow* window2 = CreateShellWindow(extension2);
++item_count;
ASSERT_EQ(item_count, launcher_->model()->item_count());
@@ -341,7 +346,7 @@ IN_PROC_BROWSER_TEST_F(LauncherPlatformAppBrowserTest, MAYBE_MultipleApps) {
CloseShellWindow(window1);
--item_count;
ASSERT_EQ(item_count, launcher_->model()->item_count());
-
+ CloseShellWindowsAndWaitForAppToExit();
}
// Confirm that app windows can be reactivated by clicking their icons and that
@@ -356,7 +361,7 @@ IN_PROC_BROWSER_TEST_F(LauncherPlatformAppBrowserTest, MAYBE_WindowActivation) {
int item_count = launcher_->model()->item_count();
// First run app.
- const Extension* extension1 = LoadAndLaunchPlatformApp("launch");
+ const Extension* extension1 = LoadPlatformApp("launch");
ShellWindow* window1 = CreateShellWindow(extension1);
++item_count;
ASSERT_EQ(item_count, launcher_->model()->item_count());
@@ -367,7 +372,7 @@ IN_PROC_BROWSER_TEST_F(LauncherPlatformAppBrowserTest, MAYBE_WindowActivation) {
EXPECT_EQ(ash::STATUS_ACTIVE, item1.status);
// Then run second app.
- const Extension* extension2 = LoadAndLaunchPlatformApp("launch_2");
+ const Extension* extension2 = LoadPlatformApp("launch_2");
ShellWindow* window2 = CreateShellWindow(extension2);
++item_count;
ASSERT_EQ(item_count, launcher_->model()->item_count());
@@ -436,13 +441,14 @@ IN_PROC_BROWSER_TEST_F(LauncherPlatformAppBrowserTest, MAYBE_WindowActivation) {
CloseShellWindow(window1);
--item_count;
EXPECT_EQ(item_count, launcher_->model()->item_count());
+ CloseShellWindowsAndWaitForAppToExit();
}
IN_PROC_BROWSER_TEST_F(LauncherPlatformAppBrowserTest, BrowserActivation) {
int item_count = launcher_->model()->item_count();
// First run app.
- const Extension* extension1 = LoadAndLaunchPlatformApp("launch");
+ const Extension* extension1 = LoadPlatformApp("launch");
CreateShellWindow(extension1);
++item_count;
ASSERT_EQ(item_count, launcher_->model()->item_count());
@@ -455,6 +461,7 @@ IN_PROC_BROWSER_TEST_F(LauncherPlatformAppBrowserTest, BrowserActivation) {
ash::wm::ActivateWindow(browser()->window()->GetNativeWindow());
EXPECT_EQ(ash::STATUS_RUNNING,
launcher_->model()->ItemByID(item_id1)->status);
+ CloseShellWindowsAndWaitForAppToExit();
}
// Test that we can launch an app with a shortcut.
diff --git a/chrome/chrome_browser_extensions.gypi b/chrome/chrome_browser_extensions.gypi
index 2fc5943..4a62728 100644
--- a/chrome/chrome_browser_extensions.gypi
+++ b/chrome/chrome_browser_extensions.gypi
@@ -581,6 +581,10 @@
'browser/extensions/permissions_updater.h',
'browser/extensions/platform_app_launcher.cc',
'browser/extensions/platform_app_launcher.h',
+ 'browser/extensions/platform_app_service.cc',
+ 'browser/extensions/platform_app_service.h',
+ 'browser/extensions/platform_app_service_factory.cc',
+ 'browser/extensions/platform_app_service_factory.h',
'browser/extensions/process_map.cc',
'browser/extensions/process_map.h',
'browser/extensions/requirements_checker.cc',
diff --git a/chrome/test/data/extensions/api_test/media_galleries_private/attachdetach/test.js b/chrome/test/data/extensions/api_test/media_galleries_private/attachdetach/test.js
index 76d6a55..232a081 100644
--- a/chrome/test/data/extensions/api_test/media_galleries_private/attachdetach/test.js
+++ b/chrome/test/data/extensions/api_test/media_galleries_private/attachdetach/test.js
@@ -48,6 +48,6 @@ function removeAttachListener() {
}
function removeDummyDetachListener() {
- chrome.mediaGalleriesPrivate.onDeviceAttached.removeListener(testDummyDetach);
+ chrome.mediaGalleriesPrivate.onDeviceDetached.removeListener(testDummyDetach);
chrome.test.sendMessage('remove_dummy_detach_ok');
}
diff --git a/chrome/test/data/extensions/platform_apps/geometry/test.js b/chrome/test/data/extensions/platform_apps/geometry/test.js
index f2a24fa..d74c9fa 100644
--- a/chrome/test/data/extensions/platform_apps/geometry/test.js
+++ b/chrome/test/data/extensions/platform_apps/geometry/test.js
@@ -3,6 +3,8 @@
// found in the LICENSE file.
chrome.app.runtime.onLaunched.addListener(function() {
+ chrome.test.sendMessage('Launched');
+
var win1;
chrome.app.window.create('empty.html',
{ id: 'test',
diff --git a/chrome/test/data/extensions/platform_apps/open_link/main.js b/chrome/test/data/extensions/platform_apps/open_link/main.js
index ddd0c8a..adb7f0e 100644
--- a/chrome/test/data/extensions/platform_apps/open_link/main.js
+++ b/chrome/test/data/extensions/platform_apps/open_link/main.js
@@ -17,3 +17,5 @@ chrome.test.getConfig(function(config) {
onmessage = function() {
chrome.test.sendMessage('Link opened');
};
+
+chrome.test.sendMessage('Launched');
diff --git a/chrome/test/data/extensions/platform_apps/windows_api_bounds/background.js b/chrome/test/data/extensions/platform_apps/windows_api_bounds/background.js
index 2bac58b..aa37b96 100644
--- a/chrome/test/data/extensions/platform_apps/windows_api_bounds/background.js
+++ b/chrome/test/data/extensions/platform_apps/windows_api_bounds/background.js
@@ -3,6 +3,7 @@
// found in the LICENSE file.
chrome.app.runtime.onLaunched.addListener(function() {
+ chrome.test.sendMessage("Launched");
chrome.app.window.create("main.html", function(win){
// Make sure we get back a bounds and that it isn't all 0's.
var bounds = win.getBounds();