OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/browser/renderer_host/sandbox_ipc_linux.h" | 5 #include "content/browser/renderer_host/sandbox_ipc_linux.h" |
6 | 6 |
7 #include <fcntl.h> | 7 #include <fcntl.h> |
8 #include <sys/poll.h> | 8 #include <sys/poll.h> |
9 #include <sys/socket.h> | 9 #include <sys/socket.h> |
10 #include <sys/stat.h> | 10 #include <sys/stat.h> |
11 | 11 |
12 #include "base/basictypes.h" | 12 #include "base/basictypes.h" |
13 #include "base/command_line.h" | 13 #include "base/command_line.h" |
14 #include "base/files/scoped_file.h" | 14 #include "base/files/scoped_file.h" |
15 #include "base/linux_util.h" | 15 #include "base/linux_util.h" |
16 #include "base/macros.h" | 16 #include "base/macros.h" |
17 #include "base/memory/scoped_vector.h" | |
18 #include "base/memory/shared_memory.h" | 17 #include "base/memory/shared_memory.h" |
19 #include "base/posix/eintr_wrapper.h" | 18 #include "base/posix/eintr_wrapper.h" |
20 #include "base/posix/unix_domain_socket_linux.h" | 19 #include "base/posix/unix_domain_socket_linux.h" |
21 #include "base/process/launch.h" | 20 #include "base/process/launch.h" |
22 #include "base/strings/string_number_conversions.h" | 21 #include "base/strings/string_number_conversions.h" |
23 #include "content/browser/renderer_host/font_utils_linux.h" | 22 #include "content/browser/renderer_host/font_utils_linux.h" |
24 #include "content/common/font_config_ipc_linux.h" | 23 #include "content/common/font_config_ipc_linux.h" |
25 #include "content/common/sandbox_linux/sandbox_linux.h" | 24 #include "content/common/sandbox_linux/sandbox_linux.h" |
26 #include "content/common/set_process_title.h" | 25 #include "content/common/set_process_title.h" |
27 #include "content/public/common/content_switches.h" | 26 #include "content/public/common/content_switches.h" |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
116 | 115 |
117 if (pfds[1].revents & POLLIN) { | 116 if (pfds[1].revents & POLLIN) { |
118 HandleRequestFromRenderer(browser_socket_); | 117 HandleRequestFromRenderer(browser_socket_); |
119 } | 118 } |
120 } | 119 } |
121 | 120 |
122 VLOG(1) << "SandboxIPCHandler stopping."; | 121 VLOG(1) << "SandboxIPCHandler stopping."; |
123 } | 122 } |
124 | 123 |
125 void SandboxIPCHandler::HandleRequestFromRenderer(int fd) { | 124 void SandboxIPCHandler::HandleRequestFromRenderer(int fd) { |
126 ScopedVector<base::ScopedFD> fds; | 125 std::vector<base::ScopedFD> fds; |
127 | 126 |
128 // A FontConfigIPC::METHOD_MATCH message could be kMaxFontFamilyLength | 127 // A FontConfigIPC::METHOD_MATCH message could be kMaxFontFamilyLength |
129 // bytes long (this is the largest message type). | 128 // bytes long (this is the largest message type). |
130 // 128 bytes padding are necessary so recvmsg() does not return MSG_TRUNC | 129 // 128 bytes padding are necessary so recvmsg() does not return MSG_TRUNC |
131 // error for a maximum length message. | 130 // error for a maximum length message. |
132 char buf[FontConfigIPC::kMaxFontFamilyLength + 128]; | 131 char buf[FontConfigIPC::kMaxFontFamilyLength + 128]; |
133 | 132 |
134 const ssize_t len = | 133 const ssize_t len = |
135 base::UnixDomainSocket::RecvMsg(fd, buf, sizeof(buf), &fds); | 134 base::UnixDomainSocket::RecvMsg(fd, buf, sizeof(buf), &fds); |
136 if (len == -1) { | 135 if (len == -1) { |
137 // TODO: should send an error reply, or the sender might block forever. | 136 // TODO: should send an error reply, or the sender might block forever. |
138 NOTREACHED() << "Sandbox host message is larger than kMaxFontFamilyLength"; | 137 NOTREACHED() << "Sandbox host message is larger than kMaxFontFamilyLength"; |
139 return; | 138 return; |
140 } | 139 } |
141 if (fds.empty()) | 140 if (fds.empty()) |
142 return; | 141 return; |
143 | 142 |
144 base::Pickle pickle(buf, len); | 143 base::Pickle pickle(buf, len); |
145 base::PickleIterator iter(pickle); | 144 base::PickleIterator iter(pickle); |
146 | 145 |
147 int kind; | 146 int kind; |
148 if (!iter.ReadInt(&kind)) | 147 if (!iter.ReadInt(&kind)) |
149 return; | 148 return; |
150 | 149 |
151 if (kind == FontConfigIPC::METHOD_MATCH) { | 150 if (kind == FontConfigIPC::METHOD_MATCH) { |
152 HandleFontMatchRequest(fd, iter, fds.get()); | 151 HandleFontMatchRequest(fd, iter, fds); |
153 } else if (kind == FontConfigIPC::METHOD_OPEN) { | 152 } else if (kind == FontConfigIPC::METHOD_OPEN) { |
154 HandleFontOpenRequest(fd, iter, fds.get()); | 153 HandleFontOpenRequest(fd, iter, fds); |
155 } else if (kind == LinuxSandbox::METHOD_GET_FALLBACK_FONT_FOR_CHAR) { | 154 } else if (kind == LinuxSandbox::METHOD_GET_FALLBACK_FONT_FOR_CHAR) { |
156 HandleGetFallbackFontForChar(fd, iter, fds.get()); | 155 HandleGetFallbackFontForChar(fd, iter, fds); |
157 } else if (kind == LinuxSandbox::METHOD_LOCALTIME) { | 156 } else if (kind == LinuxSandbox::METHOD_LOCALTIME) { |
158 HandleLocaltime(fd, iter, fds.get()); | 157 HandleLocaltime(fd, iter, fds); |
159 } else if (kind == LinuxSandbox::METHOD_GET_STYLE_FOR_STRIKE) { | 158 } else if (kind == LinuxSandbox::METHOD_GET_STYLE_FOR_STRIKE) { |
160 HandleGetStyleForStrike(fd, iter, fds.get()); | 159 HandleGetStyleForStrike(fd, iter, fds); |
161 } else if (kind == LinuxSandbox::METHOD_MAKE_SHARED_MEMORY_SEGMENT) { | 160 } else if (kind == LinuxSandbox::METHOD_MAKE_SHARED_MEMORY_SEGMENT) { |
162 HandleMakeSharedMemorySegment(fd, iter, fds.get()); | 161 HandleMakeSharedMemorySegment(fd, iter, fds); |
163 } else if (kind == LinuxSandbox::METHOD_MATCH_WITH_FALLBACK) { | 162 } else if (kind == LinuxSandbox::METHOD_MATCH_WITH_FALLBACK) { |
164 HandleMatchWithFallback(fd, iter, fds.get()); | 163 HandleMatchWithFallback(fd, iter, fds); |
165 } | 164 } |
166 } | 165 } |
167 | 166 |
168 int SandboxIPCHandler::FindOrAddPath(const SkString& path) { | 167 int SandboxIPCHandler::FindOrAddPath(const SkString& path) { |
169 int count = paths_.count(); | 168 int count = paths_.count(); |
170 for (int i = 0; i < count; ++i) { | 169 for (int i = 0; i < count; ++i) { |
171 if (path == *paths_[i]) | 170 if (path == *paths_[i]) |
172 return i; | 171 return i; |
173 } | 172 } |
174 *paths_.append() = new SkString(path); | 173 *paths_.append() = new SkString(path); |
175 return count; | 174 return count; |
176 } | 175 } |
177 | 176 |
178 void SandboxIPCHandler::HandleFontMatchRequest( | 177 void SandboxIPCHandler::HandleFontMatchRequest( |
179 int fd, | 178 int fd, |
180 base::PickleIterator iter, | 179 base::PickleIterator iter, |
181 const std::vector<base::ScopedFD*>& fds) { | 180 const std::vector<base::ScopedFD>& fds) { |
182 uint32_t requested_style; | 181 uint32_t requested_style; |
183 std::string family; | 182 std::string family; |
184 if (!iter.ReadString(&family) || !iter.ReadUInt32(&requested_style)) | 183 if (!iter.ReadString(&family) || !iter.ReadUInt32(&requested_style)) |
185 return; | 184 return; |
186 | 185 |
187 SkFontConfigInterface::FontIdentity result_identity; | 186 SkFontConfigInterface::FontIdentity result_identity; |
188 SkString result_family; | 187 SkString result_family; |
189 SkTypeface::Style result_style; | 188 SkTypeface::Style result_style; |
190 SkFontConfigInterface* fc = | 189 SkFontConfigInterface* fc = |
191 SkFontConfigInterface::GetSingletonDirectInterface(); | 190 SkFontConfigInterface::GetSingletonDirectInterface(); |
(...skipping 17 matching lines...) Expand all Loading... |
209 skia::WriteSkString(&reply, result_family); | 208 skia::WriteSkString(&reply, result_family); |
210 skia::WriteSkFontIdentity(&reply, result_identity); | 209 skia::WriteSkFontIdentity(&reply, result_identity); |
211 reply.WriteUInt32(result_style); | 210 reply.WriteUInt32(result_style); |
212 } | 211 } |
213 SendRendererReply(fds, reply, -1); | 212 SendRendererReply(fds, reply, -1); |
214 } | 213 } |
215 | 214 |
216 void SandboxIPCHandler::HandleFontOpenRequest( | 215 void SandboxIPCHandler::HandleFontOpenRequest( |
217 int fd, | 216 int fd, |
218 base::PickleIterator iter, | 217 base::PickleIterator iter, |
219 const std::vector<base::ScopedFD*>& fds) { | 218 const std::vector<base::ScopedFD>& fds) { |
220 uint32_t index; | 219 uint32_t index; |
221 if (!iter.ReadUInt32(&index)) | 220 if (!iter.ReadUInt32(&index)) |
222 return; | 221 return; |
223 if (index >= static_cast<uint32_t>(paths_.count())) | 222 if (index >= static_cast<uint32_t>(paths_.count())) |
224 return; | 223 return; |
225 const int result_fd = open(paths_[index]->c_str(), O_RDONLY); | 224 const int result_fd = open(paths_[index]->c_str(), O_RDONLY); |
226 | 225 |
227 base::Pickle reply; | 226 base::Pickle reply; |
228 if (result_fd == -1) { | 227 if (result_fd == -1) { |
229 reply.WriteBool(false); | 228 reply.WriteBool(false); |
230 } else { | 229 } else { |
231 reply.WriteBool(true); | 230 reply.WriteBool(true); |
232 } | 231 } |
233 | 232 |
234 // The receiver will have its own access to the file, so we will close it | 233 // The receiver will have its own access to the file, so we will close it |
235 // after this send. | 234 // after this send. |
236 SendRendererReply(fds, reply, result_fd); | 235 SendRendererReply(fds, reply, result_fd); |
237 | 236 |
238 if (result_fd >= 0) { | 237 if (result_fd >= 0) { |
239 int err = IGNORE_EINTR(close(result_fd)); | 238 int err = IGNORE_EINTR(close(result_fd)); |
240 DCHECK(!err); | 239 DCHECK(!err); |
241 } | 240 } |
242 } | 241 } |
243 | 242 |
244 void SandboxIPCHandler::HandleGetFallbackFontForChar( | 243 void SandboxIPCHandler::HandleGetFallbackFontForChar( |
245 int fd, | 244 int fd, |
246 base::PickleIterator iter, | 245 base::PickleIterator iter, |
247 const std::vector<base::ScopedFD*>& fds) { | 246 const std::vector<base::ScopedFD>& fds) { |
248 // The other side of this call is | 247 // The other side of this call is |
249 // content/common/child_process_sandbox_support_impl_linux.cc | 248 // content/common/child_process_sandbox_support_impl_linux.cc |
250 | 249 |
251 EnsureWebKitInitialized(); | 250 EnsureWebKitInitialized(); |
252 WebUChar32 c; | 251 WebUChar32 c; |
253 if (!iter.ReadInt(&c)) | 252 if (!iter.ReadInt(&c)) |
254 return; | 253 return; |
255 | 254 |
256 std::string preferred_locale; | 255 std::string preferred_locale; |
257 if (!iter.ReadString(&preferred_locale)) | 256 if (!iter.ReadString(&preferred_locale)) |
(...skipping 19 matching lines...) Expand all Loading... |
277 reply.WriteInt(fallbackFont.fontconfigInterfaceId); | 276 reply.WriteInt(fallbackFont.fontconfigInterfaceId); |
278 reply.WriteInt(fallbackFont.ttcIndex); | 277 reply.WriteInt(fallbackFont.ttcIndex); |
279 reply.WriteBool(fallbackFont.isBold); | 278 reply.WriteBool(fallbackFont.isBold); |
280 reply.WriteBool(fallbackFont.isItalic); | 279 reply.WriteBool(fallbackFont.isItalic); |
281 SendRendererReply(fds, reply, -1); | 280 SendRendererReply(fds, reply, -1); |
282 } | 281 } |
283 | 282 |
284 void SandboxIPCHandler::HandleGetStyleForStrike( | 283 void SandboxIPCHandler::HandleGetStyleForStrike( |
285 int fd, | 284 int fd, |
286 base::PickleIterator iter, | 285 base::PickleIterator iter, |
287 const std::vector<base::ScopedFD*>& fds) { | 286 const std::vector<base::ScopedFD>& fds) { |
288 std::string family; | 287 std::string family; |
289 bool bold, italic; | 288 bool bold, italic; |
290 uint16 pixel_size; | 289 uint16 pixel_size; |
291 | 290 |
292 if (!iter.ReadString(&family) || | 291 if (!iter.ReadString(&family) || |
293 !iter.ReadBool(&bold) || | 292 !iter.ReadBool(&bold) || |
294 !iter.ReadBool(&italic) || | 293 !iter.ReadBool(&italic) || |
295 !iter.ReadUInt16(&pixel_size)) { | 294 !iter.ReadUInt16(&pixel_size)) { |
296 return; | 295 return; |
297 } | 296 } |
(...skipping 17 matching lines...) Expand all Loading... |
315 reply.WriteInt(params.antialiasing); | 314 reply.WriteInt(params.antialiasing); |
316 reply.WriteInt(ConvertSubpixelRendering(params.subpixel_rendering)); | 315 reply.WriteInt(ConvertSubpixelRendering(params.subpixel_rendering)); |
317 reply.WriteInt(params.subpixel_positioning); | 316 reply.WriteInt(params.subpixel_positioning); |
318 | 317 |
319 SendRendererReply(fds, reply, -1); | 318 SendRendererReply(fds, reply, -1); |
320 } | 319 } |
321 | 320 |
322 void SandboxIPCHandler::HandleLocaltime( | 321 void SandboxIPCHandler::HandleLocaltime( |
323 int fd, | 322 int fd, |
324 base::PickleIterator iter, | 323 base::PickleIterator iter, |
325 const std::vector<base::ScopedFD*>& fds) { | 324 const std::vector<base::ScopedFD>& fds) { |
326 // The other side of this call is in zygote_main_linux.cc | 325 // The other side of this call is in zygote_main_linux.cc |
327 | 326 |
328 std::string time_string; | 327 std::string time_string; |
329 if (!iter.ReadString(&time_string) || time_string.size() != sizeof(time_t)) | 328 if (!iter.ReadString(&time_string) || time_string.size() != sizeof(time_t)) |
330 return; | 329 return; |
331 | 330 |
332 time_t time; | 331 time_t time; |
333 memcpy(&time, time_string.data(), sizeof(time)); | 332 memcpy(&time, time_string.data(), sizeof(time)); |
334 // We use localtime here because we need the tm_zone field to be filled | 333 // We use localtime here because we need the tm_zone field to be filled |
335 // out. Since we are a single-threaded process, this is safe. | 334 // out. Since we are a single-threaded process, this is safe. |
336 const struct tm* expanded_time = localtime(&time); | 335 const struct tm* expanded_time = localtime(&time); |
337 | 336 |
338 std::string result_string; | 337 std::string result_string; |
339 const char* time_zone_string = ""; | 338 const char* time_zone_string = ""; |
340 if (expanded_time != NULL) { | 339 if (expanded_time != NULL) { |
341 result_string = std::string(reinterpret_cast<const char*>(expanded_time), | 340 result_string = std::string(reinterpret_cast<const char*>(expanded_time), |
342 sizeof(struct tm)); | 341 sizeof(struct tm)); |
343 time_zone_string = expanded_time->tm_zone; | 342 time_zone_string = expanded_time->tm_zone; |
344 } | 343 } |
345 | 344 |
346 base::Pickle reply; | 345 base::Pickle reply; |
347 reply.WriteString(result_string); | 346 reply.WriteString(result_string); |
348 reply.WriteString(time_zone_string); | 347 reply.WriteString(time_zone_string); |
349 SendRendererReply(fds, reply, -1); | 348 SendRendererReply(fds, reply, -1); |
350 } | 349 } |
351 | 350 |
352 void SandboxIPCHandler::HandleMakeSharedMemorySegment( | 351 void SandboxIPCHandler::HandleMakeSharedMemorySegment( |
353 int fd, | 352 int fd, |
354 base::PickleIterator iter, | 353 base::PickleIterator iter, |
355 const std::vector<base::ScopedFD*>& fds) { | 354 const std::vector<base::ScopedFD>& fds) { |
356 base::SharedMemoryCreateOptions options; | 355 base::SharedMemoryCreateOptions options; |
357 uint32_t size; | 356 uint32_t size; |
358 if (!iter.ReadUInt32(&size)) | 357 if (!iter.ReadUInt32(&size)) |
359 return; | 358 return; |
360 options.size = size; | 359 options.size = size; |
361 if (!iter.ReadBool(&options.executable)) | 360 if (!iter.ReadBool(&options.executable)) |
362 return; | 361 return; |
363 int shm_fd = -1; | 362 int shm_fd = -1; |
364 base::SharedMemory shm; | 363 base::SharedMemory shm; |
365 if (shm.Create(options)) | 364 if (shm.Create(options)) |
366 shm_fd = shm.handle().fd; | 365 shm_fd = shm.handle().fd; |
367 base::Pickle reply; | 366 base::Pickle reply; |
368 SendRendererReply(fds, reply, shm_fd); | 367 SendRendererReply(fds, reply, shm_fd); |
369 } | 368 } |
370 | 369 |
371 void SandboxIPCHandler::HandleMatchWithFallback( | 370 void SandboxIPCHandler::HandleMatchWithFallback( |
372 int fd, | 371 int fd, |
373 base::PickleIterator iter, | 372 base::PickleIterator iter, |
374 const std::vector<base::ScopedFD*>& fds) { | 373 const std::vector<base::ScopedFD>& fds) { |
375 std::string face; | 374 std::string face; |
376 bool is_bold, is_italic; | 375 bool is_bold, is_italic; |
377 uint32 charset, fallback_family; | 376 uint32 charset, fallback_family; |
378 | 377 |
379 if (!iter.ReadString(&face) || face.empty() || | 378 if (!iter.ReadString(&face) || face.empty() || |
380 !iter.ReadBool(&is_bold) || | 379 !iter.ReadBool(&is_bold) || |
381 !iter.ReadBool(&is_italic) || | 380 !iter.ReadBool(&is_italic) || |
382 !iter.ReadUInt32(&charset) || | 381 !iter.ReadUInt32(&charset) || |
383 !iter.ReadUInt32(&fallback_family)) { | 382 !iter.ReadUInt32(&fallback_family)) { |
384 return; | 383 return; |
385 } | 384 } |
386 | 385 |
387 int font_fd = MatchFontFaceWithFallback( | 386 int font_fd = MatchFontFaceWithFallback( |
388 face, is_bold, is_italic, charset, fallback_family); | 387 face, is_bold, is_italic, charset, fallback_family); |
389 | 388 |
390 base::Pickle reply; | 389 base::Pickle reply; |
391 SendRendererReply(fds, reply, font_fd); | 390 SendRendererReply(fds, reply, font_fd); |
392 | 391 |
393 if (font_fd >= 0) { | 392 if (font_fd >= 0) { |
394 if (IGNORE_EINTR(close(font_fd)) < 0) | 393 if (IGNORE_EINTR(close(font_fd)) < 0) |
395 PLOG(ERROR) << "close"; | 394 PLOG(ERROR) << "close"; |
396 } | 395 } |
397 } | 396 } |
398 | 397 |
399 void SandboxIPCHandler::SendRendererReply( | 398 void SandboxIPCHandler::SendRendererReply( |
400 const std::vector<base::ScopedFD*>& fds, | 399 const std::vector<base::ScopedFD>& fds, |
401 const base::Pickle& reply, | 400 const base::Pickle& reply, |
402 int reply_fd) { | 401 int reply_fd) { |
403 struct msghdr msg; | 402 struct msghdr msg; |
404 memset(&msg, 0, sizeof(msg)); | 403 memset(&msg, 0, sizeof(msg)); |
405 struct iovec iov = {const_cast<void*>(reply.data()), reply.size()}; | 404 struct iovec iov = {const_cast<void*>(reply.data()), reply.size()}; |
406 msg.msg_iov = &iov; | 405 msg.msg_iov = &iov; |
407 msg.msg_iovlen = 1; | 406 msg.msg_iovlen = 1; |
408 | 407 |
409 char control_buffer[CMSG_SPACE(sizeof(int))]; | 408 char control_buffer[CMSG_SPACE(sizeof(int))]; |
410 | 409 |
(...skipping 10 matching lines...) Expand all Loading... |
421 msg.msg_control = control_buffer; | 420 msg.msg_control = control_buffer; |
422 msg.msg_controllen = sizeof(control_buffer); | 421 msg.msg_controllen = sizeof(control_buffer); |
423 cmsg = CMSG_FIRSTHDR(&msg); | 422 cmsg = CMSG_FIRSTHDR(&msg); |
424 cmsg->cmsg_level = SOL_SOCKET; | 423 cmsg->cmsg_level = SOL_SOCKET; |
425 cmsg->cmsg_type = SCM_RIGHTS; | 424 cmsg->cmsg_type = SCM_RIGHTS; |
426 cmsg->cmsg_len = CMSG_LEN(sizeof(int)); | 425 cmsg->cmsg_len = CMSG_LEN(sizeof(int)); |
427 memcpy(CMSG_DATA(cmsg), &reply_fd, sizeof(reply_fd)); | 426 memcpy(CMSG_DATA(cmsg), &reply_fd, sizeof(reply_fd)); |
428 msg.msg_controllen = cmsg->cmsg_len; | 427 msg.msg_controllen = cmsg->cmsg_len; |
429 } | 428 } |
430 | 429 |
431 if (HANDLE_EINTR(sendmsg(fds[0]->get(), &msg, MSG_DONTWAIT)) < 0) | 430 if (HANDLE_EINTR(sendmsg(fds[0].get(), &msg, MSG_DONTWAIT)) < 0) |
432 PLOG(ERROR) << "sendmsg"; | 431 PLOG(ERROR) << "sendmsg"; |
433 } | 432 } |
434 | 433 |
435 SandboxIPCHandler::~SandboxIPCHandler() { | 434 SandboxIPCHandler::~SandboxIPCHandler() { |
436 paths_.deleteAll(); | 435 paths_.deleteAll(); |
437 if (blink_platform_impl_) | 436 if (blink_platform_impl_) |
438 blink::shutdownWithoutV8(); | 437 blink::shutdownWithoutV8(); |
439 | 438 |
440 if (IGNORE_EINTR(close(lifeline_fd_)) < 0) | 439 if (IGNORE_EINTR(close(lifeline_fd_)) < 0) |
441 PLOG(ERROR) << "close"; | 440 PLOG(ERROR) << "close"; |
442 if (IGNORE_EINTR(close(browser_socket_)) < 0) | 441 if (IGNORE_EINTR(close(browser_socket_)) < 0) |
443 PLOG(ERROR) << "close"; | 442 PLOG(ERROR) << "close"; |
444 } | 443 } |
445 | 444 |
446 void SandboxIPCHandler::EnsureWebKitInitialized() { | 445 void SandboxIPCHandler::EnsureWebKitInitialized() { |
447 if (blink_platform_impl_) | 446 if (blink_platform_impl_) |
448 return; | 447 return; |
449 blink_platform_impl_.reset(new BlinkPlatformImpl); | 448 blink_platform_impl_.reset(new BlinkPlatformImpl); |
450 blink::initializeWithoutV8(blink_platform_impl_.get()); | 449 blink::initializeWithoutV8(blink_platform_impl_.get()); |
451 } | 450 } |
452 | 451 |
453 } // namespace content | 452 } // namespace content |
OLD | NEW |