diff options
author | mpcomplete@google.com <mpcomplete@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-02-27 19:35:09 +0000 |
---|---|---|
committer | mpcomplete@google.com <mpcomplete@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-02-27 19:35:09 +0000 |
commit | 81e6378c98d0e69339302527eb1de4735d1e2c3f (patch) | |
tree | d8020f1a2a842b0735c22a35e89a97ec7630bf17 /chrome/browser | |
parent | 4c8c60ee58cf2f22fcdc0cf3b30f1f5e8884f0ff (diff) | |
download | chromium_src-81e6378c98d0e69339302527eb1de4735d1e2c3f.zip chromium_src-81e6378c98d0e69339302527eb1de4735d1e2c3f.tar.gz chromium_src-81e6378c98d0e69339302527eb1de4735d1e2c3f.tar.bz2 |
Prototype extension process. This is a proof of concept, with a lot of
rough edges. Mostly this just fires up a renderer with an "extension" object
exposed, which right now only has a single method "getTestString".
I also did some misc cleanup along the way.
Review URL: http://codereview.chromium.org/27187
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@10620 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
-rw-r--r-- | chrome/browser/browser.scons | 2 | ||||
-rw-r--r-- | chrome/browser/browser.vcproj | 8 | ||||
-rwxr-xr-x | chrome/browser/extensions/extension_view.cc | 32 | ||||
-rwxr-xr-x | chrome/browser/extensions/extension_view.h | 46 | ||||
-rwxr-xr-x | chrome/browser/extensions/extension_view_unittest.cc | 108 | ||||
-rw-r--r-- | chrome/browser/extensions/extensions_service.cc | 15 | ||||
-rw-r--r-- | chrome/browser/extensions/extensions_service.h | 11 | ||||
-rw-r--r-- | chrome/browser/profile.cc | 3 | ||||
-rw-r--r-- | chrome/browser/renderer_host/render_view_host.cc | 25 | ||||
-rw-r--r-- | chrome/browser/renderer_host/render_view_host.h | 16 | ||||
-rw-r--r-- | chrome/browser/tab_contents/interstitial_page.cc | 2 | ||||
-rw-r--r-- | chrome/browser/views/hwnd_html_view.cc | 9 | ||||
-rw-r--r-- | chrome/browser/views/hwnd_html_view.h | 14 |
13 files changed, 263 insertions, 28 deletions
diff --git a/chrome/browser/browser.scons b/chrome/browser/browser.scons index 7e94112..ea53d85 100644 --- a/chrome/browser/browser.scons +++ b/chrome/browser/browser.scons @@ -506,6 +506,8 @@ input_files = ChromeFileList([ MSVSFilter('Extensions', [ 'extensions/extension.cc', 'extensions/extension.h', + 'extensions/extension_view.cc', + 'extensions/extension_view.h', 'extensions/extension_error_reporter.cc', 'extensions/extension_error_reporter.h', 'extensions/extension_protocols.h', diff --git a/chrome/browser/browser.vcproj b/chrome/browser/browser.vcproj index e5995c1..6f1a886 100644 --- a/chrome/browser/browser.vcproj +++ b/chrome/browser/browser.vcproj @@ -1922,6 +1922,14 @@ > </File> <File + RelativePath=".\extensions\extension_view.cc" + > + </File> + <File + RelativePath=".\extensions\extension_view.h" + > + </File> + <File RelativePath=".\extensions\extensions_service.cc" > </File> diff --git a/chrome/browser/extensions/extension_view.cc b/chrome/browser/extensions/extension_view.cc new file mode 100755 index 0000000..1647ecb --- /dev/null +++ b/chrome/browser/extensions/extension_view.cc @@ -0,0 +1,32 @@ +// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/extensions/extension_view.h" + +#include "chrome/browser/renderer_host/render_view_host.h" + +ExtensionView::ExtensionView(const GURL& url, Profile* profile) : + HWNDHtmlView(url, this, false), profile_(profile) { +} + +void ExtensionView::CreatingRenderer() { + render_view_host()->AllowExtensionBindings(); +} + +WebPreferences ExtensionView::GetWebkitPrefs() { + // TODO(mpcomplete): return some reasonable prefs. + return WebPreferences(); +} + +void ExtensionView::RunJavaScriptMessage( + const std::wstring& message, + const std::wstring& default_prompt, + const int flags, + IPC::Message* reply_msg, + bool* did_suppress_message) { + // Automatically cancel the javascript alert (otherwise the renderer hangs + // indefinitely). + *did_suppress_message = true; + render_view_host()->JavaScriptMessageBoxClosed(reply_msg, true, L""); +} diff --git a/chrome/browser/extensions/extension_view.h b/chrome/browser/extensions/extension_view.h new file mode 100755 index 0000000..5eb869c --- /dev/null +++ b/chrome/browser/extensions/extension_view.h @@ -0,0 +1,46 @@ +// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_VIEW_H_ +#define CHROME_BROWSER_EXTENSIONS_EXTENSION_VIEW_H_ + +#include "chrome/browser/renderer_host/render_view_host_delegate.h" + +// TODO(port): Port these files. +#if defined(OS_WIN) +#include "chrome/browser/views/hwnd_html_view.h" +#else +#include "chrome/common/temp_scaffolding_stubs.h" +#endif + +class Profile; +struct WebPreferences; + +// This class is the browser component of an extension component's RenderView. +// It handles setting up the renderer process, if needed, with special +// priviliges available to extensions. The view may be drawn to the screen or +// hidden. +class ExtensionView : public HWNDHtmlView, + public RenderViewHostDelegate { + public: + ExtensionView(const GURL& url, Profile* profile); + + // HWNDHtmlView + virtual void CreatingRenderer(); + + // RenderViewHostDelegate + virtual Profile* GetProfile() const { return profile_; } + virtual WebPreferences GetWebkitPrefs(); + virtual void RunJavaScriptMessage( + const std::wstring& message, + const std::wstring& default_prompt, + const int flags, + IPC::Message* reply_msg, + bool* did_suppress_message); + + private: + Profile* profile_; +}; + +#endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_VIEW_H_ diff --git a/chrome/browser/extensions/extension_view_unittest.cc b/chrome/browser/extensions/extension_view_unittest.cc new file mode 100755 index 0000000..930b068 --- /dev/null +++ b/chrome/browser/extensions/extension_view_unittest.cc @@ -0,0 +1,108 @@ +// Copyright (c) 2006-2008 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/message_loop.h" +#include "chrome/browser/browser.h" +#include "chrome/browser/renderer_host/render_view_host.h" +#include "chrome/browser/profile.h" +#include "chrome/browser/extensions/extension_view.h" +#include "chrome/browser/extensions/extensions_service.h" +#include "chrome/common/chrome_paths.h" +#include "chrome/common/notification_service.h" +#include "chrome/test/in_process_browser_test.h" +#include "chrome/test/ui_test_utils.h" + +namespace { + +// How long to wait for the extension to put up a javascript alert before giving +// up. +const int kAlertTimeoutMs = 10000; + +// The extension we're using as our test case. +const char* kExtensionId = "com.google.myextension1"; + +// This class starts up an extension process and waits until it tries to put +// up a javascript alert. +class MockExtensionView : public ExtensionView { + public: + MockExtensionView(const GURL& url, Profile* profile) + : ExtensionView(url, profile), got_message_(false) { + InitHidden(); + MessageLoop::current()->PostDelayedTask(FROM_HERE, + new MessageLoop::QuitTask, kAlertTimeoutMs); + ui_test_utils::RunMessageLoop(); + } + + bool got_message() { return got_message_; } + private: + virtual void RunJavaScriptMessage( + const std::wstring& message, + const std::wstring& default_prompt, + const int flags, + IPC::Message* reply_msg, + bool* did_suppress_message) { + got_message_ = true; + MessageLoopForUI::current()->Quit(); + } + + bool got_message_; +}; + +// This class waits for a specific extension to be loaded. +class ExtensionLoadedObserver : public NotificationObserver { + public: + explicit ExtensionLoadedObserver() : extension_(NULL) { + registrar_.Add(this, NotificationType::EXTENSIONS_LOADED, + NotificationService::AllSources()); + ui_test_utils::RunMessageLoop(); + } + + Extension* extension() { return extension_; } + private: + virtual void Observe(NotificationType type, const NotificationSource& source, + const NotificationDetails& details) { + if (type == NotificationType::EXTENSIONS_LOADED) { + ExtensionList* extensions = Details<ExtensionList>(details).ptr(); + for (size_t i = 0; i < (*extensions).size(); i++) { + if ((*extensions)[i]->id() == kExtensionId) { + extension_ = (*extensions)[i]; + MessageLoopForUI::current()->Quit(); + break; + } + } + } else { + NOTREACHED(); + } + } + + NotificationRegistrar registrar_; + Extension* extension_; +}; + +} // namespace + +class ExtensionViewTest : public InProcessBrowserTest { +}; + +IN_PROC_BROWSER_TEST_F(ExtensionViewTest, TestMe) { + // Get the path to our extension. + FilePath path; + ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &path)); + path = path.AppendASCII("extensions"). + AppendASCII("good").AppendASCII("extension1").AppendASCII("1"); + + // Load it. + Profile* profile = browser()->profile(); + profile->GetExtensionsService()->Init(); + profile->GetExtensionsService()->LoadExtension(path); + + // Now wait for it to load, and grab a pointer to it. + Extension* extension = ExtensionLoadedObserver().extension(); + ASSERT_TRUE(extension); + GURL url = Extension::GetResourceURL(extension->url(), "index.html"); + + // Start the extension process and wait for it to show a javascript alert. + MockExtensionView view(url, profile); + EXPECT_TRUE(view.got_message()); +} diff --git a/chrome/browser/extensions/extensions_service.cc b/chrome/browser/extensions/extensions_service.cc index 9fc0040..3271920 100644 --- a/chrome/browser/extensions/extensions_service.cc +++ b/chrome/browser/extensions/extensions_service.cc @@ -16,7 +16,9 @@ #include "chrome/browser/browser_process.h" #include "chrome/browser/extensions/extension_error_reporter.h" #include "chrome/browser/extensions/user_script_master.h" +#include "chrome/browser/extensions/extension_view.h" #include "chrome/browser/plugin_service.h" +#include "chrome/browser/profile.h" #include "chrome/common/json_value_serializer.h" #include "chrome/common/notification_service.h" #include "chrome/common/unzip.h" @@ -63,12 +65,12 @@ const wchar_t kRegistryExtensionVersion[] = L"version"; const char kExternalInstallFile[] = "EXTERNAL_INSTALL"; } - -ExtensionsService::ExtensionsService(const FilePath& profile_directory, +ExtensionsService::ExtensionsService(Profile* profile, UserScriptMaster* user_script_master) : message_loop_(MessageLoop::current()), backend_(new ExtensionsServiceBackend), - install_directory_(profile_directory.AppendASCII(kInstallDirectoryName)), + install_directory_(profile->GetPath().AppendASCII(kInstallDirectoryName)), + profile_(profile), user_script_master_(user_script_master) { } @@ -104,6 +106,13 @@ bool ExtensionsService::Init() { return true; } +void ExtensionsService::LaunchExtensionProcess(Extension* extension) { + // TODO(mpcomplete): Do something useful here. + GURL url = Extension::GetResourceURL(extension->url(), "index.html"); + ExtensionView* view = new ExtensionView(url, profile_); + view->InitHidden(); +} + MessageLoop* ExtensionsService::GetMessageLoop() { return message_loop_; } diff --git a/chrome/browser/extensions/extensions_service.h b/chrome/browser/extensions/extensions_service.h index efba0086..7489de7 100644 --- a/chrome/browser/extensions/extensions_service.h +++ b/chrome/browser/extensions/extensions_service.h @@ -16,6 +16,7 @@ typedef std::vector<Extension*> ExtensionList; class ExtensionsServiceBackend; +class Profile; class UserScriptMaster; // Interface for the frontend to implement. Typically, this will be @@ -51,8 +52,7 @@ class ExtensionsServiceFrontendInterface // Manages installed and running Chromium extensions. class ExtensionsService : public ExtensionsServiceFrontendInterface { public: - ExtensionsService(const FilePath& profile_directory, - UserScriptMaster* user_script_master); + ExtensionsService(Profile* profile, UserScriptMaster* user_script_master); ~ExtensionsService(); // Gets the list of currently installed extensions. @@ -63,6 +63,10 @@ class ExtensionsService : public ExtensionsServiceFrontendInterface { // Initialize and start all installed extensions. bool Init(); + // Start the extension process for this extension. TODO(mpcomplete): not sure + // how this should actually work yet. + void LaunchExtensionProcess(Extension* extension); + // ExtensionsServiceFrontendInterface virtual MessageLoop* GetMessageLoop(); virtual void InstallExtension(const FilePath& extension_path); @@ -90,6 +94,9 @@ class ExtensionsService : public ExtensionsServiceFrontendInterface { // The full path to the directory where extensions are installed. FilePath install_directory_; + // The profile associated with this set of extensions. + Profile* profile_; + // The user script master for this profile. scoped_refptr<UserScriptMaster> user_script_master_; diff --git a/chrome/browser/profile.cc b/chrome/browser/profile.cc index 9600c6c..7c7041e 100644 --- a/chrome/browser/profile.cc +++ b/chrome/browser/profile.cc @@ -371,8 +371,7 @@ void ProfileImpl::InitExtensions() { ExtensionErrorReporter::Init(true); // allow noisy errors. user_script_master_ = new UserScriptMaster( g_browser_process->file_thread()->message_loop(), script_dir); - extensions_service_ = new ExtensionsService( - FilePath(GetPath()), user_script_master_.get()); + extensions_service_ = new ExtensionsService(this, user_script_master_.get()); // If we have extensions, the extension service will kick off the first scan // after extensions are loaded. Otherwise, we need to do that now. diff --git a/chrome/browser/renderer_host/render_view_host.cc b/chrome/browser/renderer_host/render_view_host.cc index 894e02a..3da3fef 100644 --- a/chrome/browser/renderer_host/render_view_host.cc +++ b/chrome/browser/renderer_host/render_view_host.cc @@ -24,6 +24,7 @@ #include "chrome/browser/tab_contents/navigation_entry.h" #include "chrome/browser/tab_contents/site_instance.h" #include "chrome/browser/tab_contents/web_contents.h" +#include "chrome/common/bindings_policy.h" #include "chrome/common/render_messages.h" #include "chrome/common/resource_bundle.h" #include "chrome/common/notification_service.h" @@ -88,9 +89,8 @@ RenderViewHost::RenderViewHost(SiteInstance* instance, renderer_initialized_(false), waiting_for_drag_context_response_(false), debugger_attached_(false), - enable_dom_ui_bindings_(false), + enabled_bindings_(0), pending_request_id_(0), - enable_external_host_bindings_(false), modal_dialog_count_(0), navigations_suspended_(false), suspended_nav_message_(NULL), @@ -178,8 +178,7 @@ bool RenderViewHost::CreateRenderView() { // If it's enabled, tell the renderer to set up the Javascript bindings for // sending messages back to the browser. - Send(new ViewMsg_AllowBindings( - routing_id(), enable_dom_ui_bindings_, enable_external_host_bindings_)); + Send(new ViewMsg_AllowBindings(routing_id(), enabled_bindings_)); // Let our delegate know that we created a RenderView. delegate_->RenderViewCreated(this); @@ -574,24 +573,30 @@ void RenderViewHost::DragSourceSystemDragEnded() { } void RenderViewHost::AllowDomAutomationBindings() { - // Expose the binding that allows the DOM to send messages here. - Send(new ViewMsg_AllowDomAutomationBindings(routing_id(), true)); + DCHECK(!renderer_initialized_); + enabled_bindings_ |= BindingsPolicy::DOM_AUTOMATION; +} + +void RenderViewHost::AllowExternalHostBindings() { + DCHECK(!renderer_initialized_); + enabled_bindings_ |= BindingsPolicy::EXTERNAL_HOST; } void RenderViewHost::AllowDOMUIBindings() { DCHECK(!renderer_initialized_); - enable_dom_ui_bindings_ = true; + enabled_bindings_ |= BindingsPolicy::DOM_UI; RendererSecurityPolicy::GetInstance()->GrantDOMUIBindings( process()->host_id()); } -void RenderViewHost::AllowExternalHostBindings() { - enable_external_host_bindings_ = true; +void RenderViewHost::AllowExtensionBindings() { + DCHECK(!renderer_initialized_); + enabled_bindings_ |= BindingsPolicy::EXTENSION; } void RenderViewHost::SetDOMUIProperty(const std::string& name, const std::string& value) { - DCHECK(enable_dom_ui_bindings_); + DCHECK(BindingsPolicy::is_dom_ui_enabled(enabled_bindings_)); Send(new ViewMsg_SetDOMUIProperty(routing_id(), name, value)); } diff --git a/chrome/browser/renderer_host/render_view_host.h b/chrome/browser/renderer_host/render_view_host.h index 7a0a8148..79c9ca6 100644 --- a/chrome/browser/renderer_host/render_view_host.h +++ b/chrome/browser/renderer_host/render_view_host.h @@ -308,10 +308,12 @@ class RenderViewHost : public RenderWidgetHost { // Tell the render view to expose DOM automation bindings so that the js // content can send JSON-encoded data back to automation in the parent // process. + // Must be called before CreateRenderView(). void AllowDomAutomationBindings(); // Tell the render view to allow the javascript access to // the external host via automation. + // Must be called before CreateRenderView(). void AllowExternalHostBindings(); // Tell the render view to expose DOM bindings so that the JS content @@ -320,6 +322,10 @@ class RenderViewHost : public RenderWidgetHost { // Must be called before CreateRenderView(). void AllowDOMUIBindings(); + // Tell the render view to expose privileged bindings for use by extensions. + // Must be called before CreateRenderView(). + void AllowExtensionBindings(); + // Tells the renderer which render view should be inspected by developer // tools loaded in it. This method should be called before renderer is // created. @@ -574,9 +580,9 @@ class RenderViewHost : public RenderWidgetHost { // is the debugger attached to us or not bool debugger_attached_; - // True if we've been told to set up the the Javascript bindings for - // sending messages back to the browser. - bool enable_dom_ui_bindings_; + // A bitwise OR of bindings types that have been enabled for this RenderView. + // See BindingsPolicy for details. + int enabled_bindings_; // The request_id for the pending cross-site request. Set to -1 if // there is a pending request, but we have not yet started the unload @@ -585,10 +591,6 @@ class RenderViewHost : public RenderWidgetHost { // and thus started the unload process. int pending_request_id_; - // True if javascript access to the external host (through - // automation) is allowed. - bool enable_external_host_bindings_; - // Handle to an event that's set when the page is showing a modal dialog box // (or equivalent constrained window). The renderer and plugin processes // check this to know if they should pump messages/tasks then. diff --git a/chrome/browser/tab_contents/interstitial_page.cc b/chrome/browser/tab_contents/interstitial_page.cc index 9781a0e..688c6f1 100644 --- a/chrome/browser/tab_contents/interstitial_page.cc +++ b/chrome/browser/tab_contents/interstitial_page.cc @@ -256,11 +256,11 @@ RenderViewHost* InterstitialPage::CreateRenderViewHost() { view->set_parent_hwnd(tab_->GetContentNativeView()); WebContentsViewWin* web_contents_view = static_cast<WebContentsViewWin*>(tab_->view()); + render_view_host->AllowDomAutomationBindings(); render_view_host->CreateRenderView(); // SetSize must be called after CreateRenderView or the HWND won't show. view->SetSize(web_contents_view->GetContainerSize()); - render_view_host->AllowDomAutomationBindings(); return render_view_host; #else // TODO(port): RenderWidgetHost* is implemented, but Create and diff --git a/chrome/browser/views/hwnd_html_view.cc b/chrome/browser/views/hwnd_html_view.cc index 7b7fbfc..000d92b 100644 --- a/chrome/browser/views/hwnd_html_view.cc +++ b/chrome/browser/views/hwnd_html_view.cc @@ -9,6 +9,7 @@ #include "chrome/browser/renderer_host/render_view_host_delegate.h" #include "chrome/browser/tab_contents/site_instance.h" #include "chrome/views/widget.h" +#include "chrome/views/widget_win.h" HWNDHtmlView::~HWNDHtmlView() { if (render_view_host_) { @@ -18,6 +19,13 @@ HWNDHtmlView::~HWNDHtmlView() { } } +void HWNDHtmlView::InitHidden() { + // TODO(mpcomplete): make it possible to create a RenderView without an HWND. + views::WidgetWin* win = new views::WidgetWin; + win->Init(NULL, gfx::Rect(), true); + win->SetContentsView(this); +} + void HWNDHtmlView::Init(HWND parent_hwnd) { DCHECK(!render_view_host_) << "Already initialized."; RenderViewHost* rvh = new RenderViewHost( @@ -40,6 +48,7 @@ void HWNDHtmlView::Init(HWND parent_hwnd) { // Start up the renderer. if (allow_dom_ui_bindings_) rvh->AllowDOMUIBindings(); + CreatingRenderer(); rvh->CreateRenderView(); rvh->NavigateToURL(content_url_); initialized_ = true; diff --git a/chrome/browser/views/hwnd_html_view.h b/chrome/browser/views/hwnd_html_view.h index 4405f2a..67952a2 100644 --- a/chrome/browser/views/hwnd_html_view.h +++ b/chrome/browser/views/hwnd_html_view.h @@ -28,14 +28,22 @@ class HWNDHtmlView : public views::HWNDView { RenderViewHost* render_view_host() { return render_view_host_; } + // Initialize the view without a parent window. Used for extensions that + // don't display UI. + void InitHidden(); + protected: - // View overrides. - virtual void ViewHierarchyChanged(bool is_add, View *parent, View *child); + // View overrides. + virtual void ViewHierarchyChanged(bool is_add, View *parent, View *child); + + // Called just before we create the RenderView, to give subclasses an + // opportunity to do some setup. + virtual void CreatingRenderer() {} private: // Initialize the view, parented to |parent|, and show it. void Init(HWND parent); - + // The URL of the HTML content to render and show in this view. GURL content_url_; |