Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / chrome / renderer / chrome_render_process_observer.cc
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.
4
5 #include "chrome/renderer/chrome_render_process_observer.h"
6
7 #include <limits>
8 #include <vector>
9
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"
45
46 #if defined(OS_WIN)
47 #include "base/win/iat_patch_function.h"
48 #endif
49
50 #if defined(ENABLE_EXTENSIONS)
51 #include "chrome/renderer/extensions/extension_localization_peer.h"
52 #endif
53
54 using blink::WebCache;
55 using blink::WebRuntimeFeatures;
56 using blink::WebSecurityPolicy;
57 using blink::WebString;
58 using content::RenderThread;
59
60 namespace {
61
62 const int kCacheStatsDelayMS = 2000;
63
64 class RendererResourceDelegate : public content::ResourceDispatcherDelegate {
65  public:
66   RendererResourceDelegate()
67       : weak_factory_(this) {
68   }
69
70   content::RequestPeer* OnRequestComplete(content::RequestPeer* current_peer,
71                                           content::ResourceType resource_type,
72                                           int error_code) override {
73     // Update the browser about our cache.
74     // Rate limit informing the host of our cache stats.
75     if (!weak_factory_.HasWeakPtrs()) {
76       base::MessageLoop::current()->PostDelayedTask(
77           FROM_HERE,
78           base::Bind(&RendererResourceDelegate::InformHostOfCacheStats,
79                      weak_factory_.GetWeakPtr()),
80           base::TimeDelta::FromMilliseconds(kCacheStatsDelayMS));
81     }
82
83     if (error_code == net::ERR_ABORTED) {
84       return NULL;
85     }
86
87     // Resource canceled with a specific error are filtered.
88     return SecurityFilterPeer::CreateSecurityFilterPeerForDeniedRequest(
89         resource_type, current_peer, error_code);
90   }
91
92   content::RequestPeer* OnReceivedResponse(content::RequestPeer* current_peer,
93                                            const std::string& mime_type,
94                                            const GURL& url) override {
95 #if defined(ENABLE_EXTENSIONS)
96     return ExtensionLocalizationPeer::CreateExtensionLocalizationPeer(
97         current_peer, RenderThread::Get(), mime_type, url);
98 #else
99     return NULL;
100 #endif
101   }
102
103  private:
104   void InformHostOfCacheStats() {
105     WebCache::UsageStats stats;
106     WebCache::getUsageStats(&stats);
107     RenderThread::Get()->Send(new ChromeViewHostMsg_UpdatedCacheStats(stats));
108   }
109
110   base::WeakPtrFactory<RendererResourceDelegate> weak_factory_;
111
112   DISALLOW_COPY_AND_ASSIGN(RendererResourceDelegate);
113 };
114
115 #if defined(OS_WIN)
116 static base::win::IATPatchFunction g_iat_patch_createdca;
117 HDC WINAPI CreateDCAPatch(LPCSTR driver_name,
118                           LPCSTR device_name,
119                           LPCSTR output,
120                           const void* init_data) {
121   DCHECK(std::string("DISPLAY") == std::string(driver_name));
122   DCHECK(!device_name);
123   DCHECK(!output);
124   DCHECK(!init_data);
125
126   // CreateDC fails behind the sandbox, but not CreateCompatibleDC.
127   return CreateCompatibleDC(NULL);
128 }
129
130 static base::win::IATPatchFunction g_iat_patch_get_font_data;
131 DWORD WINAPI GetFontDataPatch(HDC hdc,
132                               DWORD table,
133                               DWORD offset,
134                               LPVOID buffer,
135                               DWORD length) {
136   int rv = GetFontData(hdc, table, offset, buffer, length);
137   if (rv == GDI_ERROR && hdc) {
138     HFONT font = static_cast<HFONT>(GetCurrentObject(hdc, OBJ_FONT));
139
140     LOGFONT logfont;
141     if (GetObject(font, sizeof(LOGFONT), &logfont)) {
142       std::vector<char> font_data;
143       RenderThread::Get()->PreCacheFont(logfont);
144       rv = GetFontData(hdc, table, offset, buffer, length);
145       RenderThread::Get()->ReleaseCachedFonts();
146     }
147   }
148   return rv;
149 }
150 #endif  // OS_WIN
151
152 static const int kWaitForWorkersStatsTimeoutMS = 20;
153
154 class HeapStatisticsCollector {
155  public:
156   HeapStatisticsCollector() : round_id_(0) {}
157
158   void InitiateCollection();
159   static HeapStatisticsCollector* Instance();
160
161  private:
162   void CollectOnWorkerThread(scoped_refptr<base::TaskRunner> master,
163                              int round_id);
164   void ReceiveStats(int round_id, size_t total_size, size_t used_size);
165   void SendStatsToBrowser(int round_id);
166
167   size_t total_bytes_;
168   size_t used_bytes_;
169   int workers_to_go_;
170   int round_id_;
171 };
172
173 HeapStatisticsCollector* HeapStatisticsCollector::Instance() {
174   CR_DEFINE_STATIC_LOCAL(HeapStatisticsCollector, instance, ());
175   return &instance;
176 }
177
178 void HeapStatisticsCollector::InitiateCollection() {
179   v8::HeapStatistics heap_stats;
180   v8::Isolate::GetCurrent()->GetHeapStatistics(&heap_stats);
181   total_bytes_ = heap_stats.total_heap_size();
182   used_bytes_ = heap_stats.used_heap_size();
183   base::Closure collect = base::Bind(
184       &HeapStatisticsCollector::CollectOnWorkerThread,
185       base::Unretained(this),
186       base::MessageLoopProxy::current(),
187       round_id_);
188   workers_to_go_ = RenderThread::Get()->PostTaskToAllWebWorkers(collect);
189   if (workers_to_go_) {
190     // The guard task to send out partial stats
191     // in case some workers are not responsive.
192     base::MessageLoopProxy::current()->PostDelayedTask(
193         FROM_HERE,
194         base::Bind(&HeapStatisticsCollector::SendStatsToBrowser,
195                    base::Unretained(this),
196                    round_id_),
197         base::TimeDelta::FromMilliseconds(kWaitForWorkersStatsTimeoutMS));
198   } else {
199     // No worker threads so just send out the main thread data right away.
200     SendStatsToBrowser(round_id_);
201   }
202 }
203
204 void HeapStatisticsCollector::CollectOnWorkerThread(
205     scoped_refptr<base::TaskRunner> master,
206     int round_id) {
207
208   size_t total_bytes = 0;
209   size_t used_bytes = 0;
210   v8::Isolate* isolate = v8::Isolate::GetCurrent();
211   if (isolate) {
212     v8::HeapStatistics heap_stats;
213     isolate->GetHeapStatistics(&heap_stats);
214     total_bytes = heap_stats.total_heap_size();
215     used_bytes = heap_stats.used_heap_size();
216   }
217   master->PostTask(
218       FROM_HERE,
219       base::Bind(&HeapStatisticsCollector::ReceiveStats,
220                  base::Unretained(this),
221                  round_id,
222                  total_bytes,
223                  used_bytes));
224 }
225
226 void HeapStatisticsCollector::ReceiveStats(int round_id,
227                                            size_t total_bytes,
228                                            size_t used_bytes) {
229   if (round_id != round_id_)
230     return;
231   total_bytes_ += total_bytes;
232   used_bytes_ += used_bytes;
233   if (!--workers_to_go_)
234     SendStatsToBrowser(round_id);
235 }
236
237 void HeapStatisticsCollector::SendStatsToBrowser(int round_id) {
238   if (round_id != round_id_)
239     return;
240   // TODO(alph): Do caching heap stats and use the cache if we haven't got
241   //             reply from a worker.
242   //             Currently a busy worker stats are not counted.
243   RenderThread::Get()->Send(new ChromeViewHostMsg_V8HeapStats(
244       total_bytes_, used_bytes_));
245   ++round_id_;
246 }
247
248 }  // namespace
249
250 bool ChromeRenderProcessObserver::is_incognito_process_ = false;
251
252 ChromeRenderProcessObserver::ChromeRenderProcessObserver(
253     ChromeContentRendererClient* client)
254     : client_(client),
255       webkit_initialized_(false) {
256   const CommandLine& command_line = *CommandLine::ForCurrentProcess();
257
258 #if defined(ENABLE_AUTOFILL_DIALOG)
259   WebRuntimeFeatures::enableRequestAutocomplete(true);
260 #endif
261
262   if (command_line.HasSwitch(switches::kEnableShowModalDialog))
263     WebRuntimeFeatures::enableShowModalDialog(true);
264
265   if (command_line.HasSwitch(switches::kJavaScriptHarmony)) {
266     std::string flag("--harmony");
267     v8::V8::SetFlagsFromString(flag.c_str(), static_cast<int>(flag.size()));
268   }
269
270   RenderThread* thread = RenderThread::Get();
271   resource_delegate_.reset(new RendererResourceDelegate());
272   thread->SetResourceDispatcherDelegate(resource_delegate_.get());
273
274   // Configure modules that need access to resources.
275   net::NetModule::SetResourceProvider(chrome_common_net::NetResourceProvider);
276
277 #if defined(OS_WIN)
278   // Need to patch a few functions for font loading to work correctly.
279   base::FilePath pdf;
280   if (PathService::Get(chrome::FILE_PDF_PLUGIN, &pdf) &&
281       base::PathExists(pdf)) {
282     g_iat_patch_createdca.Patch(
283         pdf.value().c_str(), "gdi32.dll", "CreateDCA", CreateDCAPatch);
284     g_iat_patch_get_font_data.Patch(
285         pdf.value().c_str(), "gdi32.dll", "GetFontData", GetFontDataPatch);
286   }
287 #endif
288
289 #if defined(OS_POSIX) && !defined(OS_MACOSX) && defined(USE_NSS)
290   // On platforms where we use system NSS shared libraries,
291   // initialize NSS now because it won't be able to load the .so's
292   // after we engage the sandbox.
293   if (!command_line.HasSwitch(switches::kSingleProcess))
294     crypto::InitNSSSafely();
295 #elif defined(OS_WIN)
296   // crypt32.dll is used to decode X509 certificates for Chromoting.
297   // Only load this library when the feature is enabled.
298   base::LoadNativeLibrary(base::FilePath(L"crypt32.dll"), NULL);
299 #endif
300   // Setup initial set of crash dump data for Field Trials in this renderer.
301   chrome_variations::SetChildProcessLoggingVariationList();
302 }
303
304 ChromeRenderProcessObserver::~ChromeRenderProcessObserver() {
305 }
306
307 bool ChromeRenderProcessObserver::OnControlMessageReceived(
308     const IPC::Message& message) {
309   bool handled = true;
310   IPC_BEGIN_MESSAGE_MAP(ChromeRenderProcessObserver, message)
311     IPC_MESSAGE_HANDLER(ChromeViewMsg_SetIsIncognitoProcess,
312                         OnSetIsIncognitoProcess)
313     IPC_MESSAGE_HANDLER(ChromeViewMsg_SetFieldTrialGroup, OnSetFieldTrialGroup)
314     IPC_MESSAGE_HANDLER(ChromeViewMsg_GetV8HeapStats, OnGetV8HeapStats)
315     IPC_MESSAGE_HANDLER(ChromeViewMsg_GetCacheResourceStats,
316                         OnGetCacheResourceStats)
317     IPC_MESSAGE_HANDLER(ChromeViewMsg_SetContentSettingRules,
318                         OnSetContentSettingRules)
319     IPC_MESSAGE_UNHANDLED(handled = false)
320   IPC_END_MESSAGE_MAP()
321   return handled;
322 }
323
324 void ChromeRenderProcessObserver::WebKitInitialized() {
325   webkit_initialized_ = true;
326   // chrome-native: is a scheme used for placeholder navigations that allow
327   // UIs to be drawn with platform native widgets instead of HTML.  These pages
328   // should not be accessible, and should also be treated as empty documents
329   // that can commit synchronously.  No code should be runnable in these pages,
330   // so it should not need to access anything nor should it allow javascript
331   // URLs since it should never be visible to the user.
332   WebString native_scheme(base::ASCIIToUTF16(chrome::kChromeNativeScheme));
333   WebSecurityPolicy::registerURLSchemeAsDisplayIsolated(native_scheme);
334   WebSecurityPolicy::registerURLSchemeAsEmptyDocument(native_scheme);
335   WebSecurityPolicy::registerURLSchemeAsNoAccess(native_scheme);
336   WebSecurityPolicy::registerURLSchemeAsNotAllowingJavascriptURLs(
337       native_scheme);
338 }
339
340 void ChromeRenderProcessObserver::OnRenderProcessShutdown() {
341   webkit_initialized_ = false;
342 }
343
344 void ChromeRenderProcessObserver::OnSetIsIncognitoProcess(
345     bool is_incognito_process) {
346   is_incognito_process_ = is_incognito_process;
347 }
348
349 void ChromeRenderProcessObserver::OnSetContentSettingRules(
350     const RendererContentSettingRules& rules) {
351   content_setting_rules_ = rules;
352 }
353
354 void ChromeRenderProcessObserver::OnGetCacheResourceStats() {
355   WebCache::ResourceTypeStats stats;
356   if (webkit_initialized_)
357     WebCache::getResourceTypeStats(&stats);
358   RenderThread::Get()->Send(new ChromeViewHostMsg_ResourceTypeStats(stats));
359 }
360
361 void ChromeRenderProcessObserver::OnSetFieldTrialGroup(
362     const std::string& field_trial_name,
363     const std::string& group_name) {
364   base::FieldTrial* trial =
365       base::FieldTrialList::CreateFieldTrial(field_trial_name, group_name);
366   // TODO(mef): Remove this check after the investigation of 359406 is complete.
367   CHECK(trial) << field_trial_name << ":" << group_name;
368   // Ensure the trial is marked as "used" by calling group() on it. This is
369   // needed to ensure the trial is properly reported in renderer crash reports.
370   trial->group();
371   chrome_variations::SetChildProcessLoggingVariationList();
372 }
373
374 void ChromeRenderProcessObserver::OnGetV8HeapStats() {
375   HeapStatisticsCollector::Instance()->InitiateCollection();
376 }
377
378 const RendererContentSettingRules*
379 ChromeRenderProcessObserver::content_setting_rules() const {
380   return &content_setting_rules_;
381 }