Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2490)

Unified Diff: chrome/browser/extensions/chrome_content_browser_client_extensions_part.cc

Issue 434023004: Move more extensions code from ChromeContentBrowserClient to ChromeContentBrowserClientExtensionsPa… (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: put back a #include Created 6 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « chrome/browser/extensions/chrome_content_browser_client_extensions_part.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/browser/extensions/chrome_content_browser_client_extensions_part.cc
diff --git a/chrome/browser/extensions/chrome_content_browser_client_extensions_part.cc b/chrome/browser/extensions/chrome_content_browser_client_extensions_part.cc
index de7be636ee5c4b2a750d8329912fce9397b3cf89..70648025a7565d473a6cb4b746e4d67b8c73e2c5 100644
--- a/chrome/browser/extensions/chrome_content_browser_client_extensions_part.cc
+++ b/chrome/browser/extensions/chrome_content_browser_client_extensions_part.cc
@@ -4,22 +4,35 @@
#include "chrome/browser/extensions/chrome_content_browser_client_extensions_part.h"
+#include <set>
+
#include "base/command_line.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/extensions/browser_permissions_policy_delegate.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_web_ui.h"
#include "chrome/browser/extensions/extension_webkit_preferences.h"
#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_io_data.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/common/chrome_constants.h"
+#include "chrome/common/extensions/extension_constants.h"
+#include "chrome/common/extensions/extension_process_policy.h"
+#include "chrome/common/extensions/manifest_handlers/app_isolation_info.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/browser_url_handler.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/site_instance.h"
#include "content/public/browser/web_contents.h"
+#include "extensions/browser/extension_host.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/browser/extension_system.h"
#include "extensions/browser/info_map.h"
#include "extensions/browser/view_type_utils.h"
#include "extensions/common/constants.h"
+#include "extensions/common/manifest_handlers/background_info.h"
+#include "extensions/common/manifest_handlers/web_accessible_resources_info.h"
#include "extensions/common/switches.h"
// TODO(thestig): Remove ifdefs when extensions no longer build on mobile.
@@ -40,14 +53,359 @@ using content::WebPreferences;
namespace extensions {
+namespace {
+
+// Used by the GetPrivilegeRequiredByUrl() and GetProcessPrivilege() functions
+// below. Extension, and isolated apps require different privileges to be
+// granted to their RenderProcessHosts. This classification allows us to make
+// sure URLs are served by hosts with the right set of privileges.
+enum RenderProcessHostPrivilege {
+ PRIV_NORMAL,
+ PRIV_HOSTED,
+ PRIV_ISOLATED,
+ PRIV_EXTENSION,
+};
+
+RenderProcessHostPrivilege GetPrivilegeRequiredByUrl(
+ const GURL& url,
+ ExtensionService* service) {
+ // Default to a normal renderer cause it is lower privileged. This should only
+ // occur if the URL on a site instance is either malformed, or uninitialized.
+ // If it is malformed, then there is no need for better privileges anyways.
+ // If it is uninitialized, but eventually settles on being an a scheme other
+ // than normal webrenderer, the navigation logic will correct us out of band
+ // anyways.
+ if (!url.is_valid())
+ return PRIV_NORMAL;
+
+ if (!url.SchemeIs(kExtensionScheme))
+ return PRIV_NORMAL;
+
+ const Extension* extension = service->extensions()->GetByID(url.host());
+ if (extension && AppIsolationInfo::HasIsolatedStorage(extension))
+ return PRIV_ISOLATED;
+ if (extension && extension->is_hosted_app())
+ return PRIV_HOSTED;
+ return PRIV_EXTENSION;
+}
+
+RenderProcessHostPrivilege GetProcessPrivilege(
+ content::RenderProcessHost* process_host,
+ ProcessMap* process_map,
+ ExtensionService* service) {
+ std::set<std::string> extension_ids =
+ process_map->GetExtensionsInProcess(process_host->GetID());
+ if (extension_ids.empty())
+ return PRIV_NORMAL;
+
+ for (std::set<std::string>::iterator iter = extension_ids.begin();
+ iter != extension_ids.end(); ++iter) {
+ const Extension* extension = service->GetExtensionById(*iter, false);
+ if (extension && AppIsolationInfo::HasIsolatedStorage(extension))
+ return PRIV_ISOLATED;
+ if (extension && extension->is_hosted_app())
+ return PRIV_HOSTED;
+ }
+
+ return PRIV_EXTENSION;
+}
+
+} // namespace
+
ChromeContentBrowserClientExtensionsPart::
ChromeContentBrowserClientExtensionsPart() {
+ permissions_policy_delegate_.reset(new BrowserPermissionsPolicyDelegate());
}
ChromeContentBrowserClientExtensionsPart::
~ChromeContentBrowserClientExtensionsPart() {
}
+// static
+GURL ChromeContentBrowserClientExtensionsPart::GetEffectiveURL(
+ Profile* profile, const GURL& url) {
+ // If the input |url| is part of an installed app, the effective URL is an
+ // extension URL with the ID of that extension as the host. This has the
+ // effect of grouping apps together in a common SiteInstance.
+ ExtensionService* extension_service =
+ ExtensionSystem::Get(profile)->extension_service();
+ if (!extension_service)
+ return url;
+
+ const Extension* extension =
+ extension_service->extensions()->GetHostedAppByURL(url);
+ if (!extension)
+ return url;
+
+ // Bookmark apps do not use the hosted app process model, and should be
+ // treated as normal URLs.
+ if (extension->from_bookmark())
+ return url;
+
+ // If the URL is part of an extension's web extent, convert it to an
+ // extension URL.
+ return extension->GetResourceURL(url.path());
+}
+
+// static
+bool ChromeContentBrowserClientExtensionsPart::ShouldUseProcessPerSite(
+ Profile* profile, const GURL& effective_url) {
+ if (!effective_url.SchemeIs(kExtensionScheme))
+ return false;
+
+ ExtensionService* extension_service =
+ ExtensionSystem::Get(profile)->extension_service();
+ if (!extension_service)
+ return false;
+
+ const Extension* extension =
+ extension_service->extensions()->GetExtensionOrAppByURL(effective_url);
+ if (!extension)
+ return false;
+
+ // If the URL is part of a hosted app that does not have the background
+ // permission, or that does not allow JavaScript access to the background
+ // page, we want to give each instance its own process to improve
+ // responsiveness.
+ if (extension->GetType() == Manifest::TYPE_HOSTED_APP) {
+ if (!extension->permissions_data()->HasAPIPermission(
+ APIPermission::kBackground) ||
+ !BackgroundInfo::AllowJSAccess(extension)) {
+ return false;
+ }
+ }
+
+ // Hosted apps that have script access to their background page must use
+ // process per site, since all instances can make synchronous calls to the
+ // background window. Other extensions should use process per site as well.
+ return true;
+}
+
+// static
+bool ChromeContentBrowserClientExtensionsPart::CanCommitURL(
+ content::RenderProcessHost* process_host, const GURL& url) {
+ // We need to let most extension URLs commit in any process, since this can
+ // be allowed due to web_accessible_resources. Most hosted app URLs may also
+ // load in any process (e.g., in an iframe). However, the Chrome Web Store
+ // cannot be loaded in iframes and should never be requested outside its
+ // process.
+ Profile* profile =
+ Profile::FromBrowserContext(process_host->GetBrowserContext());
+ ExtensionService* service =
+ ExtensionSystem::Get(profile)->extension_service();
+ if (!service)
+ return true;
+
+ const Extension* new_extension =
+ service->extensions()->GetExtensionOrAppByURL(url);
+ if (new_extension &&
+ new_extension->is_hosted_app() &&
+ new_extension->id() == extension_misc::kWebStoreAppId &&
+ !ProcessMap::Get(profile)->Contains(
+ new_extension->id(), process_host->GetID())) {
+ return false;
+ }
+ return true;
+}
+
+// static
+bool ChromeContentBrowserClientExtensionsPart::IsSuitableHost(
+ Profile* profile,
+ content::RenderProcessHost* process_host,
+ const GURL& site_url) {
+ DCHECK(profile);
+
+ ExtensionService* service =
+ ExtensionSystem::Get(profile)->extension_service();
+ ProcessMap* process_map = ProcessMap::Get(profile);
+
+ // These may be NULL during tests. In that case, just assume any site can
+ // share any host.
+ if (!service || !process_map)
+ return true;
+
+ // Otherwise, just make sure the process privilege matches the privilege
+ // required by the site.
+ RenderProcessHostPrivilege privilege_required =
+ GetPrivilegeRequiredByUrl(site_url, service);
+ return GetProcessPrivilege(process_host, process_map, service) ==
+ privilege_required;
+}
+
+// static
+bool
+ChromeContentBrowserClientExtensionsPart::ShouldTryToUseExistingProcessHost(
+ Profile* profile, const GURL& url) {
+ // This function is trying to limit the amount of processes used by extensions
+ // with background pages. It uses a globally set percentage of processes to
+ // run such extensions and if the limit is exceeded, it returns true, to
+ // indicate to the content module to group extensions together.
+ ExtensionService* service = profile ?
+ ExtensionSystem::Get(profile)->extension_service() : NULL;
+ if (!service)
+ return false;
+
+ // We have to have a valid extension with background page to proceed.
+ const Extension* extension =
+ service->extensions()->GetExtensionOrAppByURL(url);
+ if (!extension)
+ return false;
+ if (!BackgroundInfo::HasBackgroundPage(extension))
+ return false;
+
+ std::set<int> process_ids;
+ size_t max_process_count =
+ content::RenderProcessHost::GetMaxRendererProcessCount();
+
+ // Go through all profiles to ensure we have total count of extension
+ // processes containing background pages, otherwise one profile can
+ // starve the other.
+ std::vector<Profile*> profiles = g_browser_process->profile_manager()->
+ GetLoadedProfiles();
+ for (size_t i = 0; i < profiles.size(); ++i) {
+ ProcessManager* epm = ExtensionSystem::Get(profiles[i])->process_manager();
+ for (ProcessManager::const_iterator iter = epm->background_hosts().begin();
+ iter != epm->background_hosts().end(); ++iter) {
+ const ExtensionHost* host = *iter;
+ process_ids.insert(host->render_process_host()->GetID());
+ }
+ }
+
+ return (process_ids.size() >
+ (max_process_count * chrome::kMaxShareOfExtensionProcesses));
+}
+
+// static
+bool ChromeContentBrowserClientExtensionsPart::
+ ShouldSwapBrowsingInstancesForNavigation(SiteInstance* site_instance,
+ const GURL& current_url,
+ const GURL& new_url) {
+ // If we don't have an ExtensionService, then rely on the SiteInstance logic
+ // in RenderFrameHostManager to decide when to swap.
+ Profile* profile =
+ Profile::FromBrowserContext(site_instance->GetBrowserContext());
+ ExtensionService* service =
+ ExtensionSystem::Get(profile)->extension_service();
+ if (!service)
+ return false;
+
+ // We must use a new BrowsingInstance (forcing a process swap and disabling
+ // scripting by existing tabs) if one of the URLs is an extension and the
+ // other is not the exact same extension.
+ //
+ // We ignore hosted apps here so that other tabs in their BrowsingInstance can
+ // use postMessage with them. (The exception is the Chrome Web Store, which
+ // is a hosted app that requires its own BrowsingInstance.) Navigations
+ // to/from a hosted app will still trigger a SiteInstance swap in
+ // RenderFrameHostManager.
+ const Extension* current_extension =
+ service->extensions()->GetExtensionOrAppByURL(current_url);
+ if (current_extension &&
+ current_extension->is_hosted_app() &&
+ current_extension->id() != extension_misc::kWebStoreAppId)
+ current_extension = NULL;
+
+ const Extension* new_extension =
+ service->extensions()->GetExtensionOrAppByURL(new_url);
+ if (new_extension &&
+ new_extension->is_hosted_app() &&
+ new_extension->id() != extension_misc::kWebStoreAppId)
+ new_extension = NULL;
+
+ // First do a process check. We should force a BrowsingInstance swap if the
+ // current process doesn't know about new_extension, even if current_extension
+ // is somehow the same as new_extension.
+ ProcessMap* process_map = ProcessMap::Get(profile);
+ if (new_extension &&
+ site_instance->HasProcess() &&
+ !process_map->Contains(
+ new_extension->id(), site_instance->GetProcess()->GetID()))
+ return true;
+
+ // Otherwise, swap BrowsingInstances if current_extension and new_extension
+ // differ.
+ return current_extension != new_extension;
+}
+
+// static
+bool ChromeContentBrowserClientExtensionsPart::ShouldSwapProcessesForRedirect(
+ content::ResourceContext* resource_context,
+ const GURL& current_url,
+ const GURL& new_url) {
+ ProfileIOData* io_data = ProfileIOData::FromResourceContext(resource_context);
+ return CrossesExtensionProcessBoundary(
+ io_data->GetExtensionInfoMap()->extensions(),
+ current_url, new_url, false);
+}
+
+// static
+std::string ChromeContentBrowserClientExtensionsPart::GetWorkerProcessTitle(
+ const GURL& url, content::ResourceContext* context) {
+ // Check if it's an extension-created worker, in which case we want to use
+ // the name of the extension.
+ ProfileIOData* io_data = ProfileIOData::FromResourceContext(context);
+ const Extension* extension =
+ io_data->GetExtensionInfoMap()->extensions().GetByID(url.host());
+ return extension ? extension->name() : std::string();
+}
+
+// static
+bool ChromeContentBrowserClientExtensionsPart::ShouldAllowOpenURL(
+ content::SiteInstance* site_instance,
+ const GURL& from_url,
+ const GURL& to_url,
+ bool* result) {
+ DCHECK(result);
+
+ // Do not allow pages from the web or other extensions navigate to
+ // non-web-accessible extension resources.
+ if (to_url.SchemeIs(kExtensionScheme) &&
+ (from_url.SchemeIsHTTPOrHTTPS() || from_url.SchemeIs(kExtensionScheme))) {
+ Profile* profile = Profile::FromBrowserContext(
+ site_instance->GetProcess()->GetBrowserContext());
+ ExtensionService* service =
+ ExtensionSystem::Get(profile)->extension_service();
+ if (!service) {
+ *result = true;
+ return true;
+ }
+ const Extension* extension =
+ service->extensions()->GetExtensionOrAppByURL(to_url);
+ if (!extension) {
+ *result = true;
+ return true;
+ }
+ const Extension* from_extension =
+ service->extensions()->GetExtensionOrAppByURL(
+ site_instance->GetSiteURL());
+ if (from_extension && from_extension->id() == extension->id()) {
+ *result = true;
+ return true;
+ }
+
+ if (!WebAccessibleResourcesInfo::IsResourceWebAccessible(
+ extension, to_url.path())) {
+ *result = false;
+ return true;
+ }
+ }
+ return false;
+}
+
+// static
+void ChromeContentBrowserClientExtensionsPart::SetSigninProcess(
+ content::SiteInstance* site_instance) {
+ Profile* profile =
+ Profile::FromBrowserContext(site_instance->GetBrowserContext());
+ DCHECK(profile);
+ BrowserThread::PostTask(
+ BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(&InfoMap::SetSigninProcess,
+ ExtensionSystem::Get(profile)->info_map(),
+ site_instance->GetProcess()->GetID()));
+}
+
void ChromeContentBrowserClientExtensionsPart::RenderProcessWillLaunch(
content::RenderProcessHost* host) {
#if defined(ENABLE_EXTENSIONS)
« no previous file with comments | « chrome/browser/extensions/chrome_content_browser_client_extensions_part.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698