blob: 9d621da2632fb1125118e552978285e3c9eaf1ce [file] [log] [blame]
[email protected]2ac1e7c2010-03-02 20:50:561// Copyright (c) 2010 The Chromium Authors. All rights reserved.
license.botbf09a502008-08-24 00:55:552// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
initial.commit09911bf2008-07-26 23:55:294
[email protected]037fce02009-01-22 01:42:155#include "build/build_config.h"
6
[email protected]396c3a462010-03-03 05:03:227#include "chrome/renderer/render_process_impl.h"
8
[email protected]037fce02009-01-22 01:42:159#if defined(OS_WIN)
initial.commit09911bf2008-07-26 23:55:2910#include <windows.h>
11#include <objidl.h>
12#include <mlang.h>
[email protected]037fce02009-01-22 01:42:1513#endif
initial.commit09911bf2008-07-26 23:55:2914
initial.commit09911bf2008-07-26 23:55:2915#include "base/basictypes.h"
16#include "base/command_line.h"
[email protected]037fce02009-01-22 01:42:1517#include "base/compiler_specific.h"
[email protected]955ee6d62009-06-17 21:53:0318#include "base/file_util.h"
initial.commit09911bf2008-07-26 23:55:2919#include "base/message_loop.h"
20#include "base/histogram.h"
[email protected]8ee8189e2008-10-08 19:35:2121#include "base/path_service.h"
[email protected]037fce02009-01-22 01:42:1522#include "base/sys_info.h"
[email protected]f09c7182009-03-10 12:54:0423// TODO(jar): DNS calls should be renderer specific, not including browser.
24#include "chrome/browser/net/dns_global.h"
initial.commit09911bf2008-07-26 23:55:2925#include "chrome/common/chrome_switches.h"
[email protected]8ee8189e2008-10-08 19:35:2126#include "chrome/common/chrome_paths.h"
initial.commit09911bf2008-07-26 23:55:2927#include "chrome/common/render_messages.h"
[email protected]d032f492009-09-29 00:33:4628#include "chrome/common/nacl_types.h"
[email protected]e68e62fa2009-02-20 02:00:0429#include "chrome/common/transport_dib.h"
initial.commit09911bf2008-07-26 23:55:2930#include "chrome/renderer/render_view.h"
[email protected]946d1b22009-07-22 23:57:2131#include "ipc/ipc_channel.h"
32#include "ipc/ipc_message_utils.h"
[email protected]10000d62009-04-18 00:36:2233#include "media/base/media.h"
[email protected]d032f492009-09-29 00:33:4634#include "native_client/src/trusted/plugin/nacl_entry_points.h"
initial.commit09911bf2008-07-26 23:55:2935#include "webkit/glue/webkit_glue.h"
36
[email protected]0c3a16b2009-10-08 23:17:1437#if defined(OS_MACOSX)
38#include "base/mac_util.h"
39#endif
40
[email protected]396c3a462010-03-03 05:03:2241namespace {
initial.commit09911bf2008-07-26 23:55:2942
[email protected]396c3a462010-03-03 05:03:2243bool LaunchNaClProcess(const char* url,
44 int imc_fd,
45 nacl::Handle* imc_handle,
46 nacl::Handle* nacl_process_handle,
47 int* nacl_process_id) {
[email protected]d032f492009-09-29 00:33:4648 // TODO(gregoryd): nacl::FileDescriptor will be soon merged with
49 // base::FileDescriptor
[email protected]f08e47d2009-10-15 21:46:1550 nacl::FileDescriptor imc_descriptor;
[email protected]2461cf0a2009-10-22 17:42:3251 base::ProcessHandle nacl_process;
[email protected]d032f492009-09-29 00:33:4652 if (!RenderThread::current()->Send(
[email protected]f08e47d2009-10-15 21:46:1553 new ViewHostMsg_LaunchNaCl(ASCIIToWide(url),
[email protected]2461cf0a2009-10-22 17:42:3254 imc_fd,
55 &imc_descriptor,
56 &nacl_process,
57 reinterpret_cast<base::ProcessId*>(nacl_process_id)))) {
[email protected]d032f492009-09-29 00:33:4658 return false;
59 }
[email protected]103607e2010-02-01 18:57:0960 *imc_handle = nacl::ToNativeHandle(imc_descriptor);
[email protected]2461cf0a2009-10-22 17:42:3261 *nacl_process_handle = nacl_process;
[email protected]d032f492009-09-29 00:33:4662 return true;
63}
64
[email protected]396c3a462010-03-03 05:03:2265} // namespace
[email protected]e68e62fa2009-02-20 02:00:0466
[email protected]396c3a462010-03-03 05:03:2267//-----------------------------------------------------------------------------
[email protected]e68e62fa2009-02-20 02:00:0468
[email protected]396c3a462010-03-03 05:03:2269RenderProcessImpl::RenderProcessImpl()
70 : RenderProcess(),
71 ALLOW_THIS_IN_INITIALIZER_LIST(shared_mem_cache_cleaner_(
72 base::TimeDelta::FromSeconds(5),
73 this, &RenderProcessImpl::ClearTransportDIBCache)),
74 transport_dib_next_sequence_number_(0) {
75 in_process_plugins_ = InProcessPlugins();
76 for (size_t i = 0; i < arraysize(shared_mem_cache_); ++i)
77 shared_mem_cache_[i] = NULL;
[email protected]e68e62fa2009-02-20 02:00:0478
[email protected]396c3a462010-03-03 05:03:2279#if defined(OS_WIN)
80 // HACK: See http://b/issue?id=1024307 for rationale.
81 if (GetModuleHandle(L"LPK.DLL") == NULL) {
82 // Makes sure lpk.dll is loaded by gdi32 to make sure ExtTextOut() works
83 // when buffering into a EMF buffer for printing.
84 typedef BOOL (__stdcall *GdiInitializeLanguagePack)(int LoadedShapingDLLs);
85 GdiInitializeLanguagePack gdi_init_lpk =
86 reinterpret_cast<GdiInitializeLanguagePack>(GetProcAddress(
87 GetModuleHandle(L"GDI32.DLL"),
88 "GdiInitializeLanguagePack"));
89 DCHECK(gdi_init_lpk);
90 if (gdi_init_lpk)
91 gdi_init_lpk(0);
92 }
[email protected]e68e62fa2009-02-20 02:00:0493#endif
94
[email protected]396c3a462010-03-03 05:03:2295 // Out of process dev tools rely upon auto break behavior.
96 webkit_glue::SetJavaScriptFlags(
97 L"--debugger-auto-break"
98 // Enable lazy in-memory profiling.
99 L" --prof --prof-lazy --logfile=* --compress-log");
100
101 const CommandLine& command_line = *CommandLine::ForCurrentProcess();
102 if (command_line.HasSwitch(switches::kJavaScriptFlags)) {
103 webkit_glue::SetJavaScriptFlags(
104 command_line.GetSwitchValue(switches::kJavaScriptFlags));
105 }
106
107 if (command_line.HasSwitch(switches::kEnableWatchdog)) {
108 // TODO(JAR): Need to implement renderer IO msgloop watchdog.
109 }
110
111 if (command_line.HasSwitch(switches::kDumpHistogramsOnExit)) {
112 StatisticsRecorder::set_dump_on_exit(true);
113 }
114
115#ifndef DISABLE_NACL
116 if (command_line.HasSwitch(switches::kInternalNaCl))
117 RegisterInternalNaClPlugin(LaunchNaClProcess);
118#endif
119
120 if (!command_line.HasSwitch(switches::kDisableByteRangeSupport))
121 webkit_glue::SetMediaCacheEnabled(true);
122
123#if defined(OS_MACOSX)
124 FilePath bundle_path = mac_util::MainAppBundlePath();
125
126 initialized_media_library_ =
127 media::InitializeMediaLibrary(bundle_path.Append("Libraries"));
128#else
129 FilePath module_path;
130 initialized_media_library_ =
131 PathService::Get(base::DIR_MODULE, &module_path) &&
132 media::InitializeMediaLibrary(module_path);
133#endif
[email protected]e68e62fa2009-02-20 02:00:04134}
135
[email protected]396c3a462010-03-03 05:03:22136RenderProcessImpl::~RenderProcessImpl() {
137 // TODO(port): Try and limit what we pull in for our non-Win unit test bundle.
138#ifndef NDEBUG
139 // log important leaked objects
140 webkit_glue::CheckForLeaks();
141#endif
[email protected]e68e62fa2009-02-20 02:00:04142
[email protected]396c3a462010-03-03 05:03:22143 GetShutDownEvent()->Signal();
144 ClearTransportDIBCache();
145}
[email protected]e68e62fa2009-02-20 02:00:04146
[email protected]396c3a462010-03-03 05:03:22147skia::PlatformCanvas* RenderProcessImpl::GetDrawingCanvas(
148 TransportDIB** memory,
149 const gfx::Rect& rect) {
[email protected]955ee6d62009-06-17 21:53:03150 int width = rect.width();
151 int height = rect.height();
[email protected]e68e62fa2009-02-20 02:00:04152 const size_t stride = skia::PlatformCanvas::StrideForWidth(rect.width());
[email protected]bae93ec2009-08-04 17:59:20153#if defined(OS_LINUX)
[email protected]80a086c52009-08-04 17:52:04154 const size_t max_size = base::SysInfo::MaxSharedMemorySize();
[email protected]bae93ec2009-08-04 17:59:20155#else
156 const size_t max_size = 0;
157#endif
[email protected]955ee6d62009-06-17 21:53:03158
159 // If the requested size is too big, reduce the height. Ideally we might like
160 // to reduce the width as well to make the size reduction more "balanced", but
161 // it rarely comes up in practice.
162 if ((max_size != 0) && (height * stride > max_size))
163 height = max_size / stride;
164
165 const size_t size = height * stride;
initial.commit09911bf2008-07-26 23:55:29166
[email protected]8930d472009-02-21 08:05:28167 if (!GetTransportDIBFromCache(memory, size)) {
168 *memory = CreateTransportDIB(size);
[email protected]e68e62fa2009-02-20 02:00:04169 if (!*memory)
[email protected]396c3a462010-03-03 05:03:22170 return NULL;
initial.commit09911bf2008-07-26 23:55:29171 }
172
[email protected]955ee6d62009-06-17 21:53:03173 return (*memory)->GetPlatformCanvas(width, height);
initial.commit09911bf2008-07-26 23:55:29174}
175
[email protected]396c3a462010-03-03 05:03:22176void RenderProcessImpl::ReleaseTransportDIB(TransportDIB* mem) {
[email protected]8930d472009-02-21 08:05:28177 if (PutSharedMemInCache(mem)) {
178 shared_mem_cache_cleaner_.Reset();
initial.commit09911bf2008-07-26 23:55:29179 return;
180 }
[email protected]e68e62fa2009-02-20 02:00:04181
[email protected]8930d472009-02-21 08:05:28182 FreeTransportDIB(mem);
initial.commit09911bf2008-07-26 23:55:29183}
184
[email protected]396c3a462010-03-03 05:03:22185bool RenderProcessImpl::UseInProcessPlugins() const {
186 return in_process_plugins_;
187}
188
189bool RenderProcessImpl::HasInitializedMediaLibrary() const {
190 return initialized_media_library_;
191}
192
193// static
194bool RenderProcessImpl::InProcessPlugins() {
195 const CommandLine& command_line = *CommandLine::ForCurrentProcess();
196#if defined(OS_LINUX)
197 // Plugin processes require a UI message loop, and the Linux message loop
198 // implementation only allows one UI loop per process.
199 if (command_line.HasSwitch(switches::kInProcessPlugins))
200 NOTIMPLEMENTED() << ": in process plugins not supported on Linux";
201 return command_line.HasSwitch(switches::kInProcessPlugins);
202#else
203 return command_line.HasSwitch(switches::kInProcessPlugins) ||
204 command_line.HasSwitch(switches::kSingleProcess);
205#endif
206}
207
208bool RenderProcessImpl::GetTransportDIBFromCache(TransportDIB** mem,
209 size_t size) {
initial.commit09911bf2008-07-26 23:55:29210 // look for a cached object that is suitable for the requested size.
[email protected]037fce02009-01-22 01:42:15211 for (size_t i = 0; i < arraysize(shared_mem_cache_); ++i) {
[email protected]e68e62fa2009-02-20 02:00:04212 if (shared_mem_cache_[i] &&
213 size <= shared_mem_cache_[i]->size()) {
214 *mem = shared_mem_cache_[i];
initial.commit09911bf2008-07-26 23:55:29215 shared_mem_cache_[i] = NULL;
[email protected]e68e62fa2009-02-20 02:00:04216 return true;
initial.commit09911bf2008-07-26 23:55:29217 }
218 }
initial.commit09911bf2008-07-26 23:55:29219
initial.commit09911bf2008-07-26 23:55:29220 return false;
221}
222
[email protected]396c3a462010-03-03 05:03:22223bool RenderProcessImpl::PutSharedMemInCache(TransportDIB* mem) {
224 const int slot = FindFreeCacheSlot(mem->size());
225 if (slot == -1)
226 return false;
227
228 shared_mem_cache_[slot] = mem;
229 return true;
230}
231
232void RenderProcessImpl::ClearTransportDIBCache() {
233 for (size_t i = 0; i < arraysize(shared_mem_cache_); ++i) {
234 if (shared_mem_cache_[i]) {
235 FreeTransportDIB(shared_mem_cache_[i]);
236 shared_mem_cache_[i] = NULL;
237 }
238 }
239}
240
241int RenderProcessImpl::FindFreeCacheSlot(size_t size) {
[email protected]e68e62fa2009-02-20 02:00:04242 // simple algorithm:
243 // - look for an empty slot to store mem, or
244 // - if full, then replace smallest entry which is smaller than |size|
245 for (size_t i = 0; i < arraysize(shared_mem_cache_); ++i) {
246 if (shared_mem_cache_[i] == NULL)
247 return i;
248 }
249
250 size_t smallest_size = size;
251 int smallest_index = -1;
252
253 for (size_t i = 1; i < arraysize(shared_mem_cache_); ++i) {
254 const size_t entry_size = shared_mem_cache_[i]->size();
255 if (entry_size < smallest_size) {
256 smallest_size = entry_size;
257 smallest_index = i;
258 }
259 }
260
261 if (smallest_index != -1) {
262 FreeTransportDIB(shared_mem_cache_[smallest_index]);
263 shared_mem_cache_[smallest_index] = NULL;
264 }
265
266 return smallest_index;
267}
268
[email protected]396c3a462010-03-03 05:03:22269TransportDIB* RenderProcessImpl::CreateTransportDIB(size_t size) {
270#if defined(OS_WIN) || defined(OS_LINUX)
271 // Windows and Linux create transport DIBs inside the renderer
272 return TransportDIB::Create(size, transport_dib_next_sequence_number_++);
273#elif defined(OS_MACOSX) // defined(OS_WIN) || defined(OS_LINUX)
274 // Mac creates transport DIBs in the browser, so we need to do a sync IPC to
275 // get one.
276 TransportDIB::Handle handle;
277 IPC::Message* msg = new ViewHostMsg_AllocTransportDIB(size, &handle);
278 if (!main_thread()->Send(msg))
279 return NULL;
280 if (handle.fd < 0)
281 return NULL;
282 return TransportDIB::Map(handle);
283#endif // defined(OS_MACOSX)
[email protected]e68e62fa2009-02-20 02:00:04284}
285
[email protected]396c3a462010-03-03 05:03:22286void RenderProcessImpl::FreeTransportDIB(TransportDIB* dib) {
287 if (!dib)
288 return;
289
290#if defined(OS_MACOSX)
291 // On Mac we need to tell the browser that it can drop a reference to the
292 // shared memory.
293 IPC::Message* msg = new ViewHostMsg_FreeTransportDIB(dib->id());
294 main_thread()->Send(msg);
295#endif
296
297 delete dib;
initial.commit09911bf2008-07-26 23:55:29298}