ppp_content_decryptor_private_proxy.cc revision 46d4c2bc3267f3f028f39e7e311b0f89aba2e4fd
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 "ppapi/proxy/ppp_content_decryptor_private_proxy.h" 6 7#include "base/files/file.h" 8#include "ppapi/c/pp_bool.h" 9#include "ppapi/c/ppb_core.h" 10#include "ppapi/proxy/content_decryptor_private_serializer.h" 11#include "ppapi/proxy/host_dispatcher.h" 12#include "ppapi/proxy/plugin_globals.h" 13#include "ppapi/proxy/plugin_resource_tracker.h" 14#include "ppapi/proxy/ppapi_messages.h" 15#include "ppapi/proxy/ppb_buffer_proxy.h" 16#include "ppapi/proxy/serialized_var.h" 17#include "ppapi/shared_impl/scoped_pp_resource.h" 18#include "ppapi/shared_impl/var_tracker.h" 19#include "ppapi/thunk/enter.h" 20#include "ppapi/thunk/ppb_buffer_api.h" 21#include "ppapi/thunk/ppb_instance_api.h" 22#include "ppapi/thunk/thunk.h" 23 24using ppapi::thunk::EnterResourceNoLock; 25using ppapi::thunk::PPB_Buffer_API; 26using ppapi::thunk::PPB_Instance_API; 27 28namespace ppapi { 29namespace proxy { 30 31namespace { 32 33PP_Bool DescribeHostBufferResource(PP_Resource resource, uint32_t* size) { 34 EnterResourceNoLock<PPB_Buffer_API> enter(resource, true); 35 if (enter.failed()) 36 return PP_FALSE; 37 return enter.object()->Describe(size); 38} 39 40// TODO(dmichael): Refactor so this handle sharing code is in one place. 41PP_Bool ShareHostBufferResourceToPlugin( 42 HostDispatcher* dispatcher, 43 PP_Resource resource, 44 base::SharedMemoryHandle* shared_mem_handle) { 45 if (!dispatcher || resource == 0 || !shared_mem_handle) 46 return PP_FALSE; 47 EnterResourceNoLock<PPB_Buffer_API> enter(resource, true); 48 if (enter.failed()) 49 return PP_FALSE; 50 int handle; 51 int32_t result = enter.object()->GetSharedMemory(&handle); 52 if (result != PP_OK) 53 return PP_FALSE; 54 base::PlatformFile platform_file = 55 #if defined(OS_WIN) 56 reinterpret_cast<HANDLE>(static_cast<intptr_t>(handle)); 57 #elif defined(OS_POSIX) 58 handle; 59 #else 60 #error Not implemented. 61 #endif 62 63 *shared_mem_handle = dispatcher->ShareHandleWithRemote(platform_file, false); 64 return PP_TRUE; 65} 66 67// SerializedVarReceiveInput will decrement the reference count, but we want 68// to give the recipient a reference. This utility function takes care of that 69// work for the message handlers defined below. 70PP_Var ExtractReceivedVarAndAddRef(Dispatcher* dispatcher, 71 SerializedVarReceiveInput* serialized_var) { 72 PP_Var var = serialized_var->Get(dispatcher); 73 PpapiGlobals::Get()->GetVarTracker()->AddRefVar(var); 74 return var; 75} 76 77bool InitializePppDecryptorBuffer(PP_Instance instance, 78 HostDispatcher* dispatcher, 79 PP_Resource resource, 80 PPPDecryptor_Buffer* buffer) { 81 if (!buffer) { 82 NOTREACHED(); 83 return false; 84 } 85 86 if (resource == 0) { 87 buffer->resource = HostResource(); 88 buffer->handle = base::SharedMemoryHandle(); 89 buffer->size = 0; 90 return true; 91 } 92 93 HostResource host_resource; 94 host_resource.SetHostResource(instance, resource); 95 96 uint32_t size = 0; 97 if (DescribeHostBufferResource(resource, &size) == PP_FALSE) 98 return false; 99 100 base::SharedMemoryHandle handle; 101 if (ShareHostBufferResourceToPlugin(dispatcher, 102 resource, 103 &handle) == PP_FALSE) 104 return false; 105 106 buffer->resource = host_resource; 107 buffer->handle = handle; 108 buffer->size = size; 109 return true; 110} 111 112void Initialize(PP_Instance instance, 113 PP_Var key_system) { 114 HostDispatcher* dispatcher = HostDispatcher::GetForInstance(instance); 115 if (!dispatcher) { 116 NOTREACHED(); 117 return; 118 } 119 120 dispatcher->Send( 121 new PpapiMsg_PPPContentDecryptor_Initialize( 122 API_ID_PPP_CONTENT_DECRYPTOR_PRIVATE, 123 instance, 124 SerializedVarSendInput(dispatcher, key_system))); 125} 126 127void CreateSession(PP_Instance instance, 128 uint32_t session_id, 129 PP_Var type, 130 PP_Var init_data) { 131 HostDispatcher* dispatcher = HostDispatcher::GetForInstance(instance); 132 if (!dispatcher) { 133 NOTREACHED(); 134 return; 135 } 136 137 dispatcher->Send(new PpapiMsg_PPPContentDecryptor_CreateSession( 138 API_ID_PPP_CONTENT_DECRYPTOR_PRIVATE, 139 instance, 140 session_id, 141 SerializedVarSendInput(dispatcher, type), 142 SerializedVarSendInput(dispatcher, init_data))); 143} 144 145void LoadSession(PP_Instance instance, 146 uint32_t session_id, 147 PP_Var web_session_id) { 148 HostDispatcher* dispatcher = HostDispatcher::GetForInstance(instance); 149 if (!dispatcher) { 150 NOTREACHED(); 151 return; 152 } 153 154 dispatcher->Send(new PpapiMsg_PPPContentDecryptor_LoadSession( 155 API_ID_PPP_CONTENT_DECRYPTOR_PRIVATE, 156 instance, 157 session_id, 158 SerializedVarSendInput(dispatcher, web_session_id))); 159} 160 161void UpdateSession(PP_Instance instance, uint32_t session_id, PP_Var response) { 162 HostDispatcher* dispatcher = HostDispatcher::GetForInstance(instance); 163 if (!dispatcher) { 164 NOTREACHED(); 165 return; 166 } 167 168 dispatcher->Send(new PpapiMsg_PPPContentDecryptor_UpdateSession( 169 API_ID_PPP_CONTENT_DECRYPTOR_PRIVATE, 170 instance, 171 session_id, 172 SerializedVarSendInput(dispatcher, response))); 173} 174 175void ReleaseSession(PP_Instance instance, uint32_t session_id) { 176 HostDispatcher* dispatcher = HostDispatcher::GetForInstance(instance); 177 if (!dispatcher) { 178 NOTREACHED(); 179 return; 180 } 181 182 dispatcher->Send(new PpapiMsg_PPPContentDecryptor_ReleaseSession( 183 API_ID_PPP_CONTENT_DECRYPTOR_PRIVATE, instance, session_id)); 184} 185 186void Decrypt(PP_Instance instance, 187 PP_Resource encrypted_block, 188 const PP_EncryptedBlockInfo* encrypted_block_info) { 189 HostDispatcher* dispatcher = HostDispatcher::GetForInstance(instance); 190 if (!dispatcher) { 191 NOTREACHED(); 192 return; 193 } 194 195 PPPDecryptor_Buffer buffer; 196 if (!InitializePppDecryptorBuffer(instance, 197 dispatcher, 198 encrypted_block, 199 &buffer)) { 200 NOTREACHED(); 201 return; 202 } 203 204 std::string serialized_block_info; 205 if (!SerializeBlockInfo(*encrypted_block_info, &serialized_block_info)) { 206 NOTREACHED(); 207 return; 208 } 209 210 // PluginResourceTracker in the plugin process assumes that resources that it 211 // tracks have been addrefed on behalf of the plugin at the renderer side. So 212 // we explicitly do it for |encryped_block| here. 213 PpapiGlobals::Get()->GetResourceTracker()->AddRefResource(encrypted_block); 214 215 dispatcher->Send( 216 new PpapiMsg_PPPContentDecryptor_Decrypt( 217 API_ID_PPP_CONTENT_DECRYPTOR_PRIVATE, 218 instance, 219 buffer, 220 serialized_block_info)); 221} 222 223void InitializeAudioDecoder( 224 PP_Instance instance, 225 const PP_AudioDecoderConfig* decoder_config, 226 PP_Resource extra_data_buffer) { 227 HostDispatcher* dispatcher = HostDispatcher::GetForInstance(instance); 228 if (!dispatcher) { 229 NOTREACHED(); 230 return; 231 } 232 233 std::string serialized_decoder_config; 234 if (!SerializeBlockInfo(*decoder_config, &serialized_decoder_config)) { 235 NOTREACHED(); 236 return; 237 } 238 239 PPPDecryptor_Buffer buffer; 240 if (!InitializePppDecryptorBuffer(instance, 241 dispatcher, 242 extra_data_buffer, 243 &buffer)) { 244 NOTREACHED(); 245 return; 246 } 247 248 // PluginResourceTracker in the plugin process assumes that resources that it 249 // tracks have been addrefed on behalf of the plugin at the renderer side. So 250 // we explicitly do it for |extra_data_buffer| here. 251 PpapiGlobals::Get()->GetResourceTracker()->AddRefResource(extra_data_buffer); 252 253 dispatcher->Send( 254 new PpapiMsg_PPPContentDecryptor_InitializeAudioDecoder( 255 API_ID_PPP_CONTENT_DECRYPTOR_PRIVATE, 256 instance, 257 serialized_decoder_config, 258 buffer)); 259} 260 261void InitializeVideoDecoder( 262 PP_Instance instance, 263 const PP_VideoDecoderConfig* decoder_config, 264 PP_Resource extra_data_buffer) { 265 HostDispatcher* dispatcher = HostDispatcher::GetForInstance(instance); 266 if (!dispatcher) { 267 NOTREACHED(); 268 return; 269 } 270 271 std::string serialized_decoder_config; 272 if (!SerializeBlockInfo(*decoder_config, &serialized_decoder_config)) { 273 NOTREACHED(); 274 return; 275 } 276 277 PPPDecryptor_Buffer buffer; 278 if (!InitializePppDecryptorBuffer(instance, 279 dispatcher, 280 extra_data_buffer, 281 &buffer)) { 282 NOTREACHED(); 283 return; 284 } 285 286 // PluginResourceTracker in the plugin process assumes that resources that it 287 // tracks have been addrefed on behalf of the plugin at the renderer side. So 288 // we explicitly do it for |extra_data_buffer| here. 289 PpapiGlobals::Get()->GetResourceTracker()->AddRefResource(extra_data_buffer); 290 291 dispatcher->Send( 292 new PpapiMsg_PPPContentDecryptor_InitializeVideoDecoder( 293 API_ID_PPP_CONTENT_DECRYPTOR_PRIVATE, 294 instance, 295 serialized_decoder_config, 296 buffer)); 297} 298 299 300void DeinitializeDecoder(PP_Instance instance, 301 PP_DecryptorStreamType decoder_type, 302 uint32_t request_id) { 303 HostDispatcher* dispatcher = HostDispatcher::GetForInstance(instance); 304 if (!dispatcher) { 305 NOTREACHED(); 306 return; 307 } 308 309 dispatcher->Send( 310 new PpapiMsg_PPPContentDecryptor_DeinitializeDecoder( 311 API_ID_PPP_CONTENT_DECRYPTOR_PRIVATE, 312 instance, 313 decoder_type, 314 request_id)); 315} 316 317void ResetDecoder(PP_Instance instance, 318 PP_DecryptorStreamType decoder_type, 319 uint32_t request_id) { 320 HostDispatcher* dispatcher = HostDispatcher::GetForInstance(instance); 321 if (!dispatcher) { 322 NOTREACHED(); 323 return; 324 } 325 326 dispatcher->Send( 327 new PpapiMsg_PPPContentDecryptor_ResetDecoder( 328 API_ID_PPP_CONTENT_DECRYPTOR_PRIVATE, 329 instance, 330 decoder_type, 331 request_id)); 332} 333 334void DecryptAndDecode(PP_Instance instance, 335 PP_DecryptorStreamType decoder_type, 336 PP_Resource encrypted_buffer, 337 const PP_EncryptedBlockInfo* encrypted_block_info) { 338 HostDispatcher* dispatcher = HostDispatcher::GetForInstance(instance); 339 if (!dispatcher) { 340 NOTREACHED(); 341 return; 342 } 343 344 PPPDecryptor_Buffer buffer; 345 if (!InitializePppDecryptorBuffer(instance, 346 dispatcher, 347 encrypted_buffer, 348 &buffer)) { 349 NOTREACHED(); 350 return; 351 } 352 353 std::string serialized_block_info; 354 if (!SerializeBlockInfo(*encrypted_block_info, &serialized_block_info)) { 355 NOTREACHED(); 356 return; 357 } 358 359 // PluginResourceTracker in the plugin process assumes that resources that it 360 // tracks have been addrefed on behalf of the plugin at the renderer side. So 361 // we explicitly do it for |encrypted_buffer| here. 362 PpapiGlobals::Get()->GetResourceTracker()->AddRefResource(encrypted_buffer); 363 364 dispatcher->Send( 365 new PpapiMsg_PPPContentDecryptor_DecryptAndDecode( 366 API_ID_PPP_CONTENT_DECRYPTOR_PRIVATE, 367 instance, 368 decoder_type, 369 buffer, 370 serialized_block_info)); 371} 372 373static const PPP_ContentDecryptor_Private content_decryptor_interface = { 374 &Initialize, 375 &CreateSession, 376 &LoadSession, 377 &UpdateSession, 378 &ReleaseSession, 379 &Decrypt, 380 &InitializeAudioDecoder, 381 &InitializeVideoDecoder, 382 &DeinitializeDecoder, 383 &ResetDecoder, 384 &DecryptAndDecode 385}; 386 387} // namespace 388 389PPP_ContentDecryptor_Private_Proxy::PPP_ContentDecryptor_Private_Proxy( 390 Dispatcher* dispatcher) 391 : InterfaceProxy(dispatcher), 392 ppp_decryptor_impl_(NULL) { 393 if (dispatcher->IsPlugin()) { 394 ppp_decryptor_impl_ = static_cast<const PPP_ContentDecryptor_Private*>( 395 dispatcher->local_get_interface()( 396 PPP_CONTENTDECRYPTOR_PRIVATE_INTERFACE)); 397 } 398} 399 400PPP_ContentDecryptor_Private_Proxy::~PPP_ContentDecryptor_Private_Proxy() { 401} 402 403// static 404const PPP_ContentDecryptor_Private* 405 PPP_ContentDecryptor_Private_Proxy::GetProxyInterface() { 406 return &content_decryptor_interface; 407} 408 409bool PPP_ContentDecryptor_Private_Proxy::OnMessageReceived( 410 const IPC::Message& msg) { 411 if (!dispatcher()->IsPlugin()) 412 return false; // These are only valid from host->plugin. 413 // Don't allow the plugin to send these to the host. 414 415 bool handled = true; 416 IPC_BEGIN_MESSAGE_MAP(PPP_ContentDecryptor_Private_Proxy, msg) 417 IPC_MESSAGE_HANDLER(PpapiMsg_PPPContentDecryptor_Initialize, 418 OnMsgInitialize) 419 IPC_MESSAGE_HANDLER(PpapiMsg_PPPContentDecryptor_CreateSession, 420 OnMsgCreateSession) 421 IPC_MESSAGE_HANDLER(PpapiMsg_PPPContentDecryptor_LoadSession, 422 OnMsgLoadSession) 423 IPC_MESSAGE_HANDLER(PpapiMsg_PPPContentDecryptor_UpdateSession, 424 OnMsgUpdateSession) 425 IPC_MESSAGE_HANDLER(PpapiMsg_PPPContentDecryptor_ReleaseSession, 426 OnMsgReleaseSession) 427 IPC_MESSAGE_HANDLER(PpapiMsg_PPPContentDecryptor_Decrypt, 428 OnMsgDecrypt) 429 IPC_MESSAGE_HANDLER(PpapiMsg_PPPContentDecryptor_InitializeAudioDecoder, 430 OnMsgInitializeAudioDecoder) 431 IPC_MESSAGE_HANDLER(PpapiMsg_PPPContentDecryptor_InitializeVideoDecoder, 432 OnMsgInitializeVideoDecoder) 433 IPC_MESSAGE_HANDLER(PpapiMsg_PPPContentDecryptor_DeinitializeDecoder, 434 OnMsgDeinitializeDecoder) 435 IPC_MESSAGE_HANDLER(PpapiMsg_PPPContentDecryptor_ResetDecoder, 436 OnMsgResetDecoder) 437 IPC_MESSAGE_HANDLER(PpapiMsg_PPPContentDecryptor_DecryptAndDecode, 438 OnMsgDecryptAndDecode) 439 IPC_MESSAGE_UNHANDLED(handled = false) 440 IPC_END_MESSAGE_MAP() 441 DCHECK(handled); 442 return handled; 443} 444 445void PPP_ContentDecryptor_Private_Proxy::OnMsgInitialize( 446 PP_Instance instance, 447 SerializedVarReceiveInput key_system) { 448 if (ppp_decryptor_impl_) { 449 CallWhileUnlocked( 450 ppp_decryptor_impl_->Initialize, 451 instance, 452 ExtractReceivedVarAndAddRef(dispatcher(), &key_system)); 453 } 454} 455 456void PPP_ContentDecryptor_Private_Proxy::OnMsgCreateSession( 457 PP_Instance instance, 458 uint32_t session_id, 459 SerializedVarReceiveInput type, 460 SerializedVarReceiveInput init_data) { 461 if (ppp_decryptor_impl_) { 462 CallWhileUnlocked(ppp_decryptor_impl_->CreateSession, 463 instance, 464 session_id, 465 ExtractReceivedVarAndAddRef(dispatcher(), &type), 466 ExtractReceivedVarAndAddRef(dispatcher(), &init_data)); 467 } 468} 469 470void PPP_ContentDecryptor_Private_Proxy::OnMsgLoadSession( 471 PP_Instance instance, 472 uint32_t session_id, 473 SerializedVarReceiveInput web_session_id) { 474 if (ppp_decryptor_impl_) { 475 CallWhileUnlocked( 476 ppp_decryptor_impl_->LoadSession, 477 instance, 478 session_id, 479 ExtractReceivedVarAndAddRef(dispatcher(), &web_session_id)); 480 } 481} 482 483void PPP_ContentDecryptor_Private_Proxy::OnMsgUpdateSession( 484 PP_Instance instance, 485 uint32_t session_id, 486 SerializedVarReceiveInput response) { 487 if (ppp_decryptor_impl_) { 488 CallWhileUnlocked(ppp_decryptor_impl_->UpdateSession, 489 instance, 490 session_id, 491 ExtractReceivedVarAndAddRef(dispatcher(), &response)); 492 } 493} 494 495void PPP_ContentDecryptor_Private_Proxy::OnMsgReleaseSession( 496 PP_Instance instance, 497 uint32_t session_id) { 498 if (ppp_decryptor_impl_) { 499 CallWhileUnlocked(ppp_decryptor_impl_->ReleaseSession, 500 instance, 501 session_id); 502 } 503} 504 505void PPP_ContentDecryptor_Private_Proxy::OnMsgDecrypt( 506 PP_Instance instance, 507 const PPPDecryptor_Buffer& encrypted_buffer, 508 const std::string& serialized_block_info) { 509 ScopedPPResource plugin_resource( 510 ScopedPPResource::PassRef(), 511 PPB_Buffer_Proxy::AddProxyResource(encrypted_buffer.resource, 512 encrypted_buffer.handle, 513 encrypted_buffer.size)); 514 if (ppp_decryptor_impl_) { 515 PP_EncryptedBlockInfo block_info; 516 if (!DeserializeBlockInfo(serialized_block_info, &block_info)) 517 return; 518 CallWhileUnlocked(ppp_decryptor_impl_->Decrypt, 519 instance, 520 plugin_resource.get(), 521 const_cast<const PP_EncryptedBlockInfo*>(&block_info)); 522 } 523} 524 525void PPP_ContentDecryptor_Private_Proxy::OnMsgInitializeAudioDecoder( 526 PP_Instance instance, 527 const std::string& serialized_decoder_config, 528 const PPPDecryptor_Buffer& extra_data_buffer) { 529 ScopedPPResource plugin_resource; 530 if (extra_data_buffer.size > 0) { 531 plugin_resource = ScopedPPResource( 532 ScopedPPResource::PassRef(), 533 PPB_Buffer_Proxy::AddProxyResource(extra_data_buffer.resource, 534 extra_data_buffer.handle, 535 extra_data_buffer.size)); 536 } 537 538 PP_AudioDecoderConfig decoder_config; 539 if (!DeserializeBlockInfo(serialized_decoder_config, &decoder_config)) 540 return; 541 542 if (ppp_decryptor_impl_) { 543 CallWhileUnlocked( 544 ppp_decryptor_impl_->InitializeAudioDecoder, 545 instance, 546 const_cast<const PP_AudioDecoderConfig*>(&decoder_config), 547 plugin_resource.get()); 548 } 549} 550 551void PPP_ContentDecryptor_Private_Proxy::OnMsgInitializeVideoDecoder( 552 PP_Instance instance, 553 const std::string& serialized_decoder_config, 554 const PPPDecryptor_Buffer& extra_data_buffer) { 555 ScopedPPResource plugin_resource; 556 if (extra_data_buffer.resource.host_resource() != 0) { 557 plugin_resource = ScopedPPResource( 558 ScopedPPResource::PassRef(), 559 PPB_Buffer_Proxy::AddProxyResource(extra_data_buffer.resource, 560 extra_data_buffer.handle, 561 extra_data_buffer.size)); 562 } 563 564 PP_VideoDecoderConfig decoder_config; 565 if (!DeserializeBlockInfo(serialized_decoder_config, &decoder_config)) 566 return; 567 568 if (ppp_decryptor_impl_) { 569 CallWhileUnlocked( 570 ppp_decryptor_impl_->InitializeVideoDecoder, 571 instance, 572 const_cast<const PP_VideoDecoderConfig*>(&decoder_config), 573 plugin_resource.get()); 574 } 575} 576 577void PPP_ContentDecryptor_Private_Proxy::OnMsgDeinitializeDecoder( 578 PP_Instance instance, 579 PP_DecryptorStreamType decoder_type, 580 uint32_t request_id) { 581 if (ppp_decryptor_impl_) { 582 CallWhileUnlocked( 583 ppp_decryptor_impl_->DeinitializeDecoder, 584 instance, 585 decoder_type, 586 request_id); 587 } 588} 589 590void PPP_ContentDecryptor_Private_Proxy::OnMsgResetDecoder( 591 PP_Instance instance, 592 PP_DecryptorStreamType decoder_type, 593 uint32_t request_id) { 594 if (ppp_decryptor_impl_) { 595 CallWhileUnlocked( 596 ppp_decryptor_impl_->ResetDecoder, 597 instance, 598 decoder_type, 599 request_id); 600 } 601} 602 603void PPP_ContentDecryptor_Private_Proxy::OnMsgDecryptAndDecode( 604 PP_Instance instance, 605 PP_DecryptorStreamType decoder_type, 606 const PPPDecryptor_Buffer& encrypted_buffer, 607 const std::string& serialized_block_info) { 608 ScopedPPResource plugin_resource; 609 if (encrypted_buffer.resource.host_resource() != 0) { 610 plugin_resource = ScopedPPResource( 611 ScopedPPResource::PassRef(), 612 PPB_Buffer_Proxy::AddProxyResource(encrypted_buffer.resource, 613 encrypted_buffer.handle, 614 encrypted_buffer.size)); 615 } 616 617 if (ppp_decryptor_impl_) { 618 PP_EncryptedBlockInfo block_info; 619 if (!DeserializeBlockInfo(serialized_block_info, &block_info)) 620 return; 621 CallWhileUnlocked( 622 ppp_decryptor_impl_->DecryptAndDecode, 623 instance, 624 decoder_type, 625 plugin_resource.get(), 626 const_cast<const PP_EncryptedBlockInfo*>(&block_info)); 627 } 628} 629 630} // namespace proxy 631} // namespace ppapi 632