diff options
author | yoz@chromium.org <yoz@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-07-24 03:39:36 +0000 |
---|---|---|
committer | yoz@chromium.org <yoz@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-07-24 03:39:36 +0000 |
commit | 7685f64a35b6d029f7d11ce752dc126163d9474e (patch) | |
tree | 0cb10d4ed10d781bc6de27672bbcc8528134baab /extensions | |
parent | af97fe7d55c6310aacf1585bdbd8d38e3bc4c080 (diff) | |
download | chromium_src-7685f64a35b6d029f7d11ce752dc126163d9474e.zip chromium_src-7685f64a35b6d029f7d11ce752dc126163d9474e.tar.gz chromium_src-7685f64a35b6d029f7d11ce752dc126163d9474e.tar.bz2 |
Move apps/shell to extensions/shell.
This does:
- Move files
- Fix up all namespaces in these files to be extensions, not apps
- Clean up DEPS files
This does not:
- Change the name of the build targets (app_shell, app_shell_browsertests)
BUG=394987
TBR=ben@chromium.org
Review URL: https://codereview.chromium.org/412713002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@285144 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'extensions')
77 files changed, 4912 insertions, 2 deletions
diff --git a/extensions/DEPS b/extensions/DEPS index 4077a55..f544c73 100644 --- a/extensions/DEPS +++ b/extensions/DEPS @@ -1,6 +1,7 @@ include_rules = [ # Do not add Chrome dependencies. Much work went into removing them. "+components/url_matcher", + "-content", "+content/public/common", "+content/public/test", "+crypto", diff --git a/extensions/renderer/DEPS b/extensions/renderer/DEPS index 91bcd4b..ab21030 100644 --- a/extensions/renderer/DEPS +++ b/extensions/renderer/DEPS @@ -1,6 +1,4 @@ include_rules = [ - "-content", - "+content/public/common", "+content/public/renderer", "+gin", diff --git a/extensions/shell/DEPS b/extensions/shell/DEPS new file mode 100644 index 0000000..ffa7287 --- /dev/null +++ b/extensions/shell/DEPS @@ -0,0 +1,23 @@ +include_rules = [ + # The apps module has dependencies on chrome. + "-apps", + # Individual subdirectories should have their own DEPS that include + # their allowed directories. + "-extensions/shell", + "+extensions/shell/common", + "+extensions/shell/test", + + # Do not add dependencies on Chrome. Talk to OWNERS about how to refactor + # the code you need to a shared location. + "-chrome", + + # Only allow app_shell and extensions resources, not general Chrome ones. + "-grit", + "+grit/app_shell_resources.h", + "+grit/extensions_resources.h", + + # Real DEPS go in subdirectories, for example extensions/shell/browser/DEPS. + # Temporary exceptions for app_shell bring-up go here. + # TODO(jamescook): Remove these. http://crbug.com/305404 + "!chrome/browser/chrome_notification_types.h", +] diff --git a/extensions/shell/OWNERS b/extensions/shell/OWNERS new file mode 100644 index 0000000..00a9ff9 --- /dev/null +++ b/extensions/shell/OWNERS @@ -0,0 +1,3 @@ +derat@chromium.org +jamescook@chromium.org +yoz@chromium.org diff --git a/extensions/shell/README b/extensions/shell/README new file mode 100644 index 0000000..25a04d7 --- /dev/null +++ b/extensions/shell/README @@ -0,0 +1,13 @@ +# Introduction + +app_shell is an experimental project to build a minimal environment like +content_shell. + +The goal is to be able to run a v2 app and supply most of the chrome.* extension +APIs without running the rest of Chrome. + +app_shell is only officially supported on Chrome OS. + +# How to run + +app_shell --app=/path/to/extension diff --git a/extensions/shell/app/DEPS b/extensions/shell/app/DEPS new file mode 100644 index 0000000..b9b52a1 --- /dev/null +++ b/extensions/shell/app/DEPS @@ -0,0 +1,7 @@ +include_rules = [ + "+extensions/shell", + "+chromeos", + "+content/public/app", + "+content/public/browser", + "+sandbox", +] diff --git a/extensions/shell/app/README b/extensions/shell/app/README new file mode 100644 index 0000000..9dbba28 --- /dev/null +++ b/extensions/shell/app/README @@ -0,0 +1,5 @@ +"Application support" for the app_shell executable. + +This directory has nothing to do with the apps/extensions themselves. + +See content/shell/app for a similar example. diff --git a/extensions/shell/app/shell_main.cc b/extensions/shell/app/shell_main.cc new file mode 100644 index 0000000..a58ab82 --- /dev/null +++ b/extensions/shell/app/shell_main.cc @@ -0,0 +1,32 @@ +// Copyright 2014 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 "content/public/app/content_main.h" +#include "extensions/shell/app/shell_main_delegate.h" + +#if defined(OS_WIN) +#include "content/public/app/startup_helper_win.h" +#include "sandbox/win/src/sandbox_types.h" +#endif + +#if defined(OS_WIN) +int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE, wchar_t*, int) { +#else +int main(int argc, const char** argv) { +#endif + extensions::ShellMainDelegate delegate; + content::ContentMainParams params(&delegate); + +#if defined(OS_WIN) + sandbox::SandboxInterfaceInfo sandbox_info = {0}; + content::InitializeSandboxInfo(&sandbox_info); + params.instance = instance; + params.sandbox_info = &sandbox_info; +#else + params.argc = argc; + params.argv = argv; +#endif + + return content::ContentMain(params); +} diff --git a/extensions/shell/app/shell_main_delegate.cc b/extensions/shell/app/shell_main_delegate.cc new file mode 100644 index 0000000..b3b6ceb --- /dev/null +++ b/extensions/shell/app/shell_main_delegate.cc @@ -0,0 +1,109 @@ +// Copyright 2014 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 "extensions/shell/app/shell_main_delegate.h" + +#include "base/command_line.h" +#include "base/files/file_path.h" +#include "base/logging.h" +#include "base/path_service.h" +#include "content/public/browser/browser_main_runner.h" +#include "content/public/common/content_switches.h" +#include "extensions/common/extension_paths.h" +#include "extensions/shell/browser/default_shell_browser_main_delegate.h" +#include "extensions/shell/browser/shell_content_browser_client.h" +#include "extensions/shell/common/shell_content_client.h" +#include "extensions/shell/renderer/shell_content_renderer_client.h" +#include "extensions/shell/renderer/shell_renderer_main_delegate.h" +#include "ui/base/resource/resource_bundle.h" + +#if defined(OS_CHROMEOS) +#include "chromeos/chromeos_paths.h" +#endif + +namespace { + +void InitLogging() { + base::FilePath log_filename; + PathService::Get(base::DIR_EXE, &log_filename); + log_filename = log_filename.AppendASCII("app_shell.log"); + logging::LoggingSettings settings; + settings.logging_dest = logging::LOG_TO_ALL; + settings.log_file = log_filename.value().c_str(); + settings.delete_old = logging::DELETE_OLD_LOG_FILE; + logging::InitLogging(settings); + logging::SetLogItems(true, true, true, true); +} + +} // namespace + +namespace extensions { + +ShellMainDelegate::ShellMainDelegate() { +} + +ShellMainDelegate::~ShellMainDelegate() { +} + +bool ShellMainDelegate::BasicStartupComplete(int* exit_code) { + InitLogging(); + content_client_.reset(new ShellContentClient); + SetContentClient(content_client_.get()); + +#if defined(OS_CHROMEOS) + chromeos::RegisterPathProvider(); +#endif + extensions::RegisterPathProvider(); + return false; +} + +void ShellMainDelegate::PreSandboxStartup() { + std::string process_type = + CommandLine::ForCurrentProcess()->GetSwitchValueASCII( + switches::kProcessType); + if (ProcessNeedsResourceBundle(process_type)) + InitializeResourceBundle(); +} + +content::ContentBrowserClient* ShellMainDelegate::CreateContentBrowserClient() { + browser_client_.reset(CreateShellContentBrowserClient()); + return browser_client_.get(); +} + +content::ContentBrowserClient* +ShellMainDelegate::CreateShellContentBrowserClient() { + return new ShellContentBrowserClient(new DefaultShellBrowserMainDelegate()); +} + +content::ContentRendererClient* +ShellMainDelegate::CreateContentRendererClient() { + renderer_client_.reset( + new ShellContentRendererClient(CreateShellRendererMainDelegate())); + return renderer_client_.get(); +} + +scoped_ptr<ShellRendererMainDelegate> +ShellMainDelegate::CreateShellRendererMainDelegate() { + return scoped_ptr<ShellRendererMainDelegate>(); +} + +void ShellMainDelegate::InitializeResourceBundle() { + base::FilePath pak_dir; + PathService::Get(base::DIR_MODULE, &pak_dir); + ui::ResourceBundle::InitSharedInstanceWithPakPath( + pak_dir.AppendASCII("app_shell.pak")); +} + +// static +bool ShellMainDelegate::ProcessNeedsResourceBundle( + const std::string& process_type) { + // The browser process has no process type flag, but needs resources. + // On Linux the zygote process opens the resources for the renderers. + return process_type.empty() || + process_type == switches::kZygoteProcess || + process_type == switches::kRendererProcess || + process_type == switches::kUtilityProcess; +} + +} // namespace extensions diff --git a/extensions/shell/app/shell_main_delegate.h b/extensions/shell/app/shell_main_delegate.h new file mode 100644 index 0000000..7e120f4 --- /dev/null +++ b/extensions/shell/app/shell_main_delegate.h @@ -0,0 +1,60 @@ +// Copyright 2014 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 EXTENSIONS_SHELL_APP_SHELL_MAIN_DELEGATE_H_ +#define EXTENSIONS_SHELL_APP_SHELL_MAIN_DELEGATE_H_ + +#include "base/compiler_specific.h" +#include "base/memory/scoped_ptr.h" +#include "content/public/app/content_main_delegate.h" + +namespace content { +class BrowserContext; +class ContentBrowserClient; +class ContentClient; +class ContentRendererClient; +} + +namespace extensions { +class ShellBrowserMainDelegate; +class ShellRendererMainDelegate; + +class ShellMainDelegate : public content::ContentMainDelegate { + public: + ShellMainDelegate(); + virtual ~ShellMainDelegate(); + + // ContentMainDelegate implementation: + virtual bool BasicStartupComplete(int* exit_code) OVERRIDE; + virtual void PreSandboxStartup() OVERRIDE; + virtual content::ContentBrowserClient* CreateContentBrowserClient() OVERRIDE; + virtual content::ContentRendererClient* CreateContentRendererClient() + OVERRIDE; + + protected: + // The created object is owned by this object. + virtual content::ContentBrowserClient* CreateShellContentBrowserClient(); + + // The returned object is owned by ShellContentRendererClient. + virtual scoped_ptr<ShellRendererMainDelegate> + CreateShellRendererMainDelegate(); + + // Initializes the resource bundle and resources.pak. + virtual void InitializeResourceBundle(); + + private: + // |process_type| is zygote, renderer, utility, etc. Returns true if the + // process needs data from resources.pak. + static bool ProcessNeedsResourceBundle(const std::string& process_type); + + scoped_ptr<content::ContentClient> content_client_; + scoped_ptr<content::ContentBrowserClient> browser_client_; + scoped_ptr<content::ContentRendererClient> renderer_client_; + + DISALLOW_COPY_AND_ASSIGN(ShellMainDelegate); +}; + +} // namespace extensions + +#endif // EXTENSIONS_SHELL_APP_SHELL_MAIN_DELEGATE_H_ diff --git a/extensions/shell/app_shell.gyp b/extensions/shell/app_shell.gyp new file mode 100644 index 0000000..d95b385 --- /dev/null +++ b/extensions/shell/app_shell.gyp @@ -0,0 +1,223 @@ +# Copyright 2014 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. + +{ + 'variables': { + 'chromium_code': 1, + }, + 'targets': [ + { + 'target_name': 'app_shell_resources', + 'type': 'none', + 'actions': [ + { + 'action_name': 'generate_app_shell_resources', + 'variables': { + 'grit_grd_file': 'app_shell_resources.grd', + 'grit_out_dir': '<(SHARED_INTERMEDIATE_DIR)/extensions/shell', + }, + 'includes': [ '../../build/grit_action.gypi' ], + }, + ], + }, + { + 'target_name': 'app_shell_pak', + 'type': 'none', + 'dependencies': [ + 'app_shell_resources', + # Need extension related resources in common_resources.pak and + # renderer_resources_100_percent.pak + '<(DEPTH)/chrome/chrome_resources.gyp:chrome_resources', + # Need dev-tools related resources in shell_resources.pak and + # devtools_resources.pak. + '<(DEPTH)/content/content_shell_and_tests.gyp:content_shell_resources', + '<(DEPTH)/content/browser/devtools/devtools_resources.gyp:devtools_resources', + '<(DEPTH)/extensions/extensions_resources.gyp:extensions_resources', + '<(DEPTH)/extensions/extensions_strings.gyp:extensions_strings', + '<(DEPTH)/ui/resources/ui_resources.gyp:ui_resources', + '<(DEPTH)/ui/strings/ui_strings.gyp:ui_strings', + ], + 'actions': [ + { + 'action_name': 'repack_app_shell_pack', + 'variables': { + 'pak_inputs': [ + '<(SHARED_INTERMEDIATE_DIR)/chrome/common_resources.pak', + '<(SHARED_INTERMEDIATE_DIR)/chrome/extensions_api_resources.pak', + # TODO(jamescook): Extract the extension/app related resources + # from generated_resources_en-US.pak. + '<(SHARED_INTERMEDIATE_DIR)/chrome/generated_resources_en-US.pak', + '<(SHARED_INTERMEDIATE_DIR)/chrome/renderer_resources_100_percent.pak', + '<(SHARED_INTERMEDIATE_DIR)/content/shell_resources.pak', + '<(SHARED_INTERMEDIATE_DIR)/extensions/extensions_renderer_resources.pak', + '<(SHARED_INTERMEDIATE_DIR)/extensions/extensions_resources.pak', + '<(SHARED_INTERMEDIATE_DIR)/extensions/shell/app_shell_resources.pak', + '<(SHARED_INTERMEDIATE_DIR)/extensions/strings/extensions_strings_en-US.pak', + '<(SHARED_INTERMEDIATE_DIR)/ui/resources/ui_resources_100_percent.pak', + '<(SHARED_INTERMEDIATE_DIR)/ui/strings/app_locale_settings_en-US.pak', + '<(SHARED_INTERMEDIATE_DIR)/ui/strings/ui_strings_en-US.pak', + '<(SHARED_INTERMEDIATE_DIR)/webkit/devtools_resources.pak', + ], + 'pak_output': '<(PRODUCT_DIR)/app_shell.pak', + }, + 'includes': [ '../../build/repack_action.gypi' ], + }, + ], + }, + { + 'target_name': 'app_shell_lib', + 'type': 'static_library', + 'defines!': ['CONTENT_IMPLEMENTATION'], + 'dependencies': [ + 'app_shell_pak', + '<(DEPTH)/base/base.gyp:base', + '<(DEPTH)/base/base.gyp:base_prefs_test_support', + '<(DEPTH)/components/components.gyp:omaha_query_params', + '<(DEPTH)/components/components.gyp:pref_registry', + '<(DEPTH)/components/components.gyp:user_prefs', + '<(DEPTH)/content/content.gyp:content', + '<(DEPTH)/content/content.gyp:content_gpu', + '<(DEPTH)/content/content.gyp:content_ppapi_plugin', + '<(DEPTH)/content/content.gyp:content_worker', + '<(DEPTH)/content/content_shell_and_tests.gyp:content_shell_lib', + '<(DEPTH)/extensions/common/api/api.gyp:extensions_api', + '<(DEPTH)/extensions/extensions.gyp:extensions_browser', + '<(DEPTH)/extensions/extensions.gyp:extensions_common', + '<(DEPTH)/extensions/extensions.gyp:extensions_renderer', + '<(DEPTH)/extensions/extensions_resources.gyp:extensions_resources', + '<(DEPTH)/extensions/shell/common/api/api.gyp:shell_api', + '<(DEPTH)/mojo/mojo.gyp:mojo_environment_chromium', + '<(DEPTH)/mojo/mojo.gyp:mojo_system_impl', + '<(DEPTH)/skia/skia.gyp:skia', + '<(DEPTH)/third_party/WebKit/public/blink.gyp:blink', + '<(DEPTH)/ui/wm/wm.gyp:wm', + '<(DEPTH)/v8/tools/gyp/v8.gyp:v8', + ], + 'include_dirs': [ + '../..', + '<(SHARED_INTERMEDIATE_DIR)', + '<(SHARED_INTERMEDIATE_DIR)/extensions/shell', + ], + 'sources': [ + 'app/shell_main_delegate.cc', + 'app/shell_main_delegate.h', + 'browser/api/shell/shell_api.cc', + 'browser/api/shell/shell_api.h', + 'browser/default_shell_browser_main_delegate.cc', + 'browser/default_shell_browser_main_delegate.h', + 'browser/default_shell_app_window_controller.cc', + 'browser/default_shell_app_window_controller.h', + 'browser/shell_app_sorting.cc', + 'browser/shell_app_sorting.h', + 'browser/shell_app_window.cc', + 'browser/shell_app_window.h', + 'browser/shell_app_window_controller.h', + 'browser/shell_browser_context.cc', + 'browser/shell_browser_context.h', + 'browser/shell_browser_main_delegate.h', + 'browser/shell_browser_main_parts.cc', + 'browser/shell_browser_main_parts.h', + 'browser/shell_content_browser_client.cc', + 'browser/shell_content_browser_client.h', + 'browser/shell_desktop_controller.cc', + 'browser/shell_desktop_controller.h', + 'browser/shell_extension_system.cc', + 'browser/shell_extension_system.h', + 'browser/shell_extension_system_factory.cc', + 'browser/shell_extension_system_factory.h', + 'browser/shell_extension_web_contents_observer.cc', + 'browser/shell_extension_web_contents_observer.h', + 'browser/shell_extensions_browser_client.cc', + 'browser/shell_extensions_browser_client.h', + 'browser/shell_network_controller_chromeos.cc', + 'browser/shell_network_controller_chromeos.h', + 'browser/shell_omaha_query_params_delegate.cc', + 'browser/shell_omaha_query_params_delegate.h', + 'browser/shell_runtime_api_delegate.cc', + 'browser/shell_runtime_api_delegate.h', + 'browser/shell_special_storage_policy.cc', + 'browser/shell_special_storage_policy.h', + 'common/shell_content_client.cc', + 'common/shell_content_client.h', + 'common/shell_extensions_client.cc', + 'common/shell_extensions_client.h', + 'common/switches.h', + 'common/switches.cc', + 'renderer/shell_content_renderer_client.cc', + 'renderer/shell_content_renderer_client.h', + 'renderer/shell_custom_bindings.cc', + 'renderer/shell_custom_bindings.h', + 'renderer/shell_custom_bindings.js', + 'renderer/shell_dispatcher_delegate.cc', + 'renderer/shell_dispatcher_delegate.h', + 'renderer/shell_extensions_renderer_client.cc', + 'renderer/shell_extensions_renderer_client.h', + 'renderer/shell_renderer_main_delegate.h', + ], + 'conditions': [ + ['chromeos==1', { + 'dependencies': [ + '<(DEPTH)/chromeos/chromeos.gyp:chromeos', + '<(DEPTH)/ui/chromeos/ui_chromeos.gyp:ui_chromeos', + '<(DEPTH)/ui/display/display.gyp:display', + ], + }], + ], + }, + { + 'target_name': 'app_shell', + 'type': 'executable', + 'defines!': ['CONTENT_IMPLEMENTATION'], + 'dependencies': [ + 'app_shell_lib', + 'app_shell_pak', + ], + 'include_dirs': [ + '../..', + ], + 'sources': [ + 'app/shell_main.cc', + ], + 'conditions': [ + ['OS=="win"', { + 'msvs_settings': { + 'VCLinkerTool': { + 'SubSystem': '2', # Set /SUBSYSTEM:WINDOWS + }, + }, + 'dependencies': [ + '<(DEPTH)/sandbox/sandbox.gyp:sandbox', + ], + }], + ], + }, + { + 'target_name': 'app_shell_browsertests', + 'type': '<(gtest_target_type)', + 'dependencies': [ + 'app_shell_lib', + # TODO(yoz): find the right deps + '<(DEPTH)/base/base.gyp:test_support_base', + '<(DEPTH)/content/content.gyp:content_app_both', + '<(DEPTH)/content/content_shell_and_tests.gyp:content_browser_test_support', + '<(DEPTH)/content/content_shell_and_tests.gyp:test_support_content', + '<(DEPTH)/extensions/extensions.gyp:extensions_test_support', + '<(DEPTH)/testing/gtest.gyp:gtest', + ], + 'defines': [ + 'HAS_OUT_OF_PROC_TEST_RUNNER', + ], + 'sources': [ + # TODO(yoz): Refactor once we have a second test target. + 'browser/dns_apitest.cc', + 'browser/shell_browsertest.cc', + 'test/shell_test.h', + 'test/shell_test.cc', + 'test/shell_test_launcher_delegate.cc', + 'test/shell_test_launcher_delegate.h', + 'test/shell_tests_main.cc', + ], + }, + ], # targets +} diff --git a/extensions/shell/app_shell_resources.grd b/extensions/shell/app_shell_resources.grd new file mode 100644 index 0000000..236b488 --- /dev/null +++ b/extensions/shell/app_shell_resources.grd @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="UTF-8"?> +<grit latest_public_release="0" current_release="1"> + <outputs> + <output filename="grit/app_shell_resources.h" type="rc_header"> + <emit emit_type='prepend'></emit> + </output> + <output filename="app_shell_resources.pak" type="data_package" /> + </outputs> + <release seq="1"> + <includes> + <!-- Features specific to app_shell. --> + <include name="IDR_SHELL_EXTENSION_API_FEATURES" file="common\api\_api_features.json" type="BINDATA" /> + + <!-- Custom bindings for extension APIs. --> + <include name="IDR_SHELL_CUSTOM_BINDINGS_JS" file="renderer\shell_custom_bindings.js" type="BINDATA" /> + </includes> + </release> +</grit> diff --git a/extensions/shell/browser/DEPS b/extensions/shell/browser/DEPS new file mode 100644 index 0000000..edfa2580 --- /dev/null +++ b/extensions/shell/browser/DEPS @@ -0,0 +1,25 @@ +include_rules = [ + "+chromeos", + "+components/keyed_service", + "+components/omaha_query_params", + "+components/pref_registry", + "+components/user_prefs", + "+content/public/browser", + "+third_party/cros_system_api", + + # Pieces of content_shell reused in app_shell. + "+content/shell/browser/shell_browser_context.h", + "+content/shell/browser/shell_devtools_delegate.h", + "+content/shell/browser/shell_net_log.h", + + # Only used in API tests that should be moved to extensions/browser/api/... + "+net", + + "+sync/api", + + # Disallow views to keep the binary size down. + "-ui/views", + + "-webkit", + "+webkit/browser/quota", +] diff --git a/extensions/shell/browser/api/shell/shell_api.cc b/extensions/shell/browser/api/shell/shell_api.cc new file mode 100644 index 0000000..c022f16 --- /dev/null +++ b/extensions/shell/browser/api/shell/shell_api.cc @@ -0,0 +1,59 @@ +// Copyright 2014 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 "extensions/shell/browser/api/shell/shell_api.h" + +#include "base/memory/scoped_ptr.h" +#include "base/values.h" +#include "extensions/common/extension.h" +#include "extensions/shell/browser/shell_app_window.h" +#include "extensions/shell/browser/shell_desktop_controller.h" +#include "extensions/shell/common/api/shell.h" + +using base::DictionaryValue; + +namespace CreateWindow = extensions::shell_api::shell::CreateWindow; + +namespace extensions { + +namespace { + +const char kInvalidArguments[] = "Invalid arguments"; + +// Creates a function call result to send to the renderer. +DictionaryValue* CreateResult(ShellAppWindow* app_window) { + int view_id = app_window->GetRenderViewRoutingID(); + + DictionaryValue* result = new DictionaryValue; + result->Set("viewId", new base::FundamentalValue(view_id)); + return result; +} + +} // namespace + +ShellCreateWindowFunction::ShellCreateWindowFunction() { +} + +ShellCreateWindowFunction::~ShellCreateWindowFunction() { +} + +ExtensionFunction::ResponseAction ShellCreateWindowFunction::Run() { + scoped_ptr<CreateWindow::Params> params(CreateWindow::Params::Create(*args_)); + EXTENSION_FUNCTION_VALIDATE(params.get()); + + // Convert "main.html" to "chrome-extension:/<id>/main.html". + GURL url = GetExtension()->GetResourceURL(params->url); + if (!url.is_valid()) + return RespondNow(Error(kInvalidArguments)); + + // The desktop keeps ownership of the window. + ShellAppWindow* app_window = + ShellDesktopController::instance()->CreateAppWindow(browser_context()); + app_window->LoadURL(url); + + // Create the reply to send to the renderer. + return RespondNow(OneArgument(CreateResult(app_window))); +} + +} // namespace extensions diff --git a/extensions/shell/browser/api/shell/shell_api.h b/extensions/shell/browser/api/shell/shell_api.h new file mode 100644 index 0000000..fab9380 --- /dev/null +++ b/extensions/shell/browser/api/shell/shell_api.h @@ -0,0 +1,33 @@ +// Copyright 2014 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 EXTENSIONS_SHELL_BROWSER_API_SHELL_SHELL_API_H_ +#define EXTENSIONS_SHELL_BROWSER_API_SHELL_SHELL_API_H_ + +#include "base/compiler_specific.h" +#include "base/macros.h" +#include "extensions/browser/extension_function.h" +#include "extensions/browser/extension_function_histogram_value.h" + +namespace extensions { + +// Implementation of the chrome.shell.createWindow() function for app_shell. +// Opens a fullscreen window and invokes the window callback to allow access to +// the JS contentWindow. +class ShellCreateWindowFunction : public UIThreadExtensionFunction { + public: + ShellCreateWindowFunction(); + + DECLARE_EXTENSION_FUNCTION("shell.createWindow", SHELL_CREATEWINDOW); + + private: + virtual ~ShellCreateWindowFunction(); + virtual ResponseAction Run() OVERRIDE; + + DISALLOW_COPY_AND_ASSIGN(ShellCreateWindowFunction); +}; + +} // namespace extensions + +#endif // EXTENSIONS_SHELL_BROWSER_API_SHELL_SHELL_API_H_ diff --git a/extensions/shell/browser/default_shell_app_window_controller.cc b/extensions/shell/browser/default_shell_app_window_controller.cc new file mode 100644 index 0000000..778bc09 --- /dev/null +++ b/extensions/shell/browser/default_shell_app_window_controller.cc @@ -0,0 +1,45 @@ +// Copyright 2014 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 "extensions/shell/browser/default_shell_app_window_controller.h" + +#include "base/logging.h" +#include "extensions/shell/browser/shell_app_window.h" +#include "extensions/shell/browser/shell_desktop_controller.h" +#include "ui/aura/window.h" +#include "ui/aura/window_tree_host.h" + +namespace extensions { + +DefaultShellAppWindowController::DefaultShellAppWindowController( + ShellDesktopController* shell_desktop_controller) + : shell_desktop_controller_(shell_desktop_controller) { + DCHECK(shell_desktop_controller_); +} + +DefaultShellAppWindowController::~DefaultShellAppWindowController() { + // The app window must be explicitly closed before desktop teardown. + DCHECK(!app_window_); +} + +ShellAppWindow* DefaultShellAppWindowController::CreateAppWindow( + content::BrowserContext* context) { + aura::Window* root_window = shell_desktop_controller_->host()->window(); + + app_window_.reset(new ShellAppWindow); + app_window_->Init(context, root_window->bounds().size()); + + // Attach the web contents view to our window hierarchy. + aura::Window* content = app_window_->GetNativeWindow(); + root_window->AddChild(content); + content->Show(); + + return app_window_.get(); +} + +void DefaultShellAppWindowController::CloseAppWindows() { + app_window_.reset(); +} + +} // namespace extensions diff --git a/extensions/shell/browser/default_shell_app_window_controller.h b/extensions/shell/browser/default_shell_app_window_controller.h new file mode 100644 index 0000000..558022c2c --- /dev/null +++ b/extensions/shell/browser/default_shell_app_window_controller.h @@ -0,0 +1,40 @@ +// Copyright 2014 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 EXTENSIONS_SHELL_BROWSER_DEFAULT_SHELL_APP_WINDOW_CONTROLLER_H_ +#define EXTENSIONS_SHELL_BROWSER_DEFAULT_SHELL_APP_WINDOW_CONTROLLER_H_ + +#include "extensions/shell/browser/shell_app_window_controller.h" +#include "base/macros.h" +#include "base/memory/scoped_ptr.h" + +namespace extensions { + +class ShellDesktopController; + +// The default shell app window controller for app_shell. It manages only one +// app_window. +class DefaultShellAppWindowController : public ShellAppWindowController { + public: + explicit DefaultShellAppWindowController( + ShellDesktopController* shell_desktop_controller); + virtual ~DefaultShellAppWindowController(); + + // ShellAppWindowController implementation. + virtual ShellAppWindow* CreateAppWindow( + content::BrowserContext* context) OVERRIDE; + virtual void CloseAppWindows() OVERRIDE; + + private: + ShellDesktopController* shell_desktop_controller_; // Not owned + + // The desktop supports a single app window. + scoped_ptr<ShellAppWindow> app_window_; + + DISALLOW_COPY_AND_ASSIGN(DefaultShellAppWindowController); +}; + +} // namespace extensions + +#endif // EXTENSIONS_SHELL_BROWSER_DEFAULT_SHELL_APP_WINDOW_CONTROLLER_H_ diff --git a/extensions/shell/browser/default_shell_browser_main_delegate.cc b/extensions/shell/browser/default_shell_browser_main_delegate.cc new file mode 100644 index 0000000..5fb2cf1 --- /dev/null +++ b/extensions/shell/browser/default_shell_browser_main_delegate.cc @@ -0,0 +1,52 @@ +// Copyright 2014 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 "extensions/shell/browser/default_shell_browser_main_delegate.h" + +#include "base/command_line.h" +#include "base/file_util.h" +#include "base/files/file_path.h" +#include "extensions/shell/browser/default_shell_app_window_controller.h" +#include "extensions/shell/browser/shell_desktop_controller.h" +#include "extensions/shell/browser/shell_extension_system.h" +#include "extensions/shell/common/switches.h" + +namespace extensions { + +DefaultShellBrowserMainDelegate::DefaultShellBrowserMainDelegate() { +} + +DefaultShellBrowserMainDelegate::~DefaultShellBrowserMainDelegate() { +} + +void DefaultShellBrowserMainDelegate::Start( + content::BrowserContext* browser_context) { + base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); + if (command_line->HasSwitch(switches::kAppShellAppPath)) { + base::FilePath app_dir( + command_line->GetSwitchValueNative(switches::kAppShellAppPath)); + base::FilePath app_absolute_dir = base::MakeAbsoluteFilePath(app_dir); + + ShellExtensionSystem* extension_system = static_cast<ShellExtensionSystem*>( + ExtensionSystem::Get(browser_context)); + if (!extension_system->LoadApp(app_absolute_dir)) + return; + extension_system->LaunchApp(); + } else { + LOG(ERROR) << "--" << switches::kAppShellAppPath + << " unset; boredom is in your future"; + } +} + +void DefaultShellBrowserMainDelegate::Shutdown() { +} + +ShellDesktopController* +DefaultShellBrowserMainDelegate::CreateDesktopController() { + ShellDesktopController* desktop = new ShellDesktopController(); + desktop->SetAppWindowController(new DefaultShellAppWindowController(desktop)); + return desktop; +} + +} // namespace extensions diff --git a/extensions/shell/browser/default_shell_browser_main_delegate.h b/extensions/shell/browser/default_shell_browser_main_delegate.h new file mode 100644 index 0000000..a59c2e4 --- /dev/null +++ b/extensions/shell/browser/default_shell_browser_main_delegate.h @@ -0,0 +1,32 @@ +// Copyright 2014 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 EXTENSIONS_SHELL_BROWSER_DEFAULT_SHELL_BROWSER_MAIN_DELEGATE_H_ +#define EXTENSIONS_SHELL_BROWSER_DEFAULT_SHELL_BROWSER_MAIN_DELEGATE_H_ + +#include "base/compiler_specific.h" +#include "base/macros.h" +#include "extensions/shell/browser/shell_browser_main_delegate.h" + +namespace extensions { + +// A ShellBrowserMainDelegate that starts an application specified +// by the "--app" command line. This is used only in the browser process. +class DefaultShellBrowserMainDelegate : public ShellBrowserMainDelegate { + public: + DefaultShellBrowserMainDelegate(); + virtual ~DefaultShellBrowserMainDelegate(); + + // ShellBrowserMainDelegate: + virtual void Start(content::BrowserContext* context) OVERRIDE; + virtual void Shutdown() OVERRIDE; + virtual ShellDesktopController* CreateDesktopController() OVERRIDE; + + private: + DISALLOW_COPY_AND_ASSIGN(DefaultShellBrowserMainDelegate); +}; + +} // namespace extensions + +#endif // DEFAULT_SHELL_BROWSER_MAIN_DELEGATE_H_ diff --git a/extensions/shell/browser/dns_apitest.cc b/extensions/shell/browser/dns_apitest.cc new file mode 100644 index 0000000..fa2ec2f --- /dev/null +++ b/extensions/shell/browser/dns_apitest.cc @@ -0,0 +1,128 @@ +// Copyright 2014 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 "base/macros.h" +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "base/values.h" +#include "extensions/browser/api/dns/dns_api.h" +#include "extensions/browser/api/dns/host_resolver_wrapper.h" +#include "extensions/browser/api/dns/mock_host_resolver_creator.h" +#include "extensions/browser/api_test_utils.h" +#include "extensions/browser/extension_function_dispatcher.h" +#include "extensions/common/extension.h" +#include "extensions/common/extension_builder.h" +#include "extensions/shell/test/shell_test.h" +#include "net/base/net_errors.h" + +using extensions::api_test_utils::RunFunctionAndReturnSingleResult; + +namespace extensions { + +namespace { + +class TestFunctionDispatcherDelegate + : public ExtensionFunctionDispatcher::Delegate { + public: + TestFunctionDispatcherDelegate() {} + virtual ~TestFunctionDispatcherDelegate() {} + + // NULL implementation. + private: + DISALLOW_COPY_AND_ASSIGN(TestFunctionDispatcherDelegate); +}; + +} // namespace + +class DnsApiTest : public AppShellTest { + public: + DnsApiTest() : resolver_creator_(new MockHostResolverCreator()) {} + + private: + virtual void SetUpOnMainThread() OVERRIDE { + AppShellTest::SetUpOnMainThread(); + HostResolverWrapper::GetInstance()->SetHostResolverForTesting( + resolver_creator_->CreateMockHostResolver()); + } + + virtual void TearDownOnMainThread() OVERRIDE { + HostResolverWrapper::GetInstance()->SetHostResolverForTesting(NULL); + resolver_creator_->DeleteMockHostResolver(); + AppShellTest::TearDownOnMainThread(); + } + + // The MockHostResolver asserts that it's used on the same thread on which + // it's created, which is actually a stronger rule than its real counterpart. + // But that's fine; it's good practice. + scoped_refptr<MockHostResolverCreator> resolver_creator_; +}; + +IN_PROC_BROWSER_TEST_F(DnsApiTest, DnsResolveIPLiteral) { + scoped_refptr<DnsResolveFunction> resolve_function(new DnsResolveFunction()); + scoped_refptr<Extension> empty_extension( + ExtensionBuilder() + .SetManifest( + DictionaryBuilder().Set("name", "Test").Set("version", "1.0")) + .Build()); + + resolve_function->set_extension(empty_extension.get()); + resolve_function->set_has_callback(true); + + TestFunctionDispatcherDelegate delegate; + scoped_ptr<ExtensionFunctionDispatcher> dispatcher( + new ExtensionFunctionDispatcher(browser_context(), &delegate)); + + scoped_ptr<base::Value> result( + RunFunctionAndReturnSingleResult(resolve_function.get(), + "[\"127.0.0.1\"]", + browser_context(), + dispatcher.Pass())); + base::DictionaryValue* dict = NULL; + ASSERT_TRUE(result->GetAsDictionary(&dict)); + + int result_code = 0; + EXPECT_TRUE(dict->GetInteger("resultCode", &result_code)); + EXPECT_EQ(net::OK, result_code); + + std::string address; + EXPECT_TRUE(dict->GetString("address", &address)); + EXPECT_EQ("127.0.0.1", address); +} + +IN_PROC_BROWSER_TEST_F(DnsApiTest, DnsResolveHostname) { + scoped_refptr<DnsResolveFunction> resolve_function(new DnsResolveFunction()); + scoped_refptr<Extension> empty_extension( + ExtensionBuilder() + .SetManifest( + DictionaryBuilder().Set("name", "Test").Set("version", "1.0")) + .Build()); + + resolve_function->set_extension(empty_extension.get()); + resolve_function->set_has_callback(true); + + TestFunctionDispatcherDelegate delegate; + scoped_ptr<ExtensionFunctionDispatcher> dispatcher( + new ExtensionFunctionDispatcher(browser_context(), &delegate)); + + std::string function_arguments("[\""); + function_arguments += MockHostResolverCreator::kHostname; + function_arguments += "\"]"; + scoped_ptr<base::Value> result( + RunFunctionAndReturnSingleResult(resolve_function.get(), + function_arguments, + browser_context(), + dispatcher.Pass())); + base::DictionaryValue* dict = NULL; + ASSERT_TRUE(result->GetAsDictionary(&dict)); + + int result_code = 0; + EXPECT_TRUE(dict->GetInteger("resultCode", &result_code)); + EXPECT_EQ(net::OK, result_code); + + std::string address; + EXPECT_TRUE(dict->GetString("address", &address)); + EXPECT_EQ(MockHostResolverCreator::kAddress, address); +} + +} // namespace extensions diff --git a/extensions/shell/browser/shell_app_sorting.cc b/extensions/shell/browser/shell_app_sorting.cc new file mode 100644 index 0000000..146de59 --- /dev/null +++ b/extensions/shell/browser/shell_app_sorting.cc @@ -0,0 +1,105 @@ +// Copyright 2014 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 "extensions/shell/browser/shell_app_sorting.h" + +#include "sync/api/string_ordinal.h" + +namespace { + +// Ordinals for a single app on a single page. +const char kFirstApp[] = "a"; +const char kNextApp[] = "b"; +const char kFirstPage[] = "a"; + +} // namespace + +namespace extensions { + +ShellAppSorting::ShellAppSorting() { +} + +ShellAppSorting::~ShellAppSorting() { +} + +void ShellAppSorting::SetExtensionScopedPrefs(ExtensionScopedPrefs* prefs) { +} + +void ShellAppSorting::SetExtensionSyncService( + ExtensionSyncService* extension_sync_service) { +} + +void ShellAppSorting::Initialize(const ExtensionIdList& extension_ids) { +} + +void ShellAppSorting::FixNTPOrdinalCollisions() { +} + +void ShellAppSorting::EnsureValidOrdinals( + const std::string& extension_id, + const syncer::StringOrdinal& suggested_page) { +} + +void ShellAppSorting::OnExtensionMoved( + const std::string& moved_extension_id, + const std::string& predecessor_extension_id, + const std::string& successor_extension_id) { +} + +syncer::StringOrdinal ShellAppSorting::GetAppLaunchOrdinal( + const std::string& extension_id) const { + return syncer::StringOrdinal(kFirstApp); +} + +void ShellAppSorting::SetAppLaunchOrdinal( + const std::string& extension_id, + const syncer::StringOrdinal& new_app_launch_ordinal) { +} + +syncer::StringOrdinal ShellAppSorting::CreateFirstAppLaunchOrdinal( + const syncer::StringOrdinal& page_ordinal) const { + return syncer::StringOrdinal(kFirstApp); +} + +syncer::StringOrdinal ShellAppSorting::CreateNextAppLaunchOrdinal( + const syncer::StringOrdinal& page_ordinal) const { + return syncer::StringOrdinal(kNextApp); +} + +syncer::StringOrdinal ShellAppSorting::CreateFirstAppPageOrdinal() const { + return syncer::StringOrdinal(kFirstPage); +} + +syncer::StringOrdinal ShellAppSorting::GetNaturalAppPageOrdinal() const { + return syncer::StringOrdinal(kFirstPage); +} + +syncer::StringOrdinal ShellAppSorting::GetPageOrdinal( + const std::string& extension_id) const { + return syncer::StringOrdinal(kFirstPage); +} + +void ShellAppSorting::SetPageOrdinal( + const std::string& extension_id, + const syncer::StringOrdinal& new_page_ordinal) { +} + +void ShellAppSorting::ClearOrdinals(const std::string& extension_id) { +} + +int ShellAppSorting::PageStringOrdinalAsInteger( + const syncer::StringOrdinal& page_ordinal) const { + return 0; +} + +syncer::StringOrdinal ShellAppSorting::PageIntegerAsStringOrdinal( + size_t page_index) { + return syncer::StringOrdinal(kFirstPage); +} + +void ShellAppSorting::SetExtensionVisible(const std::string& extension_id, + bool visible) { +} + +} // namespace extensions diff --git a/extensions/shell/browser/shell_app_sorting.h b/extensions/shell/browser/shell_app_sorting.h new file mode 100644 index 0000000..b0dac33 --- /dev/null +++ b/extensions/shell/browser/shell_app_sorting.h @@ -0,0 +1,63 @@ +// Copyright 2014 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 EXTENSIONS_SHELL_BROWSER_SHELL_APP_SORTING_H_ +#define EXTENSIONS_SHELL_BROWSER_SHELL_APP_SORTING_H_ + +#include "base/compiler_specific.h" +#include "extensions/browser/app_sorting.h" + +namespace extensions { + +// A stub AppSorting. Since app_shell only runs a single app we don't need to +// sort them. +class ShellAppSorting : public AppSorting { + public: + ShellAppSorting(); + virtual ~ShellAppSorting(); + + // AppSorting overrides: + virtual void SetExtensionScopedPrefs(ExtensionScopedPrefs* prefs) OVERRIDE; + virtual void SetExtensionSyncService( + ExtensionSyncService* extension_sync_service) OVERRIDE; + virtual void Initialize(const ExtensionIdList& extension_ids) OVERRIDE; + virtual void FixNTPOrdinalCollisions() OVERRIDE; + virtual void EnsureValidOrdinals( + const std::string& extension_id, + const syncer::StringOrdinal& suggested_page) OVERRIDE; + virtual void OnExtensionMoved( + const std::string& moved_extension_id, + const std::string& predecessor_extension_id, + const std::string& successor_extension_id) OVERRIDE; + virtual syncer::StringOrdinal GetAppLaunchOrdinal( + const std::string& extension_id) const OVERRIDE; + virtual void SetAppLaunchOrdinal( + const std::string& extension_id, + const syncer::StringOrdinal& new_app_launch_ordinal) OVERRIDE; + virtual syncer::StringOrdinal CreateFirstAppLaunchOrdinal( + const syncer::StringOrdinal& page_ordinal) const OVERRIDE; + virtual syncer::StringOrdinal CreateNextAppLaunchOrdinal( + const syncer::StringOrdinal& page_ordinal) const OVERRIDE; + virtual syncer::StringOrdinal CreateFirstAppPageOrdinal() const OVERRIDE; + virtual syncer::StringOrdinal GetNaturalAppPageOrdinal() const OVERRIDE; + virtual syncer::StringOrdinal GetPageOrdinal( + const std::string& extension_id) const OVERRIDE; + virtual void SetPageOrdinal( + const std::string& extension_id, + const syncer::StringOrdinal& new_page_ordinal) OVERRIDE; + virtual void ClearOrdinals(const std::string& extension_id) OVERRIDE; + virtual int PageStringOrdinalAsInteger( + const syncer::StringOrdinal& page_ordinal) const OVERRIDE; + virtual syncer::StringOrdinal PageIntegerAsStringOrdinal( + size_t page_index) OVERRIDE; + virtual void SetExtensionVisible(const std::string& extension_id, + bool visible) OVERRIDE; + + private: + DISALLOW_COPY_AND_ASSIGN(ShellAppSorting); +}; + +} // namespace extensions + +#endif // EXTENSIONS_SHELL_BROWSER_SHELL_APP_SORTING_H_ diff --git a/extensions/shell/browser/shell_app_window.cc b/extensions/shell/browser/shell_app_window.cc new file mode 100644 index 0000000..a66554e --- /dev/null +++ b/extensions/shell/browser/shell_app_window.cc @@ -0,0 +1,75 @@ +// Copyright 2014 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 "extensions/shell/browser/shell_app_window.h" + +#include "content/public/browser/navigation_controller.h" +#include "content/public/browser/render_view_host.h" +#include "content/public/browser/web_contents.h" +#include "extensions/browser/view_type_utils.h" +#include "extensions/common/extension_messages.h" +#include "extensions/shell/browser/shell_extension_web_contents_observer.h" +#include "ipc/ipc_message_macros.h" + +using content::BrowserContext; +using content::WebContents; + +namespace extensions { + +ShellAppWindow::ShellAppWindow() { +} + +ShellAppWindow::~ShellAppWindow() { +} + +void ShellAppWindow::Init(BrowserContext* context, gfx::Size initial_size) { + extension_function_dispatcher_.reset( + new ExtensionFunctionDispatcher(context, this)); + + // Create the web contents with an initial size to avoid a resize. + WebContents::CreateParams create_params(context); + create_params.initial_size = initial_size; + web_contents_.reset(WebContents::Create(create_params)); + + content::WebContentsObserver::Observe(web_contents_.get()); + + // Add support for extension startup. + ShellExtensionWebContentsObserver::CreateForWebContents(web_contents_.get()); + + SetViewType(web_contents_.get(), VIEW_TYPE_APP_WINDOW); +} + +void ShellAppWindow::LoadURL(const GURL& url) { + content::NavigationController::LoadURLParams params(url); + web_contents_->GetController().LoadURLWithParams(params); + web_contents_->Focus(); +} + +aura::Window* ShellAppWindow::GetNativeWindow() { + return web_contents_->GetNativeView(); +} + +int ShellAppWindow::GetRenderViewRoutingID() { + return web_contents_->GetRenderViewHost()->GetRoutingID(); +} + +bool ShellAppWindow::OnMessageReceived(const IPC::Message& message) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(ShellAppWindow, message) + IPC_MESSAGE_HANDLER(ExtensionHostMsg_Request, OnRequest) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +content::WebContents* ShellAppWindow::GetAssociatedWebContents() const { + return web_contents_.get(); +} + +void ShellAppWindow::OnRequest(const ExtensionHostMsg_Request_Params& params) { + extension_function_dispatcher_->Dispatch(params, + web_contents_->GetRenderViewHost()); +} + +} // namespace extensions diff --git a/extensions/shell/browser/shell_app_window.h b/extensions/shell/browser/shell_app_window.h new file mode 100644 index 0000000..d85f4f0 --- /dev/null +++ b/extensions/shell/browser/shell_app_window.h @@ -0,0 +1,72 @@ +// Copyright 2014 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 EXTENSIONS_SHELL_BROWSER_SHELL_APP_WINDOW_H_ +#define EXTENSIONS_SHELL_BROWSER_SHELL_APP_WINDOW_H_ + +#include "base/macros.h" +#include "base/memory/scoped_ptr.h" +#include "content/public/browser/web_contents_observer.h" +#include "extensions/browser/extension_function_dispatcher.h" + +struct ExtensionHostMsg_Request_Params; +class GURL; + +namespace aura { +class Window; +} + +namespace content { +class BrowserContext; +class WebContents; +} + +namespace gfx { +class Size; +} + +namespace extensions { + +class ExtensionFunctionDispatcher; + +// A simplified app window created by chrome.app.window.create(). Manages the +// primary web contents for the app. +class ShellAppWindow : public content::WebContentsObserver, + public ExtensionFunctionDispatcher::Delegate { + public: + ShellAppWindow(); + virtual ~ShellAppWindow(); + + // Creates the web contents and attaches extension-specific helpers. + // Passing a valid |initial_size| to avoid a web contents resize. + void Init(content::BrowserContext* context, gfx::Size initial_size); + + // Starts loading |url| which must be an extension URL. + void LoadURL(const GURL& url); + + // Returns the window hosting the web contents. + aura::Window* GetNativeWindow(); + + // Returns the routing ID of the render view host of |web_contents_|. + int GetRenderViewRoutingID(); + + // content::WebContentsObserver implementation + virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; + + // ExtensionFunctionDispatcher::Delegate implementation + virtual content::WebContents* GetAssociatedWebContents() const OVERRIDE; + + private: + // IPC handler. + void OnRequest(const ExtensionHostMsg_Request_Params& params); + + scoped_ptr<content::WebContents> web_contents_; + scoped_ptr<ExtensionFunctionDispatcher> extension_function_dispatcher_; + + DISALLOW_COPY_AND_ASSIGN(ShellAppWindow); +}; + +} // namespace extensions + +#endif // EXTENSIONS_SHELL_BROWSER_SHELL_APP_WINDOW_H_ diff --git a/extensions/shell/browser/shell_app_window_controller.h b/extensions/shell/browser/shell_app_window_controller.h new file mode 100644 index 0000000..f8a7fa0 --- /dev/null +++ b/extensions/shell/browser/shell_app_window_controller.h @@ -0,0 +1,30 @@ +// Copyright 2014 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 EXTENSIONS_SHELL_BROWSER_SHELL_APP_WINDOW_CONTROLLER_H_ +#define EXTENSIONS_SHELL_BROWSER_SHELL_APP_WINDOW_CONTROLLER_H_ + +namespace content { +class BrowserContext; +} + +namespace extensions { + +class ShellAppWindow; + +class ShellAppWindowController { + public: + virtual ~ShellAppWindowController() {} + + // Creates a new app window and adds it to the desktop. This class should + // maintain the ownership of the window. + virtual ShellAppWindow* CreateAppWindow(content::BrowserContext* context) = 0; + + // Closes and destroys the app windows. + virtual void CloseAppWindows() = 0; +}; + +} // namespace extensions + +#endif // EXTENSIONS_SHELL_BROWSER_SHELL_APP_WINDOW_CONTROLLER_H_ diff --git a/extensions/shell/browser/shell_browser_context.cc b/extensions/shell/browser/shell_browser_context.cc new file mode 100644 index 0000000..2f83782 --- /dev/null +++ b/extensions/shell/browser/shell_browser_context.cc @@ -0,0 +1,70 @@ +// Copyright 2014 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 "extensions/shell/browser/shell_browser_context.h" +#include "extensions/shell/browser/shell_special_storage_policy.h" + +namespace extensions { + +// Create a normal recording browser context. If we used an incognito context +// then app_shell would also have to create a normal context and manage both. +ShellBrowserContext::ShellBrowserContext() + : content::ShellBrowserContext(false, NULL), + storage_policy_(new ShellSpecialStoragePolicy) { +} + +ShellBrowserContext::~ShellBrowserContext() { +} + +quota::SpecialStoragePolicy* ShellBrowserContext::GetSpecialStoragePolicy() { + return storage_policy_.get(); +} + +void ShellBrowserContext::ProfileFunctionCallOnNonProfileBrowserContext1() { + NOTREACHED(); +} +void ShellBrowserContext::ProfileFunctionCallOnNonProfileBrowserContext2() { + NOTREACHED(); +} +void ShellBrowserContext::ProfileFunctionCallOnNonProfileBrowserContext3() { + NOTREACHED(); +} +void ShellBrowserContext::ProfileFunctionCallOnNonProfileBrowserContext4() { + NOTREACHED(); +} +void ShellBrowserContext::ProfileFunctionCallOnNonProfileBrowserContext5() { + NOTREACHED(); +} +void ShellBrowserContext::ProfileFunctionCallOnNonProfileBrowserContext6() { + NOTREACHED(); +} +void ShellBrowserContext::ProfileFunctionCallOnNonProfileBrowserContext7() { + NOTREACHED(); +} +void ShellBrowserContext::ProfileFunctionCallOnNonProfileBrowserContext8() { + NOTREACHED(); +} +void ShellBrowserContext::ProfileFunctionCallOnNonProfileBrowserContext9() { + NOTREACHED(); +} +void ShellBrowserContext::ProfileFunctionCallOnNonProfileBrowserContext10() { + NOTREACHED(); +} +void ShellBrowserContext::ProfileFunctionCallOnNonProfileBrowserContext11() { + NOTREACHED(); +} +void ShellBrowserContext::ProfileFunctionCallOnNonProfileBrowserContext12() { + NOTREACHED(); +} +void ShellBrowserContext::ProfileFunctionCallOnNonProfileBrowserContext13() { + NOTREACHED(); +} +void ShellBrowserContext::ProfileFunctionCallOnNonProfileBrowserContext14() { + NOTREACHED(); +} +void ShellBrowserContext::ProfileFunctionCallOnNonProfileBrowserContext15() { + NOTREACHED(); +} + +} // namespace extensions diff --git a/extensions/shell/browser/shell_browser_context.h b/extensions/shell/browser/shell_browser_context.h new file mode 100644 index 0000000..72f3fc5 --- /dev/null +++ b/extensions/shell/browser/shell_browser_context.h @@ -0,0 +1,53 @@ +// Copyright 2014 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 EXTENSIONS_SHELL_BROWSER_SHELL_BROWSER_CONTEXT_H_ +#define EXTENSIONS_SHELL_BROWSER_SHELL_BROWSER_CONTEXT_H_ + +#include "base/compiler_specific.h" +#include "base/memory/ref_counted.h" +#include "content/shell/browser/shell_browser_context.h" +#include "webkit/browser/quota/special_storage_policy.h" + +namespace extensions { + +class ShellSpecialStoragePolicy; + +// The BrowserContext used by the content, apps and extensions systems in +// app_shell. +class ShellBrowserContext : public content::ShellBrowserContext { + public: + ShellBrowserContext(); + virtual ~ShellBrowserContext(); + + // content::BrowserContext implementation. + virtual quota::SpecialStoragePolicy* GetSpecialStoragePolicy() OVERRIDE; + + // HACK: Pad the virtual function table so we trip an assertion if someone + // tries to use |this| as a Profile. + virtual void ProfileFunctionCallOnNonProfileBrowserContext1(); + virtual void ProfileFunctionCallOnNonProfileBrowserContext2(); + virtual void ProfileFunctionCallOnNonProfileBrowserContext3(); + virtual void ProfileFunctionCallOnNonProfileBrowserContext4(); + virtual void ProfileFunctionCallOnNonProfileBrowserContext5(); + virtual void ProfileFunctionCallOnNonProfileBrowserContext6(); + virtual void ProfileFunctionCallOnNonProfileBrowserContext7(); + virtual void ProfileFunctionCallOnNonProfileBrowserContext8(); + virtual void ProfileFunctionCallOnNonProfileBrowserContext9(); + virtual void ProfileFunctionCallOnNonProfileBrowserContext10(); + virtual void ProfileFunctionCallOnNonProfileBrowserContext11(); + virtual void ProfileFunctionCallOnNonProfileBrowserContext12(); + virtual void ProfileFunctionCallOnNonProfileBrowserContext13(); + virtual void ProfileFunctionCallOnNonProfileBrowserContext14(); + virtual void ProfileFunctionCallOnNonProfileBrowserContext15(); + + private: + scoped_refptr<quota::SpecialStoragePolicy> storage_policy_; + + DISALLOW_COPY_AND_ASSIGN(ShellBrowserContext); +}; + +} // namespace extensions + +#endif // EXTENSIONS_SHELL_BROWSER_SHELL_BROWSER_CONTEXT_H_ diff --git a/extensions/shell/browser/shell_browser_main_delegate.h b/extensions/shell/browser/shell_browser_main_delegate.h new file mode 100644 index 0000000..3dbbbab --- /dev/null +++ b/extensions/shell/browser/shell_browser_main_delegate.h @@ -0,0 +1,36 @@ +// Copyright 2014 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 EXTENSIONS_SHELL_BROWSER_SHELL_BROWSER_MAIN_DELEGATE_H_ +#define EXTENSIONS_SHELL_BROWSER_SHELL_BROWSER_MAIN_DELEGATE_H_ + +namespace content { +class BrowserContext; +} + +namespace extensions { + +class ShellDesktopController; + +class ShellBrowserMainDelegate { + public: + virtual ~ShellBrowserMainDelegate() {} + + // Called to start an application after all initialization processes that are + // necesary to run apps are completed. + virtual void Start(content::BrowserContext* context) = 0; + + // Called after the main message looop has stopped, but before + // other services such as BrowserContext / extension system are shut down. + virtual void Shutdown() = 0; + + // Creates the ShellDesktopController instance to initialize the root window + // and window manager. Subclass may return its subclass to customize the + // windo manager. + virtual ShellDesktopController* CreateDesktopController() = 0; +}; + +} // namespace extensions + +#endif // EXTENSIONS_SHELL_BROWSER_SHELL_BROWSER_MAIN_DELEGATE_H_ diff --git a/extensions/shell/browser/shell_browser_main_parts.cc b/extensions/shell/browser/shell_browser_main_parts.cc new file mode 100644 index 0000000..3a33566 --- /dev/null +++ b/extensions/shell/browser/shell_browser_main_parts.cc @@ -0,0 +1,167 @@ +// Copyright 2014 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 "extensions/shell/browser/shell_browser_main_parts.h" + +#include "base/command_line.h" +#include "base/run_loop.h" +#include "components/keyed_service/content/browser_context_dependency_manager.h" +#include "components/omaha_query_params/omaha_query_params.h" +#include "content/public/common/result_codes.h" +#include "content/shell/browser/shell_devtools_delegate.h" +#include "content/shell/browser/shell_net_log.h" +#include "extensions/browser/browser_context_keyed_service_factories.h" +#include "extensions/browser/extension_system.h" +#include "extensions/shell/browser/shell_browser_context.h" +#include "extensions/shell/browser/shell_browser_main_delegate.h" +#include "extensions/shell/browser/shell_desktop_controller.h" +#include "extensions/shell/browser/shell_extension_system.h" +#include "extensions/shell/browser/shell_extension_system_factory.h" +#include "extensions/shell/browser/shell_extensions_browser_client.h" +#include "extensions/shell/browser/shell_omaha_query_params_delegate.h" +#include "extensions/shell/common/shell_extensions_client.h" +#include "extensions/shell/common/switches.h" +#include "ui/aura/window_tree_host.h" +#include "ui/base/ime/input_method_initializer.h" +#include "ui/base/resource/resource_bundle.h" + +#if defined(OS_CHROMEOS) +#include "chromeos/dbus/dbus_thread_manager.h" +#include "extensions/shell/browser/shell_network_controller_chromeos.h" +#endif + +using content::BrowserContext; + +namespace { + +// Register additional KeyedService factories here. See +// ChromeBrowserMainExtraPartsProfiles for details. +void EnsureBrowserContextKeyedServiceFactoriesBuilt() { + extensions::EnsureBrowserContextKeyedServiceFactoriesBuilt(); + extensions::ShellExtensionSystemFactory::GetInstance(); +} + +} // namespace + +namespace extensions { + +ShellBrowserMainParts::ShellBrowserMainParts( + const content::MainFunctionParams& parameters, + ShellBrowserMainDelegate* browser_main_delegate) + : extension_system_(NULL), + parameters_(parameters), + run_message_loop_(true), + browser_main_delegate_(browser_main_delegate) { +} + +ShellBrowserMainParts::~ShellBrowserMainParts() { +} + +void ShellBrowserMainParts::PreMainMessageLoopStart() { + // TODO(jamescook): Initialize touch here? +} + +void ShellBrowserMainParts::PostMainMessageLoopStart() { +#if defined(OS_CHROMEOS) + chromeos::DBusThreadManager::Initialize(); + network_controller_.reset(new ShellNetworkController( + base::CommandLine::ForCurrentProcess()->GetSwitchValueNative( + switches::kAppShellPreferredNetwork))); +#else + // Non-Chrome OS platforms are for developer convenience, so use a test IME. + ui::InitializeInputMethodForTesting(); +#endif +} + +void ShellBrowserMainParts::PreEarlyInitialization() { +} + +int ShellBrowserMainParts::PreCreateThreads() { + // TODO(jamescook): Initialize chromeos::CrosSettings here? + + // Return no error. + return 0; +} + +void ShellBrowserMainParts::PreMainMessageLoopRun() { + // Initialize our "profile" equivalent. + browser_context_.reset(new ShellBrowserContext); + + desktop_controller_.reset(browser_main_delegate_->CreateDesktopController()); + desktop_controller_->CreateRootWindow(); + + // NOTE: Much of this is culled from chrome/test/base/chrome_test_suite.cc + // TODO(jamescook): Initialize chromeos::UserManager. + net_log_.reset(new content::ShellNetLog("app_shell")); + + extensions_client_.reset(new ShellExtensionsClient()); + ExtensionsClient::Set(extensions_client_.get()); + + extensions_browser_client_.reset( + new ShellExtensionsBrowserClient(browser_context_.get())); + ExtensionsBrowserClient::Set(extensions_browser_client_.get()); + + omaha_query_params_delegate_.reset(new ShellOmahaQueryParamsDelegate); + omaha_query_params::OmahaQueryParams::SetDelegate( + omaha_query_params_delegate_.get()); + + // Create our custom ExtensionSystem first because other + // KeyedServices depend on it. + // TODO(yoz): Move this after EnsureBrowserContextKeyedServiceFactoriesBuilt. + CreateExtensionSystem(); + + ::EnsureBrowserContextKeyedServiceFactoriesBuilt(); + BrowserContextDependencyManager::GetInstance()->CreateBrowserContextServices( + browser_context_.get()); + + devtools_delegate_.reset( + new content::ShellDevToolsDelegate(browser_context_.get())); + if (parameters_.ui_task) { + // For running browser tests. + parameters_.ui_task->Run(); + delete parameters_.ui_task; + run_message_loop_ = false; + } else { + browser_main_delegate_->Start(browser_context_.get()); + } +} + +bool ShellBrowserMainParts::MainMessageLoopRun(int* result_code) { + if (!run_message_loop_) + return true; + // TODO(yoz): just return false here? + base::RunLoop run_loop; + run_loop.Run(); + *result_code = content::RESULT_CODE_NORMAL_EXIT; + return true; +} + +void ShellBrowserMainParts::PostMainMessageLoopRun() { + browser_main_delegate_->Shutdown(); + + BrowserContextDependencyManager::GetInstance()->DestroyBrowserContextServices( + browser_context_.get()); + extension_system_ = NULL; + ExtensionsBrowserClient::Set(NULL); + extensions_browser_client_.reset(); + browser_context_.reset(); + + desktop_controller_.reset(); +} + +void ShellBrowserMainParts::PostDestroyThreads() { +#if defined(OS_CHROMEOS) + network_controller_.reset(); + chromeos::DBusThreadManager::Shutdown(); +#endif +} + +void ShellBrowserMainParts::CreateExtensionSystem() { + DCHECK(browser_context_); + extension_system_ = static_cast<ShellExtensionSystem*>( + ExtensionSystem::Get(browser_context_.get())); + extension_system_->InitForRegularProfile(true); +} + +} // namespace extensions diff --git a/extensions/shell/browser/shell_browser_main_parts.h b/extensions/shell/browser/shell_browser_main_parts.h new file mode 100644 index 0000000..83915cb --- /dev/null +++ b/extensions/shell/browser/shell_browser_main_parts.h @@ -0,0 +1,95 @@ +// Copyright 2014 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 EXTENSIONS_SHELL_BROWSER_SHELL_BROWSER_MAIN_PARTS_H_ +#define EXTENSIONS_SHELL_BROWSER_SHELL_BROWSER_MAIN_PARTS_H_ + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "base/memory/scoped_ptr.h" +#include "content/public/browser/browser_main_parts.h" +#include "content/public/common/main_function_params.h" +#include "ui/aura/window_tree_host_observer.h" + +namespace content { +class ShellDevToolsDelegate; +struct MainFunctionParams; +} + +namespace views { +class Widget; +} + +namespace net { +class NetLog; +} + +namespace extensions { + +class ShellBrowserContext; +class ShellBrowserMainDelegate; +class ShellDesktopController; +class ShellExtensionsBrowserClient; +class ShellExtensionsClient; +class ShellExtensionSystem; +class ShellOmahaQueryParamsDelegate; + +#if defined(OS_CHROMEOS) +class ShellNetworkController; +#endif + +// Handles initialization of AppShell. +class ShellBrowserMainParts : public content::BrowserMainParts { + public: + ShellBrowserMainParts(const content::MainFunctionParams& parameters, + ShellBrowserMainDelegate* browser_main_delegate); + virtual ~ShellBrowserMainParts(); + + ShellBrowserContext* browser_context() { return browser_context_.get(); } + + ShellExtensionSystem* extension_system() { return extension_system_; } + + // BrowserMainParts overrides. + virtual void PreEarlyInitialization() OVERRIDE; + virtual void PreMainMessageLoopStart() OVERRIDE; + virtual void PostMainMessageLoopStart() OVERRIDE; + virtual int PreCreateThreads() OVERRIDE; + virtual void PreMainMessageLoopRun() OVERRIDE; + virtual bool MainMessageLoopRun(int* result_code) OVERRIDE; + virtual void PostMainMessageLoopRun() OVERRIDE; + virtual void PostDestroyThreads() OVERRIDE; + + private: + // Creates and initializes the ExtensionSystem. + void CreateExtensionSystem(); + +#if defined(OS_CHROMEOS) + scoped_ptr<ShellNetworkController> network_controller_; +#endif + scoped_ptr<ShellDesktopController> desktop_controller_; + scoped_ptr<ShellBrowserContext> browser_context_; + scoped_ptr<ShellExtensionsClient> extensions_client_; + scoped_ptr<ShellExtensionsBrowserClient> extensions_browser_client_; + scoped_ptr<net::NetLog> net_log_; + scoped_ptr<content::ShellDevToolsDelegate> devtools_delegate_; + scoped_ptr<ShellOmahaQueryParamsDelegate> omaha_query_params_delegate_; + + // Owned by the KeyedService system. + ShellExtensionSystem* extension_system_; + + // For running app browsertests. + const content::MainFunctionParams parameters_; + + // If true, indicates the main message loop should be run + // in MainMessageLoopRun. If false, it has already been run. + bool run_message_loop_; + + scoped_ptr<ShellBrowserMainDelegate> browser_main_delegate_; + + DISALLOW_COPY_AND_ASSIGN(ShellBrowserMainParts); +}; + +} // namespace extensions + +#endif // EXTENSIONS_SHELL_BROWSER_SHELL_BROWSER_MAIN_PARTS_H_ diff --git a/extensions/shell/browser/shell_browsertest.cc b/extensions/shell/browser/shell_browsertest.cc new file mode 100644 index 0000000..9520691 --- /dev/null +++ b/extensions/shell/browser/shell_browsertest.cc @@ -0,0 +1,31 @@ +// Copyright 2014 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 "base/files/file_path.h" +#include "base/logging.h" +#include "base/path_service.h" +#include "chrome/browser/chrome_notification_types.h" +#include "content/public/browser/notification_service.h" +#include "content/public/test/test_utils.h" +#include "extensions/common/extension_paths.h" +#include "extensions/shell/test/shell_test.h" + +namespace extensions { + +// Test that we can open an app window and wait for it to load. +IN_PROC_BROWSER_TEST_F(AppShellTest, Basic) { + base::FilePath test_data_dir; + + content::WindowedNotificationObserver test_pass_observer( + chrome::NOTIFICATION_EXTENSION_TEST_PASSED, + content::NotificationService::AllSources()); + + PathService::Get(extensions::DIR_TEST_DATA, &test_data_dir); + test_data_dir = test_data_dir.AppendASCII("platform_app"); + LoadAndLaunchApp(test_data_dir); + + test_pass_observer.Wait(); +} + +} // namespace extensions diff --git a/extensions/shell/browser/shell_content_browser_client.cc b/extensions/shell/browser/shell_content_browser_client.cc new file mode 100644 index 0000000..328fb878 --- /dev/null +++ b/extensions/shell/browser/shell_content_browser_client.cc @@ -0,0 +1,192 @@ +// Copyright 2014 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 "extensions/shell/browser/shell_content_browser_client.h" + +#include "base/command_line.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/render_process_host.h" +#include "content/public/browser/site_instance.h" +#include "content/public/common/content_switches.h" +#include "content/public/common/url_constants.h" +#include "content/shell/browser/shell_browser_context.h" +#include "extensions/browser/extension_message_filter.h" +#include "extensions/browser/extension_protocols.h" +#include "extensions/browser/extension_registry.h" +#include "extensions/browser/info_map.h" +#include "extensions/browser/process_map.h" +#include "extensions/common/constants.h" +#include "extensions/common/extension.h" +#include "extensions/common/switches.h" +#include "extensions/shell/browser/shell_browser_context.h" +#include "extensions/shell/browser/shell_browser_main_parts.h" +#include "extensions/shell/browser/shell_extension_system.h" +#include "url/gurl.h" + +using content::BrowserThread; + +namespace extensions { +namespace { + +ShellContentBrowserClient* g_instance = NULL; + +} // namespace + +ShellContentBrowserClient::ShellContentBrowserClient( + ShellBrowserMainDelegate* browser_main_delegate) + : browser_main_parts_(NULL), browser_main_delegate_(browser_main_delegate) { + DCHECK(!g_instance); + g_instance = this; +} + +ShellContentBrowserClient::~ShellContentBrowserClient() { + g_instance = NULL; +} + +// static +ShellContentBrowserClient* ShellContentBrowserClient::Get() { + return g_instance; +} + +content::BrowserContext* ShellContentBrowserClient::GetBrowserContext() { + return browser_main_parts_->browser_context(); +} + +content::BrowserMainParts* ShellContentBrowserClient::CreateBrowserMainParts( + const content::MainFunctionParams& parameters) { + browser_main_parts_ = + new ShellBrowserMainParts(parameters, browser_main_delegate_); + return browser_main_parts_; +} + +void ShellContentBrowserClient::RenderProcessWillLaunch( + content::RenderProcessHost* host) { + int render_process_id = host->GetID(); + host->AddFilter(new ExtensionMessageFilter( + render_process_id, browser_main_parts_->browser_context())); +} + +bool ShellContentBrowserClient::ShouldUseProcessPerSite( + content::BrowserContext* browser_context, + const GURL& effective_url) { + // This ensures that all render views created for a single app will use the + // same render process (see content::SiteInstance::GetProcess). Otherwise the + // default behavior of ContentBrowserClient will lead to separate render + // processes for the background page and each app window view. + return true; +} + +net::URLRequestContextGetter* ShellContentBrowserClient::CreateRequestContext( + content::BrowserContext* content_browser_context, + content::ProtocolHandlerMap* protocol_handlers, + content::URLRequestInterceptorScopedVector request_interceptors) { + // Handle only chrome-extension:// requests. app_shell does not support + // chrome-extension-resource:// requests (it does not store shared extension + // data in its installation directory). + InfoMap* extension_info_map = + browser_main_parts_->extension_system()->info_map(); + (*protocol_handlers)[kExtensionScheme] = + linked_ptr<net::URLRequestJobFactory::ProtocolHandler>( + CreateExtensionProtocolHandler(false /* is_incognito */, + extension_info_map)); + // Let content::ShellBrowserContext handle the rest of the setup. + return browser_main_parts_->browser_context()->CreateRequestContext( + protocol_handlers, request_interceptors.Pass()); +} + +bool ShellContentBrowserClient::IsHandledURL(const GURL& url) { + if (!url.is_valid()) + return false; + // Keep in sync with ProtocolHandlers added in CreateRequestContext() and in + // content::ShellURLRequestContextGetter::GetURLRequestContext(). + static const char* const kProtocolList[] = { + url::kBlobScheme, + content::kChromeDevToolsScheme, + content::kChromeUIScheme, + url::kDataScheme, + url::kFileScheme, + url::kFileSystemScheme, + kExtensionScheme, + kExtensionResourceScheme, + }; + for (size_t i = 0; i < arraysize(kProtocolList); ++i) { + if (url.scheme() == kProtocolList[i]) + return true; + } + return false; +} + +void ShellContentBrowserClient::SiteInstanceGotProcess( + content::SiteInstance* site_instance) { + // If this isn't an extension renderer there's nothing to do. + const Extension* extension = GetExtension(site_instance); + if (!extension) + return; + + ProcessMap::Get(browser_main_parts_->browser_context()) + ->Insert(extension->id(), + site_instance->GetProcess()->GetID(), + site_instance->GetId()); + + BrowserThread::PostTask( + BrowserThread::IO, + FROM_HERE, + base::Bind(&InfoMap::RegisterExtensionProcess, + browser_main_parts_->extension_system()->info_map(), + extension->id(), + site_instance->GetProcess()->GetID(), + site_instance->GetId())); +} + +void ShellContentBrowserClient::SiteInstanceDeleting( + content::SiteInstance* site_instance) { + // If this isn't an extension renderer there's nothing to do. + const Extension* extension = GetExtension(site_instance); + if (!extension) + return; + + ProcessMap::Get(browser_main_parts_->browser_context()) + ->Remove(extension->id(), + site_instance->GetProcess()->GetID(), + site_instance->GetId()); + + BrowserThread::PostTask( + BrowserThread::IO, + FROM_HERE, + base::Bind(&InfoMap::UnregisterExtensionProcess, + browser_main_parts_->extension_system()->info_map(), + extension->id(), + site_instance->GetProcess()->GetID(), + site_instance->GetId())); +} + +void ShellContentBrowserClient::AppendExtraCommandLineSwitches( + CommandLine* command_line, + int child_process_id) { + std::string process_type = + command_line->GetSwitchValueASCII(::switches::kProcessType); + if (process_type == ::switches::kRendererProcess) { + // TODO(jamescook): Should we check here if the process is in the extension + // service process map, or can we assume all renderers are extension + // renderers? + command_line->AppendSwitch(switches::kExtensionProcess); + } +} + +void ShellContentBrowserClient::GetAdditionalAllowedSchemesForFileSystem( + std::vector<std::string>* additional_allowed_schemes) { + ContentBrowserClient::GetAdditionalAllowedSchemesForFileSystem( + additional_allowed_schemes); + additional_allowed_schemes->push_back(kExtensionScheme); +} + +const Extension* ShellContentBrowserClient::GetExtension( + content::SiteInstance* site_instance) { + ExtensionRegistry* registry = + ExtensionRegistry::Get(site_instance->GetBrowserContext()); + return registry->enabled_extensions().GetExtensionOrAppByURL( + site_instance->GetSiteURL()); +} + +} // namespace extensions diff --git a/extensions/shell/browser/shell_content_browser_client.h b/extensions/shell/browser/shell_content_browser_client.h new file mode 100644 index 0000000..da884fd --- /dev/null +++ b/extensions/shell/browser/shell_content_browser_client.h @@ -0,0 +1,73 @@ +// Copyright 2014 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 EXTENSIONS_SHELL_BROWSER_SHELL_CONTENT_BROWSER_CLIENT_H_ +#define EXTENSIONS_SHELL_BROWSER_SHELL_CONTENT_BROWSER_CLIENT_H_ + +#include "base/compiler_specific.h" +#include "content/public/browser/content_browser_client.h" + +class GURL; + +namespace content { +class BrowserContext; +} + +namespace extensions { +class Extension; +class ShellBrowserMainDelegate; +class ShellBrowserMainParts; + +// Content module browser process support for app_shell. +class ShellContentBrowserClient : public content::ContentBrowserClient { + public: + explicit ShellContentBrowserClient( + ShellBrowserMainDelegate* browser_main_delegate); + virtual ~ShellContentBrowserClient(); + + // Returns the single instance. + static ShellContentBrowserClient* Get(); + + // Returns the single browser context for app_shell. + content::BrowserContext* GetBrowserContext(); + + // content::ContentBrowserClient overrides. + virtual content::BrowserMainParts* CreateBrowserMainParts( + const content::MainFunctionParams& parameters) OVERRIDE; + virtual void RenderProcessWillLaunch( + content::RenderProcessHost* host) OVERRIDE; + virtual bool ShouldUseProcessPerSite(content::BrowserContext* browser_context, + const GURL& effective_url) OVERRIDE; + virtual net::URLRequestContextGetter* CreateRequestContext( + content::BrowserContext* browser_context, + content::ProtocolHandlerMap* protocol_handlers, + content::URLRequestInterceptorScopedVector request_interceptors) OVERRIDE; + // TODO(jamescook): Quota management? + // TODO(jamescook): Speech recognition? + virtual bool IsHandledURL(const GURL& url) OVERRIDE; + virtual void SiteInstanceGotProcess( + content::SiteInstance* site_instance) OVERRIDE; + virtual void SiteInstanceDeleting( + content::SiteInstance* site_instance) OVERRIDE; + virtual void AppendExtraCommandLineSwitches(base::CommandLine* command_line, + int child_process_id) OVERRIDE; + virtual void GetAdditionalAllowedSchemesForFileSystem( + std::vector<std::string>* additional_schemes) OVERRIDE; + + private: + // Returns the extension or app associated with |site_instance| or NULL. + const Extension* GetExtension(content::SiteInstance* site_instance); + + // Owned by content::BrowserMainLoop. + ShellBrowserMainParts* browser_main_parts_; + + // Owned by ShellBrowserMainParts. + ShellBrowserMainDelegate* browser_main_delegate_; + + DISALLOW_COPY_AND_ASSIGN(ShellContentBrowserClient); +}; + +} // namespace extensions + +#endif // EXTENSIONS_SHELL_BROWSER_SHELL_CONTENT_BROWSER_CLIENT_H_ diff --git a/extensions/shell/browser/shell_desktop_controller.cc b/extensions/shell/browser/shell_desktop_controller.cc new file mode 100644 index 0000000..5cec7fe --- /dev/null +++ b/extensions/shell/browser/shell_desktop_controller.cc @@ -0,0 +1,336 @@ +// Copyright 2014 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 "extensions/shell/browser/shell_desktop_controller.h" + +#include "base/command_line.h" +#include "content/public/browser/context_factory.h" +#include "extensions/shell/browser/shell_app_window_controller.h" +#include "extensions/shell/common/switches.h" +#include "ui/aura/client/cursor_client.h" +#include "ui/aura/client/default_capture_client.h" +#include "ui/aura/env.h" +#include "ui/aura/layout_manager.h" +#include "ui/aura/test/test_screen.h" +#include "ui/aura/window.h" +#include "ui/aura/window_event_dispatcher.h" +#include "ui/aura/window_tree_host.h" +#include "ui/base/cursor/cursor.h" +#include "ui/base/cursor/image_cursors.h" +#include "ui/base/ime/input_method_initializer.h" +#include "ui/gfx/native_widget_types.h" +#include "ui/gfx/screen.h" +#include "ui/wm/core/base_focus_rules.h" +#include "ui/wm/core/compound_event_filter.h" +#include "ui/wm/core/cursor_manager.h" +#include "ui/wm/core/focus_controller.h" +#include "ui/wm/core/input_method_event_filter.h" +#include "ui/wm/core/native_cursor_manager.h" +#include "ui/wm/core/native_cursor_manager_delegate.h" +#include "ui/wm/core/user_activity_detector.h" + +#if defined(OS_CHROMEOS) +#include "ui/chromeos/user_activity_power_manager_notifier.h" +#include "ui/display/types/chromeos/display_mode.h" +#include "ui/display/types/chromeos/display_snapshot.h" +#endif + +namespace extensions { +namespace { + +// A simple layout manager that makes each new window fill its parent. +class FillLayout : public aura::LayoutManager { + public: + FillLayout() {} + virtual ~FillLayout() {} + + private: + // aura::LayoutManager: + virtual void OnWindowResized() OVERRIDE {} + + virtual void OnWindowAddedToLayout(aura::Window* child) OVERRIDE { + if (!child->parent()) + return; + + // Create a rect at 0,0 with the size of the parent. + gfx::Size parent_size = child->parent()->bounds().size(); + child->SetBounds(gfx::Rect(parent_size)); + } + + virtual void OnWillRemoveWindowFromLayout(aura::Window* child) OVERRIDE {} + + virtual void OnWindowRemovedFromLayout(aura::Window* child) OVERRIDE {} + + virtual void OnChildWindowVisibilityChanged(aura::Window* child, + bool visible) OVERRIDE {} + + virtual void SetChildBounds(aura::Window* child, + const gfx::Rect& requested_bounds) OVERRIDE { + SetChildBoundsDirect(child, requested_bounds); + } + + DISALLOW_COPY_AND_ASSIGN(FillLayout); +}; + +// A class that bridges the gap between CursorManager and Aura. It borrows +// heavily from AshNativeCursorManager. +class ShellNativeCursorManager : public wm::NativeCursorManager { + public: + explicit ShellNativeCursorManager(aura::WindowTreeHost* host) + : host_(host), image_cursors_(new ui::ImageCursors) {} + virtual ~ShellNativeCursorManager() {} + + // wm::NativeCursorManager overrides. + virtual void SetDisplay(const gfx::Display& display, + wm::NativeCursorManagerDelegate* delegate) OVERRIDE { + if (image_cursors_->SetDisplay(display, display.device_scale_factor())) + SetCursor(delegate->GetCursor(), delegate); + } + + virtual void SetCursor(gfx::NativeCursor cursor, + wm::NativeCursorManagerDelegate* delegate) OVERRIDE { + image_cursors_->SetPlatformCursor(&cursor); + cursor.set_device_scale_factor(image_cursors_->GetScale()); + delegate->CommitCursor(cursor); + + if (delegate->IsCursorVisible()) + ApplyCursor(cursor); + } + + virtual void SetVisibility( + bool visible, + wm::NativeCursorManagerDelegate* delegate) OVERRIDE { + delegate->CommitVisibility(visible); + + if (visible) { + SetCursor(delegate->GetCursor(), delegate); + } else { + gfx::NativeCursor invisible_cursor(ui::kCursorNone); + image_cursors_->SetPlatformCursor(&invisible_cursor); + ApplyCursor(invisible_cursor); + } + } + + virtual void SetCursorSet( + ui::CursorSetType cursor_set, + wm::NativeCursorManagerDelegate* delegate) OVERRIDE { + image_cursors_->SetCursorSet(cursor_set); + delegate->CommitCursorSet(cursor_set); + if (delegate->IsCursorVisible()) + SetCursor(delegate->GetCursor(), delegate); + } + + virtual void SetMouseEventsEnabled( + bool enabled, + wm::NativeCursorManagerDelegate* delegate) OVERRIDE { + delegate->CommitMouseEventsEnabled(enabled); + SetVisibility(delegate->IsCursorVisible(), delegate); + } + + private: + // Sets |cursor| as the active cursor within Aura. + void ApplyCursor(gfx::NativeCursor cursor) { host_->SetCursor(cursor); } + + aura::WindowTreeHost* host_; // Not owned. + + scoped_ptr<ui::ImageCursors> image_cursors_; + + DISALLOW_COPY_AND_ASSIGN(ShellNativeCursorManager); +}; + +class AppsFocusRules : public wm::BaseFocusRules { + public: + AppsFocusRules() {} + virtual ~AppsFocusRules() {} + + virtual bool SupportsChildActivation(aura::Window* window) const OVERRIDE { + return true; + } + + private: + DISALLOW_COPY_AND_ASSIGN(AppsFocusRules); +}; + +ShellDesktopController* g_instance = NULL; + +} // namespace + +ShellDesktopController::ShellDesktopController() { +#if defined(OS_CHROMEOS) + display_configurator_.reset(new ui::DisplayConfigurator); + display_configurator_->Init(false); + display_configurator_->ForceInitialConfigure(0); + display_configurator_->AddObserver(this); +#endif + aura::Env::CreateInstance(true); + aura::Env::GetInstance()->set_context_factory(content::GetContextFactory()); + + g_instance = this; +} + +ShellDesktopController::~ShellDesktopController() { + app_window_controller_.reset(); + g_instance = NULL; + DestroyRootWindow(); + aura::Env::DeleteInstance(); +} + +// static +ShellDesktopController* ShellDesktopController::instance() { + return g_instance; +} + +void ShellDesktopController::SetAppWindowController( + ShellAppWindowController* app_window_controller) { + app_window_controller_.reset(app_window_controller); +} + +ShellAppWindow* ShellDesktopController::CreateAppWindow( + content::BrowserContext* context) { + return app_window_controller_->CreateAppWindow(context); +} + +void ShellDesktopController::CloseAppWindows() { + if (app_window_controller_) + app_window_controller_->CloseAppWindows(); +} + +aura::Window* ShellDesktopController::GetDefaultParent( + aura::Window* context, + aura::Window* window, + const gfx::Rect& bounds) { + return host_->window(); +} + +#if defined(OS_CHROMEOS) +void ShellDesktopController::OnDisplayModeChanged( + const std::vector<ui::DisplayConfigurator::DisplayState>& displays) { + gfx::Size size = GetPrimaryDisplaySize(); + if (!size.IsEmpty()) + host_->UpdateRootWindowSize(size); +} +#endif + +void ShellDesktopController::OnHostCloseRequested( + const aura::WindowTreeHost* host) { + DCHECK_EQ(host_.get(), host); + CloseAppWindows(); + base::MessageLoop::current()->PostTask(FROM_HERE, + base::MessageLoop::QuitClosure()); +} + +void ShellDesktopController::CreateRootWindow() { + // Set up basic pieces of ui::wm. + gfx::Size size; + base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); + if (command_line->HasSwitch(switches::kAppShellHostWindowBounds)) { + const std::string size_str = + command_line->GetSwitchValueASCII(switches::kAppShellHostWindowBounds); + int width, height; + CHECK_EQ(2, sscanf(size_str.c_str(), "%dx%d", &width, &height)); + size = gfx::Size(width, height); + } else { + size = GetPrimaryDisplaySize(); + } + if (size.IsEmpty()) + size = gfx::Size(1280, 720); + + test_screen_.reset(aura::TestScreen::Create(size)); + // TODO(jamescook): Replace this with a real Screen implementation. + gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE, test_screen_.get()); + // TODO(mukai): Set up input method. + + host_.reset(test_screen_->CreateHostForPrimaryDisplay()); + host_->InitHost(); + aura::client::SetWindowTreeClient(host_->window(), this); + root_window_event_filter_.reset(new wm::CompoundEventFilter); + host_->window()->AddPreTargetHandler(root_window_event_filter_.get()); + InitWindowManager(); + + host_->AddObserver(this); + + // Ensure the X window gets mapped. + host_->Show(); +} + +void ShellDesktopController::InitWindowManager() { + wm::FocusController* focus_controller = + new wm::FocusController(CreateFocusRules()); + aura::client::SetFocusClient(host_->window(), focus_controller); + host_->window()->AddPreTargetHandler(focus_controller); + aura::client::SetActivationClient(host_->window(), focus_controller); + focus_client_.reset(focus_controller); + + input_method_filter_.reset( + new wm::InputMethodEventFilter(host_->GetAcceleratedWidget())); + input_method_filter_->SetInputMethodPropertyInRootWindow(host_->window()); + root_window_event_filter_->AddHandler(input_method_filter_.get()); + + capture_client_.reset( + new aura::client::DefaultCaptureClient(host_->window())); + + // Ensure new windows fill the display. + host_->window()->SetLayoutManager(new FillLayout); + + cursor_manager_.reset( + new wm::CursorManager(scoped_ptr<wm::NativeCursorManager>( + new ShellNativeCursorManager(host_.get())))); + cursor_manager_->SetDisplay( + gfx::Screen::GetNativeScreen()->GetPrimaryDisplay()); + cursor_manager_->SetCursor(ui::kCursorPointer); + aura::client::SetCursorClient(host_->window(), cursor_manager_.get()); + + user_activity_detector_.reset(new wm::UserActivityDetector); + host_->event_processor()->GetRootTarget()->AddPreTargetHandler( + user_activity_detector_.get()); +#if defined(OS_CHROMEOS) + user_activity_notifier_.reset( + new ui::UserActivityPowerManagerNotifier(user_activity_detector_.get())); +#endif +} + +wm::FocusRules* ShellDesktopController::CreateFocusRules() { + return new AppsFocusRules(); +} + +void ShellDesktopController::DestroyRootWindow() { + host_->RemoveObserver(this); + if (input_method_filter_) + root_window_event_filter_->RemoveHandler(input_method_filter_.get()); + if (user_activity_detector_) { + host_->event_processor()->GetRootTarget()->RemovePreTargetHandler( + user_activity_detector_.get()); + } + wm::FocusController* focus_controller = + static_cast<wm::FocusController*>(focus_client_.get()); + if (focus_controller) { + host_->window()->RemovePreTargetHandler(focus_controller); + aura::client::SetActivationClient(host_->window(), NULL); + } + root_window_event_filter_.reset(); + capture_client_.reset(); + input_method_filter_.reset(); + focus_client_.reset(); + cursor_manager_.reset(); +#if defined(OS_CHROMEOS) + user_activity_notifier_.reset(); +#endif + user_activity_detector_.reset(); + host_.reset(); +} + +gfx::Size ShellDesktopController::GetPrimaryDisplaySize() { +#if defined(OS_CHROMEOS) + const std::vector<ui::DisplayConfigurator::DisplayState>& displays = + display_configurator_->cached_displays(); + if (displays.empty()) + return gfx::Size(); + const ui::DisplayMode* mode = displays[0].display->current_mode(); + return mode ? mode->size() : gfx::Size(); +#else + return gfx::Size(); +#endif +} + +} // namespace extensions diff --git a/extensions/shell/browser/shell_desktop_controller.h b/extensions/shell/browser/shell_desktop_controller.h new file mode 100644 index 0000000..afaef8a --- /dev/null +++ b/extensions/shell/browser/shell_desktop_controller.h @@ -0,0 +1,149 @@ +// Copyright 2014 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 EXTENSIONS_SHELL_BROWSER_SHELL_DESKTOP_CONTROLLER_H_ +#define EXTENSIONS_SHELL_BROWSER_SHELL_DESKTOP_CONTROLLER_H_ + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "base/memory/scoped_ptr.h" +#include "ui/aura/client/window_tree_client.h" +#include "ui/aura/window_tree_host_observer.h" + +#if defined(OS_CHROMEOS) +#include "ui/display/chromeos/display_configurator.h" +#endif + +namespace aura { +class TestScreen; +class Window; +class WindowTreeHost; +namespace client { +class DefaultCaptureClient; +class FocusClient; +} +} + +namespace content { +class BrowserContext; +} + +namespace gfx { +class Size; +} + +#if defined(OS_CHROMEOS) +namespace ui { +class UserActivityPowerManagerNotifier; +} +#endif + +namespace wm { +class CompoundEventFilter; +class CursorManager; +class FocusRules; +class InputMethodEventFilter; +class UserActivityDetector; +} + +namespace extensions { + +class ShellAppWindow; +class ShellAppWindowController; + +// Handles desktop-related tasks for app_shell. +class ShellDesktopController : public aura::client::WindowTreeClient, + public aura::WindowTreeHostObserver +#if defined(OS_CHROMEOS) + , + public ui::DisplayConfigurator::Observer +#endif + { + public: + ShellDesktopController(); + virtual ~ShellDesktopController(); + + // Returns the single instance of the desktop. (Stateless functions like + // ShellAppWindowCreateFunction need to be able to access the desktop, so + // we need a singleton somewhere). + static ShellDesktopController* instance(); + + aura::WindowTreeHost* host() { return host_.get(); } + + // Creates the window that hosts the app. + void CreateRootWindow(); + + // Sets the controller to create/close the app windows. Takes the ownership of + // |app_window_controller|. + void SetAppWindowController(ShellAppWindowController* app_window_controller); + + // Creates a new app window and adds it to the desktop. The desktop maintains + // ownership of the window. + ShellAppWindow* CreateAppWindow(content::BrowserContext* context); + + // Closes and destroys the app windows. + void CloseAppWindows(); + + // Overridden from aura::client::WindowTreeClient: + virtual aura::Window* GetDefaultParent(aura::Window* context, + aura::Window* window, + const gfx::Rect& bounds) OVERRIDE; + +#if defined(OS_CHROMEOS) + // ui::DisplayConfigurator::Observer overrides. + virtual void OnDisplayModeChanged(const std::vector< + ui::DisplayConfigurator::DisplayState>& displays) OVERRIDE; +#endif + + // aura::WindowTreeHostObserver overrides: + virtual void OnHostCloseRequested(const aura::WindowTreeHost* host) OVERRIDE; + + protected: + // Creates and sets the aura clients and window manager stuff. Subclass may + // initialize different sets of the clients. + virtual void InitWindowManager(); + + // Creates a focus rule that is to be used in the InitWindowManager. + virtual wm::FocusRules* CreateFocusRules(); + + private: + // Closes and destroys the root window hosting the app. + void DestroyRootWindow(); + + // Returns the dimensions (in pixels) of the primary display, or an empty size + // if the dimensions can't be determined or no display is connected. + gfx::Size GetPrimaryDisplaySize(); + +#if defined(OS_CHROMEOS) + scoped_ptr<ui::DisplayConfigurator> display_configurator_; +#endif + + scoped_ptr<aura::TestScreen> test_screen_; + + scoped_ptr<aura::WindowTreeHost> host_; + + scoped_ptr<wm::CompoundEventFilter> root_window_event_filter_; + + scoped_ptr<aura::client::DefaultCaptureClient> capture_client_; + + scoped_ptr<wm::InputMethodEventFilter> input_method_filter_; + + scoped_ptr<aura::client::FocusClient> focus_client_; + + scoped_ptr<wm::CursorManager> cursor_manager_; + + scoped_ptr<wm::UserActivityDetector> user_activity_detector_; +#if defined(OS_CHROMEOS) + scoped_ptr<ui::UserActivityPowerManagerNotifier> user_activity_notifier_; +#endif + + // The desktop supports a single app window. + scoped_ptr<ShellAppWindowController> app_window_controller_; + + DISALLOW_COPY_AND_ASSIGN(ShellDesktopController); +}; + +} // namespace extensions + +#endif // EXTENSIONS_SHELL_BROWSER_SHELL_DESKTOP_CONTROLLER_H_ diff --git a/extensions/shell/browser/shell_extension_system.cc b/extensions/shell/browser/shell_extension_system.cc new file mode 100644 index 0000000..db14d32 --- /dev/null +++ b/extensions/shell/browser/shell_extension_system.cc @@ -0,0 +1,196 @@ +// Copyright 2014 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 "extensions/shell/browser/shell_extension_system.h" + +#include <string> + +#include "base/file_util.h" +#include "base/files/file_path.h" +#include "chrome/browser/chrome_notification_types.h" +#include "content/public/browser/browser_context.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/notification_details.h" +#include "content/public/browser/notification_service.h" +#include "content/public/browser/notification_source.h" +#include "extensions/browser/api/app_runtime/app_runtime_api.h" +#include "extensions/browser/event_router.h" +#include "extensions/browser/extension_prefs.h" +#include "extensions/browser/extension_registry.h" +#include "extensions/browser/info_map.h" +#include "extensions/browser/lazy_background_task_queue.h" +#include "extensions/browser/process_manager.h" +#include "extensions/browser/quota_service.h" +#include "extensions/browser/runtime_data.h" +#include "extensions/common/file_util.h" +#include "extensions/shell/browser/api/shell/shell_api.h" + +using content::BrowserContext; +using content::BrowserThread; + +namespace extensions { + +ShellExtensionSystem::ShellExtensionSystem(BrowserContext* browser_context) + : browser_context_(browser_context) { +} + +ShellExtensionSystem::~ShellExtensionSystem() { +} + +bool ShellExtensionSystem::LoadApp(const base::FilePath& app_dir) { + // app_shell only supports unpacked extensions. + // NOTE: If you add packed extension support consider removing the flag + // FOLLOW_SYMLINKS_ANYWHERE below. Packed extensions should not have symlinks. + CHECK(base::DirectoryExists(app_dir)) << app_dir.AsUTF8Unsafe(); + int load_flags = Extension::FOLLOW_SYMLINKS_ANYWHERE; + std::string load_error; + extension_ = file_util::LoadExtension( + app_dir, Manifest::COMMAND_LINE, load_flags, &load_error); + if (!extension_) { + LOG(ERROR) << "Loading extension at " << app_dir.value() + << " failed with: " << load_error; + return false; + } + app_id_ = extension_->id(); + + // TODO(jamescook): We may want to do some of these things here: + // * Create a PermissionsUpdater. + // * Call PermissionsUpdater::GrantActivePermissions(). + // * Call ExtensionService::SatisfyImports(). + // * Call ExtensionPrefs::OnExtensionInstalled(). + // * Send NOTIFICATION_EXTENSION_WILL_BE_INSTALLED_DEPRECATED. + + ExtensionRegistry::Get(browser_context_)->AddEnabled(extension_); + + RegisterExtensionWithRequestContexts(extension_); + + content::NotificationService::current()->Notify( + chrome::NOTIFICATION_EXTENSION_LOADED_DEPRECATED, + content::Source<BrowserContext>(browser_context_), + content::Details<const Extension>(extension_)); + + // Inform the rest of the extensions system to start. + ready_.Signal(); + content::NotificationService::current()->Notify( + chrome::NOTIFICATION_EXTENSIONS_READY, + content::Source<BrowserContext>(browser_context_), + content::NotificationService::NoDetails()); + return true; +} + +void ShellExtensionSystem::LaunchApp() { + // Send the onLaunched event. + DCHECK(extension_.get()); + AppRuntimeEventRouter::DispatchOnLaunchedEvent(browser_context_, + extension_.get()); +} + +void ShellExtensionSystem::Shutdown() { +} + +void ShellExtensionSystem::InitForRegularProfile(bool extensions_enabled) { + runtime_data_.reset( + new RuntimeData(ExtensionRegistry::Get(browser_context_))); + lazy_background_task_queue_.reset( + new LazyBackgroundTaskQueue(browser_context_)); + event_router_.reset( + new EventRouter(browser_context_, ExtensionPrefs::Get(browser_context_))); + process_manager_.reset(ProcessManager::Create(browser_context_)); + quota_service_.reset(new QuotaService); +} + +ExtensionService* ShellExtensionSystem::extension_service() { + return NULL; +} + +RuntimeData* ShellExtensionSystem::runtime_data() { + return runtime_data_.get(); +} + +ManagementPolicy* ShellExtensionSystem::management_policy() { + return NULL; +} + +UserScriptMaster* ShellExtensionSystem::user_script_master() { + return NULL; +} + +ProcessManager* ShellExtensionSystem::process_manager() { + return process_manager_.get(); +} + +StateStore* ShellExtensionSystem::state_store() { + return NULL; +} + +StateStore* ShellExtensionSystem::rules_store() { + return NULL; +} + +InfoMap* ShellExtensionSystem::info_map() { + if (!info_map_.get()) + info_map_ = new InfoMap; + return info_map_; +} + +LazyBackgroundTaskQueue* ShellExtensionSystem::lazy_background_task_queue() { + return lazy_background_task_queue_.get(); +} + +EventRouter* ShellExtensionSystem::event_router() { + return event_router_.get(); +} + +ExtensionWarningService* ShellExtensionSystem::warning_service() { + return NULL; +} + +Blacklist* ShellExtensionSystem::blacklist() { + return NULL; +} + +ErrorConsole* ShellExtensionSystem::error_console() { + return NULL; +} + +InstallVerifier* ShellExtensionSystem::install_verifier() { + return NULL; +} + +QuotaService* ShellExtensionSystem::quota_service() { + return quota_service_.get(); +} + +void ShellExtensionSystem::RegisterExtensionWithRequestContexts( + const Extension* extension) { + BrowserThread::PostTask(BrowserThread::IO, + FROM_HERE, + base::Bind(&InfoMap::AddExtension, + info_map(), + make_scoped_refptr(extension), + base::Time::Now(), + false, + false)); +} + +void ShellExtensionSystem::UnregisterExtensionWithRequestContexts( + const std::string& extension_id, + const UnloadedExtensionInfo::Reason reason) { +} + +const OneShotEvent& ShellExtensionSystem::ready() const { + return ready_; +} + +ContentVerifier* ShellExtensionSystem::content_verifier() { + return NULL; +} + +scoped_ptr<ExtensionSet> ShellExtensionSystem::GetDependentExtensions( + const Extension* extension) { + scoped_ptr<ExtensionSet> empty(new ExtensionSet()); + return empty.PassAs<ExtensionSet>(); +} + +} // namespace extensions diff --git a/extensions/shell/browser/shell_extension_system.h b/extensions/shell/browser/shell_extension_system.h new file mode 100644 index 0000000..b47c9a5 --- /dev/null +++ b/extensions/shell/browser/shell_extension_system.h @@ -0,0 +1,102 @@ +// Copyright 2014 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 EXTENSIONS_SHELL_BROWSER_SHELL_EXTENSION_SYSTEM_H_ +#define EXTENSIONS_SHELL_BROWSER_SHELL_EXTENSION_SYSTEM_H_ + +#include <vector> + +#include "base/compiler_specific.h" +#include "extensions/browser/extension_system.h" +#include "extensions/common/one_shot_event.h" + +class BrowserContextKeyedServiceFactory; + +namespace base { +class FilePath; +} + +namespace content { +class BrowserContext; +} + +namespace extensions { + +class EventRouter; +class InfoMap; +class LazyBackgroundTaskQueue; +class ProcessManager; +class RendererStartupHelper; + +// A simplified version of ExtensionSystem for app_shell. Allows +// app_shell to skip initialization of services it doesn't need. +class ShellExtensionSystem : public ExtensionSystem { + public: + explicit ShellExtensionSystem(content::BrowserContext* browser_context); + virtual ~ShellExtensionSystem(); + + // Loads an unpacked application from a directory. Returns true on success. + bool LoadApp(const base::FilePath& app_dir); + + // Launch the currently loaded app. + void LaunchApp(); + + // KeyedService implementation: + virtual void Shutdown() OVERRIDE; + + scoped_refptr<Extension> extension() { return extension_; } + + // ExtensionSystem implementation: + virtual void InitForRegularProfile(bool extensions_enabled) OVERRIDE; + virtual ExtensionService* extension_service() OVERRIDE; + virtual RuntimeData* runtime_data() OVERRIDE; + virtual ManagementPolicy* management_policy() OVERRIDE; + virtual UserScriptMaster* user_script_master() OVERRIDE; + virtual ProcessManager* process_manager() OVERRIDE; + virtual StateStore* state_store() OVERRIDE; + virtual StateStore* rules_store() OVERRIDE; + virtual InfoMap* info_map() OVERRIDE; + virtual LazyBackgroundTaskQueue* lazy_background_task_queue() OVERRIDE; + virtual EventRouter* event_router() OVERRIDE; + virtual ExtensionWarningService* warning_service() OVERRIDE; + virtual Blacklist* blacklist() OVERRIDE; + virtual ErrorConsole* error_console() OVERRIDE; + virtual InstallVerifier* install_verifier() OVERRIDE; + virtual QuotaService* quota_service() OVERRIDE; + virtual void RegisterExtensionWithRequestContexts( + const Extension* extension) OVERRIDE; + virtual void UnregisterExtensionWithRequestContexts( + const std::string& extension_id, + const UnloadedExtensionInfo::Reason reason) OVERRIDE; + virtual const OneShotEvent& ready() const OVERRIDE; + virtual ContentVerifier* content_verifier() OVERRIDE; + virtual scoped_ptr<ExtensionSet> GetDependentExtensions( + const Extension* extension) OVERRIDE; + + private: + content::BrowserContext* browser_context_; // Not owned. + + // Extension ID for the app. + std::string app_id_; + + scoped_refptr<Extension> extension_; + + // Data to be accessed on the IO thread. Must outlive process_manager_. + scoped_refptr<InfoMap> info_map_; + + scoped_ptr<RuntimeData> runtime_data_; + scoped_ptr<LazyBackgroundTaskQueue> lazy_background_task_queue_; + scoped_ptr<EventRouter> event_router_; + scoped_ptr<ProcessManager> process_manager_; + scoped_ptr<QuotaService> quota_service_; + + // Signaled when the extension system has completed its startup tasks. + OneShotEvent ready_; + + DISALLOW_COPY_AND_ASSIGN(ShellExtensionSystem); +}; + +} // namespace extensions + +#endif // EXTENSIONS_SHELL_BROWSER_SHELL_EXTENSION_SYSTEM_H_ diff --git a/extensions/shell/browser/shell_extension_system_factory.cc b/extensions/shell/browser/shell_extension_system_factory.cc new file mode 100644 index 0000000..73ad7d0 --- /dev/null +++ b/extensions/shell/browser/shell_extension_system_factory.cc @@ -0,0 +1,52 @@ +// Copyright 2014 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 "extensions/shell/browser/shell_extension_system_factory.h" + +#include "components/keyed_service/content/browser_context_dependency_manager.h" +#include "extensions/browser/extension_prefs_factory.h" +#include "extensions/browser/extension_registry_factory.h" +#include "extensions/shell/browser/shell_extension_system.h" + +using content::BrowserContext; + +namespace extensions { + +ExtensionSystem* ShellExtensionSystemFactory::GetForBrowserContext( + BrowserContext* context) { + return static_cast<ShellExtensionSystem*>( + GetInstance()->GetServiceForBrowserContext(context, true)); +} + +// static +ShellExtensionSystemFactory* ShellExtensionSystemFactory::GetInstance() { + return Singleton<ShellExtensionSystemFactory>::get(); +} + +ShellExtensionSystemFactory::ShellExtensionSystemFactory() + : ExtensionSystemProvider("ShellExtensionSystem", + BrowserContextDependencyManager::GetInstance()) { + DependsOn(ExtensionPrefsFactory::GetInstance()); + DependsOn(ExtensionRegistryFactory::GetInstance()); +} + +ShellExtensionSystemFactory::~ShellExtensionSystemFactory() { +} + +KeyedService* ShellExtensionSystemFactory::BuildServiceInstanceFor( + BrowserContext* context) const { + return new ShellExtensionSystem(context); +} + +BrowserContext* ShellExtensionSystemFactory::GetBrowserContextToUse( + BrowserContext* context) const { + // Use a separate instance for incognito. + return context; +} + +bool ShellExtensionSystemFactory::ServiceIsCreatedWithBrowserContext() const { + return true; +} + +} // namespace extensions diff --git a/extensions/shell/browser/shell_extension_system_factory.h b/extensions/shell/browser/shell_extension_system_factory.h new file mode 100644 index 0000000..5d0a883 --- /dev/null +++ b/extensions/shell/browser/shell_extension_system_factory.h @@ -0,0 +1,40 @@ +// Copyright 2014 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 EXTENSIONS_SHELL_BROWSER_SHELL_EXTENSION_SYSTEM_FACTORY_H_ +#define EXTENSIONS_SHELL_BROWSER_SHELL_EXTENSION_SYSTEM_FACTORY_H_ + +#include "base/memory/singleton.h" +#include "extensions/browser/extension_system_provider.h" + +namespace extensions { + +// A factory that provides ShellExtensionSystem for app_shell. +class ShellExtensionSystemFactory : public ExtensionSystemProvider { + public: + // ExtensionSystemProvider implementation: + virtual ExtensionSystem* GetForBrowserContext( + content::BrowserContext* context) OVERRIDE; + + static ShellExtensionSystemFactory* GetInstance(); + + private: + friend struct DefaultSingletonTraits<ShellExtensionSystemFactory>; + + ShellExtensionSystemFactory(); + virtual ~ShellExtensionSystemFactory(); + + // BrowserContextKeyedServiceFactory implementation: + virtual KeyedService* BuildServiceInstanceFor( + content::BrowserContext* context) const OVERRIDE; + virtual content::BrowserContext* GetBrowserContextToUse( + content::BrowserContext* context) const OVERRIDE; + virtual bool ServiceIsCreatedWithBrowserContext() const OVERRIDE; + + DISALLOW_COPY_AND_ASSIGN(ShellExtensionSystemFactory); +}; + +} // namespace extensions + +#endif // EXTENSIONS_SHELL_BROWSER_SHELL_EXTENSION_SYSTEM_FACTORY_H_ diff --git a/extensions/shell/browser/shell_extension_web_contents_observer.cc b/extensions/shell/browser/shell_extension_web_contents_observer.cc new file mode 100644 index 0000000..9dc3691 --- /dev/null +++ b/extensions/shell/browser/shell_extension_web_contents_observer.cc @@ -0,0 +1,20 @@ +// Copyright 2014 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 "extensions/shell/browser/shell_extension_web_contents_observer.h" + +DEFINE_WEB_CONTENTS_USER_DATA_KEY( + extensions::ShellExtensionWebContentsObserver); + +namespace extensions { + +ShellExtensionWebContentsObserver::ShellExtensionWebContentsObserver( + content::WebContents* web_contents) + : ExtensionWebContentsObserver(web_contents) { +} + +ShellExtensionWebContentsObserver::~ShellExtensionWebContentsObserver() { +} + +} // namespace extensions diff --git a/extensions/shell/browser/shell_extension_web_contents_observer.h b/extensions/shell/browser/shell_extension_web_contents_observer.h new file mode 100644 index 0000000..7cec042 --- /dev/null +++ b/extensions/shell/browser/shell_extension_web_contents_observer.h @@ -0,0 +1,29 @@ +// Copyright 2014 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 EXTENSIONS_SHELL_BROWSER_SHELL_EXTENSION_WEB_CONTENTS_OBSERVER_H_ +#define EXTENSIONS_SHELL_BROWSER_SHELL_EXTENSION_WEB_CONTENTS_OBSERVER_H_ + +#include "content/public/browser/web_contents_user_data.h" +#include "extensions/browser/extension_web_contents_observer.h" + +namespace extensions { + +// The app_shell version of ExtensionWebContentsObserver. +class ShellExtensionWebContentsObserver + : public ExtensionWebContentsObserver, + public content::WebContentsUserData<ShellExtensionWebContentsObserver> { + private: + friend class content::WebContentsUserData<ShellExtensionWebContentsObserver>; + + explicit ShellExtensionWebContentsObserver( + content::WebContents* web_contents); + virtual ~ShellExtensionWebContentsObserver(); + + DISALLOW_COPY_AND_ASSIGN(ShellExtensionWebContentsObserver); +}; + +} // namespace extensions + +#endif // EXTENSIONS_SHELL_BROWSER_SHELL_EXTENSION_WEB_CONTENTS_OBSERVER_H_ diff --git a/extensions/shell/browser/shell_extensions_browser_client.cc b/extensions/shell/browser/shell_extensions_browser_client.cc new file mode 100644 index 0000000..c725ebd --- /dev/null +++ b/extensions/shell/browser/shell_extensions_browser_client.cc @@ -0,0 +1,242 @@ +// Copyright 2014 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 "extensions/shell/browser/shell_extensions_browser_client.h" + +#include "base/prefs/pref_service.h" +#include "base/prefs/pref_service_factory.h" +#include "base/prefs/testing_pref_store.h" +#include "components/pref_registry/pref_registry_syncable.h" +#include "components/user_prefs/user_prefs.h" +#include "extensions/browser/api/extensions_api_client.h" +#include "extensions/browser/app_sorting.h" +#include "extensions/browser/extension_function_registry.h" +#include "extensions/browser/extension_host_delegate.h" +#include "extensions/browser/extension_prefs.h" +#include "extensions/common/api/generated_api.h" +#include "extensions/shell/browser/shell_app_sorting.h" +#include "extensions/shell/browser/shell_extension_system_factory.h" +#include "extensions/shell/browser/shell_extension_web_contents_observer.h" +#include "extensions/shell/browser/shell_runtime_api_delegate.h" +#include "extensions/shell/common/api/generated_api.h" + +using content::BrowserContext; + +namespace extensions { +namespace { + +// See chrome::RegisterProfilePrefs() in chrome/browser/prefs/browser_prefs.cc +void RegisterPrefs(user_prefs::PrefRegistrySyncable* registry) { + ExtensionPrefs::RegisterProfilePrefs(registry); +} + +// A minimal ExtensionHostDelegate. +class ShellExtensionHostDelegate : public ExtensionHostDelegate { + public: + ShellExtensionHostDelegate() {} + virtual ~ShellExtensionHostDelegate() {} + + // ExtensionHostDelegate implementation. + virtual void OnExtensionHostCreated( + content::WebContents* web_contents) OVERRIDE; + + virtual void OnRenderViewCreatedForBackgroundPage( + ExtensionHost* host) OVERRIDE {} + + virtual content::JavaScriptDialogManager* GetJavaScriptDialogManager() + OVERRIDE { + // TODO(jamescook): Create a JavaScriptDialogManager or reuse the one from + // content_shell. + NOTREACHED(); + return NULL; + } + + virtual void CreateTab(content::WebContents* web_contents, + const std::string& extension_id, + WindowOpenDisposition disposition, + const gfx::Rect& initial_pos, + bool user_gesture) OVERRIDE { + // TODO(jamescook): Should app_shell support opening popup windows? + NOTREACHED(); + } + + virtual void ProcessMediaAccessRequest( + content::WebContents* web_contents, + const content::MediaStreamRequest& request, + const content::MediaResponseCallback& callback, + const Extension* extension) OVERRIDE { + // app_shell does not support media capture. + NOTREACHED(); + } +}; + +void ShellExtensionHostDelegate::OnExtensionHostCreated( + content::WebContents* web_contents) { + ShellExtensionWebContentsObserver::CreateForWebContents(web_contents); +} + +} // namespace + +ShellExtensionsBrowserClient::ShellExtensionsBrowserClient( + BrowserContext* context) + : browser_context_(context), api_client_(new ExtensionsAPIClient) { + // Set up the preferences service. + base::PrefServiceFactory factory; + factory.set_user_prefs(new TestingPrefStore); + factory.set_extension_prefs(new TestingPrefStore); + // app_shell should not require syncable preferences, but for now we need to + // recycle some of the RegisterProfilePrefs() code in Chrome. + // TODO(jamescook): Convert this to PrefRegistrySimple. + user_prefs::PrefRegistrySyncable* pref_registry = + new user_prefs::PrefRegistrySyncable; + // Prefs should be registered before the PrefService is created. + RegisterPrefs(pref_registry); + prefs_ = factory.Create(pref_registry).Pass(); + user_prefs::UserPrefs::Set(browser_context_, prefs_.get()); +} + +ShellExtensionsBrowserClient::~ShellExtensionsBrowserClient() { +} + +bool ShellExtensionsBrowserClient::IsShuttingDown() { + return false; +} + +bool ShellExtensionsBrowserClient::AreExtensionsDisabled( + const base::CommandLine& command_line, + BrowserContext* context) { + return false; +} + +bool ShellExtensionsBrowserClient::IsValidContext(BrowserContext* context) { + return context == browser_context_; +} + +bool ShellExtensionsBrowserClient::IsSameContext(BrowserContext* first, + BrowserContext* second) { + return first == second; +} + +bool ShellExtensionsBrowserClient::HasOffTheRecordContext( + BrowserContext* context) { + return false; +} + +BrowserContext* ShellExtensionsBrowserClient::GetOffTheRecordContext( + BrowserContext* context) { + // app_shell only supports a single context. + return NULL; +} + +BrowserContext* ShellExtensionsBrowserClient::GetOriginalContext( + BrowserContext* context) { + return context; +} + +bool ShellExtensionsBrowserClient::IsGuestSession( + BrowserContext* context) const { + return false; +} + +bool ShellExtensionsBrowserClient::IsExtensionIncognitoEnabled( + const std::string& extension_id, + content::BrowserContext* context) const { + return false; +} + +bool ShellExtensionsBrowserClient::CanExtensionCrossIncognito( + const Extension* extension, + content::BrowserContext* context) const { + return false; +} + +bool ShellExtensionsBrowserClient::IsWebViewRequest( + net::URLRequest* request) const { + return false; +} + +net::URLRequestJob* +ShellExtensionsBrowserClient::MaybeCreateResourceBundleRequestJob( + net::URLRequest* request, + net::NetworkDelegate* network_delegate, + const base::FilePath& directory_path, + const std::string& content_security_policy, + bool send_cors_header) { + return NULL; +} + +bool ShellExtensionsBrowserClient::AllowCrossRendererResourceLoad( + net::URLRequest* request, + bool is_incognito, + const Extension* extension, + InfoMap* extension_info_map) { + // Note: This may need to change if app_shell supports webview. + return false; +} + +PrefService* ShellExtensionsBrowserClient::GetPrefServiceForContext( + BrowserContext* context) { + return prefs_.get(); +} + +void ShellExtensionsBrowserClient::GetEarlyExtensionPrefsObservers( + content::BrowserContext* context, + std::vector<ExtensionPrefsObserver*>* observers) const { +} + +ProcessManagerDelegate* +ShellExtensionsBrowserClient::GetProcessManagerDelegate() const { + return NULL; +} + +scoped_ptr<ExtensionHostDelegate> +ShellExtensionsBrowserClient::CreateExtensionHostDelegate() { + return scoped_ptr<ExtensionHostDelegate>(new ShellExtensionHostDelegate); +} + +bool ShellExtensionsBrowserClient::DidVersionUpdate(BrowserContext* context) { + // TODO(jamescook): We might want to tell extensions when app_shell updates. + return false; +} + +scoped_ptr<AppSorting> ShellExtensionsBrowserClient::CreateAppSorting() { + return scoped_ptr<AppSorting>(new ShellAppSorting); +} + +bool ShellExtensionsBrowserClient::IsRunningInForcedAppMode() { + return false; +} + +ApiActivityMonitor* ShellExtensionsBrowserClient::GetApiActivityMonitor( + BrowserContext* context) { + // app_shell doesn't monitor API function calls or events. + return NULL; +} + +ExtensionSystemProvider* +ShellExtensionsBrowserClient::GetExtensionSystemFactory() { + return ShellExtensionSystemFactory::GetInstance(); +} + +void ShellExtensionsBrowserClient::RegisterExtensionFunctions( + ExtensionFunctionRegistry* registry) const { + // Register core extension-system APIs. + core_api::GeneratedFunctionRegistry::RegisterAll(registry); + + // Register chrome.shell APIs. + shell_api::GeneratedFunctionRegistry::RegisterAll(registry); +} + +scoped_ptr<RuntimeAPIDelegate> +ShellExtensionsBrowserClient::CreateRuntimeAPIDelegate( + content::BrowserContext* context) const { + return scoped_ptr<RuntimeAPIDelegate>(new ShellRuntimeAPIDelegate()); +} + +ComponentExtensionResourceManager* +ShellExtensionsBrowserClient::GetComponentExtensionResourceManager() { + return NULL; +} + +} // namespace extensions diff --git a/extensions/shell/browser/shell_extensions_browser_client.h b/extensions/shell/browser/shell_extensions_browser_client.h new file mode 100644 index 0000000..648c7aa --- /dev/null +++ b/extensions/shell/browser/shell_extensions_browser_client.h @@ -0,0 +1,93 @@ +// Copyright 2014 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 EXTENSIONS_SHELL_BROWSER_SHELL_EXTENSIONS_BROWSER_CLIENT_H_ +#define EXTENSIONS_SHELL_BROWSER_SHELL_EXTENSIONS_BROWSER_CLIENT_H_ + +#include "base/compiler_specific.h" +#include "extensions/browser/extensions_browser_client.h" + +class PrefService; + +namespace extensions { + +class ExtensionsAPIClient; + +// An ExtensionsBrowserClient that supports a single content::BrowserContent +// with no related incognito context. +class ShellExtensionsBrowserClient : public ExtensionsBrowserClient { + public: + // |context| is the single BrowserContext used for IsValidContext() below. + explicit ShellExtensionsBrowserClient(content::BrowserContext* context); + virtual ~ShellExtensionsBrowserClient(); + + // ExtensionsBrowserClient overrides: + virtual bool IsShuttingDown() OVERRIDE; + virtual bool AreExtensionsDisabled(const base::CommandLine& command_line, + content::BrowserContext* context) OVERRIDE; + virtual bool IsValidContext(content::BrowserContext* context) OVERRIDE; + virtual bool IsSameContext(content::BrowserContext* first, + content::BrowserContext* second) OVERRIDE; + virtual bool HasOffTheRecordContext( + content::BrowserContext* context) OVERRIDE; + virtual content::BrowserContext* GetOffTheRecordContext( + content::BrowserContext* context) OVERRIDE; + virtual content::BrowserContext* GetOriginalContext( + content::BrowserContext* context) OVERRIDE; + virtual bool IsGuestSession(content::BrowserContext* context) const OVERRIDE; + virtual bool IsExtensionIncognitoEnabled( + const std::string& extension_id, + content::BrowserContext* context) const OVERRIDE; + virtual bool CanExtensionCrossIncognito( + const Extension* extension, + content::BrowserContext* context) const OVERRIDE; + virtual bool IsWebViewRequest(net::URLRequest* request) const OVERRIDE; + virtual net::URLRequestJob* MaybeCreateResourceBundleRequestJob( + net::URLRequest* request, + net::NetworkDelegate* network_delegate, + const base::FilePath& directory_path, + const std::string& content_security_policy, + bool send_cors_header) OVERRIDE; + virtual bool AllowCrossRendererResourceLoad( + net::URLRequest* request, + bool is_incognito, + const Extension* extension, + InfoMap* extension_info_map) OVERRIDE; + virtual PrefService* GetPrefServiceForContext( + content::BrowserContext* context) OVERRIDE; + virtual void GetEarlyExtensionPrefsObservers( + content::BrowserContext* context, + std::vector<ExtensionPrefsObserver*>* observers) const OVERRIDE; + virtual ProcessManagerDelegate* GetProcessManagerDelegate() const OVERRIDE; + virtual scoped_ptr<ExtensionHostDelegate> CreateExtensionHostDelegate() + OVERRIDE; + virtual bool DidVersionUpdate(content::BrowserContext* context) OVERRIDE; + virtual scoped_ptr<AppSorting> CreateAppSorting() OVERRIDE; + virtual bool IsRunningInForcedAppMode() OVERRIDE; + virtual ApiActivityMonitor* GetApiActivityMonitor( + content::BrowserContext* context) OVERRIDE; + virtual ExtensionSystemProvider* GetExtensionSystemFactory() OVERRIDE; + virtual void RegisterExtensionFunctions( + ExtensionFunctionRegistry* registry) const OVERRIDE; + virtual scoped_ptr<RuntimeAPIDelegate> CreateRuntimeAPIDelegate( + content::BrowserContext* context) const OVERRIDE; + virtual ComponentExtensionResourceManager* + GetComponentExtensionResourceManager() OVERRIDE; + + private: + // The single BrowserContext for app_shell. Not owned. + content::BrowserContext* browser_context_; + + // Support for extension APIs. + scoped_ptr<ExtensionsAPIClient> api_client_; + + // The PrefService for |browser_context_|. + scoped_ptr<PrefService> prefs_; + + DISALLOW_COPY_AND_ASSIGN(ShellExtensionsBrowserClient); +}; + +} // namespace extensions + +#endif // EXTENSIONS_SHELL_BROWSER_SHELL_EXTENSIONS_BROWSER_CLIENT_H_ diff --git a/extensions/shell/browser/shell_network_controller_chromeos.cc b/extensions/shell/browser/shell_network_controller_chromeos.cc new file mode 100644 index 0000000..d321e23 --- /dev/null +++ b/extensions/shell/browser/shell_network_controller_chromeos.cc @@ -0,0 +1,210 @@ +// Copyright 2014 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 "extensions/shell/browser/shell_network_controller_chromeos.h" + +#include "base/bind.h" +#include "base/location.h" +#include "base/logging.h" +#include "base/strings/stringprintf.h" +#include "base/time/time.h" +#include "chromeos/network/network_connection_handler.h" +#include "chromeos/network/network_handler.h" +#include "chromeos/network/network_handler_callbacks.h" +#include "chromeos/network/network_state.h" +#include "chromeos/network/network_state_handler.h" +#include "third_party/cros_system_api/dbus/service_constants.h" + +namespace extensions { + +namespace { + +// Frequency at which networks should be scanned when not connected to a network +// or when connected to a non-preferred network. +const int kScanIntervalSec = 10; + +void HandleEnableWifiError(const std::string& error_name, + scoped_ptr<base::DictionaryValue> error_data) { + LOG(WARNING) << "Unable to enable wifi: " << error_name; +} + +// Returns a human-readable name for the network described by |network|. +std::string GetNetworkName(const chromeos::NetworkState& network) { + return !network.name().empty() + ? network.name() + : base::StringPrintf("[%s]", network.type().c_str()); +} + +// Returns true if shill is either connected or connecting to a network. +bool IsConnectedOrConnecting() { + chromeos::NetworkStateHandler* state_handler = + chromeos::NetworkHandler::Get()->network_state_handler(); + return state_handler->ConnectedNetworkByType( + chromeos::NetworkTypePattern::Default()) || + state_handler->ConnectingNetworkByType( + chromeos::NetworkTypePattern::Default()); +} + +} // namespace + +ShellNetworkController::ShellNetworkController( + const std::string& preferred_network_name) + : state_(STATE_IDLE), + preferred_network_name_(preferred_network_name), + preferred_network_is_active_(false), + weak_ptr_factory_(this) { + chromeos::NetworkHandler::Initialize(); + chromeos::NetworkStateHandler* state_handler = + chromeos::NetworkHandler::Get()->network_state_handler(); + state_handler->AddObserver(this, FROM_HERE); + state_handler->SetTechnologyEnabled( + chromeos::NetworkTypePattern::Primitive(shill::kTypeWifi), + true, + base::Bind(&HandleEnableWifiError)); + + // If we're unconnected, trigger a connection attempt and start scanning. + NetworkConnectionStateChanged(NULL); +} + +ShellNetworkController::~ShellNetworkController() { + chromeos::NetworkHandler::Get()->network_state_handler()->RemoveObserver( + this, FROM_HERE); + chromeos::NetworkHandler::Shutdown(); +} + +void ShellNetworkController::NetworkListChanged() { + VLOG(1) << "Network list changed"; + ConnectIfUnconnected(); +} + +void ShellNetworkController::NetworkConnectionStateChanged( + const chromeos::NetworkState* network) { + if (network) { + VLOG(1) << "Network connection state changed:" + << " name=" << GetNetworkName(*network) + << " type=" << network->type() << " path=" << network->path() + << " state=" << network->connection_state(); + } else { + VLOG(1) << "Network connection state changed: [none]"; + } + + const chromeos::NetworkState* wifi_network = GetActiveWiFiNetwork(); + preferred_network_is_active_ = + wifi_network && wifi_network->name() == preferred_network_name_; + VLOG(2) << "Active WiFi network is " + << (wifi_network ? wifi_network->name() : std::string("[none]")); + + if (preferred_network_is_active_ || + (preferred_network_name_.empty() && wifi_network)) { + SetScanningEnabled(false); + } else { + SetScanningEnabled(true); + ConnectIfUnconnected(); + } +} + +const chromeos::NetworkState* ShellNetworkController::GetActiveWiFiNetwork() { + chromeos::NetworkStateHandler* state_handler = + chromeos::NetworkHandler::Get()->network_state_handler(); + const chromeos::NetworkState* network = state_handler->FirstNetworkByType( + chromeos::NetworkTypePattern::Primitive(shill::kTypeWifi)); + return network && + (network->IsConnectedState() || network->IsConnectingState()) + ? network + : NULL; +} + +void ShellNetworkController::SetScanningEnabled(bool enabled) { + const bool currently_enabled = scan_timer_.IsRunning(); + if (enabled == currently_enabled) + return; + + VLOG(1) << (enabled ? "Starting" : "Stopping") << " scanning"; + if (enabled) { + RequestScan(); + scan_timer_.Start(FROM_HERE, + base::TimeDelta::FromSeconds(kScanIntervalSec), + this, + &ShellNetworkController::RequestScan); + } else { + scan_timer_.Stop(); + } +} + +void ShellNetworkController::RequestScan() { + VLOG(1) << "Requesting scan"; + chromeos::NetworkHandler::Get()->network_state_handler()->RequestScan(); +} + +void ShellNetworkController::ConnectIfUnconnected() { + // Don't do anything if the default network is already the preferred one or if + // we have a pending request to connect to it. + if (preferred_network_is_active_ || + state_ == STATE_WAITING_FOR_PREFERRED_RESULT) + return; + + const chromeos::NetworkState* best_network = NULL; + bool can_connect_to_preferred_network = false; + + chromeos::NetworkHandler* handler = chromeos::NetworkHandler::Get(); + chromeos::NetworkStateHandler::NetworkStateList network_list; + handler->network_state_handler()->GetVisibleNetworkListByType( + chromeos::NetworkTypePattern::WiFi(), &network_list); + for (chromeos::NetworkStateHandler::NetworkStateList::const_iterator it = + network_list.begin(); + it != network_list.end(); + ++it) { + const chromeos::NetworkState* network = *it; + if (!network->connectable()) + continue; + + if (!preferred_network_name_.empty() && + network->name() == preferred_network_name_) { + best_network = network; + can_connect_to_preferred_network = true; + break; + } else if (!best_network) { + best_network = network; + } + } + + // Don't switch networks if we're already connecting/connected and wouldn't be + // switching to the preferred network. + if ((IsConnectedOrConnecting() || state_ != STATE_IDLE) && + !can_connect_to_preferred_network) + return; + + if (!best_network) { + VLOG(1) << "Didn't find any connectable networks"; + return; + } + + VLOG(1) << "Connecting to network " << GetNetworkName(*best_network) + << " with path " << best_network->path() << " and strength " + << best_network->signal_strength(); + state_ = can_connect_to_preferred_network + ? STATE_WAITING_FOR_PREFERRED_RESULT + : STATE_WAITING_FOR_NON_PREFERRED_RESULT; + handler->network_connection_handler()->ConnectToNetwork( + best_network->path(), + base::Bind(&ShellNetworkController::HandleConnectionSuccess, + weak_ptr_factory_.GetWeakPtr()), + base::Bind(&ShellNetworkController::HandleConnectionError, + weak_ptr_factory_.GetWeakPtr()), + false /* check_error_state */); +} + +void ShellNetworkController::HandleConnectionSuccess() { + VLOG(1) << "Successfully connected to network"; + state_ = STATE_IDLE; +} + +void ShellNetworkController::HandleConnectionError( + const std::string& error_name, + scoped_ptr<base::DictionaryValue> error_data) { + LOG(WARNING) << "Unable to connect to network: " << error_name; + state_ = STATE_IDLE; +} + +} // namespace extensions diff --git a/extensions/shell/browser/shell_network_controller_chromeos.h b/extensions/shell/browser/shell_network_controller_chromeos.h new file mode 100644 index 0000000..5299aa0 --- /dev/null +++ b/extensions/shell/browser/shell_network_controller_chromeos.h @@ -0,0 +1,86 @@ +// Copyright 2014 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 EXTENSIONS_SHELL_BROWSER_SHELL_NETWORK_CONTROLLER_CHROMEOS_H_ +#define EXTENSIONS_SHELL_BROWSER_SHELL_NETWORK_CONTROLLER_CHROMEOS_H_ + +#include <string> + +#include "base/compiler_specific.h" +#include "base/macros.h" +#include "base/memory/scoped_ptr.h" +#include "base/memory/weak_ptr.h" +#include "base/timer/timer.h" +#include "base/values.h" +#include "chromeos/network/network_state_handler_observer.h" + +namespace extensions { + +// Handles network-related tasks for app_shell on Chrome OS. +class ShellNetworkController : public chromeos::NetworkStateHandlerObserver { + public: + // This class must be instantiated after chromeos::DBusThreadManager and + // destroyed before it. + explicit ShellNetworkController(const std::string& preferred_network_name); + virtual ~ShellNetworkController(); + + // chromeos::NetworkStateHandlerObserver overrides: + virtual void NetworkListChanged() OVERRIDE; + virtual void NetworkConnectionStateChanged( + const chromeos::NetworkState* state) OVERRIDE; + + private: + // State of communication with the connection manager. + enum State { + // No in-progress requests. + STATE_IDLE = 0, + // Waiting for the result of an attempt to connect to the preferred network. + STATE_WAITING_FOR_PREFERRED_RESULT, + // Waiting for the result of an attempt to connect to a non-preferred + // network. + STATE_WAITING_FOR_NON_PREFERRED_RESULT, + }; + + // Returns the connected or connecting WiFi network or NULL if no network + // matches that description. + const chromeos::NetworkState* GetActiveWiFiNetwork(); + + // Controls whether scanning is performed periodically. + void SetScanningEnabled(bool enabled); + + // Asks the connection manager to scan for networks. + void RequestScan(); + + // If not currently connected or connecting, chooses a wireless network and + // asks the connection manager to connect to it. Also switches to + // |preferred_network_name_| if possible. + void ConnectIfUnconnected(); + + // Handles a successful or failed connection attempt. + void HandleConnectionSuccess(); + void HandleConnectionError(const std::string& error_name, + scoped_ptr<base::DictionaryValue> error_data); + + // Current status of communication with the chromeos::NetworkStateHandler. + // This is tracked to avoid sending duplicate requests before the handler has + // acknowledged the initial connection attempt. + State state_; + + // Invokes RequestScan() periodically. + base::RepeatingTimer<ShellNetworkController> scan_timer_; + + // Optionally-supplied name of the preferred network. + std::string preferred_network_name_; + + // True if the preferred network is connected or connecting. + bool preferred_network_is_active_; + + base::WeakPtrFactory<ShellNetworkController> weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(ShellNetworkController); +}; + +} // namespace extensions + +#endif // EXTENSIONS_SHELL_BROWSER_SHELL_NETWORK_CONTROLLER_CHROMEOS_H_ diff --git a/extensions/shell/browser/shell_omaha_query_params_delegate.cc b/extensions/shell/browser/shell_omaha_query_params_delegate.cc new file mode 100644 index 0000000..cd37c718 --- /dev/null +++ b/extensions/shell/browser/shell_omaha_query_params_delegate.cc @@ -0,0 +1,22 @@ +// Copyright 2014 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 "extensions/shell/browser/shell_omaha_query_params_delegate.h" + +namespace extensions { + +ShellOmahaQueryParamsDelegate::ShellOmahaQueryParamsDelegate() { +} + +ShellOmahaQueryParamsDelegate::~ShellOmahaQueryParamsDelegate() { +} + +std::string ShellOmahaQueryParamsDelegate::GetExtraParams() { + // This version number is high enough to be supported by Omaha + // (below 31 is unsupported), but it's fake enough to be obviously + // not a Chrome release. + return "&prodversion=38.1234.5678.9"; +} + +} // namespace extensions diff --git a/extensions/shell/browser/shell_omaha_query_params_delegate.h b/extensions/shell/browser/shell_omaha_query_params_delegate.h new file mode 100644 index 0000000..7ecb5ba --- /dev/null +++ b/extensions/shell/browser/shell_omaha_query_params_delegate.h @@ -0,0 +1,26 @@ +// Copyright 2014 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 EXTENSIONS_SHELL_BROWSER_SHELL_OMAHA_QUERY_PARAMS_DELEGATE_H_ +#define EXTENSIONS_SHELL_BROWSER_SHELL_OMAHA_QUERY_PARAMS_DELEGATE_H_ + +#include "components/omaha_query_params/omaha_query_params_delegate.h" + +namespace extensions { + +class ShellOmahaQueryParamsDelegate + : public omaha_query_params::OmahaQueryParamsDelegate { + public: + ShellOmahaQueryParamsDelegate(); + virtual ~ShellOmahaQueryParamsDelegate(); + + virtual std::string GetExtraParams() OVERRIDE; + + private: + DISALLOW_COPY_AND_ASSIGN(ShellOmahaQueryParamsDelegate); +}; + +} // namespace extensions + +#endif // EXTENSIONS_SHELL_BROWSER_SHELL_OMAHA_QUERY_PARAMS_DELEGATE_H_ diff --git a/extensions/shell/browser/shell_runtime_api_delegate.cc b/extensions/shell/browser/shell_runtime_api_delegate.cc new file mode 100644 index 0000000..3c63da7 --- /dev/null +++ b/extensions/shell/browser/shell_runtime_api_delegate.cc @@ -0,0 +1,66 @@ +// Copyright 2014 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 "extensions/shell/browser/shell_runtime_api_delegate.h" + +#include "extensions/common/api/runtime.h" + +#if defined(OS_CHROMEOS) +#include "chromeos/dbus/dbus_thread_manager.h" +#include "chromeos/dbus/power_manager_client.h" +#endif + +using extensions::core_api::runtime::PlatformInfo; + +namespace extensions { + +ShellRuntimeAPIDelegate::ShellRuntimeAPIDelegate() { +} + +ShellRuntimeAPIDelegate::~ShellRuntimeAPIDelegate() { +} + +void ShellRuntimeAPIDelegate::AddUpdateObserver(UpdateObserver* observer) { +} + +void ShellRuntimeAPIDelegate::RemoveUpdateObserver(UpdateObserver* observer) { +} + +base::Version ShellRuntimeAPIDelegate::GetPreviousExtensionVersion( + const Extension* extension) { + return base::Version(); +} + +void ShellRuntimeAPIDelegate::ReloadExtension(const std::string& extension_id) { +} + +bool ShellRuntimeAPIDelegate::CheckForUpdates( + const std::string& extension_id, + const UpdateCheckCallback& callback) { + return false; +} + +void ShellRuntimeAPIDelegate::OpenURL(const GURL& uninstall_url) { +} + +bool ShellRuntimeAPIDelegate::GetPlatformInfo(PlatformInfo* info) { +#if defined(OS_CHROMEOS) + info->os = PlatformInfo::OS_CROS_; +#elif defined(OS_LINUX) + info->os = PlatformInfo::OS_LINUX_; +#endif + return true; +} + +bool ShellRuntimeAPIDelegate::RestartDevice(std::string* error_message) { +// We allow chrome.runtime.restart() to request a device restart on ChromeOS. +#if defined(OS_CHROMEOS) + chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->RequestRestart(); + return true; +#endif + *error_message = "Restart is only supported on ChromeOS."; + return false; +} + +} // namespace extensions diff --git a/extensions/shell/browser/shell_runtime_api_delegate.h b/extensions/shell/browser/shell_runtime_api_delegate.h new file mode 100644 index 0000000..1382ec5 --- /dev/null +++ b/extensions/shell/browser/shell_runtime_api_delegate.h @@ -0,0 +1,36 @@ +// Copyright 2014 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 EXTENSIONS_SHELL_BROWSER_SHELL_RUNTIME_API_DELEGATE_H_ +#define EXTENSIONS_SHELL_BROWSER_SHELL_RUNTIME_API_DELEGATE_H_ + +#include "base/macros.h" +#include "extensions/browser/api/runtime/runtime_api_delegate.h" + +namespace extensions { + +class ShellRuntimeAPIDelegate : public RuntimeAPIDelegate { + public: + ShellRuntimeAPIDelegate(); + virtual ~ShellRuntimeAPIDelegate(); + + // RuntimeAPIDelegate implementation. + virtual void AddUpdateObserver(UpdateObserver* observer) OVERRIDE; + virtual void RemoveUpdateObserver(UpdateObserver* observer) OVERRIDE; + virtual base::Version GetPreviousExtensionVersion( + const Extension* extension) OVERRIDE; + virtual void ReloadExtension(const std::string& extension_id) OVERRIDE; + virtual bool CheckForUpdates(const std::string& extension_id, + const UpdateCheckCallback& callback) OVERRIDE; + virtual void OpenURL(const GURL& uninstall_url) OVERRIDE; + virtual bool GetPlatformInfo(core_api::runtime::PlatformInfo* info) OVERRIDE; + virtual bool RestartDevice(std::string* error_message) OVERRIDE; + + private: + DISALLOW_COPY_AND_ASSIGN(ShellRuntimeAPIDelegate); +}; + +} // namespace extensions + +#endif // EXTENSIONS_SHELL_BROWSER_SHELL_RUNTIME_API_DELEGATE_H_ diff --git a/extensions/shell/browser/shell_special_storage_policy.cc b/extensions/shell/browser/shell_special_storage_policy.cc new file mode 100644 index 0000000..a5f4120 --- /dev/null +++ b/extensions/shell/browser/shell_special_storage_policy.cc @@ -0,0 +1,43 @@ +// Copyright 2014 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 "extensions/shell/browser/shell_special_storage_policy.h" + +namespace extensions { + +ShellSpecialStoragePolicy::ShellSpecialStoragePolicy() { +} + +ShellSpecialStoragePolicy::~ShellSpecialStoragePolicy() { +} + +bool ShellSpecialStoragePolicy::IsStorageProtected(const GURL& origin) { + return true; +} + +bool ShellSpecialStoragePolicy::IsStorageUnlimited(const GURL& origin) { + return true; +} + +bool ShellSpecialStoragePolicy::IsStorageSessionOnly(const GURL& origin) { + return false; +} + +bool ShellSpecialStoragePolicy::CanQueryDiskSize(const GURL& origin) { + return true; +} + +bool ShellSpecialStoragePolicy::HasSessionOnlyOrigins() { + return false; +} + +bool ShellSpecialStoragePolicy::IsFileHandler(const std::string& extension_id) { + return true; +} + +bool ShellSpecialStoragePolicy::HasIsolatedStorage(const GURL& origin) { + return false; +} + +} // namespace extensions diff --git a/extensions/shell/browser/shell_special_storage_policy.h b/extensions/shell/browser/shell_special_storage_policy.h new file mode 100644 index 0000000..d2725d5 --- /dev/null +++ b/extensions/shell/browser/shell_special_storage_policy.h @@ -0,0 +1,33 @@ +// Copyright 2014 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 EXTENSIONS_SHELL_BROWSER_SHELL_SPECIAL_STORAGE_POLICY_H_ +#define EXTENSIONS_SHELL_BROWSER_SHELL_SPECIAL_STORAGE_POLICY_H_ + +#include "webkit/browser/quota/special_storage_policy.h" + +namespace extensions { + +// A simple storage policy for app_shell which does not limit storage +// capabilities and aims to be as permissive as possible. +class ShellSpecialStoragePolicy : public quota::SpecialStoragePolicy { + public: + ShellSpecialStoragePolicy(); + + // quota::SpecialStoragePolicy implementation. + virtual bool IsStorageProtected(const GURL& origin) OVERRIDE; + virtual bool IsStorageUnlimited(const GURL& origin) OVERRIDE; + virtual bool IsStorageSessionOnly(const GURL& origin) OVERRIDE; + virtual bool CanQueryDiskSize(const GURL& origin) OVERRIDE; + virtual bool IsFileHandler(const std::string& extension_id) OVERRIDE; + virtual bool HasIsolatedStorage(const GURL& origin) OVERRIDE; + virtual bool HasSessionOnlyOrigins() OVERRIDE; + + protected: + virtual ~ShellSpecialStoragePolicy(); +}; + +} // namespace extensions + +#endif // EXTENSIONS_SHELL_BROWSER_SHELL_SPECIAL_STORAGE_POLICY_H diff --git a/extensions/shell/common/api/_api_features.json b/extensions/shell/common/api/_api_features.json new file mode 100644 index 0000000..bcb5f71 --- /dev/null +++ b/extensions/shell/common/api/_api_features.json @@ -0,0 +1,18 @@ +// Copyright 2014 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. + +// This features file defines extension APIs implemented under src/extensions/shell. +// See extensions/common/features/* to understand this file, in particular +// feature.h, simple_feature.h, and base_feature_provider.h. +// +// Note that specifying "web_page", "blessed_web_page", or "all" as a context +// type will require manually updating chrome/renderer/resources/dispatcher.cc. + +{ + "shell": { + "channel": "dev", + "contexts": ["blessed_extension"], + "extension_types": ["platform_app"] + } +} diff --git a/extensions/shell/common/api/api.gyp b/extensions/shell/common/api/api.gyp new file mode 100644 index 0000000..2a4d126 --- /dev/null +++ b/extensions/shell/common/api/api.gyp @@ -0,0 +1,36 @@ +# Copyright 2014 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. + +{ + 'targets': [ + { + 'target_name': 'shell_api', + 'type': 'static_library', + 'sources': [ + '<@(schema_files)', + ], + # TODO(jschuh): http://crbug.com/167187 size_t -> int + 'msvs_disabled_warnings': [ 4267 ], + 'includes': [ + '../../../../build/json_schema_bundle_compile.gypi', + '../../../../build/json_schema_compile.gypi', + ], + 'variables': { + 'chromium_code': 1, + 'non_compiled_schema_files': [ + ], + # TODO(thestig): Eliminate these on Android. See crbug.com/305852. + 'schema_files': [ + 'shell.idl', + ], + 'cc_dir': 'extensions/shell/common/api', + 'root_namespace': 'extensions::shell_api', + 'impl_dir': 'extensions/shell/browser/api', + }, + 'dependencies': [ + '<(DEPTH)/skia/skia.gyp:skia', + ], + }, + ], +} diff --git a/extensions/shell/common/api/shell.idl b/extensions/shell/common/api/shell.idl new file mode 100644 index 0000000..0259535 --- /dev/null +++ b/extensions/shell/common/api/shell.idl @@ -0,0 +1,36 @@ +// Copyright 2014 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. + +// Use the <code>chrome.shell</code> API to create windows. The +// <code>createWindow</code> API is a subset of +// <code>chrome.app.window.create</code>. +namespace shell { + + // Called in the creating window (parent) before the load event is called in + // the created window (child). The parent can set fields or functions on the + // child usable from onload. E.g. background.js:<br> + // <code>function(createdWindow) { createdWindow.contentWindow.foo = + // function () { }; };</code> + // <br>window.js:<br> + // <code>window.onload = function () { foo(); }</code> + callback CreateWindowCallback = + void ([instanceOf=AppWindow] object createdWindow); + + [noinline_doc] dictionary AppWindow { + // The JavaScript 'window' object for the created child. + [instanceOf=Window] object contentWindow; + }; + + interface Functions { + // Creates a fullscreen window on the default display. Options are ignored. + static void createWindow(DOMString url, + optional object optionsPlaceholder, + optional CreateWindowCallback callback); + + // Returns an $(ref:AppWindow) object for the current script context + // (i.e. JavaScript 'window' object). + [nocompile] static AppWindow currentWindow(); + [nocompile, nodoc] static void initializeAppWindow(); + }; +}; diff --git a/extensions/shell/common/shell_content_client.cc b/extensions/shell/common/shell_content_client.cc new file mode 100644 index 0000000..5f0df03 --- /dev/null +++ b/extensions/shell/common/shell_content_client.cc @@ -0,0 +1,57 @@ +// Copyright 2014 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 "extensions/shell/common/shell_content_client.h" + +#include "base/strings/string_piece.h" +#include "base/strings/utf_string_conversions.h" +#include "content/public/common/user_agent.h" +#include "extensions/common/constants.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/base/resource/resource_bundle.h" + +namespace extensions { + +ShellContentClient::ShellContentClient() { +} + +ShellContentClient::~ShellContentClient() { +} + +void ShellContentClient::AddAdditionalSchemes( + std::vector<std::string>* standard_schemes, + std::vector<std::string>* savable_schemes) { + standard_schemes->push_back(kExtensionScheme); + savable_schemes->push_back(kExtensionScheme); + standard_schemes->push_back(kExtensionResourceScheme); + savable_schemes->push_back(kExtensionResourceScheme); +} + +std::string ShellContentClient::GetUserAgent() const { + // TODO(derat): Figure out what this should be for app_shell and determine + // whether we need to include a version number to placate browser sniffing. + return content::BuildUserAgentFromProduct("Chrome"); +} + +base::string16 ShellContentClient::GetLocalizedString(int message_id) const { + return l10n_util::GetStringUTF16(message_id); +} + +base::StringPiece ShellContentClient::GetDataResource( + int resource_id, + ui::ScaleFactor scale_factor) const { + return ResourceBundle::GetSharedInstance().GetRawDataResourceForScale( + resource_id, scale_factor); +} + +base::RefCountedStaticMemory* ShellContentClient::GetDataResourceBytes( + int resource_id) const { + return ResourceBundle::GetSharedInstance().LoadDataResourceBytes(resource_id); +} + +gfx::Image& ShellContentClient::GetNativeImageNamed(int resource_id) const { + return ResourceBundle::GetSharedInstance().GetNativeImageNamed(resource_id); +} + +} // namespace extensions diff --git a/extensions/shell/common/shell_content_client.h b/extensions/shell/common/shell_content_client.h new file mode 100644 index 0000000..f0a722e --- /dev/null +++ b/extensions/shell/common/shell_content_client.h @@ -0,0 +1,33 @@ +// Copyright 2014 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 EXTENSIONS_SHELL_COMMON_SHELL_CONTENT_CLIENT_H_ +#define EXTENSIONS_SHELL_COMMON_SHELL_CONTENT_CLIENT_H_ + +#include "base/compiler_specific.h" +#include "content/public/common/content_client.h" + +namespace extensions { + +class ShellContentClient : public content::ContentClient { + public: + ShellContentClient(); + virtual ~ShellContentClient(); + + virtual void AddAdditionalSchemes( + std::vector<std::string>* standard_schemes, + std::vector<std::string>* saveable_shemes) OVERRIDE; + virtual std::string GetUserAgent() const OVERRIDE; + virtual base::string16 GetLocalizedString(int message_id) const OVERRIDE; + virtual base::StringPiece GetDataResource( + int resource_id, + ui::ScaleFactor scale_factor) const OVERRIDE; + virtual base::RefCountedStaticMemory* GetDataResourceBytes( + int resource_id) const OVERRIDE; + virtual gfx::Image& GetNativeImageNamed(int resource_id) const OVERRIDE; +}; + +} // namespace extensions + +#endif // EXTENSIONS_SHELL_COMMON_SHELL_CONTENT_CLIENT_H_ diff --git a/extensions/shell/common/shell_extensions_client.cc b/extensions/shell/common/shell_extensions_client.cc new file mode 100644 index 0000000..0c5844f --- /dev/null +++ b/extensions/shell/common/shell_extensions_client.cc @@ -0,0 +1,204 @@ +// Copyright 2014 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 "extensions/shell/common/shell_extensions_client.h" + +#include "base/lazy_instance.h" +#include "base/logging.h" +#include "extensions/common/api/generated_schemas.h" +#include "extensions/common/api/sockets/sockets_manifest_handler.h" +#include "extensions/common/common_manifest_handlers.h" +#include "extensions/common/features/api_feature.h" +#include "extensions/common/features/base_feature_provider.h" +#include "extensions/common/features/json_feature_provider_source.h" +#include "extensions/common/features/manifest_feature.h" +#include "extensions/common/features/permission_feature.h" +#include "extensions/common/features/simple_feature.h" +#include "extensions/common/manifest_handler.h" +#include "extensions/common/permissions/permission_message_provider.h" +#include "extensions/common/permissions/permissions_info.h" +#include "extensions/common/permissions/permissions_provider.h" +#include "extensions/common/url_pattern_set.h" +#include "extensions/shell/common/api/generated_schemas.h" +#include "grit/app_shell_resources.h" +#include "grit/extensions_resources.h" + +namespace extensions { + +namespace { + +template <class FeatureClass> +SimpleFeature* CreateFeature() { + return new FeatureClass; +} + +// TODO(jamescook): Refactor ChromePermissionsMessageProvider so we can share +// code. For now, this implementation does nothing. +class ShellPermissionMessageProvider : public PermissionMessageProvider { + public: + ShellPermissionMessageProvider() {} + virtual ~ShellPermissionMessageProvider() {} + + // PermissionMessageProvider implementation. + virtual PermissionMessages GetPermissionMessages( + const PermissionSet* permissions, + Manifest::Type extension_type) const OVERRIDE { + return PermissionMessages(); + } + + virtual std::vector<base::string16> GetWarningMessages( + const PermissionSet* permissions, + Manifest::Type extension_type) const OVERRIDE { + return std::vector<base::string16>(); + } + + virtual std::vector<base::string16> GetWarningMessagesDetails( + const PermissionSet* permissions, + Manifest::Type extension_type) const OVERRIDE { + return std::vector<base::string16>(); + } + + virtual bool IsPrivilegeIncrease( + const PermissionSet* old_permissions, + const PermissionSet* new_permissions, + Manifest::Type extension_type) const OVERRIDE { + // Ensure we implement this before shipping. + CHECK(false); + return false; + } + + private: + DISALLOW_COPY_AND_ASSIGN(ShellPermissionMessageProvider); +}; + +base::LazyInstance<ShellPermissionMessageProvider> + g_permission_message_provider = LAZY_INSTANCE_INITIALIZER; + +} // namespace + +ShellExtensionsClient::ShellExtensionsClient() + : extensions_api_permissions_(ExtensionsAPIPermissions()) { +} + +ShellExtensionsClient::~ShellExtensionsClient() { +} + +void ShellExtensionsClient::Initialize() { + RegisterCommonManifestHandlers(); + + // TODO(rockot): API manifest handlers which move out to src/extensions + // should either end up in RegisterCommonManifestHandlers or some new + // initialization step specifically for API manifest handlers. + (new SocketsManifestHandler)->Register(); + + ManifestHandler::FinalizeRegistration(); + // TODO(jamescook): Do we need to whitelist any extensions? + + PermissionsInfo::GetInstance()->AddProvider(extensions_api_permissions_); +} + +const PermissionMessageProvider& +ShellExtensionsClient::GetPermissionMessageProvider() const { + NOTIMPLEMENTED(); + return g_permission_message_provider.Get(); +} + +scoped_ptr<FeatureProvider> ShellExtensionsClient::CreateFeatureProvider( + const std::string& name) const { + scoped_ptr<FeatureProvider> provider; + scoped_ptr<JSONFeatureProviderSource> source( + CreateFeatureProviderSource(name)); + if (name == "api") { + provider.reset(new BaseFeatureProvider(source->dictionary(), + CreateFeature<APIFeature>)); + } else if (name == "manifest") { + provider.reset(new BaseFeatureProvider(source->dictionary(), + CreateFeature<ManifestFeature>)); + } else if (name == "permission") { + provider.reset(new BaseFeatureProvider(source->dictionary(), + CreateFeature<PermissionFeature>)); + } else { + NOTREACHED(); + } + return provider.Pass(); +} + +scoped_ptr<JSONFeatureProviderSource> +ShellExtensionsClient::CreateFeatureProviderSource( + const std::string& name) const { + scoped_ptr<JSONFeatureProviderSource> source( + new JSONFeatureProviderSource(name)); + if (name == "api") { + source->LoadJSON(IDR_EXTENSION_API_FEATURES); + source->LoadJSON(IDR_SHELL_EXTENSION_API_FEATURES); + } else if (name == "manifest") { + source->LoadJSON(IDR_EXTENSION_MANIFEST_FEATURES); + } else if (name == "permission") { + source->LoadJSON(IDR_EXTENSION_PERMISSION_FEATURES); + } else { + NOTREACHED(); + source.reset(); + } + return source.Pass(); +} + +void ShellExtensionsClient::FilterHostPermissions( + const URLPatternSet& hosts, + URLPatternSet* new_hosts, + std::set<PermissionMessage>* messages) const { + NOTIMPLEMENTED(); +} + +void ShellExtensionsClient::SetScriptingWhitelist( + const ScriptingWhitelist& whitelist) { + scripting_whitelist_ = whitelist; +} + +const ExtensionsClient::ScriptingWhitelist& +ShellExtensionsClient::GetScriptingWhitelist() const { + // TODO(jamescook): Real whitelist. + return scripting_whitelist_; +} + +URLPatternSet ShellExtensionsClient::GetPermittedChromeSchemeHosts( + const Extension* extension, + const APIPermissionSet& api_permissions) const { + NOTIMPLEMENTED(); + return URLPatternSet(); +} + +bool ShellExtensionsClient::IsScriptableURL(const GURL& url, + std::string* error) const { + NOTIMPLEMENTED(); + return true; +} + +bool ShellExtensionsClient::IsAPISchemaGenerated( + const std::string& name) const { + // TODO(rockot): Remove dependency on src/chrome once we have some core APIs + // moved out. See http://crbug.com/349042. + // Special-case our simplified app.runtime implementation because we don't + // have the Chrome app APIs available. + return core_api::GeneratedSchemas::IsGenerated(name) || + shell_api::GeneratedSchemas::IsGenerated(name); +} + +base::StringPiece ShellExtensionsClient::GetAPISchema( + const std::string& name) const { + // Schema for chrome.shell APIs. + if (shell_api::GeneratedSchemas::IsGenerated(name)) + return shell_api::GeneratedSchemas::Get(name); + + return core_api::GeneratedSchemas::Get(name); +} + +void ShellExtensionsClient::RegisterAPISchemaResources( + ExtensionAPI* api) const { +} + +bool ShellExtensionsClient::ShouldSuppressFatalErrors() const { + return true; +} + +} // namespace extensions diff --git a/extensions/shell/common/shell_extensions_client.h b/extensions/shell/common/shell_extensions_client.h new file mode 100644 index 0000000..81c5c60 --- /dev/null +++ b/extensions/shell/common/shell_extensions_client.h @@ -0,0 +1,57 @@ +// Copyright 2014 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 EXTENSIONS_SHELL_COMMON_SHELL_EXTENSIONS_CLIENT_H_ +#define EXTENSIONS_SHELL_COMMON_SHELL_EXTENSIONS_CLIENT_H_ + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "extensions/common/extensions_client.h" +#include "extensions/common/permissions/extensions_api_permissions.h" + +namespace extensions { + +// The app_shell implementation of ExtensionsClient. +class ShellExtensionsClient : public ExtensionsClient { + public: + ShellExtensionsClient(); + virtual ~ShellExtensionsClient(); + + // ExtensionsClient overrides: + virtual void Initialize() OVERRIDE; + virtual const PermissionMessageProvider& GetPermissionMessageProvider() + const OVERRIDE; + virtual scoped_ptr<FeatureProvider> CreateFeatureProvider( + const std::string& name) const OVERRIDE; + virtual scoped_ptr<JSONFeatureProviderSource> CreateFeatureProviderSource( + const std::string& name) const OVERRIDE; + virtual void FilterHostPermissions( + const URLPatternSet& hosts, + URLPatternSet* new_hosts, + std::set<PermissionMessage>* messages) const OVERRIDE; + virtual void SetScriptingWhitelist( + const ScriptingWhitelist& whitelist) OVERRIDE; + virtual const ScriptingWhitelist& GetScriptingWhitelist() const OVERRIDE; + virtual URLPatternSet GetPermittedChromeSchemeHosts( + const Extension* extension, + const APIPermissionSet& api_permissions) const OVERRIDE; + virtual bool IsScriptableURL(const GURL& url, + std::string* error) const OVERRIDE; + virtual bool IsAPISchemaGenerated(const std::string& name) const OVERRIDE; + virtual base::StringPiece GetAPISchema( + const std::string& name) const OVERRIDE; + virtual void RegisterAPISchemaResources(ExtensionAPI* api) const OVERRIDE; + virtual bool ShouldSuppressFatalErrors() const OVERRIDE; + + private: + const ExtensionsAPIPermissions extensions_api_permissions_; + + ScriptingWhitelist scripting_whitelist_; + + DISALLOW_COPY_AND_ASSIGN(ShellExtensionsClient); +}; + +} // namespace extensions + +#endif // EXTENSIONS_SHELL_COMMON_SHELL_EXTENSIONS_CLIENT_H_ diff --git a/extensions/shell/common/switches.cc b/extensions/shell/common/switches.cc new file mode 100644 index 0000000..0186422 --- /dev/null +++ b/extensions/shell/common/switches.cc @@ -0,0 +1,20 @@ +// Copyright 2014 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 "extensions/shell/common/switches.h" + +namespace extensions { +namespace switches { + +// Path to an app to load at startup. +const char kAppShellAppPath[] = "app-shell-app-path"; + +// Bounds for the host window to create (i.e. "800x600"). +const char kAppShellHostWindowBounds[] = "app-shell-host-window-bounds"; + +// SSID of the preferred WiFi network. +const char kAppShellPreferredNetwork[] = "app-shell-preferred-network"; + +} // namespace switches +} // namespace extensions diff --git a/extensions/shell/common/switches.h b/extensions/shell/common/switches.h new file mode 100644 index 0000000..6c4911d --- /dev/null +++ b/extensions/shell/common/switches.h @@ -0,0 +1,20 @@ +// Copyright 2014 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 EXTENSIONS_SHELL_COMMON_SWITCHES_H_ +#define EXTENSIONS_SHELL_COMMON_SWITCHES_H_ + +namespace extensions { +namespace switches { + +// All switches in alphabetical order. The switches should be documented +// alongside the definition of their values in the .cc file. +extern const char kAppShellAppPath[]; +extern const char kAppShellHostWindowBounds[]; +extern const char kAppShellPreferredNetwork[]; + +} // namespace switches +} // namespace extensions + +#endif // EXTENSIONS_SHELL_COMMON_SWITCHES_H_ diff --git a/extensions/shell/renderer/DEPS b/extensions/shell/renderer/DEPS new file mode 100644 index 0000000..baafcac --- /dev/null +++ b/extensions/shell/renderer/DEPS @@ -0,0 +1,7 @@ +include_rules = [ + # Only allow includes the renderer can use. + "+content/public/renderer", + + "+third_party/WebKit/public", + "+v8/include", +] diff --git a/extensions/shell/renderer/shell_content_renderer_client.cc b/extensions/shell/renderer/shell_content_renderer_client.cc new file mode 100644 index 0000000..c7a9be6 --- /dev/null +++ b/extensions/shell/renderer/shell_content_renderer_client.cc @@ -0,0 +1,131 @@ +// Copyright 2014 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 "extensions/shell/renderer/shell_content_renderer_client.h" + +#include "content/public/renderer/render_frame.h" +#include "content/public/renderer/render_frame_observer.h" +#include "content/public/renderer/render_frame_observer_tracker.h" +#include "content/public/renderer/render_thread.h" +#include "extensions/common/extensions_client.h" +#include "extensions/renderer/dispatcher.h" +#include "extensions/renderer/extension_helper.h" +#include "extensions/shell/common/shell_extensions_client.h" +#include "extensions/shell/renderer/shell_dispatcher_delegate.h" +#include "extensions/shell/renderer/shell_extensions_renderer_client.h" +#include "extensions/shell/renderer/shell_renderer_main_delegate.h" + +using blink::WebFrame; +using blink::WebString; +using content::RenderThread; + +namespace extensions { + +namespace { + +// TODO: promote ExtensionFrameHelper to a common place and share with this. +class ShellFrameHelper + : public content::RenderFrameObserver, + public content::RenderFrameObserverTracker<ShellFrameHelper> { + public: + ShellFrameHelper(content::RenderFrame* render_frame, + Dispatcher* extension_dispatcher); + virtual ~ShellFrameHelper(); + + // RenderFrameObserver implementation. + virtual void WillReleaseScriptContext(v8::Handle<v8::Context>, + int world_id) OVERRIDE; + + private: + Dispatcher* extension_dispatcher_; + + DISALLOW_COPY_AND_ASSIGN(ShellFrameHelper); +}; + +ShellFrameHelper::ShellFrameHelper(content::RenderFrame* render_frame, + Dispatcher* extension_dispatcher) + : content::RenderFrameObserver(render_frame), + content::RenderFrameObserverTracker<ShellFrameHelper>(render_frame), + extension_dispatcher_(extension_dispatcher) { +} + +ShellFrameHelper::~ShellFrameHelper() { +} + +void ShellFrameHelper::WillReleaseScriptContext(v8::Handle<v8::Context> context, + int world_id) { + extension_dispatcher_->WillReleaseScriptContext( + render_frame()->GetWebFrame(), context, world_id); +} + +} // namespace + +ShellContentRendererClient::ShellContentRendererClient( + scoped_ptr<ShellRendererMainDelegate> delegate) + : delegate_(delegate.Pass()) { +} + +ShellContentRendererClient::~ShellContentRendererClient() { +} + +void ShellContentRendererClient::RenderThreadStarted() { + RenderThread* thread = RenderThread::Get(); + + extensions_client_.reset(new ShellExtensionsClient); + ExtensionsClient::Set(extensions_client_.get()); + + extensions_renderer_client_.reset(new ShellExtensionsRendererClient); + ExtensionsRendererClient::Set(extensions_renderer_client_.get()); + + extension_dispatcher_delegate_.reset(new ShellDispatcherDelegate()); + + // Must be initialized after ExtensionsRendererClient. + extension_dispatcher_.reset( + new Dispatcher(extension_dispatcher_delegate_.get())); + thread->AddObserver(extension_dispatcher_.get()); + + // TODO(jamescook): Init WebSecurityPolicy for chrome-extension: schemes. + // See ChromeContentRendererClient for details. + if (delegate_) + delegate_->OnThreadStarted(thread); +} + +void ShellContentRendererClient::RenderFrameCreated( + content::RenderFrame* render_frame) { + // ShellFrameHelper destroyes itself when the RenderFrame is destroyed. + new ShellFrameHelper(render_frame, extension_dispatcher_.get()); +} + +void ShellContentRendererClient::RenderViewCreated( + content::RenderView* render_view) { + new ExtensionHelper(render_view, extension_dispatcher_.get()); + if (delegate_) + delegate_->OnViewCreated(render_view); +} + +bool ShellContentRendererClient::WillSendRequest( + blink::WebFrame* frame, + content::PageTransition transition_type, + const GURL& url, + const GURL& first_party_for_cookies, + GURL* new_url) { + // TODO(jamescook): Cause an error for bad extension scheme requests? + return false; +} + +void ShellContentRendererClient::DidCreateScriptContext( + WebFrame* frame, + v8::Handle<v8::Context> context, + int extension_group, + int world_id) { + extension_dispatcher_->DidCreateScriptContext( + frame, context, extension_group, world_id); +} + +bool ShellContentRendererClient::ShouldEnableSiteIsolationPolicy() const { + // Extension renderers don't need site isolation. + return false; +} + +} // namespace extensions diff --git a/extensions/shell/renderer/shell_content_renderer_client.h b/extensions/shell/renderer/shell_content_renderer_client.h new file mode 100644 index 0000000..e7a1fbc --- /dev/null +++ b/extensions/shell/renderer/shell_content_renderer_client.h @@ -0,0 +1,55 @@ +// Copyright 2014 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 EXTENSIONS_SHELL_RENDERER_SHELL_CONTENT_RENDERER_CLIENT_H_ +#define EXTENSIONS_SHELL_RENDERER_SHELL_CONTENT_RENDERER_CLIENT_H_ + +#include "base/compiler_specific.h" +#include "base/macros.h" +#include "base/memory/scoped_ptr.h" +#include "content/public/renderer/content_renderer_client.h" + +namespace extensions { + +class Dispatcher; +class DispatcherDelegate; +class ShellExtensionsClient; +class ShellExtensionsRendererClient; +class ShellRendererMainDelegate; + +// Renderer initialization and runtime support for app_shell. +class ShellContentRendererClient : public content::ContentRendererClient { + public: + explicit ShellContentRendererClient( + scoped_ptr<ShellRendererMainDelegate> delegate); + virtual ~ShellContentRendererClient(); + + // content::ContentRendererClient implementation: + virtual void RenderThreadStarted() OVERRIDE; + virtual void RenderFrameCreated(content::RenderFrame* render_frame) OVERRIDE; + virtual void RenderViewCreated(content::RenderView* render_view) OVERRIDE; + virtual bool WillSendRequest(blink::WebFrame* frame, + content::PageTransition transition_type, + const GURL& url, + const GURL& first_party_for_cookies, + GURL* new_url) OVERRIDE; + virtual void DidCreateScriptContext(blink::WebFrame* frame, + v8::Handle<v8::Context> context, + int extension_group, + int world_id) OVERRIDE; + virtual bool ShouldEnableSiteIsolationPolicy() const OVERRIDE; + + private: + scoped_ptr<ShellRendererMainDelegate> delegate_; + scoped_ptr<ShellExtensionsClient> extensions_client_; + scoped_ptr<ShellExtensionsRendererClient> extensions_renderer_client_; + scoped_ptr<DispatcherDelegate> extension_dispatcher_delegate_; + scoped_ptr<Dispatcher> extension_dispatcher_; + + DISALLOW_COPY_AND_ASSIGN(ShellContentRendererClient); +}; + +} // namespace extensions + +#endif // EXTENSIONS_SHELL_RENDERER_SHELL_CONTENT_RENDERER_CLIENT_H_ diff --git a/extensions/shell/renderer/shell_custom_bindings.cc b/extensions/shell/renderer/shell_custom_bindings.cc new file mode 100644 index 0000000..40965ca --- /dev/null +++ b/extensions/shell/renderer/shell_custom_bindings.cc @@ -0,0 +1,57 @@ +// Copyright 2014 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 "extensions/shell/renderer/shell_custom_bindings.h" + +#include "content/public/renderer/render_thread.h" +#include "content/public/renderer/render_view.h" +#include "content/public/renderer/v8_value_converter.h" +#include "extensions/common/extension_messages.h" +#include "extensions/renderer/script_context.h" +#include "extensions/renderer/script_context_set.h" +#include "third_party/WebKit/public/web/WebFrame.h" +#include "third_party/WebKit/public/web/WebView.h" +#include "v8/include/v8.h" + +namespace extensions { + +ShellCustomBindings::ShellCustomBindings(ScriptContext* context) + : ObjectBackedNativeHandler(context) { + RouteFunction( + "GetView", + base::Bind(&ShellCustomBindings::GetView, base::Unretained(this))); +} + +void ShellCustomBindings::GetView( + const v8::FunctionCallbackInfo<v8::Value>& args) { + if (args.Length() != 1 || !args[0]->IsInt32()) + return; + + int view_id = args[0]->Int32Value(); + if (view_id == MSG_ROUTING_NONE) + return; + + content::RenderView* view = content::RenderView::FromRoutingID(view_id); + if (!view) + return; + + // Set the opener so we have a security origin set up before returning the DOM + // reference. + content::RenderView* render_view = context()->GetRenderView(); + if (!render_view) + return; + blink::WebFrame* opener = render_view->GetWebView()->mainFrame(); + blink::WebFrame* frame = view->GetWebView()->mainFrame(); + frame->setOpener(opener); + + // Resume resource requests. + content::RenderThread::Get()->Send( + new ExtensionHostMsg_ResumeRequests(view->GetRoutingID())); + + // Return the script context. + v8::Local<v8::Value> window = frame->mainWorldScriptContext()->Global(); + args.GetReturnValue().Set(window); +} + +} // namespace extensions diff --git a/extensions/shell/renderer/shell_custom_bindings.h b/extensions/shell/renderer/shell_custom_bindings.h new file mode 100644 index 0000000..aaa4abe --- /dev/null +++ b/extensions/shell/renderer/shell_custom_bindings.h @@ -0,0 +1,25 @@ +// Copyright 2014 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 EXTENSIONS_SHELL_RENDERER_SHELL_CUSTOM_BINDINGS_H_ +#define EXTENSIONS_SHELL_RENDERER_SHELL_CUSTOM_BINDINGS_H_ + +#include "extensions/renderer/object_backed_native_handler.h" + +namespace extensions { + +// Implements custom bindings for the chrome.shell API. +class ShellCustomBindings : public ObjectBackedNativeHandler { + public: + ShellCustomBindings(ScriptContext* context); + + private: + void GetView(const v8::FunctionCallbackInfo<v8::Value>& args); + + DISALLOW_COPY_AND_ASSIGN(ShellCustomBindings); +}; + +} // namespace extensions + +#endif // EXTENSIONS_SHELL_RENDERER_SHELL_CUSTOM_BINDINGS_H_ diff --git a/extensions/shell/renderer/shell_custom_bindings.js b/extensions/shell/renderer/shell_custom_bindings.js new file mode 100644 index 0000000..5fe9a9ae --- /dev/null +++ b/extensions/shell/renderer/shell_custom_bindings.js @@ -0,0 +1,78 @@ +// Copyright 2014 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. + +var shellNatives = requireNative('shell_natives'); +var Binding = require('binding').Binding; +var forEach = require('utils').forEach; +var renderViewObserverNatives = requireNative('renderViewObserverNatives'); + +var currentAppWindow = null; + +var shell = Binding.create('shell'); +shell.registerCustomHook(function(bindingsAPI) { + var apiFunctions = bindingsAPI.apiFunctions; + + apiFunctions.setCustomCallback('createWindow', + function(name, request, windowParams) { + var view = null; + + // When window creation fails, |windowParams| will be undefined. + if (windowParams && windowParams.viewId) { + view = shellNatives.GetView(windowParams.viewId); + } + + if (!view) { + // No route to created window. If given a callback, trigger it with an + // undefined object. + if (request.callback) { + request.callback(undefined); + delete request.callback; + } + return; + } + + // Initialize the app window in the newly created JS context + view.chrome.shell.initializeAppWindow(); + + var callback = request.callback; + if (callback) { + delete request.callback; + + var willCallback = + renderViewObserverNatives.OnDocumentElementCreated( + windowParams.viewId, + function(success) { + if (success) { + callback(view.chrome.shell.currentWindow()); + } else { + callback(undefined); + } + }); + if (!willCallback) { + callback(undefined); + } + } + }); + + apiFunctions.setHandleRequest('currentWindow', function() { + if (!currentAppWindow) { + console.error( + 'The JavaScript context calling chrome.shell.currentWindow() has' + + ' no associated AppWindow.'); + return null; + } + return currentAppWindow; + }); + + // This is an internal function, but needs to be bound into a closure + // so the correct JS context is used for global variables such as + // currentAppWindow. + apiFunctions.setHandleRequest('initializeAppWindow', function() { + var AppWindow = function() {}; + AppWindow.prototype.contentWindow = window; + currentAppWindow = new AppWindow; + }); +}); + +exports.binding = shell.generate(); diff --git a/extensions/shell/renderer/shell_dispatcher_delegate.cc b/extensions/shell/renderer/shell_dispatcher_delegate.cc new file mode 100644 index 0000000..0f6b04b --- /dev/null +++ b/extensions/shell/renderer/shell_dispatcher_delegate.cc @@ -0,0 +1,35 @@ +// Copyright 2014 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 "extensions/shell/renderer/shell_dispatcher_delegate.h" + +#include "extensions/renderer/module_system.h" +#include "extensions/renderer/resource_bundle_source_map.h" +#include "extensions/renderer/script_context.h" +#include "extensions/shell/renderer/shell_custom_bindings.h" +#include "grit/app_shell_resources.h" + +namespace extensions { + +ShellDispatcherDelegate::ShellDispatcherDelegate() { +} + +ShellDispatcherDelegate::~ShellDispatcherDelegate() { +} + +void ShellDispatcherDelegate::RegisterNativeHandlers( + Dispatcher* dispatcher, + ModuleSystem* module_system, + ScriptContext* context) { + module_system->RegisterNativeHandler( + "shell_natives", + scoped_ptr<NativeHandler>(new ShellCustomBindings(context))); +} + +void ShellDispatcherDelegate::PopulateSourceMap( + ResourceBundleSourceMap* source_map) { + source_map->RegisterSource("shell", IDR_SHELL_CUSTOM_BINDINGS_JS); +} + +} // namespace extensions diff --git a/extensions/shell/renderer/shell_dispatcher_delegate.h b/extensions/shell/renderer/shell_dispatcher_delegate.h new file mode 100644 index 0000000..5009ce7 --- /dev/null +++ b/extensions/shell/renderer/shell_dispatcher_delegate.h @@ -0,0 +1,33 @@ +// Copyright 2014 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 EXTENSIONS_SHELL_RENDERER_SHELL_DISPATCHER_DELEGATE_H_ +#define EXTENSIONS_SHELL_RENDERER_SHELL_DISPATCHER_DELEGATE_H_ + +#include "base/macros.h" +#include "extensions/renderer/default_dispatcher_delegate.h" + +namespace extensions { + +// app_shell's implementation of DispatcherDelegate. This inherits the behavior +// of the default delegate while augmenting its own script resources and native +// native handlers. +class ShellDispatcherDelegate : public DefaultDispatcherDelegate { + public: + ShellDispatcherDelegate(); + virtual ~ShellDispatcherDelegate(); + + // DispatcherDelegate implementation. + virtual void RegisterNativeHandlers(Dispatcher* dispatcher, + ModuleSystem* module_system, + ScriptContext* context) OVERRIDE; + virtual void PopulateSourceMap(ResourceBundleSourceMap* source_map) OVERRIDE; + + private: + DISALLOW_COPY_AND_ASSIGN(ShellDispatcherDelegate); +}; + +} // namespace extensions + +#endif // EXTENSIONS_SHELL_RENDERER_SHELL_DISPATCHER_DELEGATE_H_ diff --git a/extensions/shell/renderer/shell_extensions_renderer_client.cc b/extensions/shell/renderer/shell_extensions_renderer_client.cc new file mode 100644 index 0000000..c3be350 --- /dev/null +++ b/extensions/shell/renderer/shell_extensions_renderer_client.cc @@ -0,0 +1,27 @@ +// Copyright 2014 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 "extensions/shell/renderer/shell_extensions_renderer_client.h" + +namespace extensions { + +ShellExtensionsRendererClient::ShellExtensionsRendererClient() { +} + +ShellExtensionsRendererClient::~ShellExtensionsRendererClient() { +} + +bool ShellExtensionsRendererClient::IsIncognitoProcess() const { + // app_shell doesn't support off-the-record contexts. + return false; +} + +int ShellExtensionsRendererClient::GetLowestIsolatedWorldId() const { + // app_shell doesn't need to reserve world IDs for anything other than + // extensions, so we always return 1. Note that 0 is reserved for the global + // world. + return 1; +} + +} // namespace extensions diff --git a/extensions/shell/renderer/shell_extensions_renderer_client.h b/extensions/shell/renderer/shell_extensions_renderer_client.h new file mode 100644 index 0000000..1bbe3f4 --- /dev/null +++ b/extensions/shell/renderer/shell_extensions_renderer_client.h @@ -0,0 +1,28 @@ +// Copyright 2014 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 EXTENSIONS_SHELL_RENDERER_SHELL_EXTENSIONS_RENDERER_CLIENT_H_ +#define EXTENSIONS_SHELL_RENDERER_SHELL_EXTENSIONS_RENDERER_CLIENT_H_ + +#include "base/macros.h" +#include "extensions/renderer/extensions_renderer_client.h" + +namespace extensions { + +class ShellExtensionsRendererClient : public ExtensionsRendererClient { + public: + ShellExtensionsRendererClient(); + virtual ~ShellExtensionsRendererClient(); + + // ExtensionsRendererClient implementation. + virtual bool IsIncognitoProcess() const OVERRIDE; + virtual int GetLowestIsolatedWorldId() const OVERRIDE; + + private: + DISALLOW_COPY_AND_ASSIGN(ShellExtensionsRendererClient); +}; + +} // namespace extensions + +#endif // EXTENSIONS_SHELL_RENDERER_SHELL_EXTENSIONS_RENDERER_CLIENT_H_ diff --git a/extensions/shell/renderer/shell_renderer_main_delegate.h b/extensions/shell/renderer/shell_renderer_main_delegate.h new file mode 100644 index 0000000..51396bd --- /dev/null +++ b/extensions/shell/renderer/shell_renderer_main_delegate.h @@ -0,0 +1,30 @@ +// Copyright 2014 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 EXTENSIONS_SHELL_RENDERER_SHELL_RENDERER_MAIN_DELEGATE_H_ +#define EXTENSIONS_SHELL_RENDERER_SHELL_RENDERER_MAIN_DELEGATE_H_ + +namespace content { +class RenderThread; +class RenderView; +} + +namespace extensions { + +class ShellRendererMainDelegate { + public: + virtual ~ShellRendererMainDelegate() {} + + // Called when |thread| is started, after the extensions subsystem has been + // initialized for |thread|. + virtual void OnThreadStarted(content::RenderThread* thread) = 0; + + // Called for each RenderView created in the renderer process, after the + // extension related code has been initialized for the view. + virtual void OnViewCreated(content::RenderView* view) = 0; +}; + +} // namespace extensions + +#endif // EXTENSIONS_SHELL_RENDERER_SHELL_RENDERER_MAIN_DELEGATE_H_ diff --git a/extensions/shell/test/DEPS b/extensions/shell/test/DEPS new file mode 100644 index 0000000..c243ad4 --- /dev/null +++ b/extensions/shell/test/DEPS @@ -0,0 +1,4 @@ +include_rules = [ + # Testing utilities can access anything in extensions/shell. + "+extensions/shell", +] diff --git a/extensions/shell/test/shell_test.cc b/extensions/shell/test/shell_test.cc new file mode 100644 index 0000000..e67400d --- /dev/null +++ b/extensions/shell/test/shell_test.cc @@ -0,0 +1,57 @@ +// Copyright 2014 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 "extensions/shell/test/shell_test.h" + +#include "base/command_line.h" +#include "base/files/file_path.h" +#include "base/logging.h" +#include "content/public/common/content_switches.h" +#include "extensions/browser/extension_system.h" +#include "extensions/shell/browser/shell_content_browser_client.h" +#include "extensions/shell/browser/shell_desktop_controller.h" +#include "extensions/shell/browser/shell_extension_system.h" + +namespace extensions { + +AppShellTest::AppShellTest() : browser_context_(NULL), extension_system_(NULL) { +} + +AppShellTest::~AppShellTest() { +} + +void AppShellTest::SetUp() { + base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); + command_line->AppendSwitchASCII(switches::kTestType, "appshell"); + content::BrowserTestBase::SetUp(); +} + +void AppShellTest::SetUpOnMainThread() { + browser_context_ = ShellContentBrowserClient::Get()->GetBrowserContext(); + + extension_system_ = static_cast<ShellExtensionSystem*>( + ExtensionSystem::Get(browser_context_)); +} + +void AppShellTest::RunTestOnMainThreadLoop() { + base::MessageLoopForUI::current()->RunUntilIdle(); + + SetUpOnMainThread(); + + RunTestOnMainThread(); + + TearDownOnMainThread(); + + // Clean up the app window. + ShellDesktopController::instance()->CloseAppWindows(); +} + +bool AppShellTest::LoadAndLaunchApp(const base::FilePath& app_dir) { + bool loaded = extension_system_->LoadApp(app_dir); + if (loaded) + extension_system_->LaunchApp(); + return loaded; +} + +} // namespace extensions diff --git a/extensions/shell/test/shell_test.h b/extensions/shell/test/shell_test.h new file mode 100644 index 0000000..c9d36ed --- /dev/null +++ b/extensions/shell/test/shell_test.h @@ -0,0 +1,48 @@ +// Copyright 2014 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 EXTENSIONS_SHELL_TEST_SHELL_TEST_H_ +#define EXTENSIONS_SHELL_TEST_SHELL_TEST_H_ + +#include "base/memory/scoped_ptr.h" +#include "content/public/test/browser_test.h" +#include "content/public/test/browser_test_base.h" + +namespace base { +class FilePath; +} + +namespace content { +class BrowserContext; +} + +namespace extensions { + +class ShellExtensionSystem; + +// Base class for app shell browser tests. +class AppShellTest : public content::BrowserTestBase { + public: + AppShellTest(); + virtual ~AppShellTest(); + + // content::BrowserTestBase implementation. + virtual void SetUp() OVERRIDE; + virtual void SetUpOnMainThread() OVERRIDE; + virtual void RunTestOnMainThreadLoop() OVERRIDE; + + // Loads an unpacked application from a directory using |extension_system_| + // and attempts to launch it. Returns true on success. + bool LoadAndLaunchApp(const base::FilePath& app_dir); + + content::BrowserContext* browser_context() { return browser_context_; } + + private: + content::BrowserContext* browser_context_; + ShellExtensionSystem* extension_system_; +}; + +} // namespace extensions + +#endif // EXTENSIONS_SHELL_TEST_SHELL_TEST_H_ diff --git a/extensions/shell/test/shell_test_launcher_delegate.cc b/extensions/shell/test/shell_test_launcher_delegate.cc new file mode 100644 index 0000000..ce7bc59 --- /dev/null +++ b/extensions/shell/test/shell_test_launcher_delegate.cc @@ -0,0 +1,27 @@ +// Copyright 2014 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 "extensions/shell/test/shell_test_launcher_delegate.h" + +#include "base/test/test_suite.h" +#include "extensions/shell/app/shell_main_delegate.h" + +namespace extensions { + +int AppShellTestLauncherDelegate::RunTestSuite(int argc, char** argv) { + return base::TestSuite(argc, argv).Run(); +} + +bool AppShellTestLauncherDelegate::AdjustChildProcessCommandLine( + base::CommandLine* command_line, + const base::FilePath& temp_data_dir) { + return true; +} + +content::ContentMainDelegate* +AppShellTestLauncherDelegate::CreateContentMainDelegate() { + return new ShellMainDelegate(); +} + +} // namespace extensions diff --git a/extensions/shell/test/shell_test_launcher_delegate.h b/extensions/shell/test/shell_test_launcher_delegate.h new file mode 100644 index 0000000..8e62f5d --- /dev/null +++ b/extensions/shell/test/shell_test_launcher_delegate.h @@ -0,0 +1,23 @@ +// Copyright 2014 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 EXTENSIONS_SHELL_TEST_SHELL_TEST_LAUNCHER_DELEGATE_H_ +#define EXTENSIONS_SHELL_TEST_SHELL_TEST_LAUNCHER_DELEGATE_H_ + +#include "content/public/test/test_launcher.h" + +namespace extensions { + +class AppShellTestLauncherDelegate : public content::TestLauncherDelegate { + public: + virtual int RunTestSuite(int argc, char** argv) OVERRIDE; + virtual bool AdjustChildProcessCommandLine( + base::CommandLine* command_line, + const base::FilePath& temp_data_dir) OVERRIDE; + virtual content::ContentMainDelegate* CreateContentMainDelegate() OVERRIDE; +}; + +} // namespace extensions + +#endif // EXTENSIONS_SHELL_TEST_SHELL_TEST_LAUNCHER_DELEGATE_H_ diff --git a/extensions/shell/test/shell_tests_main.cc b/extensions/shell/test/shell_tests_main.cc new file mode 100644 index 0000000..eb16469 --- /dev/null +++ b/extensions/shell/test/shell_tests_main.cc @@ -0,0 +1,15 @@ +// Copyright 2014 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 <algorithm> + +#include "base/sys_info.h" +#include "extensions/shell/test/shell_test_launcher_delegate.h" +#include "testing/gtest/include/gtest/gtest.h" + +int main(int argc, char** argv) { + int default_jobs = std::max(1, base::SysInfo::NumberOfProcessors() / 2); + extensions::AppShellTestLauncherDelegate launcher_delegate; + return content::LaunchTests(&launcher_delegate, default_jobs, argc, argv); +} |