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/platform_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 24 using ppapi::thunk::EnterResourceNoLock; 25 using ppapi::thunk::PPB_Buffer_API; 26 using ppapi::thunk::PPB_Instance_API; 27 28 namespace ppapi { 29 namespace proxy { 30 31 namespace { 32 33 PP_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. 41 PP_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. 70 PP_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 77 bool 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 112 void 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 127 void 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 145 void UpdateSession(PP_Instance instance, uint32_t session_id, PP_Var response) { 146 HostDispatcher* dispatcher = HostDispatcher::GetForInstance(instance); 147 if (!dispatcher) { 148 NOTREACHED(); 149 return; 150 } 151 152 dispatcher->Send(new PpapiMsg_PPPContentDecryptor_UpdateSession( 153 API_ID_PPP_CONTENT_DECRYPTOR_PRIVATE, 154 instance, 155 session_id, 156 SerializedVarSendInput(dispatcher, response))); 157 } 158 159 void ReleaseSession(PP_Instance instance, uint32_t session_id) { 160 HostDispatcher* dispatcher = HostDispatcher::GetForInstance(instance); 161 if (!dispatcher) { 162 NOTREACHED(); 163 return; 164 } 165 166 dispatcher->Send(new PpapiMsg_PPPContentDecryptor_ReleaseSession( 167 API_ID_PPP_CONTENT_DECRYPTOR_PRIVATE, instance, session_id)); 168 } 169 170 void Decrypt(PP_Instance instance, 171 PP_Resource encrypted_block, 172 const PP_EncryptedBlockInfo* encrypted_block_info) { 173 HostDispatcher* dispatcher = HostDispatcher::GetForInstance(instance); 174 if (!dispatcher) { 175 NOTREACHED(); 176 return; 177 } 178 179 PPPDecryptor_Buffer buffer; 180 if (!InitializePppDecryptorBuffer(instance, 181 dispatcher, 182 encrypted_block, 183 &buffer)) { 184 NOTREACHED(); 185 return; 186 } 187 188 std::string serialized_block_info; 189 if (!SerializeBlockInfo(*encrypted_block_info, &serialized_block_info)) { 190 NOTREACHED(); 191 return; 192 } 193 194 // PluginResourceTracker in the plugin process assumes that resources that it 195 // tracks have been addrefed on behalf of the plugin at the renderer side. So 196 // we explicitly do it for |encryped_block| here. 197 PpapiGlobals::Get()->GetResourceTracker()->AddRefResource(encrypted_block); 198 199 dispatcher->Send( 200 new PpapiMsg_PPPContentDecryptor_Decrypt( 201 API_ID_PPP_CONTENT_DECRYPTOR_PRIVATE, 202 instance, 203 buffer, 204 serialized_block_info)); 205 } 206 207 void InitializeAudioDecoder( 208 PP_Instance instance, 209 const PP_AudioDecoderConfig* decoder_config, 210 PP_Resource extra_data_buffer) { 211 HostDispatcher* dispatcher = HostDispatcher::GetForInstance(instance); 212 if (!dispatcher) { 213 NOTREACHED(); 214 return; 215 } 216 217 std::string serialized_decoder_config; 218 if (!SerializeBlockInfo(*decoder_config, &serialized_decoder_config)) { 219 NOTREACHED(); 220 return; 221 } 222 223 PPPDecryptor_Buffer buffer; 224 if (!InitializePppDecryptorBuffer(instance, 225 dispatcher, 226 extra_data_buffer, 227 &buffer)) { 228 NOTREACHED(); 229 return; 230 } 231 232 // PluginResourceTracker in the plugin process assumes that resources that it 233 // tracks have been addrefed on behalf of the plugin at the renderer side. So 234 // we explicitly do it for |extra_data_buffer| here. 235 PpapiGlobals::Get()->GetResourceTracker()->AddRefResource(extra_data_buffer); 236 237 dispatcher->Send( 238 new PpapiMsg_PPPContentDecryptor_InitializeAudioDecoder( 239 API_ID_PPP_CONTENT_DECRYPTOR_PRIVATE, 240 instance, 241 serialized_decoder_config, 242 buffer)); 243 } 244 245 void InitializeVideoDecoder( 246 PP_Instance instance, 247 const PP_VideoDecoderConfig* decoder_config, 248 PP_Resource extra_data_buffer) { 249 HostDispatcher* dispatcher = HostDispatcher::GetForInstance(instance); 250 if (!dispatcher) { 251 NOTREACHED(); 252 return; 253 } 254 255 std::string serialized_decoder_config; 256 if (!SerializeBlockInfo(*decoder_config, &serialized_decoder_config)) { 257 NOTREACHED(); 258 return; 259 } 260 261 PPPDecryptor_Buffer buffer; 262 if (!InitializePppDecryptorBuffer(instance, 263 dispatcher, 264 extra_data_buffer, 265 &buffer)) { 266 NOTREACHED(); 267 return; 268 } 269 270 // PluginResourceTracker in the plugin process assumes that resources that it 271 // tracks have been addrefed on behalf of the plugin at the renderer side. So 272 // we explicitly do it for |extra_data_buffer| here. 273 PpapiGlobals::Get()->GetResourceTracker()->AddRefResource(extra_data_buffer); 274 275 dispatcher->Send( 276 new PpapiMsg_PPPContentDecryptor_InitializeVideoDecoder( 277 API_ID_PPP_CONTENT_DECRYPTOR_PRIVATE, 278 instance, 279 serialized_decoder_config, 280 buffer)); 281 } 282 283 284 void DeinitializeDecoder(PP_Instance instance, 285 PP_DecryptorStreamType decoder_type, 286 uint32_t request_id) { 287 HostDispatcher* dispatcher = HostDispatcher::GetForInstance(instance); 288 if (!dispatcher) { 289 NOTREACHED(); 290 return; 291 } 292 293 dispatcher->Send( 294 new PpapiMsg_PPPContentDecryptor_DeinitializeDecoder( 295 API_ID_PPP_CONTENT_DECRYPTOR_PRIVATE, 296 instance, 297 decoder_type, 298 request_id)); 299 } 300 301 void ResetDecoder(PP_Instance instance, 302 PP_DecryptorStreamType decoder_type, 303 uint32_t request_id) { 304 HostDispatcher* dispatcher = HostDispatcher::GetForInstance(instance); 305 if (!dispatcher) { 306 NOTREACHED(); 307 return; 308 } 309 310 dispatcher->Send( 311 new PpapiMsg_PPPContentDecryptor_ResetDecoder( 312 API_ID_PPP_CONTENT_DECRYPTOR_PRIVATE, 313 instance, 314 decoder_type, 315 request_id)); 316 } 317 318 void DecryptAndDecode(PP_Instance instance, 319 PP_DecryptorStreamType decoder_type, 320 PP_Resource encrypted_buffer, 321 const PP_EncryptedBlockInfo* encrypted_block_info) { 322 HostDispatcher* dispatcher = HostDispatcher::GetForInstance(instance); 323 if (!dispatcher) { 324 NOTREACHED(); 325 return; 326 } 327 328 PPPDecryptor_Buffer buffer; 329 if (!InitializePppDecryptorBuffer(instance, 330 dispatcher, 331 encrypted_buffer, 332 &buffer)) { 333 NOTREACHED(); 334 return; 335 } 336 337 std::string serialized_block_info; 338 if (!SerializeBlockInfo(*encrypted_block_info, &serialized_block_info)) { 339 NOTREACHED(); 340 return; 341 } 342 343 // PluginResourceTracker in the plugin process assumes that resources that it 344 // tracks have been addrefed on behalf of the plugin at the renderer side. So 345 // we explicitly do it for |encrypted_buffer| here. 346 PpapiGlobals::Get()->GetResourceTracker()->AddRefResource(encrypted_buffer); 347 348 dispatcher->Send( 349 new PpapiMsg_PPPContentDecryptor_DecryptAndDecode( 350 API_ID_PPP_CONTENT_DECRYPTOR_PRIVATE, 351 instance, 352 decoder_type, 353 buffer, 354 serialized_block_info)); 355 } 356 357 static const PPP_ContentDecryptor_Private content_decryptor_interface = { 358 &Initialize, 359 &CreateSession, 360 &UpdateSession, 361 &ReleaseSession, 362 &Decrypt, 363 &InitializeAudioDecoder, 364 &InitializeVideoDecoder, 365 &DeinitializeDecoder, 366 &ResetDecoder, 367 &DecryptAndDecode 368 }; 369 370 } // namespace 371 372 PPP_ContentDecryptor_Private_Proxy::PPP_ContentDecryptor_Private_Proxy( 373 Dispatcher* dispatcher) 374 : InterfaceProxy(dispatcher), 375 ppp_decryptor_impl_(NULL) { 376 if (dispatcher->IsPlugin()) { 377 ppp_decryptor_impl_ = static_cast<const PPP_ContentDecryptor_Private*>( 378 dispatcher->local_get_interface()( 379 PPP_CONTENTDECRYPTOR_PRIVATE_INTERFACE)); 380 } 381 } 382 383 PPP_ContentDecryptor_Private_Proxy::~PPP_ContentDecryptor_Private_Proxy() { 384 } 385 386 // static 387 const PPP_ContentDecryptor_Private* 388 PPP_ContentDecryptor_Private_Proxy::GetProxyInterface() { 389 return &content_decryptor_interface; 390 } 391 392 bool PPP_ContentDecryptor_Private_Proxy::OnMessageReceived( 393 const IPC::Message& msg) { 394 if (!dispatcher()->IsPlugin()) 395 return false; // These are only valid from host->plugin. 396 // Don't allow the plugin to send these to the host. 397 398 bool handled = true; 399 IPC_BEGIN_MESSAGE_MAP(PPP_ContentDecryptor_Private_Proxy, msg) 400 IPC_MESSAGE_HANDLER(PpapiMsg_PPPContentDecryptor_Initialize, 401 OnMsgInitialize) 402 IPC_MESSAGE_HANDLER(PpapiMsg_PPPContentDecryptor_CreateSession, 403 OnMsgCreateSession) 404 IPC_MESSAGE_HANDLER(PpapiMsg_PPPContentDecryptor_UpdateSession, 405 OnMsgUpdateSession) 406 IPC_MESSAGE_HANDLER(PpapiMsg_PPPContentDecryptor_ReleaseSession, 407 OnMsgReleaseSession) 408 IPC_MESSAGE_HANDLER(PpapiMsg_PPPContentDecryptor_Decrypt, 409 OnMsgDecrypt) 410 IPC_MESSAGE_HANDLER(PpapiMsg_PPPContentDecryptor_InitializeAudioDecoder, 411 OnMsgInitializeAudioDecoder) 412 IPC_MESSAGE_HANDLER(PpapiMsg_PPPContentDecryptor_InitializeVideoDecoder, 413 OnMsgInitializeVideoDecoder) 414 IPC_MESSAGE_HANDLER(PpapiMsg_PPPContentDecryptor_DeinitializeDecoder, 415 OnMsgDeinitializeDecoder) 416 IPC_MESSAGE_HANDLER(PpapiMsg_PPPContentDecryptor_ResetDecoder, 417 OnMsgResetDecoder) 418 IPC_MESSAGE_HANDLER(PpapiMsg_PPPContentDecryptor_DecryptAndDecode, 419 OnMsgDecryptAndDecode) 420 IPC_MESSAGE_UNHANDLED(handled = false) 421 IPC_END_MESSAGE_MAP() 422 DCHECK(handled); 423 return handled; 424 } 425 426 void PPP_ContentDecryptor_Private_Proxy::OnMsgInitialize( 427 PP_Instance instance, 428 SerializedVarReceiveInput key_system) { 429 if (ppp_decryptor_impl_) { 430 CallWhileUnlocked( 431 ppp_decryptor_impl_->Initialize, 432 instance, 433 ExtractReceivedVarAndAddRef(dispatcher(), &key_system)); 434 } 435 } 436 437 void PPP_ContentDecryptor_Private_Proxy::OnMsgCreateSession( 438 PP_Instance instance, 439 uint32_t session_id, 440 SerializedVarReceiveInput type, 441 SerializedVarReceiveInput init_data) { 442 if (ppp_decryptor_impl_) { 443 CallWhileUnlocked(ppp_decryptor_impl_->CreateSession, 444 instance, 445 session_id, 446 ExtractReceivedVarAndAddRef(dispatcher(), &type), 447 ExtractReceivedVarAndAddRef(dispatcher(), &init_data)); 448 } 449 } 450 451 void PPP_ContentDecryptor_Private_Proxy::OnMsgUpdateSession( 452 PP_Instance instance, 453 uint32_t session_id, 454 SerializedVarReceiveInput response) { 455 if (ppp_decryptor_impl_) { 456 CallWhileUnlocked(ppp_decryptor_impl_->UpdateSession, 457 instance, 458 session_id, 459 ExtractReceivedVarAndAddRef(dispatcher(), &response)); 460 } 461 } 462 463 void PPP_ContentDecryptor_Private_Proxy::OnMsgReleaseSession( 464 PP_Instance instance, 465 uint32_t session_id) { 466 if (ppp_decryptor_impl_) { 467 CallWhileUnlocked(ppp_decryptor_impl_->ReleaseSession, 468 instance, 469 session_id); 470 } 471 } 472 473 void PPP_ContentDecryptor_Private_Proxy::OnMsgDecrypt( 474 PP_Instance instance, 475 const PPPDecryptor_Buffer& encrypted_buffer, 476 const std::string& serialized_block_info) { 477 ScopedPPResource plugin_resource( 478 ScopedPPResource::PassRef(), 479 PPB_Buffer_Proxy::AddProxyResource(encrypted_buffer.resource, 480 encrypted_buffer.handle, 481 encrypted_buffer.size)); 482 if (ppp_decryptor_impl_) { 483 PP_EncryptedBlockInfo block_info; 484 if (!DeserializeBlockInfo(serialized_block_info, &block_info)) 485 return; 486 CallWhileUnlocked(ppp_decryptor_impl_->Decrypt, 487 instance, 488 plugin_resource.get(), 489 const_cast<const PP_EncryptedBlockInfo*>(&block_info)); 490 } 491 } 492 493 void PPP_ContentDecryptor_Private_Proxy::OnMsgInitializeAudioDecoder( 494 PP_Instance instance, 495 const std::string& serialized_decoder_config, 496 const PPPDecryptor_Buffer& extra_data_buffer) { 497 ScopedPPResource plugin_resource; 498 if (extra_data_buffer.size > 0) { 499 plugin_resource = ScopedPPResource( 500 ScopedPPResource::PassRef(), 501 PPB_Buffer_Proxy::AddProxyResource(extra_data_buffer.resource, 502 extra_data_buffer.handle, 503 extra_data_buffer.size)); 504 } 505 506 PP_AudioDecoderConfig decoder_config; 507 if (!DeserializeBlockInfo(serialized_decoder_config, &decoder_config)) 508 return; 509 510 if (ppp_decryptor_impl_) { 511 CallWhileUnlocked( 512 ppp_decryptor_impl_->InitializeAudioDecoder, 513 instance, 514 const_cast<const PP_AudioDecoderConfig*>(&decoder_config), 515 plugin_resource.get()); 516 } 517 } 518 519 void PPP_ContentDecryptor_Private_Proxy::OnMsgInitializeVideoDecoder( 520 PP_Instance instance, 521 const std::string& serialized_decoder_config, 522 const PPPDecryptor_Buffer& extra_data_buffer) { 523 ScopedPPResource plugin_resource; 524 if (extra_data_buffer.resource.host_resource() != 0) { 525 plugin_resource = ScopedPPResource( 526 ScopedPPResource::PassRef(), 527 PPB_Buffer_Proxy::AddProxyResource(extra_data_buffer.resource, 528 extra_data_buffer.handle, 529 extra_data_buffer.size)); 530 } 531 532 PP_VideoDecoderConfig decoder_config; 533 if (!DeserializeBlockInfo(serialized_decoder_config, &decoder_config)) 534 return; 535 536 if (ppp_decryptor_impl_) { 537 CallWhileUnlocked( 538 ppp_decryptor_impl_->InitializeVideoDecoder, 539 instance, 540 const_cast<const PP_VideoDecoderConfig*>(&decoder_config), 541 plugin_resource.get()); 542 } 543 } 544 545 void PPP_ContentDecryptor_Private_Proxy::OnMsgDeinitializeDecoder( 546 PP_Instance instance, 547 PP_DecryptorStreamType decoder_type, 548 uint32_t request_id) { 549 if (ppp_decryptor_impl_) { 550 CallWhileUnlocked( 551 ppp_decryptor_impl_->DeinitializeDecoder, 552 instance, 553 decoder_type, 554 request_id); 555 } 556 } 557 558 void PPP_ContentDecryptor_Private_Proxy::OnMsgResetDecoder( 559 PP_Instance instance, 560 PP_DecryptorStreamType decoder_type, 561 uint32_t request_id) { 562 if (ppp_decryptor_impl_) { 563 CallWhileUnlocked( 564 ppp_decryptor_impl_->ResetDecoder, 565 instance, 566 decoder_type, 567 request_id); 568 } 569 } 570 571 void PPP_ContentDecryptor_Private_Proxy::OnMsgDecryptAndDecode( 572 PP_Instance instance, 573 PP_DecryptorStreamType decoder_type, 574 const PPPDecryptor_Buffer& encrypted_buffer, 575 const std::string& serialized_block_info) { 576 ScopedPPResource plugin_resource; 577 if (encrypted_buffer.resource.host_resource() != 0) { 578 plugin_resource = ScopedPPResource( 579 ScopedPPResource::PassRef(), 580 PPB_Buffer_Proxy::AddProxyResource(encrypted_buffer.resource, 581 encrypted_buffer.handle, 582 encrypted_buffer.size)); 583 } 584 585 if (ppp_decryptor_impl_) { 586 PP_EncryptedBlockInfo block_info; 587 if (!DeserializeBlockInfo(serialized_block_info, &block_info)) 588 return; 589 CallWhileUnlocked( 590 ppp_decryptor_impl_->DecryptAndDecode, 591 instance, 592 decoder_type, 593 plugin_resource.get(), 594 const_cast<const PP_EncryptedBlockInfo*>(&block_info)); 595 } 596 } 597 598 } // namespace proxy 599 } // namespace ppapi 600