1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/renderer/chrome_render_process_observer.h"
10 #include "base/allocator/allocator_extension.h"
11 #include "base/bind.h"
12 #include "base/command_line.h"
13 #include "base/files/file_util.h"
14 #include "base/location.h"
15 #include "base/memory/weak_ptr.h"
16 #include "base/metrics/field_trial.h"
17 #include "base/metrics/histogram.h"
18 #include "base/metrics/statistics_recorder.h"
19 #include "base/native_library.h"
20 #include "base/path_service.h"
21 #include "base/single_thread_task_runner.h"
22 #include "base/strings/utf_string_conversions.h"
23 #include "base/thread_task_runner_handle.h"
24 #include "base/threading/platform_thread.h"
25 #include "chrome/common/child_process_logging.h"
26 #include "chrome/common/chrome_paths.h"
27 #include "chrome/common/chrome_switches.h"
28 #include "chrome/common/net/net_resource_provider.h"
29 #include "chrome/common/render_messages.h"
30 #include "chrome/common/resource_usage_reporter.mojom.h"
31 #include "chrome/common/resource_usage_reporter_type_converters.h"
32 #include "chrome/common/url_constants.h"
33 #include "chrome/common/variations/variations_util.h"
34 #include "chrome/renderer/content_settings_observer.h"
35 #include "chrome/renderer/security_filter_peer.h"
36 #include "content/public/child/resource_dispatcher_delegate.h"
37 #include "content/public/common/service_registry.h"
38 #include "content/public/renderer/render_thread.h"
39 #include "content/public/renderer/render_view.h"
40 #include "content/public/renderer/render_view_visitor.h"
41 #include "crypto/nss_util.h"
42 #include "net/base/net_errors.h"
43 #include "net/base/net_module.h"
44 #include "third_party/WebKit/public/web/WebCache.h"
45 #include "third_party/WebKit/public/web/WebDocument.h"
46 #include "third_party/WebKit/public/web/WebFrame.h"
47 #include "third_party/WebKit/public/web/WebRuntimeFeatures.h"
48 #include "third_party/WebKit/public/web/WebSecurityPolicy.h"
49 #include "third_party/WebKit/public/web/WebView.h"
50 #include "third_party/mojo/src/mojo/public/cpp/bindings/strong_binding.h"
52 #if defined(ENABLE_EXTENSIONS)
53 #include "chrome/renderer/extensions/extension_localization_peer.h"
56 using blink::WebCache
;
57 using blink::WebRuntimeFeatures
;
58 using blink::WebSecurityPolicy
;
59 using blink::WebString
;
60 using content::RenderThread
;
64 const int kCacheStatsDelayMS
= 2000;
66 class RendererResourceDelegate
: public content::ResourceDispatcherDelegate
{
68 RendererResourceDelegate()
69 : weak_factory_(this) {
72 content::RequestPeer
* OnRequestComplete(content::RequestPeer
* current_peer
,
73 content::ResourceType resource_type
,
74 int error_code
) override
{
75 // Update the browser about our cache.
76 // Rate limit informing the host of our cache stats.
77 if (!weak_factory_
.HasWeakPtrs()) {
78 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
80 base::Bind(&RendererResourceDelegate::InformHostOfCacheStats
,
81 weak_factory_
.GetWeakPtr()),
82 base::TimeDelta::FromMilliseconds(kCacheStatsDelayMS
));
85 if (error_code
== net::ERR_ABORTED
) {
89 // Resource canceled with a specific error are filtered.
90 return SecurityFilterPeer::CreateSecurityFilterPeerForDeniedRequest(
91 resource_type
, current_peer
, error_code
);
94 content::RequestPeer
* OnReceivedResponse(content::RequestPeer
* current_peer
,
95 const std::string
& mime_type
,
96 const GURL
& url
) override
{
97 #if defined(ENABLE_EXTENSIONS)
98 return ExtensionLocalizationPeer::CreateExtensionLocalizationPeer(
99 current_peer
, RenderThread::Get(), mime_type
, url
);
106 void InformHostOfCacheStats() {
107 WebCache::UsageStats stats
;
108 WebCache::getUsageStats(&stats
);
109 RenderThread::Get()->Send(new ChromeViewHostMsg_UpdatedCacheStats(stats
));
112 base::WeakPtrFactory
<RendererResourceDelegate
> weak_factory_
;
114 DISALLOW_COPY_AND_ASSIGN(RendererResourceDelegate
);
117 static const int kWaitForWorkersStatsTimeoutMS
= 20;
119 class ResourceUsageReporterImpl
: public ResourceUsageReporter
{
121 ResourceUsageReporterImpl(
122 base::WeakPtr
<ChromeRenderProcessObserver
> observer
,
123 mojo::InterfaceRequest
<ResourceUsageReporter
> req
)
124 : binding_(this, req
.Pass()), observer_(observer
), weak_factory_(this) {}
125 ~ResourceUsageReporterImpl() override
{}
128 static void CollectOnWorkerThread(
129 const scoped_refptr
<base::TaskRunner
>& master
,
130 base::WeakPtr
<ResourceUsageReporterImpl
> impl
) {
131 size_t total_bytes
= 0;
132 size_t used_bytes
= 0;
133 v8::Isolate
* isolate
= v8::Isolate::GetCurrent();
135 v8::HeapStatistics heap_stats
;
136 isolate
->GetHeapStatistics(&heap_stats
);
137 total_bytes
= heap_stats
.total_heap_size();
138 used_bytes
= heap_stats
.used_heap_size();
140 master
->PostTask(FROM_HERE
,
141 base::Bind(&ResourceUsageReporterImpl::ReceiveStats
, impl
,
142 total_bytes
, used_bytes
));
145 void ReceiveStats(size_t total_bytes
, size_t used_bytes
) {
146 usage_data_
->v8_bytes_allocated
+= total_bytes
;
147 usage_data_
->v8_bytes_used
+= used_bytes
;
154 if (!callback_
.is_null())
155 callback_
.Run(usage_data_
.Pass());
157 weak_factory_
.InvalidateWeakPtrs();
162 const mojo::Callback
<void(ResourceUsageDataPtr
)>& callback
) override
{
163 DCHECK(callback_
.is_null());
164 weak_factory_
.InvalidateWeakPtrs();
165 usage_data_
= ResourceUsageData::New();
166 usage_data_
->reports_v8_stats
= true;
167 callback_
= callback
;
169 if (observer_
&& observer_
->webkit_initialized()) {
170 WebCache::ResourceTypeStats stats
;
171 WebCache::getResourceTypeStats(&stats
);
172 usage_data_
->web_cache_stats
= ResourceTypeStats::From(stats
);
175 v8::Isolate
* isolate
= v8::Isolate::GetCurrent();
177 v8::HeapStatistics heap_stats
;
178 isolate
->GetHeapStatistics(&heap_stats
);
179 usage_data_
->v8_bytes_allocated
= heap_stats
.total_heap_size();
180 usage_data_
->v8_bytes_used
= heap_stats
.used_heap_size();
182 base::Closure collect
= base::Bind(
183 &ResourceUsageReporterImpl::CollectOnWorkerThread
,
184 base::ThreadTaskRunnerHandle::Get(), weak_factory_
.GetWeakPtr());
185 workers_to_go_
= RenderThread::Get()->PostTaskToAllWebWorkers(collect
);
186 if (workers_to_go_
) {
187 // The guard task to send out partial stats
188 // in case some workers are not responsive.
189 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
190 FROM_HERE
, base::Bind(&ResourceUsageReporterImpl::SendResults
,
191 weak_factory_
.GetWeakPtr()),
192 base::TimeDelta::FromMilliseconds(kWaitForWorkersStatsTimeoutMS
));
194 // No worker threads so just send out the main thread data right away.
199 ResourceUsageDataPtr usage_data_
;
200 mojo::Callback
<void(ResourceUsageDataPtr
)> callback_
;
202 mojo::StrongBinding
<ResourceUsageReporter
> binding_
;
203 base::WeakPtr
<ChromeRenderProcessObserver
> observer_
;
205 base::WeakPtrFactory
<ResourceUsageReporterImpl
> weak_factory_
;
208 void CreateResourceUsageReporter(
209 base::WeakPtr
<ChromeRenderProcessObserver
> observer
,
210 mojo::InterfaceRequest
<ResourceUsageReporter
> request
) {
211 new ResourceUsageReporterImpl(observer
, request
.Pass());
216 bool ChromeRenderProcessObserver::is_incognito_process_
= false;
218 ChromeRenderProcessObserver::ChromeRenderProcessObserver()
219 : webkit_initialized_(false), weak_factory_(this) {
220 const base::CommandLine
& command_line
=
221 *base::CommandLine::ForCurrentProcess();
223 #if defined(ENABLE_AUTOFILL_DIALOG)
224 WebRuntimeFeatures::enableRequestAutocomplete(true);
227 if (command_line
.HasSwitch(switches::kDisableJavaScriptHarmonyShipping
)) {
228 std::string
flag("--noharmony-shipping");
229 v8::V8::SetFlagsFromString(flag
.c_str(), static_cast<int>(flag
.size()));
232 if (command_line
.HasSwitch(switches::kJavaScriptHarmony
)) {
233 std::string
flag("--harmony");
234 v8::V8::SetFlagsFromString(flag
.c_str(), static_cast<int>(flag
.size()));
237 RenderThread
* thread
= RenderThread::Get();
238 resource_delegate_
.reset(new RendererResourceDelegate());
239 thread
->SetResourceDispatcherDelegate(resource_delegate_
.get());
241 content::ServiceRegistry
* service_registry
= thread
->GetServiceRegistry();
242 if (service_registry
) {
243 service_registry
->AddService
<ResourceUsageReporter
>(
244 base::Bind(CreateResourceUsageReporter
, weak_factory_
.GetWeakPtr()));
247 // Configure modules that need access to resources.
248 net::NetModule::SetResourceProvider(chrome_common_net::NetResourceProvider
);
250 #if defined(OS_POSIX) && !defined(OS_MACOSX) && defined(USE_NSS_CERTS)
251 // On platforms where we use system NSS shared libraries,
252 // initialize NSS now because it won't be able to load the .so's
253 // after we engage the sandbox.
254 if (!command_line
.HasSwitch(switches::kSingleProcess
))
255 crypto::InitNSSSafely();
256 #elif defined(OS_WIN)
257 // crypt32.dll is used to decode X509 certificates for Chromoting.
258 // Only load this library when the feature is enabled.
259 base::LoadNativeLibrary(base::FilePath(L
"crypt32.dll"), NULL
);
261 // Setup initial set of crash dump data for Field Trials in this renderer.
262 chrome_variations::SetChildProcessLoggingVariationList();
263 // Listen for field trial activations to report them to the browser.
264 base::FieldTrialList::AddObserver(this);
267 ChromeRenderProcessObserver::~ChromeRenderProcessObserver() {
270 bool ChromeRenderProcessObserver::OnControlMessageReceived(
271 const IPC::Message
& message
) {
273 IPC_BEGIN_MESSAGE_MAP(ChromeRenderProcessObserver
, message
)
274 IPC_MESSAGE_HANDLER(ChromeViewMsg_SetIsIncognitoProcess
,
275 OnSetIsIncognitoProcess
)
276 IPC_MESSAGE_HANDLER(ChromeViewMsg_SetFieldTrialGroup
, OnSetFieldTrialGroup
)
277 IPC_MESSAGE_HANDLER(ChromeViewMsg_SetContentSettingRules
,
278 OnSetContentSettingRules
)
279 IPC_MESSAGE_UNHANDLED(handled
= false)
280 IPC_END_MESSAGE_MAP()
284 void ChromeRenderProcessObserver::WebKitInitialized() {
285 webkit_initialized_
= true;
286 // chrome-native: is a scheme used for placeholder navigations that allow
287 // UIs to be drawn with platform native widgets instead of HTML. These pages
288 // should not be accessible, and should also be treated as empty documents
289 // that can commit synchronously. No code should be runnable in these pages,
290 // so it should not need to access anything nor should it allow javascript
291 // URLs since it should never be visible to the user.
292 WebString
native_scheme(base::ASCIIToUTF16(chrome::kChromeNativeScheme
));
293 WebSecurityPolicy::registerURLSchemeAsDisplayIsolated(native_scheme
);
294 WebSecurityPolicy::registerURLSchemeAsEmptyDocument(native_scheme
);
295 WebSecurityPolicy::registerURLSchemeAsNoAccess(native_scheme
);
296 WebSecurityPolicy::registerURLSchemeAsNotAllowingJavascriptURLs(
300 void ChromeRenderProcessObserver::OnRenderProcessShutdown() {
301 webkit_initialized_
= false;
304 void ChromeRenderProcessObserver::OnSetIsIncognitoProcess(
305 bool is_incognito_process
) {
306 is_incognito_process_
= is_incognito_process
;
309 void ChromeRenderProcessObserver::OnSetContentSettingRules(
310 const RendererContentSettingRules
& rules
) {
311 content_setting_rules_
= rules
;
314 void ChromeRenderProcessObserver::OnSetFieldTrialGroup(
315 const std::string
& field_trial_name
,
316 const std::string
& group_name
) {
317 base::FieldTrial
* trial
=
318 base::FieldTrialList::CreateFieldTrial(field_trial_name
, group_name
);
319 // TODO(mef): Remove this check after the investigation of 359406 is complete.
320 CHECK(trial
) << field_trial_name
<< ":" << group_name
;
321 // Ensure the trial is marked as "used" by calling group() on it if it is
322 // marked as activated.
324 chrome_variations::SetChildProcessLoggingVariationList();
327 const RendererContentSettingRules
*
328 ChromeRenderProcessObserver::content_setting_rules() const {
329 return &content_setting_rules_
;
332 void ChromeRenderProcessObserver::OnFieldTrialGroupFinalized(
333 const std::string
& trial_name
,
334 const std::string
& group_name
) {
335 content::RenderThread::Get()->Send(
336 new ChromeViewHostMsg_FieldTrialActivated(trial_name
));