[Android] Added UMA for search by image context menu.
[chromium-blink-merge.git] / chrome / renderer / chrome_render_process_observer.cc
blob282607ce0b2b65cda65bd07084641ab2ac0725ba
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/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/chrome_version_info.h"
27 #include "chrome/common/metrics/variations/variations_util.h"
28 #include "chrome/common/net/net_resource_provider.h"
29 #include "chrome/common/render_messages.h"
30 #include "chrome/common/url_constants.h"
31 #include "chrome/renderer/chrome_content_renderer_client.h"
32 #include "chrome/renderer/content_settings_observer.h"
33 #include "chrome/renderer/extensions/extension_localization_peer.h"
34 #include "chrome/renderer/security_filter_peer.h"
35 #include "content/public/child/resource_dispatcher_delegate.h"
36 #include "content/public/renderer/render_thread.h"
37 #include "content/public/renderer/render_view.h"
38 #include "content/public/renderer/render_view_visitor.h"
39 #include "crypto/nss_util.h"
40 #include "media/base/media_switches.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/WebCrossOriginPreflightResultCache.h"
45 #include "third_party/WebKit/public/web/WebDocument.h"
46 #include "third_party/WebKit/public/web/WebFontCache.h"
47 #include "third_party/WebKit/public/web/WebFrame.h"
48 #include "third_party/WebKit/public/web/WebRuntimeFeatures.h"
49 #include "third_party/WebKit/public/web/WebSecurityPolicy.h"
50 #include "third_party/WebKit/public/web/WebView.h"
51 #include "third_party/sqlite/sqlite3.h"
52 #include "v8/include/v8.h"
54 #if defined(OS_WIN)
55 #include "base/win/iat_patch_function.h"
56 #endif
58 using WebKit::WebCache;
59 using WebKit::WebCrossOriginPreflightResultCache;
60 using WebKit::WebFontCache;
61 using WebKit::WebRuntimeFeatures;
62 using WebKit::WebSecurityPolicy;
63 using WebKit::WebString;
64 using content::RenderThread;
66 namespace {
68 static const int kCacheStatsDelayMS = 2000;
70 class RendererResourceDelegate : public content::ResourceDispatcherDelegate {
71 public:
72 RendererResourceDelegate()
73 : weak_factory_(this) {
76 virtual webkit_glue::ResourceLoaderBridge::Peer* OnRequestComplete(
77 webkit_glue::ResourceLoaderBridge::Peer* current_peer,
78 ResourceType::Type resource_type,
79 int error_code) OVERRIDE {
80 // Update the browser about our cache.
81 // Rate limit informing the host of our cache stats.
82 if (!weak_factory_.HasWeakPtrs()) {
83 base::MessageLoop::current()->PostDelayedTask(
84 FROM_HERE,
85 base::Bind(&RendererResourceDelegate::InformHostOfCacheStats,
86 weak_factory_.GetWeakPtr()),
87 base::TimeDelta::FromMilliseconds(kCacheStatsDelayMS));
90 if (error_code == net::ERR_ABORTED) {
91 return NULL;
94 // Resource canceled with a specific error are filtered.
95 return SecurityFilterPeer::CreateSecurityFilterPeerForDeniedRequest(
96 resource_type, current_peer, error_code);
99 virtual webkit_glue::ResourceLoaderBridge::Peer* OnReceivedResponse(
100 webkit_glue::ResourceLoaderBridge::Peer* current_peer,
101 const std::string& mime_type,
102 const GURL& url) OVERRIDE {
103 return ExtensionLocalizationPeer::CreateExtensionLocalizationPeer(
104 current_peer, RenderThread::Get(), mime_type, url);
107 private:
108 void InformHostOfCacheStats() {
109 WebCache::UsageStats stats;
110 WebCache::getUsageStats(&stats);
111 RenderThread::Get()->Send(new ChromeViewHostMsg_UpdatedCacheStats(stats));
114 base::WeakPtrFactory<RendererResourceDelegate> weak_factory_;
116 DISALLOW_COPY_AND_ASSIGN(RendererResourceDelegate);
119 #if defined(OS_WIN)
120 static base::win::IATPatchFunction g_iat_patch_createdca;
121 HDC WINAPI CreateDCAPatch(LPCSTR driver_name,
122 LPCSTR device_name,
123 LPCSTR output,
124 const void* init_data) {
125 DCHECK(std::string("DISPLAY") == std::string(driver_name));
126 DCHECK(!device_name);
127 DCHECK(!output);
128 DCHECK(!init_data);
130 // CreateDC fails behind the sandbox, but not CreateCompatibleDC.
131 return CreateCompatibleDC(NULL);
134 static base::win::IATPatchFunction g_iat_patch_get_font_data;
135 DWORD WINAPI GetFontDataPatch(HDC hdc,
136 DWORD table,
137 DWORD offset,
138 LPVOID buffer,
139 DWORD length) {
140 int rv = GetFontData(hdc, table, offset, buffer, length);
141 if (rv == GDI_ERROR && hdc) {
142 HFONT font = static_cast<HFONT>(GetCurrentObject(hdc, OBJ_FONT));
144 LOGFONT logfont;
145 if (GetObject(font, sizeof(LOGFONT), &logfont)) {
146 std::vector<char> font_data;
147 RenderThread::Get()->PreCacheFont(logfont);
148 rv = GetFontData(hdc, table, offset, buffer, length);
149 RenderThread::Get()->ReleaseCachedFonts();
152 return rv;
154 #endif // OS_WIN
156 static const int kWaitForWorkersStatsTimeoutMS = 20;
158 class HeapStatisticsCollector {
159 public:
160 HeapStatisticsCollector() : round_id_(0) {}
162 void InitiateCollection();
163 static HeapStatisticsCollector* Instance();
165 private:
166 void CollectOnWorkerThread(scoped_refptr<base::TaskRunner> master,
167 int round_id);
168 void ReceiveStats(int round_id, size_t total_size, size_t used_size);
169 void SendStatsToBrowser(int round_id);
171 size_t total_bytes_;
172 size_t used_bytes_;
173 int workers_to_go_;
174 int round_id_;
177 HeapStatisticsCollector* HeapStatisticsCollector::Instance() {
178 CR_DEFINE_STATIC_LOCAL(HeapStatisticsCollector, instance, ());
179 return &instance;
182 void HeapStatisticsCollector::InitiateCollection() {
183 v8::HeapStatistics heap_stats;
184 v8::Isolate::GetCurrent()->GetHeapStatistics(&heap_stats);
185 total_bytes_ = heap_stats.total_heap_size();
186 used_bytes_ = heap_stats.used_heap_size();
187 base::Closure collect = base::Bind(
188 &HeapStatisticsCollector::CollectOnWorkerThread,
189 base::Unretained(this),
190 base::MessageLoopProxy::current(),
191 round_id_);
192 workers_to_go_ = RenderThread::Get()->PostTaskToAllWebWorkers(collect);
193 if (workers_to_go_) {
194 // The guard task to send out partial stats
195 // in case some workers are not responsive.
196 base::MessageLoopProxy::current()->PostDelayedTask(
197 FROM_HERE,
198 base::Bind(&HeapStatisticsCollector::SendStatsToBrowser,
199 base::Unretained(this),
200 round_id_),
201 base::TimeDelta::FromMilliseconds(kWaitForWorkersStatsTimeoutMS));
202 } else {
203 // No worker threads so just send out the main thread data right away.
204 SendStatsToBrowser(round_id_);
208 void HeapStatisticsCollector::CollectOnWorkerThread(
209 scoped_refptr<base::TaskRunner> master,
210 int round_id) {
212 size_t total_bytes = 0;
213 size_t used_bytes = 0;
214 v8::Isolate* isolate = v8::Isolate::GetCurrent();
215 if (isolate) {
216 v8::HeapStatistics heap_stats;
217 isolate->GetHeapStatistics(&heap_stats);
218 total_bytes = heap_stats.total_heap_size();
219 used_bytes = heap_stats.used_heap_size();
221 master->PostTask(
222 FROM_HERE,
223 base::Bind(&HeapStatisticsCollector::ReceiveStats,
224 base::Unretained(this),
225 round_id,
226 total_bytes,
227 used_bytes));
230 void HeapStatisticsCollector::ReceiveStats(int round_id,
231 size_t total_bytes,
232 size_t used_bytes) {
233 if (round_id != round_id_)
234 return;
235 total_bytes_ += total_bytes;
236 used_bytes_ += used_bytes;
237 if (!--workers_to_go_)
238 SendStatsToBrowser(round_id);
241 void HeapStatisticsCollector::SendStatsToBrowser(int round_id) {
242 if (round_id != round_id_)
243 return;
244 // TODO(alph): Do caching heap stats and use the cache if we haven't got
245 // reply from a worker.
246 // Currently a busy worker stats are not counted.
247 RenderThread::Get()->Send(new ChromeViewHostMsg_V8HeapStats(
248 total_bytes_, used_bytes_));
249 ++round_id_;
252 } // namespace
254 bool ChromeRenderProcessObserver::is_incognito_process_ = false;
256 bool ChromeRenderProcessObserver::extension_activity_log_enabled_ = false;
258 ChromeRenderProcessObserver::ChromeRenderProcessObserver(
259 chrome::ChromeContentRendererClient* client)
260 : client_(client),
261 clear_cache_pending_(false) {
262 const CommandLine& command_line = *CommandLine::ForCurrentProcess();
263 if (command_line.HasSwitch(switches::kEnableWatchdog)) {
264 // TODO(JAR): Need to implement renderer IO msgloop watchdog.
267 #if defined(ENABLE_AUTOFILL_DIALOG)
268 #if defined(OS_MACOSX)
269 bool enableAutofill = command_line.HasSwitch(
270 autofill::switches::kEnableInteractiveAutocomplete);
271 #else
272 bool enableAutofill = !command_line.HasSwitch(
273 autofill::switches::kDisableInteractiveAutocomplete);
274 #endif
275 WebRuntimeFeatures::enableRequestAutocomplete(
276 enableAutofill ||
277 command_line.HasSwitch(switches::kEnableExperimentalWebPlatformFeatures));
278 #endif
280 RenderThread* thread = RenderThread::Get();
281 resource_delegate_.reset(new RendererResourceDelegate());
282 thread->SetResourceDispatcherDelegate(resource_delegate_.get());
284 // Configure modules that need access to resources.
285 net::NetModule::SetResourceProvider(chrome_common_net::NetResourceProvider);
287 #if defined(OS_WIN)
288 // Need to patch a few functions for font loading to work correctly.
289 base::FilePath pdf;
290 if (PathService::Get(chrome::FILE_PDF_PLUGIN, &pdf) &&
291 base::PathExists(pdf)) {
292 g_iat_patch_createdca.Patch(
293 pdf.value().c_str(), "gdi32.dll", "CreateDCA", CreateDCAPatch);
294 g_iat_patch_get_font_data.Patch(
295 pdf.value().c_str(), "gdi32.dll", "GetFontData", GetFontDataPatch);
297 #endif
299 #if defined(OS_POSIX) && !defined(OS_MACOSX) && defined(USE_NSS)
300 // On platforms where we use system NSS shared libraries,
301 // initialize NSS now because it won't be able to load the .so's
302 // after we engage the sandbox.
303 if (!command_line.HasSwitch(switches::kSingleProcess))
304 crypto::InitNSSSafely();
305 #elif defined(OS_WIN)
306 // crypt32.dll is used to decode X509 certificates for Chromoting.
307 // Only load this library when the feature is enabled.
308 std::string error;
309 base::LoadNativeLibrary(base::FilePath(L"crypt32.dll"), &error);
310 #endif
311 // Setup initial set of crash dump data for Field Trials in this renderer.
312 chrome_variations::SetChildProcessLoggingVariationList();
315 ChromeRenderProcessObserver::~ChromeRenderProcessObserver() {
318 bool ChromeRenderProcessObserver::OnControlMessageReceived(
319 const IPC::Message& message) {
320 bool handled = true;
321 IPC_BEGIN_MESSAGE_MAP(ChromeRenderProcessObserver, message)
322 IPC_MESSAGE_HANDLER(ChromeViewMsg_SetIsIncognitoProcess,
323 OnSetIsIncognitoProcess)
324 IPC_MESSAGE_HANDLER(ChromeViewMsg_SetExtensionActivityLogEnabled,
325 OnSetExtensionActivityLogEnabled)
326 IPC_MESSAGE_HANDLER(ChromeViewMsg_SetCacheCapacities, OnSetCacheCapacities)
327 IPC_MESSAGE_HANDLER(ChromeViewMsg_ClearCache, OnClearCache)
328 IPC_MESSAGE_HANDLER(ChromeViewMsg_SetFieldTrialGroup, OnSetFieldTrialGroup)
329 IPC_MESSAGE_HANDLER(ChromeViewMsg_GetV8HeapStats, OnGetV8HeapStats)
330 IPC_MESSAGE_HANDLER(ChromeViewMsg_GetCacheResourceStats,
331 OnGetCacheResourceStats)
332 IPC_MESSAGE_HANDLER(ChromeViewMsg_PurgeMemory, OnPurgeMemory)
333 IPC_MESSAGE_HANDLER(ChromeViewMsg_SetContentSettingRules,
334 OnSetContentSettingRules)
335 IPC_MESSAGE_UNHANDLED(handled = false)
336 IPC_END_MESSAGE_MAP()
337 return handled;
340 void ChromeRenderProcessObserver::WebKitInitialized() {
341 // chrome-native: is a scheme used for placeholder navigations that allow
342 // UIs to be drawn with platform native widgets instead of HTML. These pages
343 // should not be accessible, and should also be treated as empty documents
344 // that can commit synchronously. No code should be runnable in these pages,
345 // so it should not need to access anything nor should it allow javascript
346 // URLs since it should never be visible to the user.
347 WebString native_scheme(ASCIIToUTF16(chrome::kChromeNativeScheme));
348 WebSecurityPolicy::registerURLSchemeAsDisplayIsolated(native_scheme);
349 WebSecurityPolicy::registerURLSchemeAsEmptyDocument(native_scheme);
350 WebSecurityPolicy::registerURLSchemeAsNoAccess(native_scheme);
351 WebSecurityPolicy::registerURLSchemeAsNotAllowingJavascriptURLs(
352 native_scheme);
355 void ChromeRenderProcessObserver::OnSetIsIncognitoProcess(
356 bool is_incognito_process) {
357 is_incognito_process_ = is_incognito_process;
360 void ChromeRenderProcessObserver::OnSetExtensionActivityLogEnabled(
361 bool extension_activity_log_enabled) {
362 extension_activity_log_enabled_ = extension_activity_log_enabled;
365 void ChromeRenderProcessObserver::OnSetContentSettingRules(
366 const RendererContentSettingRules& rules) {
367 content_setting_rules_ = rules;
370 void ChromeRenderProcessObserver::OnSetCacheCapacities(size_t min_dead_capacity,
371 size_t max_dead_capacity,
372 size_t capacity) {
373 WebCache::setCapacities(
374 min_dead_capacity, max_dead_capacity, capacity);
377 void ChromeRenderProcessObserver::OnClearCache(bool on_navigation) {
378 if (on_navigation) {
379 clear_cache_pending_ = true;
380 } else {
381 WebCache::clear();
385 void ChromeRenderProcessObserver::OnGetCacheResourceStats() {
386 WebCache::ResourceTypeStats stats;
387 WebCache::getResourceTypeStats(&stats);
388 RenderThread::Get()->Send(new ChromeViewHostMsg_ResourceTypeStats(stats));
391 void ChromeRenderProcessObserver::OnSetFieldTrialGroup(
392 const std::string& field_trial_name,
393 const std::string& group_name) {
394 base::FieldTrial* trial =
395 base::FieldTrialList::CreateFieldTrial(field_trial_name, group_name);
396 // Ensure the trial is marked as "used" by calling group() on it. This is
397 // needed to ensure the trial is properly reported in renderer crash reports.
398 trial->group();
399 chrome_variations::SetChildProcessLoggingVariationList();
402 void ChromeRenderProcessObserver::OnGetV8HeapStats() {
403 HeapStatisticsCollector::Instance()->InitiateCollection();
406 void ChromeRenderProcessObserver::OnPurgeMemory() {
407 RenderThread::Get()->EnsureWebKitInitialized();
409 // Clear the object cache (as much as possible; some live objects cannot be
410 // freed).
411 WebCache::clear();
413 // Clear the font/glyph cache.
414 WebFontCache::clear();
416 // Clear the Cross-Origin Preflight cache.
417 WebCrossOriginPreflightResultCache::clear();
419 // Release all freeable memory from the SQLite process-global page cache (a
420 // low-level object which backs the Connection-specific page caches).
421 while (sqlite3_release_memory(std::numeric_limits<int>::max()) > 0) {
424 v8::V8::LowMemoryNotification();
426 // Tell our allocator to release any free pages it's still holding.
427 base::allocator::ReleaseFreeMemory();
429 if (client_)
430 client_->OnPurgeMemory();
433 void ChromeRenderProcessObserver::ExecutePendingClearCache() {
434 if (clear_cache_pending_) {
435 clear_cache_pending_ = false;
436 WebCache::clear();
440 const RendererContentSettingRules*
441 ChromeRenderProcessObserver::content_setting_rules() const {
442 return &content_setting_rules_;