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/path_service.h"
20 #include "base/single_thread_task_runner.h"
21 #include "base/strings/utf_string_conversions.h"
22 #include "base/thread_task_runner_handle.h"
23 #include "base/threading/platform_thread.h"
24 #include "chrome/common/child_process_logging.h"
25 #include "chrome/common/chrome_paths.h"
26 #include "chrome/common/chrome_switches.h"
27 #include "chrome/common/net/net_resource_provider.h"
28 #include "chrome/common/render_messages.h"
29 #include "chrome/common/resource_usage_reporter.mojom.h"
30 #include "chrome/common/resource_usage_reporter_type_converters.h"
31 #include "chrome/common/url_constants.h"
32 #include "chrome/renderer/content_settings_observer.h"
33 #include "chrome/renderer/security_filter_peer.h"
34 #include "components/variations/variations_util.h"
35 #include "content/public/child/resource_dispatcher_delegate.h"
36 #include "content/public/common/service_registry.h"
37 #include "content/public/renderer/render_thread.h"
38 #include "content/public/renderer/render_view.h"
39 #include "content/public/renderer/render_view_visitor.h"
40 #include "crypto/nss_util.h"
41 #include "net/base/net_errors.h"
42 #include "net/base/net_module.h"
43 #include "third_party/WebKit/public/web/WebCache.h"
44 #include "third_party/WebKit/public/web/WebDocument.h"
45 #include "third_party/WebKit/public/web/WebFrame.h"
46 #include "third_party/WebKit/public/web/WebRuntimeFeatures.h"
47 #include "third_party/WebKit/public/web/WebSecurityPolicy.h"
48 #include "third_party/WebKit/public/web/WebView.h"
49 #include "third_party/mojo/src/mojo/public/cpp/bindings/strong_binding.h"
51 #if defined(ENABLE_EXTENSIONS)
52 #include "chrome/renderer/extensions/extension_localization_peer.h"
55 using blink::WebCache
;
56 using blink::WebRuntimeFeatures
;
57 using blink::WebSecurityPolicy
;
58 using blink::WebString
;
59 using content::RenderThread
;
63 const int kCacheStatsDelayMS
= 2000;
65 class RendererResourceDelegate
: public content::ResourceDispatcherDelegate
{
67 RendererResourceDelegate()
68 : weak_factory_(this) {
71 content::RequestPeer
* OnRequestComplete(content::RequestPeer
* current_peer
,
72 content::ResourceType resource_type
,
73 int error_code
) override
{
74 // Update the browser about our cache.
75 // Rate limit informing the host of our cache stats.
76 if (!weak_factory_
.HasWeakPtrs()) {
77 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
79 base::Bind(&RendererResourceDelegate::InformHostOfCacheStats
,
80 weak_factory_
.GetWeakPtr()),
81 base::TimeDelta::FromMilliseconds(kCacheStatsDelayMS
));
84 if (error_code
== net::ERR_ABORTED
) {
88 // Resource canceled with a specific error are filtered.
89 return SecurityFilterPeer::CreateSecurityFilterPeerForDeniedRequest(
90 resource_type
, current_peer
, error_code
);
93 content::RequestPeer
* OnReceivedResponse(content::RequestPeer
* current_peer
,
94 const std::string
& mime_type
,
95 const GURL
& url
) override
{
96 #if defined(ENABLE_EXTENSIONS)
97 return ExtensionLocalizationPeer::CreateExtensionLocalizationPeer(
98 current_peer
, RenderThread::Get(), mime_type
, url
);
105 void InformHostOfCacheStats() {
106 WebCache::UsageStats stats
;
107 WebCache::getUsageStats(&stats
);
108 RenderThread::Get()->Send(new ChromeViewHostMsg_UpdatedCacheStats(stats
));
111 base::WeakPtrFactory
<RendererResourceDelegate
> weak_factory_
;
113 DISALLOW_COPY_AND_ASSIGN(RendererResourceDelegate
);
116 static const int kWaitForWorkersStatsTimeoutMS
= 20;
118 class ResourceUsageReporterImpl
: public ResourceUsageReporter
{
120 ResourceUsageReporterImpl(
121 base::WeakPtr
<ChromeRenderProcessObserver
> observer
,
122 mojo::InterfaceRequest
<ResourceUsageReporter
> req
)
123 : binding_(this, req
.Pass()), observer_(observer
), weak_factory_(this) {}
124 ~ResourceUsageReporterImpl() override
{}
127 static void CollectOnWorkerThread(
128 const scoped_refptr
<base::TaskRunner
>& master
,
129 base::WeakPtr
<ResourceUsageReporterImpl
> impl
) {
130 size_t total_bytes
= 0;
131 size_t used_bytes
= 0;
132 v8::Isolate
* isolate
= v8::Isolate::GetCurrent();
134 v8::HeapStatistics heap_stats
;
135 isolate
->GetHeapStatistics(&heap_stats
);
136 total_bytes
= heap_stats
.total_heap_size();
137 used_bytes
= heap_stats
.used_heap_size();
139 master
->PostTask(FROM_HERE
,
140 base::Bind(&ResourceUsageReporterImpl::ReceiveStats
, impl
,
141 total_bytes
, used_bytes
));
144 void ReceiveStats(size_t total_bytes
, size_t used_bytes
) {
145 usage_data_
->v8_bytes_allocated
+= total_bytes
;
146 usage_data_
->v8_bytes_used
+= used_bytes
;
153 if (!callback_
.is_null())
154 callback_
.Run(usage_data_
.Pass());
156 weak_factory_
.InvalidateWeakPtrs();
161 const mojo::Callback
<void(ResourceUsageDataPtr
)>& callback
) override
{
162 DCHECK(callback_
.is_null());
163 weak_factory_
.InvalidateWeakPtrs();
164 usage_data_
= ResourceUsageData::New();
165 usage_data_
->reports_v8_stats
= true;
166 callback_
= callback
;
168 // Since it is not safe to call any Blink or V8 functions until Blink has
169 // been initialized (which also initializes V8), early out and send 0 back
170 // for all resources.
171 if (!observer_
|| !observer_
->webkit_initialized()) {
176 WebCache::ResourceTypeStats stats
;
177 WebCache::getResourceTypeStats(&stats
);
178 usage_data_
->web_cache_stats
= ResourceTypeStats::From(stats
);
180 v8::Isolate
* isolate
= v8::Isolate::GetCurrent();
182 v8::HeapStatistics heap_stats
;
183 isolate
->GetHeapStatistics(&heap_stats
);
184 usage_data_
->v8_bytes_allocated
= heap_stats
.total_heap_size();
185 usage_data_
->v8_bytes_used
= heap_stats
.used_heap_size();
187 base::Closure collect
= base::Bind(
188 &ResourceUsageReporterImpl::CollectOnWorkerThread
,
189 base::ThreadTaskRunnerHandle::Get(), weak_factory_
.GetWeakPtr());
190 workers_to_go_
= RenderThread::Get()->PostTaskToAllWebWorkers(collect
);
191 if (workers_to_go_
) {
192 // The guard task to send out partial stats
193 // in case some workers are not responsive.
194 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
195 FROM_HERE
, base::Bind(&ResourceUsageReporterImpl::SendResults
,
196 weak_factory_
.GetWeakPtr()),
197 base::TimeDelta::FromMilliseconds(kWaitForWorkersStatsTimeoutMS
));
199 // No worker threads so just send out the main thread data right away.
204 ResourceUsageDataPtr usage_data_
;
205 mojo::Callback
<void(ResourceUsageDataPtr
)> callback_
;
207 mojo::StrongBinding
<ResourceUsageReporter
> binding_
;
208 base::WeakPtr
<ChromeRenderProcessObserver
> observer_
;
210 base::WeakPtrFactory
<ResourceUsageReporterImpl
> weak_factory_
;
213 void CreateResourceUsageReporter(
214 base::WeakPtr
<ChromeRenderProcessObserver
> observer
,
215 mojo::InterfaceRequest
<ResourceUsageReporter
> request
) {
216 new ResourceUsageReporterImpl(observer
, request
.Pass());
221 bool ChromeRenderProcessObserver::is_incognito_process_
= false;
223 ChromeRenderProcessObserver::ChromeRenderProcessObserver()
224 : webkit_initialized_(false), weak_factory_(this) {
225 const base::CommandLine
& command_line
=
226 *base::CommandLine::ForCurrentProcess();
228 #if defined(ENABLE_AUTOFILL_DIALOG)
229 WebRuntimeFeatures::enableRequestAutocomplete(true);
232 if (command_line
.HasSwitch(switches::kDisableJavaScriptHarmonyShipping
)) {
233 std::string
flag("--noharmony-shipping");
234 v8::V8::SetFlagsFromString(flag
.c_str(), static_cast<int>(flag
.size()));
237 if (command_line
.HasSwitch(switches::kJavaScriptHarmony
)) {
238 std::string
flag("--harmony");
239 v8::V8::SetFlagsFromString(flag
.c_str(), static_cast<int>(flag
.size()));
242 RenderThread
* thread
= RenderThread::Get();
243 resource_delegate_
.reset(new RendererResourceDelegate());
244 thread
->SetResourceDispatcherDelegate(resource_delegate_
.get());
246 content::ServiceRegistry
* service_registry
= thread
->GetServiceRegistry();
247 if (service_registry
) {
248 service_registry
->AddService
<ResourceUsageReporter
>(
249 base::Bind(CreateResourceUsageReporter
, weak_factory_
.GetWeakPtr()));
252 // Configure modules that need access to resources.
253 net::NetModule::SetResourceProvider(chrome_common_net::NetResourceProvider
);
255 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(USE_OPENSSL)
256 // On platforms where we use system NSS shared libraries,
257 // initialize NSS now because it won't be able to load the .so's
258 // after we engage the sandbox.
259 if (!command_line
.HasSwitch(switches::kSingleProcess
))
260 crypto::InitNSSSafely();
262 // Setup initial set of crash dump data for Field Trials in this renderer.
263 variations::SetVariationListCrashKeys();
264 // Listen for field trial activations to report them to the browser.
265 base::FieldTrialList::AddObserver(this);
268 ChromeRenderProcessObserver::~ChromeRenderProcessObserver() {
271 bool ChromeRenderProcessObserver::OnControlMessageReceived(
272 const IPC::Message
& message
) {
274 IPC_BEGIN_MESSAGE_MAP(ChromeRenderProcessObserver
, message
)
275 IPC_MESSAGE_HANDLER(ChromeViewMsg_SetIsIncognitoProcess
,
276 OnSetIsIncognitoProcess
)
277 IPC_MESSAGE_HANDLER(ChromeViewMsg_SetFieldTrialGroup
, OnSetFieldTrialGroup
)
278 IPC_MESSAGE_HANDLER(ChromeViewMsg_SetContentSettingRules
,
279 OnSetContentSettingRules
)
280 IPC_MESSAGE_UNHANDLED(handled
= false)
281 IPC_END_MESSAGE_MAP()
285 void ChromeRenderProcessObserver::WebKitInitialized() {
286 webkit_initialized_
= true;
287 // chrome-native: is a scheme used for placeholder navigations that allow
288 // UIs to be drawn with platform native widgets instead of HTML. These pages
289 // should not be accessible, and should also be treated as empty documents
290 // that can commit synchronously. No code should be runnable in these pages,
291 // so it should not need to access anything nor should it allow javascript
292 // URLs since it should never be visible to the user.
293 WebString
native_scheme(base::ASCIIToUTF16(chrome::kChromeNativeScheme
));
294 WebSecurityPolicy::registerURLSchemeAsDisplayIsolated(native_scheme
);
295 WebSecurityPolicy::registerURLSchemeAsEmptyDocument(native_scheme
);
296 WebSecurityPolicy::registerURLSchemeAsNoAccess(native_scheme
);
297 WebSecurityPolicy::registerURLSchemeAsNotAllowingJavascriptURLs(
301 void ChromeRenderProcessObserver::OnRenderProcessShutdown() {
302 webkit_initialized_
= false;
305 void ChromeRenderProcessObserver::OnSetIsIncognitoProcess(
306 bool is_incognito_process
) {
307 is_incognito_process_
= is_incognito_process
;
310 void ChromeRenderProcessObserver::OnSetContentSettingRules(
311 const RendererContentSettingRules
& rules
) {
312 content_setting_rules_
= rules
;
315 void ChromeRenderProcessObserver::OnSetFieldTrialGroup(
316 const std::string
& field_trial_name
,
317 const std::string
& group_name
) {
318 base::FieldTrial
* trial
=
319 base::FieldTrialList::CreateFieldTrial(field_trial_name
, group_name
);
320 // TODO(mef): Remove this check after the investigation of 359406 is complete.
321 CHECK(trial
) << field_trial_name
<< ":" << group_name
;
322 // Ensure the trial is marked as "used" by calling group() on it if it is
323 // marked as activated.
325 variations::SetVariationListCrashKeys();
328 const RendererContentSettingRules
*
329 ChromeRenderProcessObserver::content_setting_rules() const {
330 return &content_setting_rules_
;
333 void ChromeRenderProcessObserver::OnFieldTrialGroupFinalized(
334 const std::string
& trial_name
,
335 const std::string
& group_name
) {
336 content::RenderThread::Get()->Send(
337 new ChromeViewHostMsg_FieldTrialActivated(trial_name
));