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/memory/weak_ptr.h"
15 #include "base/message_loop/message_loop.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/strings/utf_string_conversions.h"
22 #include "base/threading/platform_thread.h"
23 #include "chrome/common/child_process_logging.h"
24 #include "chrome/common/chrome_paths.h"
25 #include "chrome/common/chrome_switches.h"
26 #include "chrome/common/net/net_resource_provider.h"
27 #include "chrome/common/render_messages.h"
28 #include "chrome/common/url_constants.h"
29 #include "chrome/common/variations/variations_util.h"
30 #include "chrome/renderer/content_settings_observer.h"
31 #include "chrome/renderer/security_filter_peer.h"
32 #include "content/public/child/resource_dispatcher_delegate.h"
33 #include "content/public/renderer/render_thread.h"
34 #include "content/public/renderer/render_view.h"
35 #include "content/public/renderer/render_view_visitor.h"
36 #include "crypto/nss_util.h"
37 #include "net/base/net_errors.h"
38 #include "net/base/net_module.h"
39 #include "third_party/WebKit/public/web/WebCache.h"
40 #include "third_party/WebKit/public/web/WebDocument.h"
41 #include "third_party/WebKit/public/web/WebFrame.h"
42 #include "third_party/WebKit/public/web/WebRuntimeFeatures.h"
43 #include "third_party/WebKit/public/web/WebSecurityPolicy.h"
44 #include "third_party/WebKit/public/web/WebView.h"
46 #if defined(ENABLE_EXTENSIONS)
47 #include "chrome/renderer/extensions/extension_localization_peer.h"
50 using blink::WebCache
;
51 using blink::WebRuntimeFeatures
;
52 using blink::WebSecurityPolicy
;
53 using blink::WebString
;
54 using content::RenderThread
;
58 const int kCacheStatsDelayMS
= 2000;
60 class RendererResourceDelegate
: public content::ResourceDispatcherDelegate
{
62 RendererResourceDelegate()
63 : weak_factory_(this) {
66 content::RequestPeer
* OnRequestComplete(content::RequestPeer
* current_peer
,
67 content::ResourceType resource_type
,
68 int error_code
) override
{
69 // Update the browser about our cache.
70 // Rate limit informing the host of our cache stats.
71 if (!weak_factory_
.HasWeakPtrs()) {
72 base::MessageLoop::current()->PostDelayedTask(
74 base::Bind(&RendererResourceDelegate::InformHostOfCacheStats
,
75 weak_factory_
.GetWeakPtr()),
76 base::TimeDelta::FromMilliseconds(kCacheStatsDelayMS
));
79 if (error_code
== net::ERR_ABORTED
) {
83 // Resource canceled with a specific error are filtered.
84 return SecurityFilterPeer::CreateSecurityFilterPeerForDeniedRequest(
85 resource_type
, current_peer
, error_code
);
88 content::RequestPeer
* OnReceivedResponse(content::RequestPeer
* current_peer
,
89 const std::string
& mime_type
,
90 const GURL
& url
) override
{
91 #if defined(ENABLE_EXTENSIONS)
92 return ExtensionLocalizationPeer::CreateExtensionLocalizationPeer(
93 current_peer
, RenderThread::Get(), mime_type
, url
);
100 void InformHostOfCacheStats() {
101 WebCache::UsageStats stats
;
102 WebCache::getUsageStats(&stats
);
103 RenderThread::Get()->Send(new ChromeViewHostMsg_UpdatedCacheStats(stats
));
106 base::WeakPtrFactory
<RendererResourceDelegate
> weak_factory_
;
108 DISALLOW_COPY_AND_ASSIGN(RendererResourceDelegate
);
111 static const int kWaitForWorkersStatsTimeoutMS
= 20;
113 class HeapStatisticsCollector
{
115 HeapStatisticsCollector() : round_id_(0) {}
117 void InitiateCollection();
118 static HeapStatisticsCollector
* Instance();
121 void CollectOnWorkerThread(scoped_refptr
<base::TaskRunner
> master
,
123 void ReceiveStats(int round_id
, size_t total_size
, size_t used_size
);
124 void SendStatsToBrowser(int round_id
);
132 HeapStatisticsCollector
* HeapStatisticsCollector::Instance() {
133 CR_DEFINE_STATIC_LOCAL(HeapStatisticsCollector
, instance
, ());
137 void HeapStatisticsCollector::InitiateCollection() {
138 v8::HeapStatistics heap_stats
;
139 v8::Isolate::GetCurrent()->GetHeapStatistics(&heap_stats
);
140 total_bytes_
= heap_stats
.total_heap_size();
141 used_bytes_
= heap_stats
.used_heap_size();
142 base::Closure collect
= base::Bind(
143 &HeapStatisticsCollector::CollectOnWorkerThread
,
144 base::Unretained(this),
145 base::MessageLoopProxy::current(),
147 workers_to_go_
= RenderThread::Get()->PostTaskToAllWebWorkers(collect
);
148 if (workers_to_go_
) {
149 // The guard task to send out partial stats
150 // in case some workers are not responsive.
151 base::MessageLoopProxy::current()->PostDelayedTask(
153 base::Bind(&HeapStatisticsCollector::SendStatsToBrowser
,
154 base::Unretained(this),
156 base::TimeDelta::FromMilliseconds(kWaitForWorkersStatsTimeoutMS
));
158 // No worker threads so just send out the main thread data right away.
159 SendStatsToBrowser(round_id_
);
163 void HeapStatisticsCollector::CollectOnWorkerThread(
164 scoped_refptr
<base::TaskRunner
> master
,
167 size_t total_bytes
= 0;
168 size_t used_bytes
= 0;
169 v8::Isolate
* isolate
= v8::Isolate::GetCurrent();
171 v8::HeapStatistics heap_stats
;
172 isolate
->GetHeapStatistics(&heap_stats
);
173 total_bytes
= heap_stats
.total_heap_size();
174 used_bytes
= heap_stats
.used_heap_size();
178 base::Bind(&HeapStatisticsCollector::ReceiveStats
,
179 base::Unretained(this),
185 void HeapStatisticsCollector::ReceiveStats(int round_id
,
188 if (round_id
!= round_id_
)
190 total_bytes_
+= total_bytes
;
191 used_bytes_
+= used_bytes
;
192 if (!--workers_to_go_
)
193 SendStatsToBrowser(round_id
);
196 void HeapStatisticsCollector::SendStatsToBrowser(int round_id
) {
197 if (round_id
!= round_id_
)
199 // TODO(alph): Do caching heap stats and use the cache if we haven't got
200 // reply from a worker.
201 // Currently a busy worker stats are not counted.
202 RenderThread::Get()->Send(new ChromeViewHostMsg_V8HeapStats(
203 total_bytes_
, used_bytes_
));
209 bool ChromeRenderProcessObserver::is_incognito_process_
= false;
211 ChromeRenderProcessObserver::ChromeRenderProcessObserver()
212 : webkit_initialized_(false) {
213 const base::CommandLine
& command_line
=
214 *base::CommandLine::ForCurrentProcess();
216 #if defined(ENABLE_AUTOFILL_DIALOG)
217 WebRuntimeFeatures::enableRequestAutocomplete(true);
220 if (command_line
.HasSwitch(switches::kDisableJavaScriptHarmonyShipping
)) {
221 std::string
flag("--noharmony-shipping");
222 v8::V8::SetFlagsFromString(flag
.c_str(), static_cast<int>(flag
.size()));
225 if (command_line
.HasSwitch(switches::kJavaScriptHarmony
)) {
226 std::string
flag("--harmony");
227 v8::V8::SetFlagsFromString(flag
.c_str(), static_cast<int>(flag
.size()));
230 RenderThread
* thread
= RenderThread::Get();
231 resource_delegate_
.reset(new RendererResourceDelegate());
232 thread
->SetResourceDispatcherDelegate(resource_delegate_
.get());
234 // Configure modules that need access to resources.
235 net::NetModule::SetResourceProvider(chrome_common_net::NetResourceProvider
);
237 #if defined(OS_POSIX) && !defined(OS_MACOSX) && defined(USE_NSS_CERTS)
238 // On platforms where we use system NSS shared libraries,
239 // initialize NSS now because it won't be able to load the .so's
240 // after we engage the sandbox.
241 if (!command_line
.HasSwitch(switches::kSingleProcess
))
242 crypto::InitNSSSafely();
243 #elif defined(OS_WIN)
244 // crypt32.dll is used to decode X509 certificates for Chromoting.
245 // Only load this library when the feature is enabled.
246 base::LoadNativeLibrary(base::FilePath(L
"crypt32.dll"), NULL
);
248 // Setup initial set of crash dump data for Field Trials in this renderer.
249 chrome_variations::SetChildProcessLoggingVariationList();
250 // Listen for field trial activations to report them to the browser.
251 base::FieldTrialList::AddObserver(this);
254 ChromeRenderProcessObserver::~ChromeRenderProcessObserver() {
257 bool ChromeRenderProcessObserver::OnControlMessageReceived(
258 const IPC::Message
& message
) {
260 IPC_BEGIN_MESSAGE_MAP(ChromeRenderProcessObserver
, message
)
261 IPC_MESSAGE_HANDLER(ChromeViewMsg_SetIsIncognitoProcess
,
262 OnSetIsIncognitoProcess
)
263 IPC_MESSAGE_HANDLER(ChromeViewMsg_SetFieldTrialGroup
, OnSetFieldTrialGroup
)
264 IPC_MESSAGE_HANDLER(ChromeViewMsg_GetV8HeapStats
, OnGetV8HeapStats
)
265 IPC_MESSAGE_HANDLER(ChromeViewMsg_GetCacheResourceStats
,
266 OnGetCacheResourceStats
)
267 IPC_MESSAGE_HANDLER(ChromeViewMsg_SetContentSettingRules
,
268 OnSetContentSettingRules
)
269 IPC_MESSAGE_UNHANDLED(handled
= false)
270 IPC_END_MESSAGE_MAP()
274 void ChromeRenderProcessObserver::WebKitInitialized() {
275 webkit_initialized_
= true;
276 // chrome-native: is a scheme used for placeholder navigations that allow
277 // UIs to be drawn with platform native widgets instead of HTML. These pages
278 // should not be accessible, and should also be treated as empty documents
279 // that can commit synchronously. No code should be runnable in these pages,
280 // so it should not need to access anything nor should it allow javascript
281 // URLs since it should never be visible to the user.
282 WebString
native_scheme(base::ASCIIToUTF16(chrome::kChromeNativeScheme
));
283 WebSecurityPolicy::registerURLSchemeAsDisplayIsolated(native_scheme
);
284 WebSecurityPolicy::registerURLSchemeAsEmptyDocument(native_scheme
);
285 WebSecurityPolicy::registerURLSchemeAsNoAccess(native_scheme
);
286 WebSecurityPolicy::registerURLSchemeAsNotAllowingJavascriptURLs(
290 void ChromeRenderProcessObserver::OnRenderProcessShutdown() {
291 webkit_initialized_
= false;
294 void ChromeRenderProcessObserver::OnSetIsIncognitoProcess(
295 bool is_incognito_process
) {
296 is_incognito_process_
= is_incognito_process
;
299 void ChromeRenderProcessObserver::OnSetContentSettingRules(
300 const RendererContentSettingRules
& rules
) {
301 content_setting_rules_
= rules
;
304 void ChromeRenderProcessObserver::OnGetCacheResourceStats() {
305 WebCache::ResourceTypeStats stats
;
306 if (webkit_initialized_
)
307 WebCache::getResourceTypeStats(&stats
);
308 RenderThread::Get()->Send(new ChromeViewHostMsg_ResourceTypeStats(stats
));
311 void ChromeRenderProcessObserver::OnSetFieldTrialGroup(
312 const std::string
& field_trial_name
,
313 const std::string
& group_name
) {
314 base::FieldTrial
* trial
=
315 base::FieldTrialList::CreateFieldTrial(field_trial_name
, group_name
);
316 // TODO(mef): Remove this check after the investigation of 359406 is complete.
317 CHECK(trial
) << field_trial_name
<< ":" << group_name
;
318 // Ensure the trial is marked as "used" by calling group() on it if it is
319 // marked as activated.
321 chrome_variations::SetChildProcessLoggingVariationList();
324 void ChromeRenderProcessObserver::OnGetV8HeapStats() {
325 HeapStatisticsCollector::Instance()->InitiateCollection();
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
));