OLD | NEW |
| (Empty) |
1 // Copyright (c) 2010 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 "build/build_config.h" | |
6 | |
7 #if defined(OS_WIN) | |
8 #include <windows.h> | |
9 #include <objidl.h> | |
10 #include <mlang.h> | |
11 #endif | |
12 | |
13 #include "chrome/renderer/render_process.h" | |
14 | |
15 #include "app/surface/transport_dib.h" | |
16 #include "base/basictypes.h" | |
17 #include "base/command_line.h" | |
18 #include "base/compiler_specific.h" | |
19 #include "base/file_util.h" | |
20 #include "base/message_loop.h" | |
21 #include "base/histogram.h" | |
22 #include "base/path_service.h" | |
23 #include "base/sys_info.h" | |
24 // TODO(jar): DNS calls should be renderer specific, not including browser. | |
25 #include "chrome/browser/net/dns_global.h" | |
26 #include "chrome/common/chrome_switches.h" | |
27 #include "chrome/common/chrome_paths.h" | |
28 #include "chrome/common/render_messages.h" | |
29 #include "chrome/common/nacl_types.h" | |
30 #include "chrome/renderer/render_view.h" | |
31 #include "ipc/ipc_channel.h" | |
32 #include "ipc/ipc_message_utils.h" | |
33 #include "media/base/media.h" | |
34 #include "media/base/media_switches.h" | |
35 #include "native_client/src/trusted/plugin/nacl_entry_points.h" | |
36 #include "webkit/glue/webkit_glue.h" | |
37 | |
38 #if defined(OS_MACOSX) | |
39 #include "base/mac_util.h" | |
40 #endif | |
41 | |
42 //----------------------------------------------------------------------------- | |
43 | |
44 RenderProcess::RenderProcess() | |
45 : ALLOW_THIS_IN_INITIALIZER_LIST(shared_mem_cache_cleaner_( | |
46 base::TimeDelta::FromSeconds(5), | |
47 this, &RenderProcess::ClearTransportDIBCache)), | |
48 sequence_number_(0) { | |
49 in_process_plugins_ = InProcessPlugins(); | |
50 for (size_t i = 0; i < arraysize(shared_mem_cache_); ++i) | |
51 shared_mem_cache_[i] = NULL; | |
52 | |
53 #if defined(OS_WIN) | |
54 // HACK: See http://b/issue?id=1024307 for rationale. | |
55 if (GetModuleHandle(L"LPK.DLL") == NULL) { | |
56 // Makes sure lpk.dll is loaded by gdi32 to make sure ExtTextOut() works | |
57 // when buffering into a EMF buffer for printing. | |
58 typedef BOOL (__stdcall *GdiInitializeLanguagePack)(int LoadedShapingDLLs); | |
59 GdiInitializeLanguagePack gdi_init_lpk = | |
60 reinterpret_cast<GdiInitializeLanguagePack>(GetProcAddress( | |
61 GetModuleHandle(L"GDI32.DLL"), | |
62 "GdiInitializeLanguagePack")); | |
63 DCHECK(gdi_init_lpk); | |
64 if (gdi_init_lpk) { | |
65 gdi_init_lpk(0); | |
66 } | |
67 } | |
68 #endif | |
69 | |
70 // Out of process dev tools rely upon auto break behavior. | |
71 webkit_glue::SetJavaScriptFlags( | |
72 L"--debugger-auto-break" | |
73 // Enable lazy in-memory profiling. | |
74 L" --prof --prof-lazy --logfile=* --compress-log"); | |
75 | |
76 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); | |
77 if (command_line.HasSwitch(switches::kJavaScriptFlags)) { | |
78 webkit_glue::SetJavaScriptFlags( | |
79 command_line.GetSwitchValue(switches::kJavaScriptFlags)); | |
80 } | |
81 | |
82 if (command_line.HasSwitch(switches::kEnableWatchdog)) { | |
83 // TODO(JAR): Need to implement renderer IO msgloop watchdog. | |
84 } | |
85 | |
86 if (command_line.HasSwitch(switches::kDumpHistogramsOnExit)) { | |
87 StatisticsRecorder::set_dump_on_exit(true); | |
88 } | |
89 | |
90 #ifndef DISABLE_NACL | |
91 if (command_line.HasSwitch(switches::kInternalNaCl)) | |
92 RegisterInternalNaClPlugin(RenderProcess::LaunchNaClProcess); | |
93 #endif | |
94 | |
95 if (!command_line.HasSwitch(switches::kDisableByteRangeSupport)) { | |
96 webkit_glue::SetMediaCacheEnabled(true); | |
97 } | |
98 | |
99 #if defined(OS_MACOSX) | |
100 FilePath bundle_path = mac_util::MainAppBundlePath(); | |
101 | |
102 initialized_media_library_ = | |
103 media::InitializeMediaLibrary(bundle_path.Append("Libraries")); | |
104 #else | |
105 FilePath module_path; | |
106 initialized_media_library_ = | |
107 PathService::Get(base::DIR_MODULE, &module_path) && | |
108 media::InitializeMediaLibrary(module_path); | |
109 | |
110 // TODO(hclam): Add more checks here. Currently this is not used. | |
111 if (CommandLine::ForCurrentProcess()->HasSwitch( | |
112 switches::kEnableOpenMax)) { | |
113 media::InitializeOpenMaxLibrary(module_path); | |
114 } | |
115 #endif | |
116 } | |
117 | |
118 RenderProcess::~RenderProcess() { | |
119 // TODO(port): Try and limit what we pull in for our non-Win unit test bundle. | |
120 #ifndef NDEBUG | |
121 // log important leaked objects | |
122 webkit_glue::CheckForLeaks(); | |
123 #endif | |
124 | |
125 GetShutDownEvent()->Signal(); | |
126 ClearTransportDIBCache(); | |
127 } | |
128 | |
129 bool RenderProcess::InProcessPlugins() { | |
130 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); | |
131 #if defined(OS_LINUX) | |
132 // Plugin processes require a UI message loop, and the Linux message loop | |
133 // implementation only allows one UI loop per process. | |
134 if (command_line.HasSwitch(switches::kInProcessPlugins)) | |
135 NOTIMPLEMENTED() << ": in process plugins not supported on Linux"; | |
136 return command_line.HasSwitch(switches::kInProcessPlugins); | |
137 #else | |
138 return command_line.HasSwitch(switches::kInProcessPlugins) || | |
139 command_line.HasSwitch(switches::kSingleProcess); | |
140 #endif | |
141 } | |
142 | |
143 bool RenderProcess::LaunchNaClProcess(const char* url, | |
144 int imc_fd, | |
145 nacl::Handle* imc_handle, | |
146 nacl::Handle* nacl_process_handle, | |
147 int* nacl_process_id) { | |
148 // TODO(gregoryd): nacl::FileDescriptor will be soon merged with | |
149 // base::FileDescriptor | |
150 nacl::FileDescriptor imc_descriptor; | |
151 base::ProcessHandle nacl_process; | |
152 if (!RenderThread::current()->Send( | |
153 new ViewHostMsg_LaunchNaCl(ASCIIToWide(url), | |
154 imc_fd, | |
155 &imc_descriptor, | |
156 &nacl_process, | |
157 reinterpret_cast<base::ProcessId*>(nacl_process_id)))) { | |
158 return false; | |
159 } | |
160 *imc_handle = nacl::ToNativeHandle(imc_descriptor); | |
161 *nacl_process_handle = nacl_process; | |
162 return true; | |
163 } | |
164 | |
165 // ----------------------------------------------------------------------------- | |
166 // Platform specific code for dealing with bitmap transport... | |
167 | |
168 TransportDIB* RenderProcess::CreateTransportDIB(size_t size) { | |
169 #if defined(OS_WIN) || defined(OS_LINUX) | |
170 // Windows and Linux create transport DIBs inside the renderer | |
171 return TransportDIB::Create(size, sequence_number_++); | |
172 #elif defined(OS_MACOSX) // defined(OS_WIN) || defined(OS_LINUX) | |
173 // Mac creates transport DIBs in the browser, so we need to do a sync IPC to | |
174 // get one. The TransportDIB is cached in the browser. | |
175 TransportDIB::Handle handle; | |
176 IPC::Message* msg = new ViewHostMsg_AllocTransportDIB(size, true, &handle); | |
177 if (!main_thread()->Send(msg)) | |
178 return NULL; | |
179 if (handle.fd < 0) | |
180 return NULL; | |
181 return TransportDIB::Map(handle); | |
182 #endif // defined(OS_MACOSX) | |
183 } | |
184 | |
185 void RenderProcess::FreeTransportDIB(TransportDIB* dib) { | |
186 if (!dib) | |
187 return; | |
188 | |
189 #if defined(OS_MACOSX) | |
190 // On Mac we need to tell the browser that it can drop a reference to the | |
191 // shared memory. | |
192 IPC::Message* msg = new ViewHostMsg_FreeTransportDIB(dib->id()); | |
193 main_thread()->Send(msg); | |
194 #endif | |
195 | |
196 delete dib; | |
197 } | |
198 | |
199 // ----------------------------------------------------------------------------- | |
200 | |
201 | |
202 skia::PlatformCanvas* RenderProcess::GetDrawingCanvas( | |
203 TransportDIB** memory, const gfx::Rect& rect) { | |
204 int width = rect.width(); | |
205 int height = rect.height(); | |
206 const size_t stride = skia::PlatformCanvas::StrideForWidth(rect.width()); | |
207 #if defined(OS_LINUX) | |
208 const size_t max_size = base::SysInfo::MaxSharedMemorySize(); | |
209 #else | |
210 const size_t max_size = 0; | |
211 #endif | |
212 | |
213 // If the requested size is too big, reduce the height. Ideally we might like | |
214 // to reduce the width as well to make the size reduction more "balanced", but | |
215 // it rarely comes up in practice. | |
216 if ((max_size != 0) && (height * stride > max_size)) | |
217 height = max_size / stride; | |
218 | |
219 const size_t size = height * stride; | |
220 | |
221 if (!GetTransportDIBFromCache(memory, size)) { | |
222 *memory = CreateTransportDIB(size); | |
223 if (!*memory) | |
224 return false; | |
225 } | |
226 | |
227 return (*memory)->GetPlatformCanvas(width, height); | |
228 } | |
229 | |
230 void RenderProcess::ReleaseTransportDIB(TransportDIB* mem) { | |
231 if (PutSharedMemInCache(mem)) { | |
232 shared_mem_cache_cleaner_.Reset(); | |
233 return; | |
234 } | |
235 | |
236 FreeTransportDIB(mem); | |
237 } | |
238 | |
239 bool RenderProcess::GetTransportDIBFromCache(TransportDIB** mem, | |
240 size_t size) { | |
241 // look for a cached object that is suitable for the requested size. | |
242 for (size_t i = 0; i < arraysize(shared_mem_cache_); ++i) { | |
243 if (shared_mem_cache_[i] && | |
244 size <= shared_mem_cache_[i]->size()) { | |
245 *mem = shared_mem_cache_[i]; | |
246 shared_mem_cache_[i] = NULL; | |
247 return true; | |
248 } | |
249 } | |
250 | |
251 return false; | |
252 } | |
253 | |
254 int RenderProcess::FindFreeCacheSlot(size_t size) { | |
255 // simple algorithm: | |
256 // - look for an empty slot to store mem, or | |
257 // - if full, then replace smallest entry which is smaller than |size| | |
258 for (size_t i = 0; i < arraysize(shared_mem_cache_); ++i) { | |
259 if (shared_mem_cache_[i] == NULL) | |
260 return i; | |
261 } | |
262 | |
263 size_t smallest_size = size; | |
264 int smallest_index = -1; | |
265 | |
266 for (size_t i = 1; i < arraysize(shared_mem_cache_); ++i) { | |
267 const size_t entry_size = shared_mem_cache_[i]->size(); | |
268 if (entry_size < smallest_size) { | |
269 smallest_size = entry_size; | |
270 smallest_index = i; | |
271 } | |
272 } | |
273 | |
274 if (smallest_index != -1) { | |
275 FreeTransportDIB(shared_mem_cache_[smallest_index]); | |
276 shared_mem_cache_[smallest_index] = NULL; | |
277 } | |
278 | |
279 return smallest_index; | |
280 } | |
281 | |
282 bool RenderProcess::PutSharedMemInCache(TransportDIB* mem) { | |
283 const int slot = FindFreeCacheSlot(mem->size()); | |
284 if (slot == -1) | |
285 return false; | |
286 | |
287 shared_mem_cache_[slot] = mem; | |
288 return true; | |
289 } | |
290 | |
291 void RenderProcess::ClearTransportDIBCache() { | |
292 for (size_t i = 0; i < arraysize(shared_mem_cache_); ++i) { | |
293 if (shared_mem_cache_[i]) { | |
294 FreeTransportDIB(shared_mem_cache_[i]); | |
295 shared_mem_cache_[i] = NULL; | |
296 } | |
297 } | |
298 } | |
OLD | NEW |