app_shell: Make renderer run background page JavaScript

* Install URL protocol handler for chrome-extension:// and chrome-extension-resource://
* Allow extension urls to be handled.
* Register extensions with IO thread extension InfoMap.
* Bonus: app_shell no longer crashes on startup.

With this change an extension background page can print "Hello world" using console.log().

BUG=288226,332982
TEST=browser_tests. Also run app_shell --app=/path/to/extension with an extension with background.js. The JavaScript executes and console.log() works.

Review URL: https://codereview.chromium.org/136453005

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@245325 0039d316-1c4b-4281-b951-d872f2087c98
parent a208843d
...@@ -6,6 +6,8 @@ include_rules = [ ...@@ -6,6 +6,8 @@ include_rules = [
# TODO(jamescook): Remove these. http://crbug.com/305404 # TODO(jamescook): Remove these. http://crbug.com/305404
# Chrome pieces for bring-up. # Chrome pieces for bring-up.
"+chrome/browser/extensions/extension_protocols.h",
"+chrome/browser/extensions/extension_resource_protocols.h",
"+chrome/common/chrome_paths.h", "+chrome/common/chrome_paths.h",
"+chrome/common/extensions/extension_file_util.h", "+chrome/common/extensions/extension_file_util.h",
"+chrome/common/extensions/features/base_feature_provider.h", "+chrome/common/extensions/features/base_feature_provider.h",
......
...@@ -46,6 +46,10 @@ class ShellBrowserMainParts : public content::BrowserMainParts, ...@@ -46,6 +46,10 @@ class ShellBrowserMainParts : public content::BrowserMainParts,
return browser_context_.get(); return browser_context_.get();
} }
extensions::ShellExtensionSystem* extension_system() {
return extension_system_;
}
// BrowserMainParts overrides. // BrowserMainParts overrides.
virtual void PreEarlyInitialization() OVERRIDE; virtual void PreEarlyInitialization() OVERRIDE;
virtual void PreMainMessageLoopStart() OVERRIDE; virtual void PreMainMessageLoopStart() OVERRIDE;
......
...@@ -6,7 +6,25 @@ ...@@ -6,7 +6,25 @@
#include "apps/shell/shell_browser_context.h" #include "apps/shell/shell_browser_context.h"
#include "apps/shell/shell_browser_main_parts.h" #include "apps/shell/shell_browser_main_parts.h"
#include "apps/shell/shell_extension_system.h"
#include "base/command_line.h"
#include "chrome/browser/extensions/extension_protocols.h"
#include "chrome/browser/extensions/extension_resource_protocols.h"
#include "chrome/common/chrome_switches.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 "content/shell/browser/shell_browser_context.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/browser/info_map.h"
#include "extensions/common/constants.h"
#include "extensions/common/extension.h"
#include "url/gurl.h"
using content::BrowserThread;
using extensions::ExtensionRegistry;
namespace apps { namespace apps {
...@@ -27,9 +45,99 @@ net::URLRequestContextGetter* ...@@ -27,9 +45,99 @@ net::URLRequestContextGetter*
ShellContentBrowserClient::CreateRequestContext( ShellContentBrowserClient::CreateRequestContext(
content::BrowserContext* content_browser_context, content::BrowserContext* content_browser_context,
content::ProtocolHandlerMap* protocol_handlers) { content::ProtocolHandlerMap* protocol_handlers) {
// TODO(jamescook): Should this be an off-the-record context? // Handle chrome-extension: and chrome-extension-resource: requests.
extensions::InfoMap* extension_info_map =
browser_main_parts_->extension_system()->info_map();
(*protocol_handlers)[extensions::kExtensionScheme] =
linked_ptr<net::URLRequestJobFactory::ProtocolHandler>(
CreateExtensionProtocolHandler(false /*is_incognito*/,
extension_info_map));
(*protocol_handlers)[extensions::kExtensionResourceScheme] =
linked_ptr<net::URLRequestJobFactory::ProtocolHandler>(
CreateExtensionResourceProtocolHandler());
// Let content::ShellBrowserContext handle the rest of the setup.
return browser_main_parts_->browser_context()->CreateRequestContext( return browser_main_parts_->browser_context()->CreateRequestContext(
protocol_handlers); protocol_handlers);
} }
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[] = {
chrome::kBlobScheme,
chrome::kChromeUIScheme,
chrome::kChromeDevToolsScheme,
chrome::kDataScheme,
content::kFileScheme,
content::kFileSystemScheme,
extensions::kExtensionScheme,
extensions::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 extensions::Extension* extension = GetExtension(site_instance);
if (!extension)
return;
// TODO(jamescook): Add to extension service process_map().
BrowserThread::PostTask(
BrowserThread::IO,
FROM_HERE,
base::Bind(&extensions::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 extensions::Extension* extension = GetExtension(site_instance);
if (!extension)
return;
// TODO(jamescook): Remove from extension service process_map().
BrowserThread::PostTask(
BrowserThread::IO,
FROM_HERE,
base::Bind(&extensions::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);
}
}
const extensions::Extension* ShellContentBrowserClient::GetExtension(
content::SiteInstance* site_instance) {
ExtensionRegistry* registry =
ExtensionRegistry::Get(site_instance->GetBrowserContext());
return registry->enabled_extensions().GetExtensionOrAppByURL(
site_instance->GetSiteURL());
}
} // namespace apps } // namespace apps
...@@ -8,6 +8,12 @@ ...@@ -8,6 +8,12 @@
#include "base/compiler_specific.h" #include "base/compiler_specific.h"
#include "content/public/browser/content_browser_client.h" #include "content/public/browser/content_browser_client.h"
class GURL;
namespace extensions {
class Extension;
}
namespace apps { namespace apps {
class ShellBrowserMainParts; class ShellBrowserMainParts;
...@@ -24,8 +30,19 @@ class ShellContentBrowserClient : public content::ContentBrowserClient { ...@@ -24,8 +30,19 @@ class ShellContentBrowserClient : public content::ContentBrowserClient {
content::ProtocolHandlerMap* protocol_handlers) OVERRIDE; content::ProtocolHandlerMap* protocol_handlers) OVERRIDE;
// TODO(jamescook): Quota management? // TODO(jamescook): Quota management?
// TODO(jamescook): Speech recognition? // 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(CommandLine* command_line,
int child_process_id) OVERRIDE;
private: private:
// Returns the extension or app associated with |site_instance| or NULL.
const extensions::Extension* GetExtension(
content::SiteInstance* site_instance);
// Owned by content::BrowserMainLoop. // Owned by content::BrowserMainLoop.
ShellBrowserMainParts* browser_main_parts_; ShellBrowserMainParts* browser_main_parts_;
......
...@@ -12,15 +12,18 @@ ...@@ -12,15 +12,18 @@
#include "chrome/browser/extensions/extension_prefs.h" #include "chrome/browser/extensions/extension_prefs.h"
#include "chrome/common/extensions/extension_file_util.h" #include "chrome/common/extensions/extension_file_util.h"
#include "content/public/browser/browser_context.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_details.h"
#include "content/public/browser/notification_service.h" #include "content/public/browser/notification_service.h"
#include "content/public/browser/notification_source.h" #include "content/public/browser/notification_source.h"
#include "extensions/browser/event_router.h" #include "extensions/browser/event_router.h"
#include "extensions/browser/extension_registry.h" #include "extensions/browser/extension_registry.h"
#include "extensions/browser/info_map.h"
#include "extensions/browser/lazy_background_task_queue.h" #include "extensions/browser/lazy_background_task_queue.h"
#include "extensions/browser/process_manager.h" #include "extensions/browser/process_manager.h"
using content::BrowserContext; using content::BrowserContext;
using content::BrowserThread;
namespace extensions { namespace extensions {
...@@ -44,10 +47,16 @@ bool ShellExtensionSystem::LoadAndLaunchApp(const base::FilePath& app_dir) { ...@@ -44,10 +47,16 @@ bool ShellExtensionSystem::LoadAndLaunchApp(const base::FilePath& app_dir) {
return false; return false;
} }
// 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_INSTALLED.
ExtensionRegistry::Get(browser_context_)->AddEnabled(extension); ExtensionRegistry::Get(browser_context_)->AddEnabled(extension);
// TODO(jamescook): If RegisterExtensionWithRequestContexts() did something, RegisterExtensionWithRequestContexts(extension);
// this would be the place to call it.
content::NotificationService::current()->Notify( content::NotificationService::current()->Notify(
chrome::NOTIFICATION_EXTENSION_LOADED, chrome::NOTIFICATION_EXTENSION_LOADED,
...@@ -56,9 +65,6 @@ bool ShellExtensionSystem::LoadAndLaunchApp(const base::FilePath& app_dir) { ...@@ -56,9 +65,6 @@ bool ShellExtensionSystem::LoadAndLaunchApp(const base::FilePath& app_dir) {
// Inform the rest of the extensions system to start. // Inform the rest of the extensions system to start.
ready_.Signal(); ready_.Signal();
LOG(WARNING) << "-----------------------------------";
LOG(WARNING) << "app_shell is expected to crash now.";
LOG(WARNING) << "-----------------------------------";
content::NotificationService::current()->Notify( content::NotificationService::current()->Notify(
chrome::NOTIFICATION_EXTENSIONS_READY, chrome::NOTIFICATION_EXTENSIONS_READY,
content::Source<BrowserContext>(browser_context_), content::Source<BrowserContext>(browser_context_),
...@@ -79,7 +85,6 @@ void ShellExtensionSystem::InitForRegularProfile(bool extensions_enabled) { ...@@ -79,7 +85,6 @@ void ShellExtensionSystem::InitForRegularProfile(bool extensions_enabled) {
} }
ExtensionService* ShellExtensionSystem::extension_service() { ExtensionService* ShellExtensionSystem::extension_service() {
NOTREACHED();
return NULL; return NULL;
} }
...@@ -104,7 +109,9 @@ StateStore* ShellExtensionSystem::rules_store() { ...@@ -104,7 +109,9 @@ StateStore* ShellExtensionSystem::rules_store() {
} }
InfoMap* ShellExtensionSystem::info_map() { InfoMap* ShellExtensionSystem::info_map() {
return NULL; if (!info_map_.get())
info_map_ = new InfoMap;
return info_map_;
} }
LazyBackgroundTaskQueue* ShellExtensionSystem::lazy_background_task_queue() { LazyBackgroundTaskQueue* ShellExtensionSystem::lazy_background_task_queue() {
...@@ -133,6 +140,11 @@ InstallVerifier* ShellExtensionSystem::install_verifier() { ...@@ -133,6 +140,11 @@ InstallVerifier* ShellExtensionSystem::install_verifier() {
void ShellExtensionSystem::RegisterExtensionWithRequestContexts( void ShellExtensionSystem::RegisterExtensionWithRequestContexts(
const Extension* extension) { 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( void ShellExtensionSystem::UnregisterExtensionWithRequestContexts(
......
...@@ -20,6 +20,7 @@ class BrowserContext; ...@@ -20,6 +20,7 @@ class BrowserContext;
namespace extensions { namespace extensions {
class EventRouter; class EventRouter;
class InfoMap;
class LazyBackgroundTaskQueue; class LazyBackgroundTaskQueue;
class ProcessManager; class ProcessManager;
...@@ -63,6 +64,9 @@ class ShellExtensionSystem : public ExtensionSystem { ...@@ -63,6 +64,9 @@ class ShellExtensionSystem : public ExtensionSystem {
private: private:
content::BrowserContext* browser_context_; // Not owned. content::BrowserContext* browser_context_; // Not owned.
// Data to be accessed on the IO thread. Must outlive process_manager_.
scoped_refptr<InfoMap> info_map_;
scoped_ptr<LazyBackgroundTaskQueue> lazy_background_task_queue_; scoped_ptr<LazyBackgroundTaskQueue> lazy_background_task_queue_;
scoped_ptr<EventRouter> event_router_; scoped_ptr<EventRouter> event_router_;
scoped_ptr<ProcessManager> process_manager_; scoped_ptr<ProcessManager> process_manager_;
......
...@@ -30,6 +30,8 @@ ...@@ -30,6 +30,8 @@
#include "content/public/browser/content_browser_client.h" #include "content/public/browser/content_browser_client.h"
#include "content/public/browser/native_web_keyboard_event.h" #include "content/public/browser/native_web_keyboard_event.h"
#include "content/public/browser/notification_service.h" #include "content/public/browser/notification_service.h"
#include "content/public/browser/notification_source.h"
#include "content/public/browser/notification_types.h"
#include "content/public/browser/render_process_host.h" #include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_view_host.h" #include "content/public/browser/render_view_host.h"
#include "content/public/browser/render_widget_host_view.h" #include "content/public/browser/render_widget_host_view.h"
...@@ -191,13 +193,19 @@ void ExtensionHost::CreateRenderViewSoon() { ...@@ -191,13 +193,19 @@ void ExtensionHost::CreateRenderViewSoon() {
void ExtensionHost::CreateRenderViewNow() { void ExtensionHost::CreateRenderViewNow() {
LoadInitialURL(); LoadInitialURL();
if (IsBackgroundPage()) { if (!IsBackgroundPage()) {
DCHECK(IsRenderViewLive()); DCHECK(IsRenderViewLive());
ExtensionSystem::GetForBrowserContext(browser_context_)-> ExtensionService* service = GetExtensionService();
extension_service()->DidCreateRenderViewForBackgroundPage(this); if (service)
service->DidCreateRenderViewForBackgroundPage(this);
} }
} }
ExtensionService* ExtensionHost::GetExtensionService() {
return ExtensionSystem::GetForBrowserContext(browser_context_)
->extension_service();
}
const GURL& ExtensionHost::GetURL() const { const GURL& ExtensionHost::GetURL() const {
return host_contents()->GetURL(); return host_contents()->GetURL();
} }
...@@ -315,8 +323,13 @@ void ExtensionHost::DocumentAvailableInMainFrame() { ...@@ -315,8 +323,13 @@ void ExtensionHost::DocumentAvailableInMainFrame() {
void ExtensionHost::OnDocumentAvailable() { void ExtensionHost::OnDocumentAvailable() {
DCHECK(extension_host_type_ == VIEW_TYPE_EXTENSION_BACKGROUND_PAGE); DCHECK(extension_host_type_ == VIEW_TYPE_EXTENSION_BACKGROUND_PAGE);
ExtensionSystem::GetForBrowserContext(browser_context_)-> ExtensionService* service = GetExtensionService();
extension_service()->SetBackgroundPageReady(extension_); if (service)
service->SetBackgroundPageReady(extension_);
content::NotificationService::current()->Notify(
chrome::NOTIFICATION_EXTENSION_BACKGROUND_PAGE_READY,
content::Source<const Extension>(extension_),
content::NotificationService::NoDetails());
} }
void ExtensionHost::CloseContents(WebContents* contents) { void ExtensionHost::CloseContents(WebContents* contents) {
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include "extensions/common/stack_frame.h" #include "extensions/common/stack_frame.h"
#include "extensions/common/view_type.h" #include "extensions/common/view_type.h"
class ExtensionService;
class PrefsTabHelper; class PrefsTabHelper;
namespace content { namespace content {
...@@ -128,6 +129,9 @@ class ExtensionHost : public content::WebContentsDelegate, ...@@ -128,6 +129,9 @@ class ExtensionHost : public content::WebContentsDelegate,
// Actually create the RenderView for this host. See CreateRenderViewSoon. // Actually create the RenderView for this host. See CreateRenderViewSoon.
void CreateRenderViewNow(); void CreateRenderViewNow();
// Returns the ExtensionService for |browser_context_| or NULL if none exists.
ExtensionService* GetExtensionService();
// Message handlers. // Message handlers.
void OnRequest(const ExtensionHostMsg_Request_Params& params); void OnRequest(const ExtensionHostMsg_Request_Params& params);
void OnEventAck(); void OnEventAck();
......
...@@ -2502,6 +2502,8 @@ void ExtensionService::Observe(int type, ...@@ -2502,6 +2502,8 @@ void ExtensionService::Observe(int type,
break; break;
} }
case content::NOTIFICATION_RENDERER_PROCESS_CREATED: { case content::NOTIFICATION_RENDERER_PROCESS_CREATED: {
// TODO(jamescook): Extract this block of code to src/extensions so it
// can be shared with app_shell.
content::RenderProcessHost* process = content::RenderProcessHost* process =
content::Source<content::RenderProcessHost>(source).ptr(); content::Source<content::RenderProcessHost>(source).ptr();
Profile* host_profile = Profile* host_profile =
...@@ -2623,10 +2625,6 @@ bool ExtensionService::IsBackgroundPageReady(const Extension* extension) const { ...@@ -2623,10 +2625,6 @@ bool ExtensionService::IsBackgroundPageReady(const Extension* extension) const {
void ExtensionService::SetBackgroundPageReady(const Extension* extension) { void ExtensionService::SetBackgroundPageReady(const Extension* extension) {
DCHECK(extensions::BackgroundInfo::HasBackgroundPage(extension)); DCHECK(extensions::BackgroundInfo::HasBackgroundPage(extension));
extension_runtime_data_[extension->id()].background_page_ready = true; extension_runtime_data_[extension->id()].background_page_ready = true;
content::NotificationService::current()->Notify(
chrome::NOTIFICATION_EXTENSION_BACKGROUND_PAGE_READY,
content::Source<const Extension>(extension),
content::NotificationService::NoDetails());
} }
bool ExtensionService::IsBeingUpgraded(const Extension* extension) const { bool ExtensionService::IsBeingUpgraded(const Extension* extension) const {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment