render_message_filter.cc revision 558790d6acca3451cf3a6b497803a5f07d0bec58
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 "content/browser/renderer_host/render_message_filter.h" 6 7#include <map> 8 9#include "base/bind.h" 10#include "base/bind_helpers.h" 11#include "base/command_line.h" 12#include "base/debug/alias.h" 13#include "base/strings/sys_string_conversions.h" 14#include "base/strings/utf_string_conversions.h" 15#include "base/threading/thread.h" 16#include "base/threading/worker_pool.h" 17#include "content/browser/browser_main_loop.h" 18#include "content/browser/child_process_security_policy_impl.h" 19#include "content/browser/dom_storage/dom_storage_context_impl.h" 20#include "content/browser/dom_storage/session_storage_namespace_impl.h" 21#include "content/browser/download/download_stats.h" 22#include "content/browser/gpu/gpu_data_manager_impl.h" 23#include "content/browser/loader/resource_dispatcher_host_impl.h" 24#include "content/browser/media/media_internals.h" 25#include "content/browser/plugin_process_host.h" 26#include "content/browser/plugin_service_impl.h" 27#include "content/browser/ppapi_plugin_process_host.h" 28#include "content/browser/renderer_host/render_process_host_impl.h" 29#include "content/browser/renderer_host/render_view_host_delegate.h" 30#include "content/browser/renderer_host/render_widget_helper.h" 31#include "content/common/child_process_host_impl.h" 32#include "content/common/child_process_messages.h" 33#include "content/common/cookie_data.h" 34#include "content/common/desktop_notification_messages.h" 35#include "content/common/media/media_param_traits.h" 36#include "content/common/view_messages.h" 37#include "content/public/browser/browser_child_process_host.h" 38#include "content/public/browser/browser_context.h" 39#include "content/public/browser/browser_thread.h" 40#include "content/public/browser/content_browser_client.h" 41#include "content/public/browser/download_save_info.h" 42#include "content/public/browser/plugin_service_filter.h" 43#include "content/public/browser/resource_context.h" 44#include "content/public/browser/user_metrics.h" 45#include "content/public/common/content_switches.h" 46#include "content/public/common/context_menu_params.h" 47#include "content/public/common/url_constants.h" 48#include "content/public/common/webplugininfo.h" 49#include "ipc/ipc_channel_handle.h" 50#include "ipc/ipc_platform_file.h" 51#include "media/audio/audio_manager.h" 52#include "media/audio/audio_manager_base.h" 53#include "media/audio/audio_parameters.h" 54#include "media/base/media_log_event.h" 55#include "net/base/io_buffer.h" 56#include "net/base/keygen_handler.h" 57#include "net/base/mime_util.h" 58#include "net/base/request_priority.h" 59#include "net/cookies/canonical_cookie.h" 60#include "net/cookies/cookie_monster.h" 61#include "net/http/http_cache.h" 62#include "net/url_request/url_request_context.h" 63#include "net/url_request/url_request_context_getter.h" 64#include "third_party/WebKit/public/web/WebNotificationPresenter.h" 65#include "ui/gfx/color_profile.h" 66#include "webkit/plugins/plugin_constants.h" 67 68#if defined(OS_MACOSX) 69#include "content/common/mac/font_descriptor.h" 70#else 71#include "gpu/GLES2/gl2extchromium.h" 72#include "third_party/khronos/GLES2/gl2.h" 73#include "third_party/khronos/GLES2/gl2ext.h" 74#endif 75#if defined(OS_POSIX) 76#include "base/file_descriptor_posix.h" 77#endif 78#if defined(OS_WIN) 79#include "content/browser/renderer_host/backing_store_win.h" 80#include "content/common/font_cache_dispatcher_win.h" 81#endif 82#if defined(OS_ANDROID) 83#include "media/base/android/webaudio_media_codec_bridge.h" 84#endif 85 86using net::CookieStore; 87 88namespace content { 89namespace { 90 91const int kPluginsRefreshThresholdInSeconds = 3; 92 93// When two CPU usage queries arrive within this interval, we sample the CPU 94// usage only once and send it as a response for both queries. 95static const int64 kCPUUsageSampleIntervalMs = 900; 96 97// On Windows, |g_color_profile| can run on an arbitrary background thread. 98// We avoid races by using LazyInstance's constructor lock to initialize the 99// object. 100base::LazyInstance<gfx::ColorProfile>::Leaky g_color_profile = 101 LAZY_INSTANCE_INITIALIZER; 102 103// Common functionality for converting a sync renderer message to a callback 104// function in the browser. Derive from this, create it on the heap when 105// issuing your callback. When done, write your reply parameters into 106// reply_msg(), and then call SendReplyAndDeleteThis(). 107class RenderMessageCompletionCallback { 108 public: 109 RenderMessageCompletionCallback(RenderMessageFilter* filter, 110 IPC::Message* reply_msg) 111 : filter_(filter), 112 reply_msg_(reply_msg) { 113 } 114 115 virtual ~RenderMessageCompletionCallback() { 116 } 117 118 RenderMessageFilter* filter() { return filter_.get(); } 119 IPC::Message* reply_msg() { return reply_msg_; } 120 121 void SendReplyAndDeleteThis() { 122 filter_->Send(reply_msg_); 123 delete this; 124 } 125 126 private: 127 scoped_refptr<RenderMessageFilter> filter_; 128 IPC::Message* reply_msg_; 129}; 130 131class OpenChannelToPpapiPluginCallback 132 : public RenderMessageCompletionCallback, 133 public PpapiPluginProcessHost::PluginClient { 134 public: 135 OpenChannelToPpapiPluginCallback(RenderMessageFilter* filter, 136 ResourceContext* context, 137 IPC::Message* reply_msg) 138 : RenderMessageCompletionCallback(filter, reply_msg), 139 context_(context) { 140 } 141 142 virtual void GetPpapiChannelInfo(base::ProcessHandle* renderer_handle, 143 int* renderer_id) OVERRIDE { 144 *renderer_handle = filter()->PeerHandle(); 145 *renderer_id = filter()->render_process_id(); 146 } 147 148 virtual void OnPpapiChannelOpened(const IPC::ChannelHandle& channel_handle, 149 base::ProcessId plugin_pid, 150 int plugin_child_id) OVERRIDE { 151 ViewHostMsg_OpenChannelToPepperPlugin::WriteReplyParams( 152 reply_msg(), channel_handle, plugin_pid, plugin_child_id); 153 SendReplyAndDeleteThis(); 154 } 155 156 virtual bool OffTheRecord() OVERRIDE { 157 return filter()->OffTheRecord(); 158 } 159 160 virtual ResourceContext* GetResourceContext() OVERRIDE { 161 return context_; 162 } 163 164 private: 165 ResourceContext* context_; 166}; 167 168class OpenChannelToPpapiBrokerCallback 169 : public PpapiPluginProcessHost::BrokerClient { 170 public: 171 OpenChannelToPpapiBrokerCallback(RenderMessageFilter* filter, 172 int routing_id, 173 int request_id) 174 : filter_(filter), 175 routing_id_(routing_id), 176 request_id_(request_id) { 177 } 178 179 virtual ~OpenChannelToPpapiBrokerCallback() {} 180 181 virtual void GetPpapiChannelInfo(base::ProcessHandle* renderer_handle, 182 int* renderer_id) OVERRIDE { 183 *renderer_handle = filter_->PeerHandle(); 184 *renderer_id = filter_->render_process_id(); 185 } 186 187 virtual void OnPpapiChannelOpened(const IPC::ChannelHandle& channel_handle, 188 base::ProcessId plugin_pid, 189 int /* plugin_child_id */) OVERRIDE { 190 filter_->Send(new ViewMsg_PpapiBrokerChannelCreated(routing_id_, 191 request_id_, 192 plugin_pid, 193 channel_handle)); 194 delete this; 195 } 196 197 virtual bool OffTheRecord() OVERRIDE { 198 return filter_->OffTheRecord(); 199 } 200 201 private: 202 scoped_refptr<RenderMessageFilter> filter_; 203 int routing_id_; 204 int request_id_; 205}; 206 207} // namespace 208 209class RenderMessageFilter::OpenChannelToNpapiPluginCallback 210 : public RenderMessageCompletionCallback, 211 public PluginProcessHost::Client { 212 public: 213 OpenChannelToNpapiPluginCallback(RenderMessageFilter* filter, 214 ResourceContext* context, 215 IPC::Message* reply_msg) 216 : RenderMessageCompletionCallback(filter, reply_msg), 217 context_(context), 218 host_(NULL), 219 sent_plugin_channel_request_(false) { 220 } 221 222 virtual int ID() OVERRIDE { 223 return filter()->render_process_id(); 224 } 225 226 virtual ResourceContext* GetResourceContext() OVERRIDE { 227 return context_; 228 } 229 230 virtual bool OffTheRecord() OVERRIDE { 231 if (filter()->OffTheRecord()) 232 return true; 233 if (GetContentClient()->browser()->AllowSaveLocalState(context_)) 234 return false; 235 236 // For now, only disallow storing data for Flash <http://crbug.com/97319>. 237 for (size_t i = 0; i < info_.mime_types.size(); ++i) { 238 if (info_.mime_types[i].mime_type == kFlashPluginSwfMimeType) 239 return true; 240 } 241 return false; 242 } 243 244 virtual void SetPluginInfo(const WebPluginInfo& info) OVERRIDE { 245 info_ = info; 246 } 247 248 virtual void OnFoundPluginProcessHost(PluginProcessHost* host) OVERRIDE { 249 DCHECK(host); 250 host_ = host; 251 } 252 253 virtual void OnSentPluginChannelRequest() OVERRIDE { 254 sent_plugin_channel_request_ = true; 255 } 256 257 virtual void OnChannelOpened(const IPC::ChannelHandle& handle) OVERRIDE { 258 WriteReplyAndDeleteThis(handle); 259 } 260 261 virtual void OnError() OVERRIDE { 262 WriteReplyAndDeleteThis(IPC::ChannelHandle()); 263 } 264 265 PluginProcessHost* host() const { 266 return host_; 267 } 268 269 bool sent_plugin_channel_request() const { 270 return sent_plugin_channel_request_; 271 } 272 273 void Cancel() { 274 delete this; 275 } 276 277 private: 278 void WriteReplyAndDeleteThis(const IPC::ChannelHandle& handle) { 279 ViewHostMsg_OpenChannelToPlugin::WriteReplyParams(reply_msg(), 280 handle, info_); 281 filter()->OnCompletedOpenChannelToNpapiPlugin(this); 282 SendReplyAndDeleteThis(); 283 } 284 285 ResourceContext* context_; 286 WebPluginInfo info_; 287 PluginProcessHost* host_; 288 bool sent_plugin_channel_request_; 289}; 290 291RenderMessageFilter::RenderMessageFilter( 292 int render_process_id, 293 bool is_guest, 294 PluginServiceImpl* plugin_service, 295 BrowserContext* browser_context, 296 net::URLRequestContextGetter* request_context, 297 RenderWidgetHelper* render_widget_helper, 298 media::AudioManager* audio_manager, 299 MediaInternals* media_internals, 300 DOMStorageContextImpl* dom_storage_context) 301 : resource_dispatcher_host_(ResourceDispatcherHostImpl::Get()), 302 plugin_service_(plugin_service), 303 profile_data_directory_(browser_context->GetPath()), 304 request_context_(request_context), 305 resource_context_(browser_context->GetResourceContext()), 306 render_widget_helper_(render_widget_helper), 307 incognito_(browser_context->IsOffTheRecord()), 308 dom_storage_context_(dom_storage_context), 309 render_process_id_(render_process_id), 310 is_guest_(is_guest), 311 cpu_usage_(0), 312 audio_manager_(audio_manager), 313 media_internals_(media_internals) { 314 DCHECK(request_context_.get()); 315 316 render_widget_helper_->Init(render_process_id_, resource_dispatcher_host_); 317} 318 319RenderMessageFilter::~RenderMessageFilter() { 320 // This function should be called on the IO thread. 321 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 322 DCHECK(plugin_host_clients_.empty()); 323} 324 325void RenderMessageFilter::OnChannelClosing() { 326 BrowserMessageFilter::OnChannelClosing(); 327#if defined(ENABLE_PLUGINS) 328 for (std::set<OpenChannelToNpapiPluginCallback*>::iterator it = 329 plugin_host_clients_.begin(); it != plugin_host_clients_.end(); ++it) { 330 OpenChannelToNpapiPluginCallback* client = *it; 331 if (client->host()) { 332 if (client->sent_plugin_channel_request()) { 333 client->host()->CancelSentRequest(client); 334 } else { 335 client->host()->CancelPendingRequest(client); 336 } 337 } else { 338 plugin_service_->CancelOpenChannelToNpapiPlugin(client); 339 } 340 client->Cancel(); 341 } 342#endif // defined(ENABLE_PLUGINS) 343 plugin_host_clients_.clear(); 344} 345 346void RenderMessageFilter::OnChannelConnected(int32 peer_id) { 347 BrowserMessageFilter::OnChannelConnected(peer_id); 348 base::ProcessHandle handle = PeerHandle(); 349#if defined(OS_MACOSX) 350 process_metrics_.reset(base::ProcessMetrics::CreateProcessMetrics(handle, 351 NULL)); 352#else 353 process_metrics_.reset(base::ProcessMetrics::CreateProcessMetrics(handle)); 354#endif 355 cpu_usage_ = process_metrics_->GetCPUUsage(); // Initialize CPU usage counters 356 cpu_usage_sample_time_ = base::TimeTicks::Now(); 357} 358 359bool RenderMessageFilter::OnMessageReceived(const IPC::Message& message, 360 bool* message_was_ok) { 361 bool handled = true; 362 IPC_BEGIN_MESSAGE_MAP_EX(RenderMessageFilter, message, *message_was_ok) 363#if defined(OS_WIN) 364 IPC_MESSAGE_HANDLER(ViewHostMsg_PreCacheFontCharacters, 365 OnPreCacheFontCharacters) 366#endif 367 IPC_MESSAGE_HANDLER(ViewHostMsg_GetProcessMemorySizes, 368 OnGetProcessMemorySizes) 369 IPC_MESSAGE_HANDLER(ViewHostMsg_GenerateRoutingID, OnGenerateRoutingID) 370 IPC_MESSAGE_HANDLER(ViewHostMsg_CreateWindow, OnCreateWindow) 371 IPC_MESSAGE_HANDLER(ViewHostMsg_CreateWidget, OnCreateWidget) 372 IPC_MESSAGE_HANDLER(ViewHostMsg_CreateFullscreenWidget, 373 OnCreateFullscreenWidget) 374 IPC_MESSAGE_HANDLER(ViewHostMsg_SetCookie, OnSetCookie) 375 IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_GetCookies, OnGetCookies) 376 IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_GetRawCookies, OnGetRawCookies) 377 IPC_MESSAGE_HANDLER(ViewHostMsg_DeleteCookie, OnDeleteCookie) 378 IPC_MESSAGE_HANDLER(ViewHostMsg_CookiesEnabled, OnCookiesEnabled) 379#if defined(OS_MACOSX) 380 IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_LoadFont, OnLoadFont) 381#endif 382 IPC_MESSAGE_HANDLER(ViewHostMsg_DownloadUrl, OnDownloadUrl) 383#if defined(ENABLE_PLUGINS) 384 IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_GetPlugins, OnGetPlugins) 385 IPC_MESSAGE_HANDLER(ViewHostMsg_GetPluginInfo, OnGetPluginInfo) 386 IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_OpenChannelToPlugin, 387 OnOpenChannelToPlugin) 388 IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_OpenChannelToPepperPlugin, 389 OnOpenChannelToPepperPlugin) 390 IPC_MESSAGE_HANDLER(ViewHostMsg_DidCreateOutOfProcessPepperInstance, 391 OnDidCreateOutOfProcessPepperInstance) 392 IPC_MESSAGE_HANDLER(ViewHostMsg_DidDeleteOutOfProcessPepperInstance, 393 OnDidDeleteOutOfProcessPepperInstance) 394 IPC_MESSAGE_HANDLER(ViewHostMsg_OpenChannelToPpapiBroker, 395 OnOpenChannelToPpapiBroker) 396#endif 397 IPC_MESSAGE_HANDLER_GENERIC(ViewHostMsg_UpdateRect, 398 render_widget_helper_->DidReceiveBackingStoreMsg(message)) 399 IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateIsDelayed, OnUpdateIsDelayed) 400 IPC_MESSAGE_HANDLER(DesktopNotificationHostMsg_CheckPermission, 401 OnCheckNotificationPermission) 402 IPC_MESSAGE_HANDLER(ChildProcessHostMsg_SyncAllocateSharedMemory, 403 OnAllocateSharedMemory) 404#if defined(OS_POSIX) && !defined(TOOLKIT_GTK) && !defined(OS_ANDROID) 405 IPC_MESSAGE_HANDLER(ViewHostMsg_AllocTransportDIB, OnAllocTransportDIB) 406 IPC_MESSAGE_HANDLER(ViewHostMsg_FreeTransportDIB, OnFreeTransportDIB) 407#endif 408 IPC_MESSAGE_HANDLER(ViewHostMsg_DidGenerateCacheableMetadata, 409 OnCacheableMetadataAvailable) 410 IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_Keygen, OnKeygen) 411 IPC_MESSAGE_HANDLER(ViewHostMsg_AsyncOpenFile, OnAsyncOpenFile) 412 IPC_MESSAGE_HANDLER(ViewHostMsg_GetCPUUsage, OnGetCPUUsage) 413 IPC_MESSAGE_HANDLER(ViewHostMsg_GetAudioHardwareConfig, 414 OnGetAudioHardwareConfig) 415 IPC_MESSAGE_HANDLER(ViewHostMsg_GetMonitorColorProfile, 416 OnGetMonitorColorProfile) 417 IPC_MESSAGE_HANDLER(ViewHostMsg_MediaLogEvents, OnMediaLogEvents) 418 IPC_MESSAGE_HANDLER(ViewHostMsg_Are3DAPIsBlocked, OnAre3DAPIsBlocked) 419 IPC_MESSAGE_HANDLER(ViewHostMsg_DidLose3DContext, OnDidLose3DContext) 420#if defined(OS_ANDROID) 421 IPC_MESSAGE_HANDLER(ViewHostMsg_RunWebAudioMediaCodec, OnWebAudioMediaCodec) 422#endif 423 IPC_MESSAGE_UNHANDLED(handled = false) 424 IPC_END_MESSAGE_MAP_EX() 425 426 return handled; 427} 428 429void RenderMessageFilter::OnDestruct() const { 430 BrowserThread::DeleteOnIOThread::Destruct(this); 431} 432 433base::TaskRunner* RenderMessageFilter::OverrideTaskRunnerForMessage( 434 const IPC::Message& message) { 435#if defined(OS_WIN) 436 // Windows monitor profile must be read from a file. 437 if (message.type() == ViewHostMsg_GetMonitorColorProfile::ID) 438 return BrowserThread::GetBlockingPool(); 439#endif 440#if defined(OS_MACOSX) 441 // OSX CoreAudio calls must all happen on the main thread. 442 if (message.type() == ViewHostMsg_GetAudioHardwareConfig::ID) 443 return audio_manager_->GetMessageLoop().get(); 444#endif 445 return NULL; 446} 447 448bool RenderMessageFilter::OffTheRecord() const { 449 return incognito_; 450} 451 452void RenderMessageFilter::OnCreateWindow( 453 const ViewHostMsg_CreateWindow_Params& params, 454 int* route_id, 455 int* main_frame_route_id, 456 int* surface_id, 457 int64* cloned_session_storage_namespace_id) { 458 bool no_javascript_access; 459 bool can_create_window = 460 GetContentClient()->browser()->CanCreateWindow( 461 params.opener_url, 462 params.opener_security_origin, 463 params.window_container_type, 464 params.target_url, 465 params.referrer, 466 params.disposition, 467 params.features, 468 params.user_gesture, 469 params.opener_suppressed, 470 resource_context_, 471 render_process_id_, 472 is_guest_, 473 params.opener_id, 474 &no_javascript_access); 475 476 if (!can_create_window) { 477 *route_id = MSG_ROUTING_NONE; 478 *main_frame_route_id = MSG_ROUTING_NONE; 479 *surface_id = 0; 480 return; 481 } 482 483 // This will clone the sessionStorage for namespace_id_to_clone. 484 scoped_refptr<SessionStorageNamespaceImpl> cloned_namespace = 485 new SessionStorageNamespaceImpl(dom_storage_context_.get(), 486 params.session_storage_namespace_id); 487 *cloned_session_storage_namespace_id = cloned_namespace->id(); 488 489 render_widget_helper_->CreateNewWindow(params, 490 no_javascript_access, 491 PeerHandle(), 492 route_id, 493 main_frame_route_id, 494 surface_id, 495 cloned_namespace.get()); 496} 497 498void RenderMessageFilter::OnCreateWidget(int opener_id, 499 WebKit::WebPopupType popup_type, 500 int* route_id, 501 int* surface_id) { 502 render_widget_helper_->CreateNewWidget( 503 opener_id, popup_type, route_id, surface_id); 504} 505 506void RenderMessageFilter::OnCreateFullscreenWidget(int opener_id, 507 int* route_id, 508 int* surface_id) { 509 render_widget_helper_->CreateNewFullscreenWidget( 510 opener_id, route_id, surface_id); 511} 512 513void RenderMessageFilter::OnGetProcessMemorySizes(size_t* private_bytes, 514 size_t* shared_bytes) { 515 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 516 using base::ProcessMetrics; 517#if !defined(OS_MACOSX) || defined(OS_IOS) 518 scoped_ptr<ProcessMetrics> metrics(ProcessMetrics::CreateProcessMetrics( 519 PeerHandle())); 520#else 521 scoped_ptr<ProcessMetrics> metrics(ProcessMetrics::CreateProcessMetrics( 522 PeerHandle(), content::BrowserChildProcessHost::GetPortProvider())); 523#endif 524 if (!metrics->GetMemoryBytes(private_bytes, shared_bytes)) { 525 *private_bytes = 0; 526 *shared_bytes = 0; 527 } 528} 529 530void RenderMessageFilter::OnSetCookie(const IPC::Message& message, 531 const GURL& url, 532 const GURL& first_party_for_cookies, 533 const std::string& cookie) { 534 ChildProcessSecurityPolicyImpl* policy = 535 ChildProcessSecurityPolicyImpl::GetInstance(); 536 if (!policy->CanAccessCookiesForOrigin(render_process_id_, url)) 537 return; 538 539 net::CookieOptions options; 540 if (GetContentClient()->browser()->AllowSetCookie( 541 url, first_party_for_cookies, cookie, 542 resource_context_, render_process_id_, message.routing_id(), 543 &options)) { 544 net::URLRequestContext* context = GetRequestContextForURL(url); 545 // Pass a null callback since we don't care about when the 'set' completes. 546 context->cookie_store()->SetCookieWithOptionsAsync( 547 url, cookie, options, net::CookieMonster::SetCookiesCallback()); 548 } 549} 550 551void RenderMessageFilter::OnGetCookies(const GURL& url, 552 const GURL& first_party_for_cookies, 553 IPC::Message* reply_msg) { 554 ChildProcessSecurityPolicyImpl* policy = 555 ChildProcessSecurityPolicyImpl::GetInstance(); 556 if (!policy->CanAccessCookiesForOrigin(render_process_id_, url)) { 557 SendGetCookiesResponse(reply_msg, std::string()); 558 return; 559 } 560 561 // If we crash here, figure out what URL the renderer was requesting. 562 // http://crbug.com/99242 563 char url_buf[128]; 564 base::strlcpy(url_buf, url.spec().c_str(), arraysize(url_buf)); 565 base::debug::Alias(url_buf); 566 567 net::URLRequestContext* context = GetRequestContextForURL(url); 568 net::CookieMonster* cookie_monster = 569 context->cookie_store()->GetCookieMonster(); 570 cookie_monster->GetAllCookiesForURLAsync( 571 url, base::Bind(&RenderMessageFilter::CheckPolicyForCookies, this, url, 572 first_party_for_cookies, reply_msg)); 573} 574 575void RenderMessageFilter::OnGetRawCookies( 576 const GURL& url, 577 const GURL& first_party_for_cookies, 578 IPC::Message* reply_msg) { 579 ChildProcessSecurityPolicyImpl* policy = 580 ChildProcessSecurityPolicyImpl::GetInstance(); 581 // Only return raw cookies to trusted renderers or if this request is 582 // not targeted to an an external host like ChromeFrame. 583 // TODO(ananta) We need to support retreiving raw cookies from external 584 // hosts. 585 if (!policy->CanReadRawCookies(render_process_id_) || 586 !policy->CanAccessCookiesForOrigin(render_process_id_, url)) { 587 SendGetRawCookiesResponse(reply_msg, net::CookieList()); 588 return; 589 } 590 591 // We check policy here to avoid sending back cookies that would not normally 592 // be applied to outbound requests for the given URL. Since this cookie info 593 // is visible in the developer tools, it is helpful to make it match reality. 594 net::URLRequestContext* context = GetRequestContextForURL(url); 595 net::CookieMonster* cookie_monster = 596 context->cookie_store()->GetCookieMonster(); 597 cookie_monster->GetAllCookiesForURLAsync( 598 url, base::Bind(&RenderMessageFilter::SendGetRawCookiesResponse, 599 this, reply_msg)); 600} 601 602void RenderMessageFilter::OnDeleteCookie(const GURL& url, 603 const std::string& cookie_name) { 604 ChildProcessSecurityPolicyImpl* policy = 605 ChildProcessSecurityPolicyImpl::GetInstance(); 606 if (!policy->CanAccessCookiesForOrigin(render_process_id_, url)) 607 return; 608 609 net::URLRequestContext* context = GetRequestContextForURL(url); 610 context->cookie_store()->DeleteCookieAsync(url, cookie_name, base::Closure()); 611} 612 613void RenderMessageFilter::OnCookiesEnabled( 614 const GURL& url, 615 const GURL& first_party_for_cookies, 616 bool* cookies_enabled) { 617 // TODO(ananta): If this render view is associated with an automation channel, 618 // aka ChromeFrame then we need to retrieve cookie settings from the external 619 // host. 620 *cookies_enabled = GetContentClient()->browser()->AllowGetCookie( 621 url, first_party_for_cookies, net::CookieList(), resource_context_, 622 render_process_id_, MSG_ROUTING_CONTROL); 623} 624 625#if defined(OS_MACOSX) 626void RenderMessageFilter::OnLoadFont(const FontDescriptor& font, 627 IPC::Message* reply_msg) { 628 FontLoader::Result* result = new FontLoader::Result; 629 630 BrowserThread::PostTaskAndReply( 631 BrowserThread::FILE, FROM_HERE, 632 base::Bind(&FontLoader::LoadFont, font, result), 633 base::Bind(&RenderMessageFilter::SendLoadFontReply, this, reply_msg, 634 base::Owned(result))); 635} 636 637void RenderMessageFilter::SendLoadFontReply(IPC::Message* reply, 638 FontLoader::Result* result) { 639 base::SharedMemoryHandle handle; 640 if (result->font_data_size == 0 || result->font_id == 0) { 641 result->font_data_size = 0; 642 result->font_id = 0; 643 handle = base::SharedMemory::NULLHandle(); 644 } else { 645 result->font_data.GiveToProcess(base::GetCurrentProcessHandle(), &handle); 646 } 647 ViewHostMsg_LoadFont::WriteReplyParams( 648 reply, result->font_data_size, handle, result->font_id); 649 Send(reply); 650} 651#endif // OS_MACOSX 652 653void RenderMessageFilter::OnGetPlugins( 654 bool refresh, 655 IPC::Message* reply_msg) { 656 // Don't refresh if the specified threshold has not been passed. Note that 657 // this check is performed before off-loading to the file thread. The reason 658 // we do this is that some pages tend to request that the list of plugins be 659 // refreshed at an excessive rate. This instigates disk scanning, as the list 660 // is accumulated by doing multiple reads from disk. This effect is 661 // multiplied when we have several pages requesting this operation. 662 if (refresh) { 663 const base::TimeDelta threshold = base::TimeDelta::FromSeconds( 664 kPluginsRefreshThresholdInSeconds); 665 const base::TimeTicks now = base::TimeTicks::Now(); 666 if (now - last_plugin_refresh_time_ >= threshold) { 667 // Only refresh if the threshold hasn't been exceeded yet. 668 PluginServiceImpl::GetInstance()->RefreshPlugins(); 669 last_plugin_refresh_time_ = now; 670 } 671 } 672 673 PluginServiceImpl::GetInstance()->GetPlugins( 674 base::Bind(&RenderMessageFilter::GetPluginsCallback, this, reply_msg)); 675} 676 677void RenderMessageFilter::GetPluginsCallback( 678 IPC::Message* reply_msg, 679 const std::vector<WebPluginInfo>& all_plugins) { 680 // Filter the plugin list. 681 PluginServiceFilter* filter = PluginServiceImpl::GetInstance()->GetFilter(); 682 std::vector<WebPluginInfo> plugins; 683 684 int child_process_id = -1; 685 int routing_id = MSG_ROUTING_NONE; 686 for (size_t i = 0; i < all_plugins.size(); ++i) { 687 // Copy because the filter can mutate. 688 WebPluginInfo plugin(all_plugins[i]); 689 if (!filter || filter->IsPluginAvailable(child_process_id, 690 routing_id, 691 resource_context_, 692 GURL(), 693 GURL(), 694 &plugin)) { 695 plugins.push_back(plugin); 696 } 697 } 698 699 ViewHostMsg_GetPlugins::WriteReplyParams(reply_msg, plugins); 700 Send(reply_msg); 701} 702 703void RenderMessageFilter::OnGetPluginInfo( 704 int routing_id, 705 const GURL& url, 706 const GURL& page_url, 707 const std::string& mime_type, 708 bool* found, 709 WebPluginInfo* info, 710 std::string* actual_mime_type) { 711 bool allow_wildcard = true; 712 *found = plugin_service_->GetPluginInfo( 713 render_process_id_, routing_id, resource_context_, 714 url, page_url, mime_type, allow_wildcard, 715 NULL, info, actual_mime_type); 716} 717 718void RenderMessageFilter::OnOpenChannelToPlugin(int routing_id, 719 const GURL& url, 720 const GURL& policy_url, 721 const std::string& mime_type, 722 IPC::Message* reply_msg) { 723 OpenChannelToNpapiPluginCallback* client = 724 new OpenChannelToNpapiPluginCallback(this, resource_context_, reply_msg); 725 DCHECK(!ContainsKey(plugin_host_clients_, client)); 726 plugin_host_clients_.insert(client); 727 plugin_service_->OpenChannelToNpapiPlugin( 728 render_process_id_, routing_id, 729 url, policy_url, mime_type, client); 730} 731 732void RenderMessageFilter::OnOpenChannelToPepperPlugin( 733 const base::FilePath& path, 734 IPC::Message* reply_msg) { 735 plugin_service_->OpenChannelToPpapiPlugin( 736 render_process_id_, 737 path, 738 profile_data_directory_, 739 new OpenChannelToPpapiPluginCallback(this, resource_context_, reply_msg)); 740} 741 742void RenderMessageFilter::OnDidCreateOutOfProcessPepperInstance( 743 int plugin_child_id, 744 int32 pp_instance, 745 PepperRendererInstanceData instance_data, 746 bool is_external) { 747 // It's important that we supply the render process ID ourselves based on the 748 // channel the message arrived on. We use the 749 // PP_Instance -> (process id, view id) 750 // mapping to decide how to handle messages received from the (untrusted) 751 // plugin, so an exploited renderer must not be able to insert fake mappings 752 // that may allow it access to other render processes. 753 DCHECK_EQ(0, instance_data.render_process_id); 754 instance_data.render_process_id = render_process_id_; 755 if (is_external) { 756 // We provide the BrowserPpapiHost to the embedder, so it's safe to cast. 757 BrowserPpapiHostImpl* host = static_cast<BrowserPpapiHostImpl*>( 758 GetContentClient()->browser()->GetExternalBrowserPpapiHost( 759 plugin_child_id)); 760 if (host) 761 host->AddInstance(pp_instance, instance_data); 762 } else { 763 PpapiPluginProcessHost::DidCreateOutOfProcessInstance( 764 plugin_child_id, pp_instance, instance_data); 765 } 766} 767 768void RenderMessageFilter::OnDidDeleteOutOfProcessPepperInstance( 769 int plugin_child_id, 770 int32 pp_instance, 771 bool is_external) { 772 if (is_external) { 773 // We provide the BrowserPpapiHost to the embedder, so it's safe to cast. 774 BrowserPpapiHostImpl* host = static_cast<BrowserPpapiHostImpl*>( 775 GetContentClient()->browser()->GetExternalBrowserPpapiHost( 776 plugin_child_id)); 777 if (host) 778 host->DeleteInstance(pp_instance); 779 } else { 780 PpapiPluginProcessHost::DidDeleteOutOfProcessInstance( 781 plugin_child_id, pp_instance); 782 } 783} 784 785void RenderMessageFilter::OnOpenChannelToPpapiBroker( 786 int routing_id, 787 int request_id, 788 const base::FilePath& path) { 789 plugin_service_->OpenChannelToPpapiBroker( 790 render_process_id_, 791 path, 792 new OpenChannelToPpapiBrokerCallback(this, routing_id, request_id)); 793} 794 795void RenderMessageFilter::OnGenerateRoutingID(int* route_id) { 796 *route_id = render_widget_helper_->GetNextRoutingID(); 797} 798 799void RenderMessageFilter::OnGetCPUUsage(int* cpu_usage) { 800 base::TimeTicks now = base::TimeTicks::Now(); 801 int64 since_last_sample_ms = (now - cpu_usage_sample_time_).InMilliseconds(); 802 if (since_last_sample_ms > kCPUUsageSampleIntervalMs) { 803 cpu_usage_sample_time_ = now; 804 cpu_usage_ = static_cast<int>(process_metrics_->GetCPUUsage()); 805 } 806 *cpu_usage = cpu_usage_; 807} 808 809void RenderMessageFilter::OnGetAudioHardwareConfig( 810 media::AudioParameters* input_params, 811 media::AudioParameters* output_params) { 812 DCHECK(input_params); 813 DCHECK(output_params); 814 *output_params = audio_manager_->GetDefaultOutputStreamParameters(); 815 816 // TODO(henrika): add support for all available input devices. 817 *input_params = audio_manager_->GetInputStreamParameters( 818 media::AudioManagerBase::kDefaultDeviceId); 819} 820 821void RenderMessageFilter::OnGetMonitorColorProfile(std::vector<char>* profile) { 822#if defined(OS_WIN) 823 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::IO)); 824 if (BackingStoreWin::ColorManagementEnabled()) 825 return; 826#endif 827 *profile = g_color_profile.Get().profile(); 828} 829 830void RenderMessageFilter::OnDownloadUrl(const IPC::Message& message, 831 const GURL& url, 832 const Referrer& referrer, 833 const string16& suggested_name) { 834 scoped_ptr<DownloadSaveInfo> save_info(new DownloadSaveInfo()); 835 save_info->suggested_name = suggested_name; 836 scoped_ptr<net::URLRequest> request( 837 resource_context_->GetRequestContext()->CreateRequest(url, NULL)); 838 RecordDownloadSource(INITIATED_BY_RENDERER); 839 resource_dispatcher_host_->BeginDownload( 840 request.Pass(), 841 referrer, 842 true, // is_content_initiated 843 resource_context_, 844 render_process_id_, 845 message.routing_id(), 846 false, 847 save_info.Pass(), 848 content::DownloadItem::kInvalidId, 849 ResourceDispatcherHostImpl::DownloadStartedCallback()); 850} 851 852void RenderMessageFilter::OnCheckNotificationPermission( 853 const GURL& source_origin, int* result) { 854#if defined(ENABLE_NOTIFICATIONS) 855 *result = GetContentClient()->browser()-> 856 CheckDesktopNotificationPermission(source_origin, resource_context_, 857 render_process_id_); 858#else 859 *result = WebKit::WebNotificationPresenter::PermissionAllowed; 860#endif 861} 862 863void RenderMessageFilter::OnAllocateSharedMemory( 864 uint32 buffer_size, 865 base::SharedMemoryHandle* handle) { 866 ChildProcessHostImpl::AllocateSharedMemory( 867 buffer_size, PeerHandle(), handle); 868} 869 870net::URLRequestContext* RenderMessageFilter::GetRequestContextForURL( 871 const GURL& url) { 872 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 873 874 net::URLRequestContext* context = 875 GetContentClient()->browser()->OverrideRequestContextForURL( 876 url, resource_context_); 877 if (!context) 878 context = request_context_->GetURLRequestContext(); 879 880 return context; 881} 882 883#if defined(OS_POSIX) && !defined(TOOLKIT_GTK) && !defined(OS_ANDROID) 884void RenderMessageFilter::OnAllocTransportDIB( 885 uint32 size, bool cache_in_browser, TransportDIB::Handle* handle) { 886 render_widget_helper_->AllocTransportDIB(size, cache_in_browser, handle); 887} 888 889void RenderMessageFilter::OnFreeTransportDIB( 890 TransportDIB::Id dib_id) { 891 render_widget_helper_->FreeTransportDIB(dib_id); 892} 893#endif 894 895bool RenderMessageFilter::CheckPreparsedJsCachingEnabled() const { 896 static bool checked = false; 897 static bool result = false; 898 if (!checked) { 899 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); 900 result = command_line.HasSwitch(switches::kEnablePreparsedJsCaching); 901 checked = true; 902 } 903 return result; 904} 905 906void RenderMessageFilter::OnCacheableMetadataAvailable( 907 const GURL& url, 908 double expected_response_time, 909 const std::vector<char>& data) { 910 if (!CheckPreparsedJsCachingEnabled()) 911 return; 912 913 net::HttpCache* cache = request_context_->GetURLRequestContext()-> 914 http_transaction_factory()->GetCache(); 915 DCHECK(cache); 916 917 // Use the same priority for the metadata write as for script 918 // resources (see defaultPriorityForResourceType() in WebKit's 919 // CachedResource.cpp). Note that WebURLRequest::PriorityMedium 920 // corresponds to net::LOW (see ConvertWebKitPriorityToNetPriority() 921 // in weburlloader_impl.cc). 922 const net::RequestPriority kPriority = net::LOW; 923 scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(data.size())); 924 memcpy(buf->data(), &data.front(), data.size()); 925 cache->WriteMetadata(url, 926 kPriority, 927 base::Time::FromDoubleT(expected_response_time), 928 buf.get(), 929 data.size()); 930} 931 932void RenderMessageFilter::OnKeygen(uint32 key_size_index, 933 const std::string& challenge_string, 934 const GURL& url, 935 IPC::Message* reply_msg) { 936 // Map displayed strings indicating level of keysecurity in the <keygen> 937 // menu to the key size in bits. (See SSLKeyGeneratorChromium.cpp in WebCore.) 938 int key_size_in_bits; 939 switch (key_size_index) { 940 case 0: 941 key_size_in_bits = 2048; 942 break; 943 case 1: 944 key_size_in_bits = 1024; 945 break; 946 default: 947 DCHECK(false) << "Illegal key_size_index " << key_size_index; 948 ViewHostMsg_Keygen::WriteReplyParams(reply_msg, std::string()); 949 Send(reply_msg); 950 return; 951 } 952 953 VLOG(1) << "Dispatching keygen task to worker pool."; 954 // Dispatch to worker pool, so we do not block the IO thread. 955 if (!base::WorkerPool::PostTask( 956 FROM_HERE, 957 base::Bind( 958 &RenderMessageFilter::OnKeygenOnWorkerThread, this, 959 key_size_in_bits, challenge_string, url, reply_msg), 960 true)) { 961 NOTREACHED() << "Failed to dispatch keygen task to worker pool"; 962 ViewHostMsg_Keygen::WriteReplyParams(reply_msg, std::string()); 963 Send(reply_msg); 964 return; 965 } 966} 967 968void RenderMessageFilter::OnKeygenOnWorkerThread( 969 int key_size_in_bits, 970 const std::string& challenge_string, 971 const GURL& url, 972 IPC::Message* reply_msg) { 973 DCHECK(reply_msg); 974 975 // Generate a signed public key and challenge, then send it back. 976 net::KeygenHandler keygen_handler(key_size_in_bits, challenge_string, url); 977 978#if defined(USE_NSS) 979 // Attach a password delegate so we can authenticate. 980 keygen_handler.set_crypto_module_password_delegate( 981 GetContentClient()->browser()->GetCryptoPasswordDelegate(url)); 982#endif // defined(USE_NSS) 983 984 ViewHostMsg_Keygen::WriteReplyParams( 985 reply_msg, 986 keygen_handler.GenKeyAndSignChallenge()); 987 Send(reply_msg); 988} 989 990void RenderMessageFilter::OnAsyncOpenFile(const IPC::Message& msg, 991 const base::FilePath& path, 992 int flags, 993 int message_id) { 994 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 995 996 if (!ChildProcessSecurityPolicyImpl::GetInstance()->HasPermissionsForFile( 997 render_process_id_, path, flags)) { 998 DLOG(ERROR) << "Bad flags in ViewMsgHost_AsyncOpenFile message: " << flags; 999 RecordAction(UserMetricsAction("BadMessageTerminate_AOF")); 1000 BadMessageReceived(); 1001 return; 1002 } 1003 1004 BrowserThread::PostTask( 1005 BrowserThread::FILE, FROM_HERE, base::Bind( 1006 &RenderMessageFilter::AsyncOpenFileOnFileThread, this, 1007 path, flags, message_id, msg.routing_id())); 1008} 1009 1010void RenderMessageFilter::AsyncOpenFileOnFileThread(const base::FilePath& path, 1011 int flags, 1012 int message_id, 1013 int routing_id) { 1014 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 1015 base::PlatformFileError error_code = base::PLATFORM_FILE_OK; 1016 base::PlatformFile file = base::CreatePlatformFile( 1017 path, flags, NULL, &error_code); 1018 IPC::PlatformFileForTransit file_for_transit = 1019 file != base::kInvalidPlatformFileValue ? 1020 IPC::GetFileHandleForProcess(file, PeerHandle(), true) : 1021 IPC::InvalidPlatformFileForTransit(); 1022 1023 IPC::Message* reply = new ViewMsg_AsyncOpenFile_ACK( 1024 routing_id, error_code, file_for_transit, message_id); 1025 BrowserThread::PostTask( 1026 BrowserThread::IO, FROM_HERE, 1027 base::Bind(base::IgnoreResult(&RenderMessageFilter::Send), this, reply)); 1028} 1029 1030void RenderMessageFilter::OnMediaLogEvents( 1031 const std::vector<media::MediaLogEvent>& events) { 1032 if (media_internals_) 1033 media_internals_->OnMediaEvents(render_process_id_, events); 1034} 1035 1036void RenderMessageFilter::CheckPolicyForCookies( 1037 const GURL& url, 1038 const GURL& first_party_for_cookies, 1039 IPC::Message* reply_msg, 1040 const net::CookieList& cookie_list) { 1041 net::URLRequestContext* context = GetRequestContextForURL(url); 1042 // Check the policy for get cookies, and pass cookie_list to the 1043 // TabSpecificContentSetting for logging purpose. 1044 if (GetContentClient()->browser()->AllowGetCookie( 1045 url, first_party_for_cookies, cookie_list, resource_context_, 1046 render_process_id_, reply_msg->routing_id())) { 1047 // Gets the cookies from cookie store if allowed. 1048 context->cookie_store()->GetCookiesWithOptionsAsync( 1049 url, net::CookieOptions(), 1050 base::Bind(&RenderMessageFilter::SendGetCookiesResponse, 1051 this, reply_msg)); 1052 } else { 1053 SendGetCookiesResponse(reply_msg, std::string()); 1054 } 1055} 1056 1057void RenderMessageFilter::SendGetCookiesResponse(IPC::Message* reply_msg, 1058 const std::string& cookies) { 1059 ViewHostMsg_GetCookies::WriteReplyParams(reply_msg, cookies); 1060 Send(reply_msg); 1061} 1062 1063void RenderMessageFilter::SendGetRawCookiesResponse( 1064 IPC::Message* reply_msg, 1065 const net::CookieList& cookie_list) { 1066 std::vector<CookieData> cookies; 1067 for (size_t i = 0; i < cookie_list.size(); ++i) 1068 cookies.push_back(CookieData(cookie_list[i])); 1069 ViewHostMsg_GetRawCookies::WriteReplyParams(reply_msg, cookies); 1070 Send(reply_msg); 1071} 1072 1073void RenderMessageFilter::OnCompletedOpenChannelToNpapiPlugin( 1074 OpenChannelToNpapiPluginCallback* client) { 1075 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 1076 DCHECK(ContainsKey(plugin_host_clients_, client)); 1077 plugin_host_clients_.erase(client); 1078} 1079 1080void RenderMessageFilter::OnUpdateIsDelayed(const IPC::Message& msg) { 1081 // When not in accelerated compositing mode, in certain cases (e.g. waiting 1082 // for a resize or if no backing store) the RenderWidgetHost is blocking the 1083 // UI thread for some time, waiting for an UpdateRect from the renderer. If we 1084 // are going to switch to accelerated compositing, the GPU process may need 1085 // round-trips to the UI thread before finishing the frame, causing deadlocks 1086 // if we delay the UpdateRect until we receive the OnSwapBuffersComplete. So 1087 // the renderer sent us this message, so that we can unblock the UI thread. 1088 // We will simply re-use the UpdateRect unblock mechanism, just with a 1089 // different message. 1090 render_widget_helper_->DidReceiveBackingStoreMsg(msg); 1091} 1092 1093void RenderMessageFilter::OnAre3DAPIsBlocked(int render_view_id, 1094 const GURL& top_origin_url, 1095 ThreeDAPIType requester, 1096 bool* blocked) { 1097 *blocked = GpuDataManagerImpl::GetInstance()->Are3DAPIsBlocked( 1098 top_origin_url, render_process_id_, render_view_id, requester); 1099} 1100 1101void RenderMessageFilter::OnDidLose3DContext( 1102 const GURL& top_origin_url, 1103 ThreeDAPIType /* unused */, 1104 int arb_robustness_status_code) { 1105#if defined(OS_MACOSX) 1106 // TODO(kbr): this file indirectly includes npapi.h, which on Mac 1107 // OS pulls in the system OpenGL headers. For some 1108 // not-yet-investigated reason this breaks the build with the 10.6 1109 // SDK but not 10.7. For now work around this in a way compatible 1110 // with the Khronos headers. 1111#ifndef GL_GUILTY_CONTEXT_RESET_ARB 1112#define GL_GUILTY_CONTEXT_RESET_ARB 0x8253 1113#endif 1114#ifndef GL_INNOCENT_CONTEXT_RESET_ARB 1115#define GL_INNOCENT_CONTEXT_RESET_ARB 0x8254 1116#endif 1117#ifndef GL_UNKNOWN_CONTEXT_RESET_ARB 1118#define GL_UNKNOWN_CONTEXT_RESET_ARB 0x8255 1119#endif 1120 1121#endif 1122 GpuDataManagerImpl::DomainGuilt guilt; 1123 switch (arb_robustness_status_code) { 1124 case GL_GUILTY_CONTEXT_RESET_ARB: 1125 guilt = GpuDataManagerImpl::DOMAIN_GUILT_KNOWN; 1126 break; 1127 case GL_UNKNOWN_CONTEXT_RESET_ARB: 1128 guilt = GpuDataManagerImpl::DOMAIN_GUILT_UNKNOWN; 1129 break; 1130 default: 1131 // Ignore lost contexts known to be innocent. 1132 return; 1133 } 1134 1135 GpuDataManagerImpl::GetInstance()->BlockDomainFrom3DAPIs( 1136 top_origin_url, guilt); 1137} 1138 1139#if defined(OS_WIN) 1140void RenderMessageFilter::OnPreCacheFontCharacters(const LOGFONT& font, 1141 const string16& str) { 1142 // First, comments from FontCacheDispatcher::OnPreCacheFont do apply here too. 1143 // Except that for True Type fonts, 1144 // GetTextMetrics will not load the font in memory. 1145 // The only way windows seem to load properly, it is to create a similar 1146 // device (like the one in which we print), then do an ExtTextOut, 1147 // as we do in the printing thread, which is sandboxed. 1148 HDC hdc = CreateEnhMetaFile(NULL, NULL, NULL, NULL); 1149 HFONT font_handle = CreateFontIndirect(&font); 1150 DCHECK(NULL != font_handle); 1151 1152 HGDIOBJ old_font = SelectObject(hdc, font_handle); 1153 DCHECK(NULL != old_font); 1154 1155 ExtTextOut(hdc, 0, 0, ETO_GLYPH_INDEX, 0, str.c_str(), str.length(), NULL); 1156 1157 SelectObject(hdc, old_font); 1158 DeleteObject(font_handle); 1159 1160 HENHMETAFILE metafile = CloseEnhMetaFile(hdc); 1161 1162 if (metafile) { 1163 DeleteEnhMetaFile(metafile); 1164 } 1165} 1166#endif 1167 1168#if defined(OS_ANDROID) 1169void RenderMessageFilter::OnWebAudioMediaCodec( 1170 base::SharedMemoryHandle encoded_data_handle, 1171 base::FileDescriptor pcm_output, 1172 uint32_t data_size) { 1173 // Let a WorkerPool handle this request since the WebAudio 1174 // MediaCodec bridge is slow and can block while sending the data to 1175 // the renderer. 1176 base::WorkerPool::PostTask( 1177 FROM_HERE, 1178 base::Bind(&media::WebAudioMediaCodecBridge::RunWebAudioMediaCodec, 1179 encoded_data_handle, pcm_output, data_size), 1180 true); 1181} 1182#endif 1183} // namespace content 1184