Files.app: Start to use DeviceEventRouter.
[chromium-blink-merge.git] / chrome / renderer / chrome_render_process_observer.cc
blobed483c95978115585d1a19b512cfdaaffd6aae78
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"
7 #include <limits>
8 #include <vector>
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/extensions/extension_localization_peer.h"
32 #include "chrome/renderer/security_filter_peer.h"
33 #include "content/public/child/resource_dispatcher_delegate.h"
34 #include "content/public/renderer/render_thread.h"
35 #include "content/public/renderer/render_view.h"
36 #include "content/public/renderer/render_view_visitor.h"
37 #include "crypto/nss_util.h"
38 #include "net/base/net_errors.h"
39 #include "net/base/net_module.h"
40 #include "third_party/WebKit/public/web/WebCache.h"
41 #include "third_party/WebKit/public/web/WebDocument.h"
42 #include "third_party/WebKit/public/web/WebFrame.h"
43 #include "third_party/WebKit/public/web/WebRuntimeFeatures.h"
44 #include "third_party/WebKit/public/web/WebSecurityPolicy.h"
45 #include "third_party/WebKit/public/web/WebView.h"
47 #if defined(OS_WIN)
48 #include "base/win/iat_patch_function.h"
49 #endif
51 using blink::WebCache;
52 using blink::WebRuntimeFeatures;
53 using blink::WebSecurityPolicy;
54 using blink::WebString;
55 using content::RenderThread;
57 namespace {
59 const int kCacheStatsDelayMS = 2000;
60 const size_t kUnitializedCacheCapacity = UINT_MAX;
62 class RendererResourceDelegate : public content::ResourceDispatcherDelegate {
63 public:
64 RendererResourceDelegate()
65 : weak_factory_(this) {
68 virtual content::RequestPeer* OnRequestComplete(
69 content::RequestPeer* current_peer,
70 content::ResourceType resource_type,
71 int error_code) OVERRIDE {
72 // Update the browser about our cache.
73 // Rate limit informing the host of our cache stats.
74 if (!weak_factory_.HasWeakPtrs()) {
75 base::MessageLoop::current()->PostDelayedTask(
76 FROM_HERE,
77 base::Bind(&RendererResourceDelegate::InformHostOfCacheStats,
78 weak_factory_.GetWeakPtr()),
79 base::TimeDelta::FromMilliseconds(kCacheStatsDelayMS));
82 if (error_code == net::ERR_ABORTED) {
83 return NULL;
86 // Resource canceled with a specific error are filtered.
87 return SecurityFilterPeer::CreateSecurityFilterPeerForDeniedRequest(
88 resource_type, current_peer, error_code);
91 virtual content::RequestPeer* OnReceivedResponse(
92 content::RequestPeer* current_peer,
93 const std::string& mime_type,
94 const GURL& url) OVERRIDE {
95 return ExtensionLocalizationPeer::CreateExtensionLocalizationPeer(
96 current_peer, RenderThread::Get(), mime_type, url);
99 private:
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 #if defined(OS_WIN)
112 static base::win::IATPatchFunction g_iat_patch_createdca;
113 HDC WINAPI CreateDCAPatch(LPCSTR driver_name,
114 LPCSTR device_name,
115 LPCSTR output,
116 const void* init_data) {
117 DCHECK(std::string("DISPLAY") == std::string(driver_name));
118 DCHECK(!device_name);
119 DCHECK(!output);
120 DCHECK(!init_data);
122 // CreateDC fails behind the sandbox, but not CreateCompatibleDC.
123 return CreateCompatibleDC(NULL);
126 static base::win::IATPatchFunction g_iat_patch_get_font_data;
127 DWORD WINAPI GetFontDataPatch(HDC hdc,
128 DWORD table,
129 DWORD offset,
130 LPVOID buffer,
131 DWORD length) {
132 int rv = GetFontData(hdc, table, offset, buffer, length);
133 if (rv == GDI_ERROR && hdc) {
134 HFONT font = static_cast<HFONT>(GetCurrentObject(hdc, OBJ_FONT));
136 LOGFONT logfont;
137 if (GetObject(font, sizeof(LOGFONT), &logfont)) {
138 std::vector<char> font_data;
139 RenderThread::Get()->PreCacheFont(logfont);
140 rv = GetFontData(hdc, table, offset, buffer, length);
141 RenderThread::Get()->ReleaseCachedFonts();
144 return rv;
146 #endif // OS_WIN
148 static const int kWaitForWorkersStatsTimeoutMS = 20;
150 class HeapStatisticsCollector {
151 public:
152 HeapStatisticsCollector() : round_id_(0) {}
154 void InitiateCollection();
155 static HeapStatisticsCollector* Instance();
157 private:
158 void CollectOnWorkerThread(scoped_refptr<base::TaskRunner> master,
159 int round_id);
160 void ReceiveStats(int round_id, size_t total_size, size_t used_size);
161 void SendStatsToBrowser(int round_id);
163 size_t total_bytes_;
164 size_t used_bytes_;
165 int workers_to_go_;
166 int round_id_;
169 HeapStatisticsCollector* HeapStatisticsCollector::Instance() {
170 CR_DEFINE_STATIC_LOCAL(HeapStatisticsCollector, instance, ());
171 return &instance;
174 void HeapStatisticsCollector::InitiateCollection() {
175 v8::HeapStatistics heap_stats;
176 v8::Isolate::GetCurrent()->GetHeapStatistics(&heap_stats);
177 total_bytes_ = heap_stats.total_heap_size();
178 used_bytes_ = heap_stats.used_heap_size();
179 base::Closure collect = base::Bind(
180 &HeapStatisticsCollector::CollectOnWorkerThread,
181 base::Unretained(this),
182 base::MessageLoopProxy::current(),
183 round_id_);
184 workers_to_go_ = RenderThread::Get()->PostTaskToAllWebWorkers(collect);
185 if (workers_to_go_) {
186 // The guard task to send out partial stats
187 // in case some workers are not responsive.
188 base::MessageLoopProxy::current()->PostDelayedTask(
189 FROM_HERE,
190 base::Bind(&HeapStatisticsCollector::SendStatsToBrowser,
191 base::Unretained(this),
192 round_id_),
193 base::TimeDelta::FromMilliseconds(kWaitForWorkersStatsTimeoutMS));
194 } else {
195 // No worker threads so just send out the main thread data right away.
196 SendStatsToBrowser(round_id_);
200 void HeapStatisticsCollector::CollectOnWorkerThread(
201 scoped_refptr<base::TaskRunner> master,
202 int round_id) {
204 size_t total_bytes = 0;
205 size_t used_bytes = 0;
206 v8::Isolate* isolate = v8::Isolate::GetCurrent();
207 if (isolate) {
208 v8::HeapStatistics heap_stats;
209 isolate->GetHeapStatistics(&heap_stats);
210 total_bytes = heap_stats.total_heap_size();
211 used_bytes = heap_stats.used_heap_size();
213 master->PostTask(
214 FROM_HERE,
215 base::Bind(&HeapStatisticsCollector::ReceiveStats,
216 base::Unretained(this),
217 round_id,
218 total_bytes,
219 used_bytes));
222 void HeapStatisticsCollector::ReceiveStats(int round_id,
223 size_t total_bytes,
224 size_t used_bytes) {
225 if (round_id != round_id_)
226 return;
227 total_bytes_ += total_bytes;
228 used_bytes_ += used_bytes;
229 if (!--workers_to_go_)
230 SendStatsToBrowser(round_id);
233 void HeapStatisticsCollector::SendStatsToBrowser(int round_id) {
234 if (round_id != round_id_)
235 return;
236 // TODO(alph): Do caching heap stats and use the cache if we haven't got
237 // reply from a worker.
238 // Currently a busy worker stats are not counted.
239 RenderThread::Get()->Send(new ChromeViewHostMsg_V8HeapStats(
240 total_bytes_, used_bytes_));
241 ++round_id_;
244 } // namespace
246 bool ChromeRenderProcessObserver::is_incognito_process_ = false;
248 ChromeRenderProcessObserver::ChromeRenderProcessObserver(
249 ChromeContentRendererClient* client)
250 : client_(client),
251 clear_cache_pending_(false),
252 webkit_initialized_(false),
253 pending_cache_min_dead_capacity_(0),
254 pending_cache_max_dead_capacity_(0),
255 pending_cache_capacity_(kUnitializedCacheCapacity) {
256 const CommandLine& command_line = *CommandLine::ForCurrentProcess();
258 #if defined(ENABLE_AUTOFILL_DIALOG)
259 WebRuntimeFeatures::enableRequestAutocomplete(true);
260 #endif
262 if (command_line.HasSwitch(switches::kEnableShowModalDialog))
263 WebRuntimeFeatures::enableShowModalDialog(true);
265 RenderThread* thread = RenderThread::Get();
266 resource_delegate_.reset(new RendererResourceDelegate());
267 thread->SetResourceDispatcherDelegate(resource_delegate_.get());
269 // Configure modules that need access to resources.
270 net::NetModule::SetResourceProvider(chrome_common_net::NetResourceProvider);
272 #if defined(OS_WIN)
273 // Need to patch a few functions for font loading to work correctly.
274 base::FilePath pdf;
275 if (PathService::Get(chrome::FILE_PDF_PLUGIN, &pdf) &&
276 base::PathExists(pdf)) {
277 g_iat_patch_createdca.Patch(
278 pdf.value().c_str(), "gdi32.dll", "CreateDCA", CreateDCAPatch);
279 g_iat_patch_get_font_data.Patch(
280 pdf.value().c_str(), "gdi32.dll", "GetFontData", GetFontDataPatch);
282 #endif
284 #if defined(OS_POSIX) && !defined(OS_MACOSX) && defined(USE_NSS)
285 // On platforms where we use system NSS shared libraries,
286 // initialize NSS now because it won't be able to load the .so's
287 // after we engage the sandbox.
288 if (!command_line.HasSwitch(switches::kSingleProcess))
289 crypto::InitNSSSafely();
290 #elif defined(OS_WIN)
291 // crypt32.dll is used to decode X509 certificates for Chromoting.
292 // Only load this library when the feature is enabled.
293 base::LoadNativeLibrary(base::FilePath(L"crypt32.dll"), NULL);
294 #endif
295 // Setup initial set of crash dump data for Field Trials in this renderer.
296 chrome_variations::SetChildProcessLoggingVariationList();
299 ChromeRenderProcessObserver::~ChromeRenderProcessObserver() {
302 bool ChromeRenderProcessObserver::OnControlMessageReceived(
303 const IPC::Message& message) {
304 bool handled = true;
305 IPC_BEGIN_MESSAGE_MAP(ChromeRenderProcessObserver, message)
306 IPC_MESSAGE_HANDLER(ChromeViewMsg_SetIsIncognitoProcess,
307 OnSetIsIncognitoProcess)
308 IPC_MESSAGE_HANDLER(ChromeViewMsg_SetCacheCapacities, OnSetCacheCapacities)
309 IPC_MESSAGE_HANDLER(ChromeViewMsg_ClearCache, OnClearCache)
310 IPC_MESSAGE_HANDLER(ChromeViewMsg_SetFieldTrialGroup, OnSetFieldTrialGroup)
311 IPC_MESSAGE_HANDLER(ChromeViewMsg_GetV8HeapStats, OnGetV8HeapStats)
312 IPC_MESSAGE_HANDLER(ChromeViewMsg_GetCacheResourceStats,
313 OnGetCacheResourceStats)
314 IPC_MESSAGE_HANDLER(ChromeViewMsg_SetContentSettingRules,
315 OnSetContentSettingRules)
316 IPC_MESSAGE_UNHANDLED(handled = false)
317 IPC_END_MESSAGE_MAP()
318 return handled;
321 void ChromeRenderProcessObserver::WebKitInitialized() {
322 webkit_initialized_ = true;
323 if (pending_cache_capacity_ != kUnitializedCacheCapacity) {
324 WebCache::setCapacities(pending_cache_min_dead_capacity_,
325 pending_cache_max_dead_capacity_,
326 pending_cache_capacity_);
329 // chrome-native: is a scheme used for placeholder navigations that allow
330 // UIs to be drawn with platform native widgets instead of HTML. These pages
331 // should not be accessible, and should also be treated as empty documents
332 // that can commit synchronously. No code should be runnable in these pages,
333 // so it should not need to access anything nor should it allow javascript
334 // URLs since it should never be visible to the user.
335 WebString native_scheme(base::ASCIIToUTF16(chrome::kChromeNativeScheme));
336 WebSecurityPolicy::registerURLSchemeAsDisplayIsolated(native_scheme);
337 WebSecurityPolicy::registerURLSchemeAsEmptyDocument(native_scheme);
338 WebSecurityPolicy::registerURLSchemeAsNoAccess(native_scheme);
339 WebSecurityPolicy::registerURLSchemeAsNotAllowingJavascriptURLs(
340 native_scheme);
343 void ChromeRenderProcessObserver::OnRenderProcessShutdown() {
344 webkit_initialized_ = false;
347 void ChromeRenderProcessObserver::OnSetIsIncognitoProcess(
348 bool is_incognito_process) {
349 is_incognito_process_ = is_incognito_process;
352 void ChromeRenderProcessObserver::OnSetContentSettingRules(
353 const RendererContentSettingRules& rules) {
354 content_setting_rules_ = rules;
357 void ChromeRenderProcessObserver::OnSetCacheCapacities(size_t min_dead_capacity,
358 size_t max_dead_capacity,
359 size_t capacity) {
360 if (!webkit_initialized_) {
361 pending_cache_min_dead_capacity_ = min_dead_capacity;
362 pending_cache_max_dead_capacity_ = max_dead_capacity;
363 pending_cache_capacity_ = capacity;
364 return;
367 WebCache::setCapacities(
368 min_dead_capacity, max_dead_capacity, capacity);
371 void ChromeRenderProcessObserver::OnClearCache(bool on_navigation) {
372 if (on_navigation || !webkit_initialized_) {
373 clear_cache_pending_ = true;
374 } else {
375 WebCache::clear();
379 void ChromeRenderProcessObserver::OnGetCacheResourceStats() {
380 WebCache::ResourceTypeStats stats;
381 if (webkit_initialized_)
382 WebCache::getResourceTypeStats(&stats);
383 RenderThread::Get()->Send(new ChromeViewHostMsg_ResourceTypeStats(stats));
386 void ChromeRenderProcessObserver::OnSetFieldTrialGroup(
387 const std::string& field_trial_name,
388 const std::string& group_name) {
389 base::FieldTrial* trial =
390 base::FieldTrialList::CreateFieldTrial(field_trial_name, group_name);
391 // TODO(mef): Remove this check after the investigation of 359406 is complete.
392 CHECK(trial) << field_trial_name << ":" << group_name;
393 // Ensure the trial is marked as "used" by calling group() on it. This is
394 // needed to ensure the trial is properly reported in renderer crash reports.
395 trial->group();
396 chrome_variations::SetChildProcessLoggingVariationList();
399 void ChromeRenderProcessObserver::OnGetV8HeapStats() {
400 HeapStatisticsCollector::Instance()->InitiateCollection();
403 void ChromeRenderProcessObserver::ExecutePendingClearCache() {
404 if (clear_cache_pending_ && webkit_initialized_) {
405 clear_cache_pending_ = false;
406 WebCache::clear();
410 const RendererContentSettingRules*
411 ChromeRenderProcessObserver::content_setting_rules() const {
412 return &content_setting_rules_;