diff options
author | aa@chromium.org <aa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-05-11 22:07:08 +0000 |
---|---|---|
committer | aa@chromium.org <aa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-05-11 22:07:08 +0000 |
commit | 41999c790950781a3598bad03b6179d685e9d82a (patch) | |
tree | ae629d8bb881848b3c71eed3f5d458780d655085 | |
parent | 85d85890e689af734e46660b561fcfc2b69f993f (diff) | |
download | chromium_src-41999c790950781a3598bad03b6179d685e9d82a.zip chromium_src-41999c790950781a3598bad03b6179d685e9d82a.tar.gz chromium_src-41999c790950781a3598bad03b6179d685e9d82a.tar.bz2 |
Revert "Revert "Looks like this introduced leaks in sync ui tests. Sigh.""
This reverts commit cb8e078c2e7bebf0604871ec0bda69ceac3734d2.
TBR=mpcomplete@chromium.org
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@85058 0039d316-1c4b-4281-b951-d872f2087c98
38 files changed, 518 insertions, 460 deletions
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc index 8efed98..b7ce694 100644 --- a/chrome/browser/chrome_content_browser_client.cc +++ b/chrome/browser/chrome_content_browser_client.cc @@ -26,19 +26,13 @@ #include "chrome/browser/ui/webui/chrome_web_ui_factory.h" #include "chrome/common/child_process_logging.h" #include "chrome/common/chrome_switches.h" -#include "chrome/common/extensions/extension_messages.h" #include "chrome/common/pref_names.h" -#include "chrome/common/url_constants.h" -#include "content/browser/browsing_instance.h" -#include "content/browser/child_process_security_policy.h" #include "content/browser/renderer_host/browser_render_process_host.h" #include "content/browser/renderer_host/render_view_host.h" #include "content/browser/renderer_host/render_view_host_notification_task.h" #include "content/browser/resource_context.h" -#include "content/browser/site_instance.h" #include "content/browser/tab_contents/tab_contents.h" #include "content/browser/worker_host/worker_process_host.h" -#include "content/common/bindings_policy.h" #include "net/base/cookie_monster.h" #include "net/base/cookie_options.h" #include "net/base/static_cookie_policy.h" @@ -48,65 +42,6 @@ #include "chrome/browser/crash_handler_host_linux.h" #endif // OS_LINUX -namespace { - -void InitRenderViewHostForExtensions(RenderViewHost* render_view_host) { - // Note that due to GetEffectiveURL(), even hosted apps will have a - // chrome-extension:// URL for their site, so we can ignore that wrinkle here. - SiteInstance* site_instance = render_view_host->site_instance(); - const GURL& site = site_instance->site(); - RenderProcessHost* process = render_view_host->process(); - - if (!site.SchemeIs(chrome::kExtensionScheme)) - return; - - Profile* profile = site_instance->browsing_instance()->profile(); - ExtensionService* service = profile->GetExtensionService(); - if (!service) - return; - - ExtensionProcessManager* process_manager = - profile->GetExtensionProcessManager(); - CHECK(process_manager); - - // This can happen if somebody typos a chrome-extension:// URL. - const Extension* extension = service->GetExtensionByURL(site); - if (!extension) - return; - - site_instance->GetProcess()->mark_is_extension_process(); - - // Register the association between extension and process with - // ExtensionProcessManager. - process_manager->RegisterExtensionProcess(extension->id(), process->id()); - - // Record which, if any, installed app is associated with this process. - // TODO(aa): Totally lame to store this state in a global map in extension - // service. Can we get it from EPM instead? - if (extension->is_app()) - service->SetInstalledAppForRenderer(process->id(), extension); - - // Some extensions use chrome:// URLs. - Extension::Type type = extension->GetType(); - if (type == Extension::TYPE_EXTENSION || - type == Extension::TYPE_PACKAGED_APP) { - ChildProcessSecurityPolicy::GetInstance()->GrantScheme( - process->id(), chrome::kChromeUIScheme); - } - - // Enable extension bindings for the renderer. Currently only extensions, - // packaged apps, and hosted component apps use extension bindings. - if (type == Extension::TYPE_EXTENSION || - type == Extension::TYPE_PACKAGED_APP || - (type == Extension::TYPE_HOSTED_APP && - extension->location() == Extension::COMPONENT)) { - render_view_host->Send(new ExtensionMsg_ActivateExtension(extension->id())); - render_view_host->AllowBindings(BindingsPolicy::EXTENSION); - } -} - -} - namespace chrome { void ChromeContentBrowserClient::RenderViewHostCreated( @@ -115,8 +50,24 @@ void ChromeContentBrowserClient::RenderViewHostCreated( new DesktopNotificationHandler(render_view_host); new DevToolsHandler(render_view_host); new ExtensionMessageHandler(render_view_host); +} - InitRenderViewHostForExtensions(render_view_host); +void ChromeContentBrowserClient::PreCreateRenderView( + RenderViewHost* render_view_host, + Profile* profile, + const GURL& url) { + // Tell the RenderViewHost whether it will be used for an extension process. + ExtensionService* service = profile->GetExtensionService(); + if (service) { + bool is_extension_process = service->ExtensionBindingsAllowed(url); + render_view_host->set_is_extension_process(is_extension_process); + + const Extension* installed_app = service->GetInstalledApp(url); + if (installed_app) { + service->SetInstalledAppForRenderer( + render_view_host->process()->id(), installed_app); + } + } } void ChromeContentBrowserClient::BrowserRenderProcessHostCreated( diff --git a/chrome/browser/chrome_content_browser_client.h b/chrome/browser/chrome_content_browser_client.h index 2ba3e24..ee81fd3 100644 --- a/chrome/browser/chrome_content_browser_client.h +++ b/chrome/browser/chrome_content_browser_client.h @@ -13,6 +13,9 @@ namespace chrome { class ChromeContentBrowserClient : public content::ContentBrowserClient { public: virtual void RenderViewHostCreated(RenderViewHost* render_view_host); + virtual void PreCreateRenderView(RenderViewHost* render_view_host, + Profile* profile, + const GURL& url); virtual void BrowserRenderProcessHostCreated(BrowserRenderProcessHost* host); virtual void WorkerProcessHostCreated(WorkerProcessHost* host); virtual content::WebUIFactory* GetWebUIFactory(); diff --git a/chrome/browser/extensions/extension_bookmark_manager_api.cc b/chrome/browser/extensions/extension_bookmark_manager_api.cc index 6d89d373..6f23fe8 100644 --- a/chrome/browser/extensions/extension_bookmark_manager_api.cc +++ b/chrome/browser/extensions/extension_bookmark_manager_api.cc @@ -365,13 +365,12 @@ bool StartDragBookmarkManagerFunction::RunImpl() { EXTENSION_FUNCTION_VALIDATE( GetNodesFromArguments(model, args_.get(), 0, &nodes)); - if (render_view_host_->delegate()->GetRenderViewType() == + if (dispatcher()->render_view_host()->delegate()->GetRenderViewType() == ViewType::TAB_CONTENTS) { - TabContents* tab_contents = - dispatcher()->delegate()->GetAssociatedTabContents(); - CHECK(tab_contents); - bookmark_utils::DragBookmarks(profile(), nodes, - tab_contents->GetNativeView()); + ExtensionWebUI* web_ui = + static_cast<ExtensionWebUI*>(dispatcher()->delegate()); + bookmark_utils::DragBookmarks( + profile(), nodes, web_ui->tab_contents()->GetNativeView()); return true; } else { @@ -407,14 +406,10 @@ bool DropBookmarkManagerFunction::RunImpl() { else drop_index = drop_parent->child_count(); - if (render_view_host_->delegate()->GetRenderViewType() == + if (dispatcher()->render_view_host()->delegate()->GetRenderViewType() == ViewType::TAB_CONTENTS) { - TabContents* tab_contents = - dispatcher()->delegate()->GetAssociatedTabContents(); - CHECK(tab_contents); ExtensionWebUI* web_ui = - static_cast<ExtensionWebUI*>(tab_contents->web_ui()); - CHECK(web_ui); + static_cast<ExtensionWebUI*>(dispatcher()->delegate()); ExtensionBookmarkManagerEventRouter* router = web_ui->extension_bookmark_manager_event_router(); diff --git a/chrome/browser/extensions/extension_bookmarks_module.cc b/chrome/browser/extensions/extension_bookmarks_module.cc index 37a814f..1777e79 100644 --- a/chrome/browser/extensions/extension_bookmarks_module.cc +++ b/chrome/browser/extensions/extension_bookmarks_module.cc @@ -856,7 +856,7 @@ void BookmarksIOFunction::ShowSelectFileDialog(SelectFileDialog::Type type, file_type_info.extensions[0].push_back(FILE_PATH_LITERAL("html")); TabContents* tab_contents = dispatcher()->delegate()-> - GetAssociatedTabContents(); + associated_tab_contents(); // |tab_contents| can be NULL (for background pages), which is fine. In such // a case if file-selection dialogs are forbidden by policy, we will not diff --git a/chrome/browser/extensions/extension_file_browser_private_api.cc b/chrome/browser/extensions/extension_file_browser_private_api.cc index 6063d3c..bff14a5 100644 --- a/chrome/browser/extensions/extension_file_browser_private_api.cc +++ b/chrome/browser/extensions/extension_file_browser_private_api.cc @@ -352,7 +352,8 @@ void RequestLocalFileSystemFunction::RequestOnFileThread( } bool RequestLocalFileSystemFunction::RunImpl() { - if (!dispatcher() || !render_view_host() || !render_view_host()->process()) + if (!dispatcher() || !dispatcher()->render_view_host() || + !dispatcher()->render_view_host()->process()) return false; BrowserThread::PostTask( @@ -360,7 +361,7 @@ bool RequestLocalFileSystemFunction::RunImpl() { NewRunnableMethod(this, &RequestLocalFileSystemFunction::RequestOnFileThread, source_url_, - render_view_host()->process()->id())); + dispatcher()->render_view_host()->process()->id())); // Will finish asynchronously. return true; } @@ -677,7 +678,7 @@ void ExecuteTasksFileBrowserFunction::RequestFileEntryOnFileThread( new ExecuteTasksFileSystemCallbackDispatcher( this, profile(), - render_view_host()->process()->id(), + dispatcher()->render_view_host()->process()->id(), source_url, GetExtension(), task_id, @@ -803,13 +804,13 @@ FileDialogFunction::Callback::Find(int32 tab_id) { int32 FileDialogFunction::GetTabId() const { - return dispatcher()->delegate()->GetAssociatedTabContents()-> + return dispatcher()->delegate()->associated_tab_contents()-> controller().session_id().id(); } const FileDialogFunction::Callback& FileDialogFunction::GetCallback() const { if (!dispatcher() || !dispatcher()->delegate() || - !dispatcher()->delegate()->GetAssociatedTabContents()) { + !dispatcher()->delegate()->associated_tab_contents()) { return Callback::null(); } return Callback::Find(GetTabId()); @@ -817,7 +818,7 @@ const FileDialogFunction::Callback& FileDialogFunction::GetCallback() const { void FileDialogFunction::CloseDialog(HtmlDialogView* dialog) { DCHECK(dialog); - TabContents* contents = dispatcher()->delegate()->GetAssociatedTabContents(); + TabContents* contents = dispatcher()->delegate()->associated_tab_contents(); if (contents) dialog->CloseContents(contents); } diff --git a/chrome/browser/extensions/extension_function.cc b/chrome/browser/extensions/extension_function.cc index f390d72..9f0d065 100644 --- a/chrome/browser/extensions/extension_function.cc +++ b/chrome/browser/extensions/extension_function.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2010 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -9,31 +9,6 @@ #include "chrome/browser/extensions/extension_function_dispatcher.h" #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/common/extensions/extension_messages.h" -#include "content/browser/renderer_host/render_process_host.h" -#include "content/browser/renderer_host/render_view_host.h" -#include "content/browser/user_metrics.h" -#include "content/common/notification_source.h" -#include "content/common/notification_type.h" -#include "content/common/result_codes.h" - -ExtensionFunction::RenderViewHostTracker::RenderViewHostTracker( - ExtensionFunction* function) - : function_(function) { - registrar_.Add(this, - NotificationType::RENDER_VIEW_HOST_DELETED, - Source<RenderViewHost>(function->render_view_host())); -} - -void ExtensionFunction::RenderViewHostTracker::Observe( - NotificationType type, - const NotificationSource& source, - const NotificationDetails& details) { - CHECK(type == NotificationType::RENDER_VIEW_HOST_DELETED); - CHECK(Source<RenderViewHost>(source).ptr() == - function_->render_view_host()); - function_->SetRenderViewHost(NULL); -} ExtensionFunction::ExtensionFunction() : request_id_(-1), @@ -46,11 +21,6 @@ ExtensionFunction::ExtensionFunction() ExtensionFunction::~ExtensionFunction() { } -void ExtensionFunction::SetRenderViewHost(RenderViewHost* render_view_host) { - render_view_host_ = render_view_host; - tracker_.reset(render_view_host ? new RenderViewHostTracker(this) : NULL); -} - const Extension* ExtensionFunction::GetExtension() { ExtensionService* service = profile_->GetExtensionService(); DCHECK(service); @@ -58,7 +28,7 @@ const Extension* ExtensionFunction::GetExtension() { } Browser* ExtensionFunction::GetCurrentBrowser() { - return dispatcher()->GetCurrentBrowser(render_view_host_, include_incognito_); + return dispatcher()->GetCurrentBrowser(include_incognito_); } AsyncExtensionFunction::AsyncExtensionFunction() @@ -91,28 +61,12 @@ void AsyncExtensionFunction::Run() { } void AsyncExtensionFunction::SendResponse(bool success) { - if (!render_view_host_ || !dispatcher()) + if (!dispatcher()) return; if (bad_message_) { - HandleBadMessage(); - return; - } - - render_view_host_->Send(new ExtensionMsg_Response( - render_view_host_->routing_id(), request_id_, success, - GetResult(), GetError())); -} - -void AsyncExtensionFunction::HandleBadMessage() { - LOG(ERROR) << "bad extension message " << name_ << " : terminating renderer."; - if (RenderProcessHost::run_renderer_in_process()) { - // In single process mode it is better if we don't suicide but just crash. - CHECK(false); + dispatcher()->HandleBadMessage(this); } else { - NOTREACHED(); - UserMetrics::RecordAction(UserMetricsAction("BadMessageTerminate_EFD")); - base::KillProcess(render_view_host_->process()->GetHandle(), - ResultCodes::KILLED_BAD_MESSAGE, false); + dispatcher()->SendResponse(this, success); } } diff --git a/chrome/browser/extensions/extension_function.h b/chrome/browser/extensions/extension_function.h index 7806a0a..7913703 100644 --- a/chrome/browser/extensions/extension_function.h +++ b/chrome/browser/extensions/extension_function.h @@ -11,8 +11,6 @@ #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" -#include "content/common/notification_observer.h" -#include "content/common/notification_registrar.h" #include "chrome/browser/extensions/extension_function_dispatcher.h" class ExtensionFunctionDispatcher; @@ -39,13 +37,10 @@ class Value; // Abstract base class for extension functions the ExtensionFunctionDispatcher // knows how to dispatch to. -class ExtensionFunction - : public base::RefCountedThreadSafe<ExtensionFunction> { +class ExtensionFunction : public base::RefCountedThreadSafe<ExtensionFunction> { public: ExtensionFunction(); - virtual ~ExtensionFunction(); - // Specifies the name of the function. void set_name(const std::string& name) { name_ = name; } const std::string name() const { return name_; } @@ -61,9 +56,6 @@ class ExtensionFunction } std::string extension_id() const { return extension_id_; } - void SetRenderViewHost(RenderViewHost* render_view_host); - RenderViewHost* render_view_host() const { return render_view_host_; } - // Specifies the raw arguments to the function, as a JSON value. virtual void SetArgs(const ListValue* args) = 0; @@ -110,6 +102,8 @@ class ExtensionFunction protected: friend class base::RefCountedThreadSafe<ExtensionFunction>; + virtual ~ExtensionFunction(); + // Gets the extension that called this function. This can return NULL for // async functions, for example if the extension is unloaded while the // function is running. @@ -136,9 +130,6 @@ class ExtensionFunction // The peer to the dispatcher that will service this extension function call. scoped_refptr<ExtensionFunctionDispatcher::Peer> peer_; - // The RenderViewHost we will send responses too. - RenderViewHost* render_view_host_; - // Id of this request, used to map the response back to the caller. int request_id_; @@ -167,26 +158,6 @@ class ExtensionFunction // True if the call was made in response of user gesture. bool user_gesture_; - private: - // Helper class to track the lifetime of ExtensionFunction's RenderViewHost - // pointer and NULL it out when it dies. We use this separate class (instead - // of implementing NotificationObserver on ExtensionFunction) because it is - // common for subclasses of ExtensionFunction to be NotificationObservers, and - // it would be an easy error to forget to call the base class's Observe() - // method. - class RenderViewHostTracker : public NotificationObserver { - public: - explicit RenderViewHostTracker(ExtensionFunction* extension_function); - private: - virtual void Observe(NotificationType type, - const NotificationSource& source, - const NotificationDetails& details); - ExtensionFunction* function_; - NotificationRegistrar registrar_; - }; - - scoped_ptr<RenderViewHostTracker> tracker_; - DISALLOW_COPY_AND_ASSIGN(ExtensionFunction); }; @@ -233,13 +204,6 @@ class AsyncExtensionFunction : public ExtensionFunction { // returning. The calling renderer process will be killed. bool bad_message_; - private: - // Called when we receive an extension api request that is invalid in a way - // that JSON validation in the renderer should have caught. This should never - // happen and could be an attacker trying to exploit the browser, so we crash - // the renderer instead. - void HandleBadMessage(); - DISALLOW_COPY_AND_ASSIGN(AsyncExtensionFunction); }; diff --git a/chrome/browser/extensions/extension_function_dispatcher.cc b/chrome/browser/extensions/extension_function_dispatcher.cc index 8a27836..6a69d42 100644 --- a/chrome/browser/extensions/extension_function_dispatcher.cc +++ b/chrome/browser/extensions/extension_function_dispatcher.cc @@ -30,6 +30,7 @@ #include "chrome/browser/extensions/extension_omnibox_api.h" #include "chrome/browser/extensions/extension_page_actions_module.h" #include "chrome/browser/extensions/extension_preference_api.h" +#include "chrome/browser/extensions/extension_process_manager.h" #include "chrome/browser/extensions/extension_processes_api.h" #include "chrome/browser/extensions/extension_proxy_api.h" #include "chrome/browser/extensions/extension_rlz_module.h" @@ -51,6 +52,9 @@ #include "content/browser/child_process_security_policy.h" #include "content/browser/renderer_host/render_process_host.h" #include "content/browser/renderer_host/render_view_host.h" +#include "content/browser/user_metrics.h" +#include "content/common/notification_service.h" +#include "content/common/result_codes.h" #include "ipc/ipc_message.h" #include "ipc/ipc_message_macros.h" #include "third_party/skia/include/core/SkBitmap.h" @@ -381,19 +385,71 @@ void ExtensionFunctionDispatcher::ResetFunctions() { FactoryRegistry::GetInstance()->ResetFunctions(); } -ExtensionFunctionDispatcher::ExtensionFunctionDispatcher(Profile* profile, - Delegate* delegate) - : profile_(profile), +ExtensionFunctionDispatcher* ExtensionFunctionDispatcher::Create( + RenderViewHost* render_view_host, + Delegate* delegate, + const GURL& url) { + ExtensionService* service = + render_view_host->process()->profile()->GetExtensionService(); + DCHECK(service); + + if (!service->ExtensionBindingsAllowed(url)) + return NULL; + + const Extension* extension = service->GetExtensionByURL(url); + if (!extension) + extension = service->GetExtensionByWebExtent(url); + + if (extension) + return new ExtensionFunctionDispatcher(render_view_host, delegate, + extension, url); + else + return NULL; +} + +ExtensionFunctionDispatcher::ExtensionFunctionDispatcher( + RenderViewHost* render_view_host, + Delegate* delegate, + const Extension* extension, + const GURL& url) + : profile_(render_view_host->process()->profile()), + render_view_host_(render_view_host), delegate_(delegate), + url_(url), + extension_id_(extension->id()), ALLOW_THIS_IN_INITIALIZER_LIST(peer_(new Peer(this))) { + // TODO(erikkay) should we do something for these errors in Release? + DCHECK(extension); + DCHECK(url.SchemeIs(chrome::kExtensionScheme) || + extension->location() == Extension::COMPONENT); + + // Notify the ExtensionProcessManager that the view was created. + ExtensionProcessManager* epm = profile()->GetExtensionProcessManager(); + epm->RegisterExtensionProcess(extension_id(), + render_view_host->process()->id()); + + // Activate this extension in the renderer. This must be done before any + // extension JavaScript code runs because it controls some privileges the + // extension code has in the renderer. + render_view_host->Send(new ExtensionMsg_ActivateExtension(extension->id())); + + NotificationService::current()->Notify( + NotificationType::EXTENSION_FUNCTION_DISPATCHER_CREATED, + Source<Profile>(profile_), + Details<ExtensionFunctionDispatcher>(this)); } ExtensionFunctionDispatcher::~ExtensionFunctionDispatcher() { peer_->dispatcher_ = NULL; + + NotificationService::current()->Notify( + NotificationType::EXTENSION_FUNCTION_DISPATCHER_DESTROYED, + Source<Profile>(profile_), + Details<ExtensionFunctionDispatcher>(this)); } Browser* ExtensionFunctionDispatcher::GetCurrentBrowser( - RenderViewHost* render_view_host, bool include_incognito) { + bool include_incognito) { Browser* browser = delegate_->GetBrowser(); // If the delegate has an associated browser, that is always the right answer. @@ -405,7 +461,7 @@ Browser* ExtensionFunctionDispatcher::GetCurrentBrowser( // profile. Note that the profile may already be incognito, in which case // we will search the incognito version only, regardless of the value of // |include_incognito|. - Profile* profile = render_view_host->process()->profile(); + Profile* profile = render_view_host()->process()->profile(); browser = BrowserList::FindTabbedBrowser(profile, include_incognito); // NOTE(rafaelw): This can return NULL in some circumstances. In particular, @@ -417,84 +473,88 @@ Browser* ExtensionFunctionDispatcher::GetCurrentBrowser( return browser; } -void ExtensionFunctionDispatcher::Dispatch( - const ExtensionHostMsg_Request_Params& params, - RenderViewHost* render_view_host) { - // TODO(aa): It would be cool to use ExtensionProcessManager to track which - // processes are extension processes rather than ChildProcessSecurityPolicy. - // EPM has richer information: it not only knows which processes contain - // at least one extension, but it knows which extensions are inside and what - // permissions the have. So we would be able to enforce permissions more - // granularly. - if (!ChildProcessSecurityPolicy::GetInstance()->HasExtensionBindings( - render_view_host->process()->id())) { - // TODO(aa): Allow content scripts access to low-threat extension APIs. - // See: crbug.com/80308. - LOG(ERROR) << "Extension API called from non-extension process."; - SendAccessDenied(render_view_host, params.request_id); - return; - } - - ExtensionService* service = profile()->GetExtensionService(); - if (!service) - return; - - if (!service->ExtensionBindingsAllowed(params.source_url)) { - LOG(ERROR) << "Extension bindings not allowed for URL: " - << params.source_url.spec(); - SendAccessDenied(render_view_host, params.request_id); - return; - } - - // TODO(aa): When we allow content scripts to call extension APIs, we will - // have to pass the extension ID explicitly here, not use the source URL. - const Extension* extension = service->GetExtensionByURL(params.source_url); - if (!extension) - extension = service->GetExtensionByWebExtent(params.source_url); - if (!extension) { - LOG(ERROR) << "Extension does not exist for URL: " - << params.source_url.spec(); - SendAccessDenied(render_view_host, params.request_id); - return; - } +bool ExtensionFunctionDispatcher::OnMessageReceived( + const IPC::Message& message) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(ExtensionFunctionDispatcher, message) + IPC_MESSAGE_HANDLER(ExtensionHostMsg_Request, OnRequest) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} - if (!extension->HasApiPermission(params.name)) { - LOG(ERROR) << "Extension " << extension->id() << " does not have " - << "permission to function: " << params.name; - SendAccessDenied(render_view_host, params.request_id); +void ExtensionFunctionDispatcher::OnRequest( + const ExtensionHostMsg_Request_Params& params) { + if (!ChildProcessSecurityPolicy::GetInstance()-> + HasExtensionBindings(render_view_host_->process()->id())) { + // This can happen if someone uses window.open() to open an extension URL + // from a non-extension context. + render_view_host_->Send(new ExtensionMsg_Response( + render_view_host_->routing_id(), params.request_id, false, + std::string(), "Access to extension API denied.")); return; } scoped_refptr<ExtensionFunction> function( FactoryRegistry::GetInstance()->NewFunction(params.name)); - function->SetRenderViewHost(render_view_host); function->set_dispatcher_peer(peer_); function->set_profile(profile_); - function->set_extension_id(extension->id()); + function->set_extension_id(extension_id()); function->SetArgs(¶ms.arguments); function->set_source_url(params.source_url); function->set_request_id(params.request_id); function->set_has_callback(params.has_callback); function->set_user_gesture(params.user_gesture); + ExtensionService* service = profile()->GetExtensionService(); + DCHECK(service); + const Extension* extension = service->GetExtensionById(extension_id(), false); + DCHECK(extension); function->set_include_incognito(service->CanCrossIncognito(extension)); + if (!service->ExtensionBindingsAllowed(function->source_url()) || + !extension->HasApiPermission(function->name())) { + render_view_host_->Send(new ExtensionMsg_Response( + render_view_host_->routing_id(), function->request_id(), false, + std::string(), "Access to extension API denied.")); + return; + } + ExtensionsQuotaService* quota = service->quota_service(); - if (quota->Assess(extension->id(), function, ¶ms.arguments, + if (quota->Assess(extension_id(), function, ¶ms.arguments, base::TimeTicks::Now())) { // See crbug.com/39178. ExternalProtocolHandler::PermitLaunchUrl(); function->Run(); } else { - render_view_host->Send(new ExtensionMsg_Response( - render_view_host->routing_id(), function->request_id(), false, + render_view_host_->Send(new ExtensionMsg_Response( + render_view_host_->routing_id(), function->request_id(), false, std::string(), QuotaLimitHeuristic::kGenericOverQuotaError)); } } -void ExtensionFunctionDispatcher::SendAccessDenied( - RenderViewHost* render_view_host, int request_id) { - render_view_host->Send(new ExtensionMsg_Response( - render_view_host->routing_id(), request_id, false, std::string(), - "Access to extension API denied.")); +void ExtensionFunctionDispatcher::SendResponse(ExtensionFunction* function, + bool success) { + render_view_host_->Send(new ExtensionMsg_Response( + render_view_host_->routing_id(), function->request_id(), success, + function->GetResult(), function->GetError())); +} + +void ExtensionFunctionDispatcher::HandleBadMessage(ExtensionFunction* api) { + LOG(ERROR) << "bad extension message " << + api->name() << + " : terminating renderer."; + if (RenderProcessHost::run_renderer_in_process()) { + // In single process mode it is better if we don't suicide but just crash. + CHECK(false); + } else { + NOTREACHED(); + UserMetrics::RecordAction(UserMetricsAction("BadMessageTerminate_EFD")); + base::KillProcess(render_view_host_->process()->GetHandle(), + ResultCodes::KILLED_BAD_MESSAGE, false); + } +} + +Profile* ExtensionFunctionDispatcher::profile() { + return profile_; } diff --git a/chrome/browser/extensions/extension_function_dispatcher.h b/chrome/browser/extensions/extension_function_dispatcher.h index d3b8d1c..9f91d9d 100644 --- a/chrome/browser/extensions/extension_function_dispatcher.h +++ b/chrome/browser/extensions/extension_function_dispatcher.h @@ -11,6 +11,7 @@ #include "base/memory/ref_counted.h" #include "googleurl/src/gurl.h" +#include "ipc/ipc_channel.h" #include "ui/gfx/native_widget_types.h" class Browser; @@ -26,19 +27,9 @@ struct ExtensionHostMsg_Request_Params; typedef ExtensionFunction* (*ExtensionFunctionFactory)(); // ExtensionFunctionDispatcher receives requests to execute functions from -// Chrome extensions running in a RenderViewHost and dispatches them to the +// Chromium extensions running in a RenderViewHost and dispatches them to the // appropriate handler. It lives entirely on the UI thread. -// -// ExtensionFunctionDispatcher should be a member of some class that hosts -// RenderViewHosts and wants them to be able to display extension content. -// This class should also implement ExtensionFunctionDispatcher::Delegate. -// -// Note that a single ExtensionFunctionDispatcher does *not* correspond to a -// single RVH, a single extension, or a single URL. This is by design so that -// we can gracefully handle cases like TabContents, where the RVH, extension, -// and URL can all change over the lifetime of the tab. Instead, these items -// are all passed into each request. -class ExtensionFunctionDispatcher { +class ExtensionFunctionDispatcher : public IPC::Channel::Listener { public: class Delegate { public: @@ -54,7 +45,7 @@ class ExtensionFunctionDispatcher { // context. For example, the TabContents in which an infobar or // chrome-extension://<id> URL are being shown. Callers must check for a // NULL return value (as in the case of a background page). - virtual TabContents* GetAssociatedTabContents() const = 0; + virtual TabContents* associated_tab_contents() const = 0; protected: virtual ~Delegate() {} @@ -85,19 +76,21 @@ class ExtensionFunctionDispatcher { // Resets all functions to their initial implementation. static void ResetFunctions(); - // Public constructor. Callers must ensure that: - // - |delegate| outlives this object. - // - This object outlives any RenderViewHost's passed to created - // ExtensionFunctions. - ExtensionFunctionDispatcher(Profile* profile, Delegate* delegate); + // Creates an instance for the specified RenderViewHost and URL. If the URL + // does not contain a valid extension, returns NULL. + static ExtensionFunctionDispatcher* Create(RenderViewHost* render_view_host, + Delegate* delegate, + const GURL& url); ~ExtensionFunctionDispatcher(); Delegate* delegate() { return delegate_; } - // Message handlers. - void Dispatch(const ExtensionHostMsg_Request_Params& params, - RenderViewHost* sender); + // If |message| is an extension request, handle it. Returns true if handled. + virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; + + // Send a response to a function. + void SendResponse(ExtensionFunction* api, bool success); // Returns the current browser. Callers should generally prefer // ExtensionFunction::GetCurrentBrowser() over this method, as that one @@ -105,20 +98,46 @@ class ExtensionFunctionDispatcher { // // See the comments for ExtensionFunction::GetCurrentBrowser() for more // details. - Browser* GetCurrentBrowser(RenderViewHost* render_view_host, - bool include_incognito); + Browser* GetCurrentBrowser(bool include_incognito); + + // Handle a malformed message. Possibly the result of an attack, so kill + // the renderer. + void HandleBadMessage(ExtensionFunction* api); + + // Gets the URL for the view we're displaying. + const GURL& url() { return url_; } + + // Gets the ID for this extension. + const std::string extension_id() { return extension_id_; } // The profile that this dispatcher is associated with. - Profile* profile() { return profile_; } + Profile* profile(); + + // The RenderViewHost this dispatcher is associated with. + RenderViewHost* render_view_host() { return render_view_host_; } private: - // Helper to send an access denied error to the requesting render view. - void SendAccessDenied(RenderViewHost* render_view_host, int request_id); + ExtensionFunctionDispatcher(RenderViewHost* render_view_host, + Delegate* delegate, + const Extension* extension, + const GURL& url); + // Message handlers. + void OnRequest(const ExtensionHostMsg_Request_Params& params); + + // We need to keep a pointer to the profile because we use it in the dtor + // in sending EXTENSION_FUNCTION_DISPATCHER_DESTROYED, but by that point + // the render_view_host_ has been deleted. Profile* profile_; + RenderViewHost* render_view_host_; + Delegate* delegate_; + GURL url_; + + std::string extension_id_; + scoped_refptr<Peer> peer_; }; diff --git a/chrome/browser/extensions/extension_host.cc b/chrome/browser/extensions/extension_host.cc index 318ca0b..7badebf 100644 --- a/chrome/browser/extensions/extension_host.cc +++ b/chrome/browser/extensions/extension_host.cc @@ -28,7 +28,6 @@ #include "chrome/common/chrome_constants.h" #include "chrome/common/extensions/extension.h" #include "chrome/common/extensions/extension_constants.h" -#include "chrome/common/extensions/extension_messages.h" #include "chrome/common/render_messages.h" #include "chrome/common/url_constants.h" #include "chrome/common/view_types.h" @@ -132,13 +131,17 @@ ExtensionHost::ExtensionHost(const Extension* extension, did_stop_loading_(false), document_element_available_(false), url_(url), - ALLOW_THIS_IN_INITIALIZER_LIST( - extension_function_dispatcher_(profile_, this)), extension_host_type_(host_type), associated_tab_contents_(NULL), suppress_javascript_messages_(false) { render_view_host_ = new RenderViewHost(site_instance, this, MSG_ROUTING_NONE, NULL); + render_view_host_->set_is_extension_process(true); + if (extension->is_app()) { + profile()->GetExtensionService()->SetInstalledAppForRenderer( + render_view_host_->process()->id(), extension); + } + render_view_host_->AllowBindings(BindingsPolicy::EXTENSION); if (enable_dom_automation_) render_view_host_->AllowBindings(BindingsPolicy::DOM_AUTOMATION); @@ -179,7 +182,7 @@ void ExtensionHost::CreateView(Browser* browser) { #endif } -TabContents* ExtensionHost::GetAssociatedTabContents() const { +TabContents* ExtensionHost::associated_tab_contents() const { return associated_tab_contents_; } @@ -311,9 +314,6 @@ void ExtensionHost::RenderViewGone(RenderViewHost* render_view_host, if (!extension_) return; - // TODO(aa): This is suspicious. There can be multiple views in an extension, - // and they aren't all going to use ExtensionHost. This should be in someplace - // more central, like EPM maybe. DCHECK_EQ(render_view_host_, render_view_host); NotificationService::current()->Notify( NotificationType::EXTENSION_PROCESS_TERMINATED, @@ -327,7 +327,29 @@ void ExtensionHost::DidNavigate(RenderViewHost* render_view_host, if (!PageTransition::IsMainFrame(params.transition)) return; + if (!params.url.SchemeIs(chrome::kExtensionScheme)) { + extension_function_dispatcher_.reset(NULL); + url_ = params.url; + return; + } + + // This catches two bogus use cases: + // (1) URLs that look like chrome-extension://somethingbogus or + // chrome-extension://nosuchid/, in other words, no Extension would + // be found. + // (2) URLs that refer to a different extension than this one. + // In both cases, we preserve the old URL and reset the EFD to NULL. This + // will leave the host in kind of a bad state with poor UI and errors, but + // it's better than the alternative. + // TODO(erikkay) Perhaps we should display errors in developer mode. + if (params.url.host() != extension_id()) { + extension_function_dispatcher_.reset(NULL); + return; + } + url_ = params.url; + extension_function_dispatcher_.reset( + ExtensionFunctionDispatcher::Create(render_view_host_, this, url_)); } void ExtensionHost::InsertInfobarCSS() { @@ -443,8 +465,7 @@ gfx::NativeWindow ExtensionHost::GetMessageBoxRootWindow() { return platform_util::GetTopLevel(native_view); // Otherwise, try the active tab's view. - Browser* browser = extension_function_dispatcher_.GetCurrentBrowser( - render_view_host_, true); + Browser* browser = extension_function_dispatcher_->GetCurrentBrowser(true); if (browser) { TabContents* active_tab = browser->GetSelectedTabContents(); if (active_tab) @@ -486,7 +507,7 @@ void ExtensionHost::Close(RenderViewHost* render_view_host) { RendererPreferences ExtensionHost::GetRendererPrefs(Profile* profile) const { RendererPreferences preferences; - TabContents* associated_contents = GetAssociatedTabContents(); + TabContents* associated_contents = associated_tab_contents(); if (associated_contents) preferences = static_cast<RenderViewHostDelegate*>(associated_contents)-> @@ -540,7 +561,7 @@ void ExtensionHost::CreateNewWindow( params.window_container_type, params.frame_name); - TabContents* associated_contents = GetAssociatedTabContents(); + TabContents* associated_contents = associated_tab_contents(); if (associated_contents && associated_contents->delegate()) associated_contents->delegate()->TabContentsCreated(new_contents); } @@ -595,7 +616,7 @@ void ExtensionHost::ShowCreatedWindow(int route_id, // the case of extensions in 'spanning' incognito mode, they can mismatch. // We don't want to end up putting a normal tab into an incognito window, or // vice versa. - TabContents* associated_contents = GetAssociatedTabContents(); + TabContents* associated_contents = associated_tab_contents(); if (associated_contents && associated_contents->profile() == contents->profile()) { associated_contents->AddNewContents( @@ -753,19 +774,19 @@ ViewType::Type ExtensionHost::GetRenderViewType() const { } bool ExtensionHost::OnMessageReceived(const IPC::Message& message) { + if (extension_function_dispatcher_.get() && + extension_function_dispatcher_->OnMessageReceived(message)) { + return true; + } + bool handled = true; IPC_BEGIN_MESSAGE_MAP(ExtensionHost, message) IPC_MESSAGE_HANDLER(ViewHostMsg_RunFileChooser, OnRunFileChooser) - IPC_MESSAGE_HANDLER(ExtensionHostMsg_Request, OnRequest) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() return handled; } -void ExtensionHost::OnRequest(const ExtensionHostMsg_Request_Params& params) { - extension_function_dispatcher_.Dispatch(params, render_view_host_); -} - const GURL& ExtensionHost::GetURL() const { return url_; } @@ -774,6 +795,13 @@ void ExtensionHost::RenderViewCreated(RenderViewHost* render_view_host) { if (view_.get()) view_->RenderViewCreated(); + // TODO(mpcomplete): This is duplicated in DidNavigate, which means that + // we'll create 2 EFDs for the first navigation. We should try to find a + // better way to unify them. + // See http://code.google.com/p/chromium/issues/detail?id=18240 + extension_function_dispatcher_.reset( + ExtensionFunctionDispatcher::Create(render_view_host, this, url_)); + if (extension_host_type_ == ViewType::EXTENSION_POPUP || extension_host_type_ == ViewType::EXTENSION_INFOBAR) { render_view_host->EnablePreferredSizeChangedMode( @@ -804,5 +832,5 @@ void ExtensionHost::OnRunFileChooser( if (file_select_helper_.get() == NULL) file_select_helper_.reset(new FileSelectHelper(profile())); file_select_helper_->RunFileChooser(render_view_host_, - GetAssociatedTabContents(), params); + associated_tab_contents(), params); } diff --git a/chrome/browser/extensions/extension_host.h b/chrome/browser/extensions/extension_host.h index 87b691c..311975d 100644 --- a/chrome/browser/extensions/extension_host.h +++ b/chrome/browser/extensions/extension_host.h @@ -86,7 +86,7 @@ class ExtensionHost : public RenderViewHostDelegate, ViewType::Type extension_host_type() const { return extension_host_type_; } // ExtensionFunctionDispatcher::Delegate - virtual TabContents* GetAssociatedTabContents() const; + virtual TabContents* associated_tab_contents() const; void set_associated_tab_contents(TabContents* associated_tab_contents) { associated_tab_contents_ = associated_tab_contents; } @@ -229,7 +229,6 @@ class ExtensionHost : public RenderViewHostDelegate, // Message handlers. void OnRunFileChooser(const ViewHostMsg_RunFileChooser_Params& params); - void OnRequest(const ExtensionHostMsg_Request_Params& params); // Handles keyboard events that were not handled by HandleKeyboardEvent(). // Platform specific implementation may override this method to handle the @@ -275,7 +274,7 @@ class ExtensionHost : public RenderViewHostDelegate, NotificationRegistrar registrar_; - ExtensionFunctionDispatcher extension_function_dispatcher_; + scoped_ptr<ExtensionFunctionDispatcher> extension_function_dispatcher_; // Only EXTENSION_INFOBAR, EXTENSION_POPUP, and EXTENSION_BACKGROUND_PAGE // are used here, others are not hosted by ExtensionHost. diff --git a/chrome/browser/extensions/extension_tab_helper.cc b/chrome/browser/extensions/extension_tab_helper.cc index 8a1caa5..6f44f6c 100644 --- a/chrome/browser/extensions/extension_tab_helper.cc +++ b/chrome/browser/extensions/extension_tab_helper.cc @@ -6,15 +6,12 @@ #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/browser/ui/browser.h" -#include "chrome/browser/ui/browser_list.h" #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" #include "chrome/browser/ui/tab_contents/tab_contents_wrapper_delegate.h" #include "chrome/common/extensions/extension_action.h" #include "chrome/common/extensions/extension_icon_set.h" #include "chrome/common/extensions/extension_messages.h" #include "chrome/common/extensions/extension_resource.h" -#include "content/browser/renderer_host/render_widget_host_view.h" #include "content/browser/tab_contents/tab_contents.h" #include "content/browser/tab_contents/navigation_controller.h" #include "content/common/notification_service.h" @@ -22,8 +19,6 @@ ExtensionTabHelper::ExtensionTabHelper(TabContentsWrapper* wrapper) : TabContentsObserver(wrapper->tab_contents()), extension_app_(NULL), - ALLOW_THIS_IN_INITIALIZER_LIST( - extension_function_dispatcher_(wrapper->profile(), this)), wrapper_(wrapper) { } @@ -118,7 +113,6 @@ bool ExtensionTabHelper::OnMessageReceived(const IPC::Message& message) { OnDidGetApplicationInfo) IPC_MESSAGE_HANDLER(ExtensionHostMsg_InstallApplication, OnInstallApplication) - IPC_MESSAGE_HANDLER(ExtensionHostMsg_Request, OnRequest) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() return handled; @@ -137,12 +131,6 @@ void ExtensionTabHelper::OnInstallApplication(const WebApplicationInfo& info) { wrapper_->delegate()->OnInstallApplication(wrapper_, info); } -void ExtensionTabHelper::OnRequest( - const ExtensionHostMsg_Request_Params& request) { - extension_function_dispatcher_.Dispatch(request, - tab_contents()->render_view_host()); -} - void ExtensionTabHelper::UpdateExtensionAppIcon(const Extension* extension) { extension_app_icon_.reset(); @@ -173,37 +161,3 @@ void ExtensionTabHelper::OnImageLoaded(SkBitmap* image, tab_contents()->NotifyNavigationStateChanged(TabContents::INVALIDATE_TAB); } } - -Browser* ExtensionTabHelper::GetBrowser() { - TabContents* contents = tab_contents(); - TabContentsIterator tab_iterator; - for (; !tab_iterator.done(); ++tab_iterator) { - if (contents == (*tab_iterator)->tab_contents()) - return tab_iterator.browser(); - } - - return NULL; -} - -TabContents* ExtensionTabHelper::GetAssociatedTabContents() const { - return tab_contents(); -} - -gfx::NativeWindow ExtensionTabHelper::GetCustomFrameNativeWindow() { - if (GetBrowser()) - return NULL; - - // If there was no browser associated with the function dispatcher delegate, - // then this WebUI may be hosted in an ExternalTabContainer, and a framing - // window will be accessible through the tab_contents. - TabContentsDelegate* tab_contents_delegate = tab_contents()->delegate(); - if (tab_contents_delegate) - return tab_contents_delegate->GetFrameNativeWindow(); - else - return NULL; -} - -gfx::NativeView ExtensionTabHelper::GetNativeViewOfHost() { - RenderWidgetHostView* rwhv = tab_contents()->GetRenderWidgetHostView(); - return rwhv ? rwhv->GetNativeView() : NULL; -} diff --git a/chrome/browser/extensions/extension_tab_helper.h b/chrome/browser/extensions/extension_tab_helper.h index 8a4b51e..46b0348 100644 --- a/chrome/browser/extensions/extension_tab_helper.h +++ b/chrome/browser/extensions/extension_tab_helper.h @@ -7,7 +7,6 @@ #pragma once #include "content/browser/tab_contents/tab_contents_observer.h" -#include "chrome/browser/extensions/extension_function_dispatcher.h" #include "chrome/browser/extensions/image_loading_tracker.h" #include "chrome/common/web_apps.h" #include "third_party/skia/include/core/SkBitmap.h" @@ -18,7 +17,6 @@ struct WebApplicationInfo; // Per-tab extension helper. Also handles non-extension apps. class ExtensionTabHelper : public TabContentsObserver, - public ExtensionFunctionDispatcher::Delegate, public ImageLoadingTracker::Observer { public: explicit ExtensionTabHelper(TabContentsWrapper* wrapper); @@ -79,16 +77,9 @@ class ExtensionTabHelper : public TabContentsObserver, const ViewHostMsg_FrameNavigate_Params& params) OVERRIDE; virtual bool OnMessageReceived(const IPC::Message& message); - // ExtensionFunctionDispatcher::Delegate overrides. - virtual Browser* GetBrowser(); - virtual gfx::NativeView GetNativeViewOfHost(); - virtual gfx::NativeWindow GetCustomFrameNativeWindow(); - virtual TabContents* GetAssociatedTabContents() const; - // Message handlers. void OnDidGetApplicationInfo(int32 page_id, const WebApplicationInfo& info); void OnInstallApplication(const WebApplicationInfo& info); - void OnRequest(const ExtensionHostMsg_Request_Params& params); // App extensions related methods: @@ -110,9 +101,6 @@ class ExtensionTabHelper : public TabContentsObserver, // non-extension apps. SkBitmap extension_app_icon_; - // Process any extension messages coming from the tab. - ExtensionFunctionDispatcher extension_function_dispatcher_; - // Used for loading extension_app_icon_. scoped_ptr<ImageLoadingTracker> extension_app_image_loader_; diff --git a/chrome/browser/extensions/extension_tabs_module.cc b/chrome/browser/extensions/extension_tabs_module.cc index 97654bf..a43d894 100644 --- a/chrome/browser/extensions/extension_tabs_module.cc +++ b/chrome/browser/extensions/extension_tabs_module.cc @@ -793,7 +793,7 @@ bool GetTabFunction::RunImpl() { bool GetCurrentTabFunction::RunImpl() { DCHECK(dispatcher()); - TabContents* contents = dispatcher()->delegate()->GetAssociatedTabContents(); + TabContents* contents = dispatcher()->delegate()->associated_tab_contents(); if (contents) result_.reset(ExtensionTabUtil::CreateTabValue(contents)); diff --git a/chrome/browser/extensions/extension_web_ui.cc b/chrome/browser/extensions/extension_web_ui.cc index a816c76..e398c46 100644 --- a/chrome/browser/extensions/extension_web_ui.cc +++ b/chrome/browser/extensions/extension_web_ui.cc @@ -24,9 +24,11 @@ #include "chrome/common/extensions/extension_icon_set.h" #include "chrome/common/extensions/extension_resource.h" #include "chrome/common/url_constants.h" +#include "content/browser/renderer_host/render_widget_host_view.h" #include "content/browser/tab_contents/tab_contents.h" #include "content/common/bindings_policy.h" #include "content/common/page_transition_types.h" +#include "ipc/ipc_message.h" #include "net/base/file_stream.h" #include "third_party/skia/include/core/SkBitmap.h" #include "ui/gfx/codec/png_codec.h" @@ -138,6 +140,7 @@ ExtensionWebUI::ExtensionWebUI(TabContents* tab_contents, const GURL& url) // component apps like bookmark manager. should_hide_url_ = !extension->is_hosted_app(); + bindings_ = BindingsPolicy::EXTENSION; // Bind externalHost to Extension WebUI loaded in Chrome Frame. const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess(); if (browser_command_line.HasSwitch(switches::kChromeFrame)) @@ -152,23 +155,86 @@ ExtensionWebUI::ExtensionWebUI(TabContents* tab_contents, const GURL& url) should_hide_url_ = false; } } +} + +ExtensionWebUI::~ExtensionWebUI() {} +void ExtensionWebUI::ResetExtensionFunctionDispatcher( + RenderViewHost* render_view_host) { + // TODO(jcivelli): http://crbug.com/60608 we should get the URL out of the + // active entry of the navigation controller. + extension_function_dispatcher_.reset( + ExtensionFunctionDispatcher::Create(render_view_host, this, url_)); + DCHECK(extension_function_dispatcher_.get()); +} + +void ExtensionWebUI::ResetExtensionBookmarkManagerEventRouter() { // Hack: A few things we specialize just for the bookmark manager. - if (extension->id() == extension_misc::kBookmarkManagerId) { + if (extension_function_dispatcher_->extension_id() == + extension_misc::kBookmarkManagerId) { extension_bookmark_manager_event_router_.reset( - new ExtensionBookmarkManagerEventRouter(GetProfile(), tab_contents)); + new ExtensionBookmarkManagerEventRouter(GetProfile(), tab_contents())); link_transition_type_ = PageTransition::AUTO_BOOKMARK; } } -ExtensionWebUI::~ExtensionWebUI() {} +void ExtensionWebUI::RenderViewCreated(RenderViewHost* render_view_host) { + ResetExtensionFunctionDispatcher(render_view_host); + ResetExtensionBookmarkManagerEventRouter(); +} + +void ExtensionWebUI::RenderViewReused(RenderViewHost* render_view_host) { + ResetExtensionFunctionDispatcher(render_view_host); + ResetExtensionBookmarkManagerEventRouter(); +} + +bool ExtensionWebUI::OnMessageReceived(const IPC::Message& message) { + if (extension_function_dispatcher_.get()) + return extension_function_dispatcher_->OnMessageReceived(message); + + return false; +} + +Browser* ExtensionWebUI::GetBrowser() { + TabContents* contents = tab_contents(); + TabContentsIterator tab_iterator; + for (; !tab_iterator.done(); ++tab_iterator) { + if (contents == (*tab_iterator)->tab_contents()) + return tab_iterator.browser(); + } + + return NULL; +} + +TabContents* ExtensionWebUI::associated_tab_contents() const { + return tab_contents(); +} ExtensionBookmarkManagerEventRouter* ExtensionWebUI::extension_bookmark_manager_event_router() { return extension_bookmark_manager_event_router_.get(); } +gfx::NativeWindow ExtensionWebUI::GetCustomFrameNativeWindow() { + if (GetBrowser()) + return NULL; + + // If there was no browser associated with the function dispatcher delegate, + // then this WebUI may be hosted in an ExternalTabContainer, and a framing + // window will be accessible through the tab_contents. + TabContentsDelegate* tab_contents_delegate = tab_contents()->delegate(); + if (tab_contents_delegate) + return tab_contents_delegate->GetFrameNativeWindow(); + else + return NULL; +} + +gfx::NativeView ExtensionWebUI::GetNativeViewOfHost() { + RenderWidgetHostView* rwhv = tab_contents()->GetRenderWidgetHostView(); + return rwhv ? rwhv->GetNativeView() : NULL; +} + //////////////////////////////////////////////////////////////////////////////// // chrome:// URL overrides diff --git a/chrome/browser/extensions/extension_web_ui.h b/chrome/browser/extensions/extension_web_ui.h index 4aad170..3a3a80b 100644 --- a/chrome/browser/extensions/extension_web_ui.h +++ b/chrome/browser/extensions/extension_web_ui.h @@ -10,9 +10,11 @@ #include "base/memory/scoped_ptr.h" #include "chrome/browser/extensions/extension_bookmark_manager_api.h" +#include "chrome/browser/extensions/extension_function_dispatcher.h" #include "chrome/browser/favicon/favicon_service.h" #include "chrome/common/extensions/extension.h" #include "content/browser/webui/web_ui.h" +#include "ipc/ipc_channel.h" class GURL; class ListValue; @@ -20,12 +22,15 @@ class PrefService; class Profile; class RenderViewHost; class TabContents; +struct ExtensionHostMsg_Request_Params; // This class implements WebUI for extensions and allows extensions to put UI in // the main tab contents area. For example, each extension can specify an // "options_page", and that page is displayed in the tab contents area and is // hosted by this class. -class ExtensionWebUI : public WebUI { +class ExtensionWebUI + : public WebUI, + public ExtensionFunctionDispatcher::Delegate { public: static const char kExtensionURLOverrides[]; @@ -33,6 +38,21 @@ class ExtensionWebUI : public WebUI { virtual ~ExtensionWebUI(); + ExtensionFunctionDispatcher* extension_function_dispatcher() const { + return extension_function_dispatcher_.get(); + } + + // WebUI + virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; + virtual void RenderViewCreated(RenderViewHost* render_view_host); + virtual void RenderViewReused(RenderViewHost* render_view_host); + + // ExtensionFunctionDispatcher::Delegate + virtual Browser* GetBrowser(); + virtual gfx::NativeView GetNativeViewOfHost(); + virtual gfx::NativeWindow GetCustomFrameNativeWindow(); + virtual TabContents* associated_tab_contents() const; + virtual ExtensionBookmarkManagerEventRouter* extension_bookmark_manager_event_router(); @@ -67,6 +87,15 @@ class ExtensionWebUI : public WebUI { ListValue* list, Value* override); + // When the RenderViewHost changes (RenderViewCreated and RenderViewReused), + // we need to reset the ExtensionFunctionDispatcher so it's talking to the + // right one, as well as being linked to the correct URL. + void ResetExtensionFunctionDispatcher(RenderViewHost* render_view_host); + + void ResetExtensionBookmarkManagerEventRouter(); + + scoped_ptr<ExtensionFunctionDispatcher> extension_function_dispatcher_; + // TODO(aa): This seems out of place. Why is it not with the event routers for // the other extension APIs? scoped_ptr<ExtensionBookmarkManagerEventRouter> diff --git a/chrome/browser/extensions/extension_webstore_private_api.cc b/chrome/browser/extensions/extension_webstore_private_api.cc index 7c46cff..8dbf650 100644 --- a/chrome/browser/extensions/extension_webstore_private_api.cc +++ b/chrome/browser/extensions/extension_webstore_private_api.cc @@ -461,7 +461,7 @@ bool CompleteInstallFunction::RunImpl() { // install flow. The above call to SetWhitelistedInstallId will bypass the // normal permissions install dialog. NavigationController& controller = - dispatcher()->delegate()->GetAssociatedTabContents()->controller(); + dispatcher()->delegate()->associated_tab_contents()->controller(); controller.LoadURL(url, source_url(), PageTransition::LINK); return true; @@ -519,7 +519,7 @@ bool PromptBrowserLoginFunction::RunImpl() { // Login can currently only be invoked tab-modal. Since this is // coming from the webstore, we should always have a tab, but check // just in case. - TabContents* tab = dispatcher()->delegate()->GetAssociatedTabContents(); + TabContents* tab = dispatcher()->delegate()->associated_tab_contents(); if (!tab) return false; diff --git a/chrome/browser/extensions/extensions_ui.cc b/chrome/browser/extensions/extensions_ui.cc index 37e4fd9..8022dc4 100644 --- a/chrome/browser/extensions/extensions_ui.cc +++ b/chrome/browser/extensions/extensions_ui.cc @@ -20,6 +20,7 @@ #include "chrome/browser/extensions/crx_installer.h" #include "chrome/browser/extensions/extension_disabled_infobar_delegate.h" #include "chrome/browser/extensions/extension_error_reporter.h" +#include "chrome/browser/extensions/extension_function_dispatcher.h" #include "chrome/browser/extensions/extension_host.h" #include "chrome/browser/extensions/extension_message_service.h" #include "chrome/browser/extensions/extension_service.h" @@ -299,11 +300,13 @@ void ExtensionsDOMHandler::RegisterForNotifications() { NotificationService::AllSources()); registrar_.Add(this, NotificationType::EXTENSION_UPDATE_DISABLED, NotificationService::AllSources()); + registrar_.Add(this, NotificationType::EXTENSION_FUNCTION_DISPATCHER_CREATED, + NotificationService::AllSources()); registrar_.Add(this, - NotificationType::NAV_ENTRY_COMMITTED, + NotificationType::EXTENSION_FUNCTION_DISPATCHER_DESTROYED, NotificationService::AllSources()); registrar_.Add(this, - NotificationType::RENDER_VIEW_HOST_CREATED, + NotificationType::NAV_ENTRY_COMMITTED, NotificationService::AllSources()); registrar_.Add(this, NotificationType::RENDER_VIEW_HOST_DELETED, @@ -628,11 +631,9 @@ void ExtensionsDOMHandler::Observe(NotificationType type, // we don't know about the views for an extension at EXTENSION_LOADED, but // if we only listen to EXTENSION_PROCESS_CREATED, we'll miss extensions // that don't have a process at startup. Similarly, NAV_ENTRY_COMMITTED & - // RENDER_VIEW_HOST_CREATED because we want to handle both - // the case of navigating from a non-extension page to an extension page in - // a TabContents (which will generate NAV_ENTRY_COMMITTED) as well as - // extension content being shown in popups and balloons (which will generate - // RENDER_VIEW_HOST_CREATED but no NAV_ENTRY_COMMITTED). + // EXTENSION_FUNCTION_DISPATCHER_CREATED because we want to handle both + // the case of live app pages (which don't have an EFD) and + // chrome-extension:// urls which are served in a TabContents. // // Doing it this way gets everything but causes the page to be rendered // more than we need. It doesn't seem to result in any noticeable flicker. @@ -648,7 +649,8 @@ void ExtensionsDOMHandler::Observe(NotificationType type, case NotificationType::EXTENSION_PROCESS_CREATED: case NotificationType::EXTENSION_UNLOADED: case NotificationType::EXTENSION_UPDATE_DISABLED: - case NotificationType::RENDER_VIEW_HOST_CREATED: + case NotificationType::EXTENSION_FUNCTION_DISPATCHER_CREATED: + case NotificationType::EXTENSION_FUNCTION_DISPATCHER_DESTROYED: case NotificationType::NAV_ENTRY_COMMITTED: case NotificationType::BACKGROUND_CONTENTS_NAVIGATED: case NotificationType::EXTENSION_BROWSER_ACTION_VISIBILITY_CHANGED: diff --git a/chrome/browser/memory_details.cc b/chrome/browser/memory_details.cc index 074e42d..ea1c834 100644 --- a/chrome/browser/memory_details.cc +++ b/chrome/browser/memory_details.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2010 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -171,7 +171,7 @@ void MemoryDetails::CollectChildInfoOnUIThread() { } TabContents* contents = host_delegate->GetAsTabContents(); if (!contents) { - if (host->process()->is_extension_process()) { + if (host->is_extension_process()) { const Extension* extension = extension_service->GetExtensionByURL(url); if (extension) { diff --git a/chrome/browser/notifications/balloon_host.cc b/chrome/browser/notifications/balloon_host.cc index 7219be0..3d600a0 100644 --- a/chrome/browser/notifications/balloon_host.cc +++ b/chrome/browser/notifications/balloon_host.cc @@ -3,13 +3,14 @@ // found in the LICENSE file. #include "chrome/browser/notifications/balloon_host.h" +#include "chrome/browser/extensions/extension_process_manager.h" +#include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/notifications/balloon.h" #include "chrome/browser/notifications/notification.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/renderer_preferences_util.h" #include "chrome/browser/ui/browser_list.h" #include "chrome/browser/ui/webui/chrome_web_ui_factory.h" -#include "chrome/common/extensions/extension_messages.h" #include "chrome/common/render_messages.h" #include "chrome/common/url_constants.h" #include "content/browser/renderer_host/browser_render_process_host.h" @@ -29,12 +30,20 @@ BalloonHost::BalloonHost(Balloon* balloon) balloon_(balloon), initialized_(false), should_notify_on_disconnect_(false), - enable_web_ui_(false), - ALLOW_THIS_IN_INITIALIZER_LIST( - extension_function_dispatcher_(GetProfile(), this)) { - CHECK(balloon_); - site_instance_ = SiteInstance::CreateSiteInstanceForURL(balloon_->profile(), - GetURL()); + enable_web_ui_(false) { + DCHECK(balloon_); + + // If the notification is for an extension URL, make sure to use the extension + // process to render it, so that it can communicate with other views in the + // extension. + const GURL& balloon_url = balloon_->notification().content_url(); + if (balloon_url.SchemeIs(chrome::kExtensionScheme)) { + site_instance_ = + balloon_->profile()->GetExtensionProcessManager()->GetSiteInstanceForURL( + balloon_url); + } else { + site_instance_ = SiteInstance::CreateSiteInstance(balloon_->profile()); + } } void BalloonHost::Shutdown() { @@ -55,9 +64,7 @@ gfx::NativeView BalloonHost::GetNativeViewOfHost() { return NULL; } -TabContents* BalloonHost::GetAssociatedTabContents() const { - return NULL; -} +TabContents* BalloonHost::associated_tab_contents() const { return NULL; } const string16& BalloonHost::GetSource() const { return balloon_->notification().display_source(); @@ -126,16 +133,10 @@ RenderViewHostDelegate::View* BalloonHost::GetViewDelegate() { } bool BalloonHost::OnMessageReceived(const IPC::Message& message) { - bool handled = true; - IPC_BEGIN_MESSAGE_MAP(BalloonHost, message) - IPC_MESSAGE_HANDLER(ExtensionHostMsg_Request, OnRequest) - IPC_MESSAGE_UNHANDLED(handled = false) - IPC_END_MESSAGE_MAP() - return handled; -} + if (extension_function_dispatcher_.get()) + return extension_function_dispatcher_->OnMessageReceived(message); -void BalloonHost::OnRequest(const ExtensionHostMsg_Request_Params& params) { - extension_function_dispatcher_.Dispatch(params, render_view_host_); + return false; } // RenderViewHostDelegate::View methods implemented to allow links to @@ -195,8 +196,24 @@ void BalloonHost::Init() { DCHECK(!render_view_host_) << "BalloonViewHost already initialized."; RenderViewHost* rvh = new RenderViewHost( site_instance_.get(), this, MSG_ROUTING_NONE, NULL); - if (enable_web_ui_) + if (GetProfile()->GetExtensionService()) { + extension_function_dispatcher_.reset( + ExtensionFunctionDispatcher::Create( + rvh, this, balloon_->notification().content_url())); + } + if (extension_function_dispatcher_.get()) { + rvh->AllowBindings(BindingsPolicy::EXTENSION); + rvh->set_is_extension_process(true); + const Extension* installed_app = + GetProfile()->GetExtensionService()->GetInstalledApp( + balloon_->notification().content_url()); + if (installed_app) { + GetProfile()->GetExtensionService()->SetInstalledAppForRenderer( + rvh->process()->id(), installed_app); + } + } else if (enable_web_ui_) { rvh->AllowBindings(BindingsPolicy::WEB_UI); + } // Do platform-specific initialization. render_view_host_ = rvh; diff --git a/chrome/browser/notifications/balloon_host.h b/chrome/browser/notifications/balloon_host.h index 2a03506..9a70e61 100644 --- a/chrome/browser/notifications/balloon_host.h +++ b/chrome/browser/notifications/balloon_host.h @@ -44,7 +44,7 @@ class BalloonHost : public RenderViewHostDelegate, // ExtensionFunctionDispatcher::Delegate overrides. virtual Browser* GetBrowser(); virtual gfx::NativeView GetNativeViewOfHost(); - virtual TabContents* GetAssociatedTabContents() const; + virtual TabContents* associated_tab_contents() const; RenderViewHost* render_view_host() const { return render_view_host_; } @@ -137,9 +137,6 @@ class BalloonHost : public RenderViewHostDelegate, // RenderViewHostDelegate virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; - // Message handlers - void OnRequest(const ExtensionHostMsg_Request_Params& params); - // Called to send an event that the balloon has been disconnected from // a renderer (if should_notify_on_disconnect_ is true). void NotifyDisconnect(); @@ -161,12 +158,14 @@ class BalloonHost : public RenderViewHostDelegate, // Common implementations of some RenderViewHostDelegate::View methods. RenderViewHostDelegateViewHelper delegate_view_helper_; + // Handles requests to extension APIs. Will only be non-NULL if we are + // rendering a page from an extension. + scoped_ptr<ExtensionFunctionDispatcher> extension_function_dispatcher_; + // A flag to enable Web UI. bool enable_web_ui_; NotificationRegistrar registrar_; - - ExtensionFunctionDispatcher extension_function_dispatcher_; }; #endif // CHROME_BROWSER_NOTIFICATIONS_BALLOON_HOST_H_ diff --git a/chrome/browser/sidebar/sidebar_container.cc b/chrome/browser/sidebar/sidebar_container.cc index d1e4a33..99c69a5 100644 --- a/chrome/browser/sidebar/sidebar_container.cc +++ b/chrome/browser/sidebar/sidebar_container.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2010 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -16,6 +16,7 @@ #include "content/browser/tab_contents/navigation_entry.h" #include "content/browser/tab_contents/tab_contents.h" #include "content/browser/tab_contents/tab_contents_view.h" +#include "content/common/bindings_policy.h" #include "googleurl/src/gurl.h" #include "third_party/skia/include/core/SkBitmap.h" @@ -31,6 +32,17 @@ SidebarContainer::SidebarContainer(TabContents* tab, // Create TabContents for sidebar. sidebar_contents_.reset( new TabContents(tab->profile(), NULL, MSG_ROUTING_NONE, NULL, NULL)); + sidebar_contents_->render_view_host()->set_is_extension_process(true); + const Extension* extension = GetExtension(); + if (extension && extension->is_app()) { + ExtensionService* service = tab->profile()->GetExtensionService(); + if (service) { + service->SetInstalledAppForRenderer( + sidebar_contents_->render_view_host()->process()->id(), extension); + } + } + sidebar_contents_->render_view_host()->AllowBindings( + BindingsPolicy::EXTENSION); sidebar_contents_->set_delegate(this); } diff --git a/chrome/browser/ui/webui/options/extension_settings_handler.cc b/chrome/browser/ui/webui/options/extension_settings_handler.cc index c1760b7..0aa8434 100644 --- a/chrome/browser/ui/webui/options/extension_settings_handler.cc +++ b/chrome/browser/ui/webui/options/extension_settings_handler.cc @@ -20,6 +20,7 @@ #include "chrome/browser/extensions/crx_installer.h" #include "chrome/browser/extensions/extension_disabled_infobar_delegate.h" #include "chrome/browser/extensions/extension_error_reporter.h" +#include "chrome/browser/extensions/extension_function_dispatcher.h" #include "chrome/browser/extensions/extension_host.h" #include "chrome/browser/extensions/extension_message_service.h" #include "chrome/browser/extensions/extension_service.h" @@ -406,11 +407,13 @@ void ExtensionsDOMHandler::OnIconsLoaded(DictionaryValue* json) { NotificationService::AllSources()); registrar_.Add(this, NotificationType::EXTENSION_UPDATE_DISABLED, NotificationService::AllSources()); + registrar_.Add(this, NotificationType::EXTENSION_FUNCTION_DISPATCHER_CREATED, + NotificationService::AllSources()); registrar_.Add(this, - NotificationType::NAV_ENTRY_COMMITTED, + NotificationType::EXTENSION_FUNCTION_DISPATCHER_DESTROYED, NotificationService::AllSources()); registrar_.Add(this, - NotificationType::RENDER_VIEW_HOST_CREATED, + NotificationType::NAV_ENTRY_COMMITTED, NotificationService::AllSources()); registrar_.Add(this, NotificationType::RENDER_VIEW_HOST_DELETED, @@ -721,11 +724,9 @@ void ExtensionsDOMHandler::Observe(NotificationType type, // we don't know about the views for an extension at EXTENSION_LOADED, but // if we only listen to EXTENSION_PROCESS_CREATED, we'll miss extensions // that don't have a process at startup. Similarly, NAV_ENTRY_COMMITTED & - // RENDER_VIEW_HOST_CREATED because we want to handle both - // the case of navigating from a non-extension page to an extension page in - // a TabContents (which will generate NAV_ENTRY_COMMITTED) as well as - // extension content being shown in popups and balloons (which will generate - // RENDER_VIEW_CREATED but no NAV_ENTRY_COMMITTED). + // EXTENSION_FUNCTION_DISPATCHER_CREATED because we want to handle both + // the case of live app pages (which don't have an EFD) and + // chrome-extension:// urls which are served in a TabContents. // // Doing it this way gets everything but causes the page to be rendered // more than we need. It doesn't seem to result in any noticeable flicker. @@ -741,7 +742,8 @@ void ExtensionsDOMHandler::Observe(NotificationType type, case NotificationType::EXTENSION_PROCESS_CREATED: case NotificationType::EXTENSION_UNLOADED: case NotificationType::EXTENSION_UPDATE_DISABLED: - case NotificationType::RENDER_VIEW_HOST_CREATED: + case NotificationType::EXTENSION_FUNCTION_DISPATCHER_CREATED: + case NotificationType::EXTENSION_FUNCTION_DISPATCHER_DESTROYED: case NotificationType::NAV_ENTRY_COMMITTED: case NotificationType::BACKGROUND_CONTENTS_NAVIGATED: case NotificationType::EXTENSION_BROWSER_ACTION_VISIBILITY_CHANGED: diff --git a/chrome/browser/visitedlink/visitedlink_unittest.cc b/chrome/browser/visitedlink/visitedlink_unittest.cc index 96bcd31..6f58ad7 100644 --- a/chrome/browser/visitedlink/visitedlink_unittest.cc +++ b/chrome/browser/visitedlink/visitedlink_unittest.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2010 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -505,7 +505,7 @@ class VisitRelayingRenderProcessHost : public BrowserRenderProcessHost { Source<RenderProcessHost>(this), NotificationService::NoDetails()); } - virtual bool Init(bool is_accessibility_enabled) { + virtual bool Init(bool is_accessibility_enabled, bool is_extension_process) { return true; } diff --git a/chrome/renderer/extensions/extension_dispatcher.cc b/chrome/renderer/extensions/extension_dispatcher.cc index 13339c3..a2bb8c0 100644 --- a/chrome/renderer/extensions/extension_dispatcher.cc +++ b/chrome/renderer/extensions/extension_dispatcher.cc @@ -35,8 +35,7 @@ using WebKit::WebFrame; using WebKit::WebSecurityPolicy; using WebKit::WebString; -ExtensionDispatcher::ExtensionDispatcher() - : is_webkit_initialized_(false) { +ExtensionDispatcher::ExtensionDispatcher() { std::string type_str = CommandLine::ForCurrentProcess()->GetSwitchValueASCII( switches::kProcessType); is_extension_process_ = type_str == switches::kExtensionProcess || @@ -89,17 +88,6 @@ void ExtensionDispatcher::WebKitInitialized() { RegisterExtension(EventBindings::Get(this), true); RegisterExtension(RendererExtensionBindings::Get(this), true); RegisterExtension(ExtensionApiTestV8Extension::Get(), true); - - // Initialize host permissions for any extensions that were activated before - // WebKit was initialized. - for (std::set<std::string>::iterator iter = active_extension_ids_.begin(); - iter != active_extension_ids_.end(); ++iter) { - const Extension* extension = extensions_.GetByID(*iter); - if (extension) - InitHostPermissions(extension); - } - - is_webkit_initialized_ = true; } void ExtensionDispatcher::IdleNotification() { @@ -214,11 +202,6 @@ void ExtensionDispatcher::OnActivateExtension( if (!extension) return; - if (is_webkit_initialized_) - InitHostPermissions(extension); -} - -void ExtensionDispatcher::InitHostPermissions(const Extension* extension) { if (extension->HasApiPermission(Extension::kManagementPermission)) { WebSecurityPolicy::addOriginAccessWhitelistEntry( extension->url(), @@ -227,7 +210,13 @@ void ExtensionDispatcher::InitHostPermissions(const Extension* extension) { false); } - const URLPatternList& permissions = extension->host_permissions(); + SetHostPermissions(extension->url(), + extension->host_permissions()); +} + +void ExtensionDispatcher::SetHostPermissions( + const GURL& extension_url, + const std::vector<URLPattern>& permissions) { for (size_t i = 0; i < permissions.size(); ++i) { const char* schemes[] = { chrome::kHttpScheme, @@ -238,7 +227,7 @@ void ExtensionDispatcher::InitHostPermissions(const Extension* extension) { for (size_t j = 0; j < arraysize(schemes); ++j) { if (permissions[i].MatchesScheme(schemes[j])) { WebSecurityPolicy::addOriginAccessWhitelistEntry( - extension->url(), + extension_url, WebString::fromUTF8(schemes[j]), WebString::fromUTF8(permissions[i].host()), permissions[i].match_subdomains()); diff --git a/chrome/renderer/extensions/extension_dispatcher.h b/chrome/renderer/extensions/extension_dispatcher.h index bce3c0f..c966d37 100644 --- a/chrome/renderer/extensions/extension_dispatcher.h +++ b/chrome/renderer/extensions/extension_dispatcher.h @@ -81,8 +81,9 @@ class ExtensionDispatcher : public RenderProcessObserver { // extension is for Chrome Extensions only. void RegisterExtension(v8::Extension* extension, bool restrict_to_extensions); - // Sets up the host permissions for |extension|. - void InitHostPermissions(const Extension* extension); + // Sets the host permissions for a particular extension. + void SetHostPermissions(const GURL& extension_url, + const std::vector<URLPattern>& permissions); // True if this renderer is running extensions. bool is_extension_process_; @@ -107,9 +108,6 @@ class ExtensionDispatcher : public RenderProcessObserver { // The extensions that are active in this process. std::set<std::string> active_extension_ids_; - // True once WebKit has been initialized (and it is therefore safe to poke). - bool is_webkit_initialized_; - DISALLOW_COPY_AND_ASSIGN(ExtensionDispatcher); }; diff --git a/content/browser/content_browser_client.cc b/content/browser/content_browser_client.cc index 901097e..84603af 100644 --- a/content/browser/content_browser_client.cc +++ b/content/browser/content_browser_client.cc @@ -14,6 +14,11 @@ void ContentBrowserClient::RenderViewHostCreated( RenderViewHost* render_view_host) { } +void ContentBrowserClient::PreCreateRenderView(RenderViewHost* render_view_host, + Profile* profile, + const GURL& url) { +} + void ContentBrowserClient::BrowserRenderProcessHostCreated( BrowserRenderProcessHost* host) { } diff --git a/content/browser/content_browser_client.h b/content/browser/content_browser_client.h index 7772188..2de7751 100644 --- a/content/browser/content_browser_client.h +++ b/content/browser/content_browser_client.h @@ -34,7 +34,14 @@ class ContentBrowserClient { // Notifies that a new RenderHostView has been created. virtual void RenderViewHostCreated(RenderViewHost* render_view_host); - // Notifies that a BrowserRenderProcessHost has been created. + // Initialize a RenderViewHost before its CreateRenderView method is called. + virtual void PreCreateRenderView(RenderViewHost* render_view_host, + Profile* profile, + const GURL& url); + + // Notifies that a BrowserRenderProcessHost has been created. This is called + // before the content layer adds its own BrowserMessageFilters, so that the + // embedder's IPC filters have priority. virtual void BrowserRenderProcessHostCreated(BrowserRenderProcessHost* host); // Notifies that a WorkerProcessHost has been created. diff --git a/content/browser/renderer_host/browser_render_process_host.cc b/content/browser/renderer_host/browser_render_process_host.cc index 4868e89..aa5808f 100644 --- a/content/browser/renderer_host/browser_render_process_host.cc +++ b/content/browser/renderer_host/browser_render_process_host.cc @@ -192,7 +192,7 @@ BrowserRenderProcessHost::BrowserRenderProcessHost(Profile* profile) base::TimeDelta::FromSeconds(5), this, &BrowserRenderProcessHost::ClearTransportDIBCache)), accessibility_enabled_(false), - is_initialized_(false) { + extension_process_(false) { widget_helper_ = new RenderWidgetHelper(); WebCacheManager::GetInstance()->Add(id()); @@ -239,7 +239,8 @@ BrowserRenderProcessHost::~BrowserRenderProcessHost() { ClearTransportDIBCache(); } -bool BrowserRenderProcessHost::Init(bool is_accessibility_enabled) { +bool BrowserRenderProcessHost::Init( + bool is_accessibility_enabled, bool is_extensions_process) { // calling Init() more than once does nothing, this makes it more convenient // for the view host which may not be sure in some cases if (channel_.get()) @@ -247,6 +248,10 @@ bool BrowserRenderProcessHost::Init(bool is_accessibility_enabled) { accessibility_enabled_ = is_accessibility_enabled; + // It is possible for an extension process to be reused for non-extension + // content, e.g. if an extension calls window.open. + extension_process_ = extension_process_ || is_extensions_process; + CommandLine::StringType renderer_prefix; #if defined(OS_POSIX) // A command prefix is something prepended to the command line of the spawned @@ -327,7 +332,6 @@ bool BrowserRenderProcessHost::Init(bool is_accessibility_enabled) { fast_shutdown_started_ = false; } - is_initialized_ = true; return true; } @@ -466,8 +470,8 @@ void BrowserRenderProcessHost::AppendRendererCommandLine( // Extensions use a special pseudo-process type to make them distinguishable, // even though they're just renderers. command_line->AppendSwitchASCII(switches::kProcessType, - is_extension_process_ ? switches::kExtensionProcess : - switches::kRendererProcess); + extension_process_ ? switches::kExtensionProcess : + switches::kRendererProcess); if (logging::DialogsAreSuppressed()) command_line->AppendSwitch(switches::kNoErrorDialogs); @@ -758,13 +762,8 @@ void BrowserRenderProcessHost::ClearTransportDIBCache() { bool BrowserRenderProcessHost::Send(IPC::Message* msg) { if (!channel_.get()) { - if (!is_initialized_) { - queued_messages_.push(msg); - return true; - } else { - delete msg; - return false; - } + delete msg; + return false; } if (child_process_launcher_.get() && child_process_launcher_->IsStarting()) { @@ -853,15 +852,15 @@ void BrowserRenderProcessHost::OnChannelError() { if (status == base::TERMINATION_STATUS_PROCESS_CRASHED || status == base::TERMINATION_STATUS_ABNORMAL_TERMINATION) { UMA_HISTOGRAM_PERCENTAGE("BrowserRenderProcessHost.ChildCrashes", - is_extension_process_ ? 2 : 1); + extension_process_ ? 2 : 1); } if (status == base::TERMINATION_STATUS_PROCESS_WAS_KILLED) { UMA_HISTOGRAM_PERCENTAGE("BrowserRenderProcessHost.ChildKills", - is_extension_process_ ? 2 : 1); + extension_process_ ? 2 : 1); } - RendererClosedDetails details(status, exit_code, is_extension_process_); + RendererClosedDetails details(status, exit_code, extension_process_); NotificationService::current()->Notify( NotificationType::RENDERER_PROCESS_CLOSED, Source<RenderProcessHost>(this), diff --git a/content/browser/renderer_host/browser_render_process_host.h b/content/browser/renderer_host/browser_render_process_host.h index fb46c82..3f7a23c 100644 --- a/content/browser/renderer_host/browser_render_process_host.h +++ b/content/browser/renderer_host/browser_render_process_host.h @@ -47,7 +47,7 @@ class BrowserRenderProcessHost : public RenderProcessHost, ~BrowserRenderProcessHost(); // RenderProcessHost implementation (public portion). - virtual bool Init(bool is_accessibility_enabled); + virtual bool Init(bool is_accessibility_enabled, bool is_extensions_process); virtual int GetNextRoutingID(); virtual void CancelResourceRequests(int render_widget_id); virtual void CrossSiteClosePageACK(const ViewMsg_ClosePage_Params& params); @@ -131,9 +131,9 @@ class BrowserRenderProcessHost : public RenderProcessHost, // True if this prcoess should have accessibility enabled; bool accessibility_enabled_; - // True after Init() has been called. We can't just check channel_ because we - // also reset that in the case of process termination. - bool is_initialized_; + // True iff this process is being used as an extension process. Not valid + // when running in single-process mode. + bool extension_process_; // Used to launch and terminate the process without blocking the UI thread. scoped_ptr<ChildProcessLauncher> child_process_launcher_; diff --git a/content/browser/renderer_host/mock_render_process_host.cc b/content/browser/renderer_host/mock_render_process_host.cc index dec107a..104395f 100644 --- a/content/browser/renderer_host/mock_render_process_host.cc +++ b/content/browser/renderer_host/mock_render_process_host.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 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. @@ -23,7 +23,8 @@ MockRenderProcessHost::~MockRenderProcessHost() { factory_->Remove(this); } -bool MockRenderProcessHost::Init(bool is_accessibility_enabled) { +bool MockRenderProcessHost::Init( + bool is_accessibility_enabled, bool is_extensions_process) { return true; } diff --git a/content/browser/renderer_host/mock_render_process_host.h b/content/browser/renderer_host/mock_render_process_host.h index a6804a1..0e7656c 100644 --- a/content/browser/renderer_host/mock_render_process_host.h +++ b/content/browser/renderer_host/mock_render_process_host.h @@ -36,7 +36,7 @@ class MockRenderProcessHost : public RenderProcessHost { int bad_msg_count() const { return bad_msg_count_; } // RenderProcessHost implementation (public portion). - virtual bool Init(bool is_accessibility_enabled); + virtual bool Init(bool is_accessibility_enabled, bool is_extensions_process); virtual int GetNextRoutingID(); virtual void CancelResourceRequests(int render_widget_id); virtual void CrossSiteClosePageACK(const ViewMsg_ClosePage_Params& params); diff --git a/content/browser/renderer_host/render_process_host.cc b/content/browser/renderer_host/render_process_host.cc index 5466004..379ce99 100644 --- a/content/browser/renderer_host/render_process_host.cc +++ b/content/browser/renderer_host/render_process_host.cc @@ -94,7 +94,6 @@ RenderProcessHost::RenderProcessHost(Profile* profile) : max_page_id_(-1), fast_shutdown_started_(false), deleting_soon_(false), - is_extension_process_(false), pending_views_(0), id_(ChildProcessInfo::GenerateChildProcessUniqueId()), profile_(profile), diff --git a/content/browser/renderer_host/render_process_host.h b/content/browser/renderer_host/render_process_host.h index 9d3b8fc..b43fbe2 100644 --- a/content/browser/renderer_host/render_process_host.h +++ b/content/browser/renderer_host/render_process_host.h @@ -88,9 +88,6 @@ class RenderProcessHost : public IPC::Channel::Sender, sudden_termination_allowed_ = enabled; } - bool is_extension_process() const { return is_extension_process_; } - void mark_is_extension_process() { is_extension_process_ = true; } - // Used for refcounting, each holder of this object must Attach and Release // just like it would for a COM object. This object should be allocated on // the heap; when no listeners own it any more, it will delete itself. @@ -166,7 +163,8 @@ class RenderProcessHost : public IPC::Channel::Sender, // be called once before the object can be used, but can be called after // that with no effect. Therefore, if the caller isn't sure about whether // the process has been created, it should just call Init(). - virtual bool Init(bool is_accessibility_enabled) = 0; + virtual bool Init( + bool is_accessibility_enabled, bool is_extensions_process) = 0; // Gets the next available routing id. virtual int GetNextRoutingID() = 0; @@ -284,10 +282,6 @@ class RenderProcessHost : public IPC::Channel::Sender, // True if we've posted a DeleteTask and will be deleted soon. bool deleting_soon_; - // True iff this process is being used as an extension process. Not valid - // when running in single-process mode. - bool is_extension_process_; - // The count of currently swapped out but pending RenderViews. We have // started to swap these in, so the renderer process should not exit if // this count is non-zero. diff --git a/content/browser/renderer_host/render_view_host.cc b/content/browser/renderer_host/render_view_host.cc index c74ac5e..47e5457 100644 --- a/content/browser/renderer_host/render_view_host.cc +++ b/content/browser/renderer_host/render_view_host.cc @@ -102,6 +102,7 @@ RenderViewHost::RenderViewHost(SiteInstance* instance, are_javascript_messages_suppressed_(false), sudden_termination_allowed_(false), session_storage_namespace_(session_storage), + is_extension_process_(false), save_accessibility_tree_for_testing_(false), render_view_termination_status_(base::TERMINATION_STATUS_STILL_RUNNING) { if (!session_storage_namespace_) { @@ -113,11 +114,6 @@ RenderViewHost::RenderViewHost(SiteInstance* instance, DCHECK(delegate_); content::GetContentClient()->browser()->RenderViewHostCreated(this); - - NotificationService::current()->Notify( - NotificationType::RENDER_VIEW_HOST_CREATED, - Source<RenderViewHost>(this), - NotificationService::NoDetails()); } RenderViewHost::~RenderViewHost() { @@ -143,7 +139,7 @@ bool RenderViewHost::CreateRenderView(const string16& frame_name) { // initialized it) or may not (we have our own process or the old process // crashed) have been initialized. Calling Init multiple times will be // ignored, so this is safe. - if (!process()->Init(renderer_accessible())) + if (!process()->Init(renderer_accessible(), is_extension_process_)) return false; DCHECK(process()->HasConnection()); DCHECK(process()->profile()); @@ -156,6 +152,10 @@ bool RenderViewHost::CreateRenderView(const string16& frame_name) { if (BindingsPolicy::is_extension_enabled(enabled_bindings_)) { ChildProcessSecurityPolicy::GetInstance()->GrantExtensionBindings( process()->id()); + + // Extensions may have permission to access chrome:// URLs. + ChildProcessSecurityPolicy::GetInstance()->GrantScheme( + process()->id(), chrome::kChromeUIScheme); } renderer_initialized_ = true; diff --git a/content/browser/renderer_host/render_view_host.h b/content/browser/renderer_host/render_view_host.h index b29f2ed..bfd7bf85 100644 --- a/content/browser/renderer_host/render_view_host.h +++ b/content/browser/renderer_host/render_view_host.h @@ -314,6 +314,12 @@ class RenderViewHost : public RenderWidgetHost { // RenderView. See BindingsPolicy for details. int enabled_bindings() const { return enabled_bindings_; } + // See variable comment. + bool is_extension_process() const { return is_extension_process_; } + void set_is_extension_process(bool is_extension_process) { + is_extension_process_ = is_extension_process; + } + // Sets a property with the given name and value on the Web UI binding object. // Must call AllowWebUIBindings() on this renderer first. void SetWebUIProperty(const std::string& name, const std::string& value); @@ -593,6 +599,10 @@ class RenderViewHost : public RenderWidgetHost { // The session storage namespace to be used by the associated render view. scoped_refptr<SessionStorageNamespace> session_storage_namespace_; + // Whether this render view will get extension api bindings. This controls + // what process type we use. + bool is_extension_process_; + // Whether the accessibility tree should be saved, for unit testing. bool save_accessibility_tree_for_testing_; diff --git a/content/browser/tab_contents/render_view_host_manager.cc b/content/browser/tab_contents/render_view_host_manager.cc index 442e91c8..22ae236 100644 --- a/content/browser/tab_contents/render_view_host_manager.cc +++ b/content/browser/tab_contents/render_view_host_manager.cc @@ -506,6 +506,11 @@ bool RenderViewHostManager::InitRenderView(RenderViewHost* render_view_host, if (pending_web_ui_.get()) render_view_host->AllowBindings(pending_web_ui_->bindings()); + // Give the embedder a chance to initialize the render view. + Profile* profile = delegate_->GetControllerForRenderManager().profile(); + content::GetContentClient()->browser()->PreCreateRenderView( + render_view_host, profile, entry.url()); + return delegate_->CreateRenderViewForRenderManager(render_view_host); } diff --git a/content/common/notification_type.h b/content/common/notification_type.h index c7e4d6a..850b887 100644 --- a/content/common/notification_type.h +++ b/content/common/notification_type.h @@ -459,10 +459,6 @@ class NotificationType { // Used only in testing. RENDER_WIDGET_HOST_DID_RECEIVE_INPUT_EVENT_ACK, - // Sent from RenderViewHost constructor. The source is the RenderViewHost, - // the details unused. - RENDER_VIEW_HOST_CREATED, - // Sent from ~RenderViewHost. The source is the RenderViewHost, the details // unused. RENDER_VIEW_HOST_DELETED, @@ -869,6 +865,18 @@ class NotificationType { // Extension, and the source is a Profile. EXTENSION_USER_SCRIPTS_UPDATED, + // Sent after a new ExtensionFunctionDispatcher is created. The details are + // an ExtensionFunctionDispatcher* and the source is a Profile*. This is + // similar in timing to EXTENSION_HOST_CREATED, but also fires when an + // extension view which is hosted in TabContents* is created. + EXTENSION_FUNCTION_DISPATCHER_CREATED, + + // Sent before an ExtensionHost is destroyed. The details are + // an ExtensionFunctionDispatcher* and the source is a Profile*. This is + // similar in timing to EXTENSION_HOST_DESTROYED, but also fires when an + // extension view which is hosted in TabContents* is destroyed. + EXTENSION_FUNCTION_DISPATCHER_DESTROYED, + // Sent after a new ExtensionHost is created. The details are // an ExtensionHost* and the source is an ExtensionProcessManager*. EXTENSION_HOST_CREATED, |