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