Implement app process model isolation.
The process grouping logic is unfortunately duplicated in SiteInstance and
RenderView. URLs that are part of extension X's web extent get converted into
a pseudo URL of the form chrome-extension://X/path. This groups pages from an
extension app and its offline resources into the same process.
The rest is mostly plumbing and passing data around.
BUG=41273
Review URL: http://codereview.chromium.org/1735004
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@45384 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/chrome/browser/extensions/app_process_apitest.cc b/chrome/browser/extensions/app_process_apitest.cc
new file mode 100644
index 0000000..ecf0c63
--- /dev/null
+++ b/chrome/browser/extensions/app_process_apitest.cc
@@ -0,0 +1,107 @@
+// Copyright (c) 2010 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/browser.h"
+#include "chrome/browser/extensions/extension_apitest.h"
+#include "chrome/browser/extensions/extension_host.h"
+#include "chrome/browser/extensions/extension_process_manager.h"
+#include "chrome/browser/profile.h"
+#include "chrome/browser/renderer_host/render_view_host.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/test/ui_test_utils.h"
+#include "net/base/mock_host_resolver.h"
+
+class AppApiTest : public ExtensionApiTest {
+ public:
+ void SetUpCommandLine(CommandLine* command_line) {
+ ExtensionApiTest::SetUpCommandLine(command_line);
+ command_line->AppendSwitch(switches::kEnableExtensionApps);
+ }
+};
+
+// Simulates a page calling window.open on an URL, and waits for the navigation.
+static void WindowOpenHelper(Browser* browser,
+ RenderViewHost* opener_host, const GURL& url) {
+ bool result = false;
+ ui_test_utils::ExecuteJavaScriptAndExtractBool(
+ opener_host, L"",
+ L"window.open('" + UTF8ToWide(url.spec()) + L"');"
+ L"window.domAutomationController.send(true);",
+ &result);
+ ASSERT_TRUE(result);
+
+ // Now the current tab should be the new tab.
+ TabContents* newtab = browser->GetSelectedTabContents();
+ if (!newtab->controller().GetLastCommittedEntry() ||
+ newtab->controller().GetLastCommittedEntry()->url() != url)
+ ui_test_utils::WaitForNavigation(&newtab->controller());
+ EXPECT_EQ(url, newtab->controller().GetLastCommittedEntry()->url());
+}
+
+// Simulates a page navigating itself to an URL, and waits for the navigation.
+static void NavigateTabHelper(TabContents* contents, const GURL& url) {
+ bool result = false;
+ ui_test_utils::ExecuteJavaScriptAndExtractBool(
+ contents->render_view_host(), L"",
+ L"window.location = '" + UTF8ToWide(url.spec()) + L"';"
+ L"window.domAutomationController.send(true);",
+ &result);
+ ASSERT_TRUE(result);
+
+ if (contents->controller().GetLastCommittedEntry() ||
+ contents->controller().GetLastCommittedEntry()->url() != url)
+ ui_test_utils::WaitForNavigation(&contents->controller());
+ EXPECT_EQ(url, contents->controller().GetLastCommittedEntry()->url());
+}
+
+IN_PROC_BROWSER_TEST_F(AppApiTest, AppProcess) {
+ host_resolver()->AddRule("*", "127.0.0.1");
+ StartHTTPServer();
+
+ ASSERT_TRUE(RunExtensionTest("app_process")) << message_;
+
+ Extension* extension = GetSingleLoadedExtension();
+ ExtensionHost* host = browser()->profile()->GetExtensionProcessManager()->
+ GetBackgroundHostForExtension(extension);
+ ASSERT_TRUE(host);
+
+ // The extension should have opened 3 new tabs. Including the original blank
+ // tab, we now have 4 tabs. Two should be part of the extension app, and
+ // grouped in the extension process.
+ ASSERT_EQ(4, browser()->tab_count());
+ EXPECT_EQ(host->render_process_host(),
+ browser()->GetTabContentsAt(1)->render_view_host()->process());
+ EXPECT_EQ(host->render_process_host(),
+ browser()->GetTabContentsAt(2)->render_view_host()->process());
+ EXPECT_NE(host->render_process_host(),
+ browser()->GetTabContentsAt(3)->render_view_host()->process());
+
+ // Now let's do the same using window.open. The same should happen.
+ WindowOpenHelper(browser(), host->render_view_host(),
+ browser()->GetTabContentsAt(1)->GetURL());
+ WindowOpenHelper(browser(), host->render_view_host(),
+ browser()->GetTabContentsAt(2)->GetURL());
+ WindowOpenHelper(browser(), host->render_view_host(),
+ browser()->GetTabContentsAt(3)->GetURL());
+
+ ASSERT_EQ(7, browser()->tab_count());
+ EXPECT_EQ(host->render_process_host(),
+ browser()->GetTabContentsAt(4)->render_view_host()->process());
+ EXPECT_EQ(host->render_process_host(),
+ browser()->GetTabContentsAt(5)->render_view_host()->process());
+ EXPECT_NE(host->render_process_host(),
+ browser()->GetTabContentsAt(6)->render_view_host()->process());
+
+ // Now let's have these pages navigate, into or out of the extension web
+ // extent. They should switch processes.
+ const GURL& app_url(browser()->GetTabContentsAt(1)->GetURL());
+ const GURL& non_app_url(browser()->GetTabContentsAt(3)->GetURL());
+ NavigateTabHelper(browser()->GetTabContentsAt(1), non_app_url);
+ NavigateTabHelper(browser()->GetTabContentsAt(3), app_url);
+ EXPECT_NE(host->render_process_host(),
+ browser()->GetTabContentsAt(1)->render_view_host()->process());
+ EXPECT_EQ(host->render_process_host(),
+ browser()->GetTabContentsAt(3)->render_view_host()->process());
+}