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.
5 #include "ppapi/proxy/ppp_content_decryptor_private_proxy.h"
7 #include "base/files/file.h"
8 #include "media/base/limits.h"
9 #include "ppapi/c/pp_bool.h"
10 #include "ppapi/c/ppb_core.h"
11 #include "ppapi/proxy/content_decryptor_private_serializer.h"
12 #include "ppapi/proxy/host_dispatcher.h"
13 #include "ppapi/proxy/plugin_globals.h"
14 #include "ppapi/proxy/plugin_resource_tracker.h"
15 #include "ppapi/proxy/ppapi_messages.h"
16 #include "ppapi/proxy/ppb_buffer_proxy.h"
17 #include "ppapi/proxy/serialized_var.h"
18 #include "ppapi/shared_impl/scoped_pp_resource.h"
19 #include "ppapi/shared_impl/scoped_pp_var.h"
20 #include "ppapi/shared_impl/var_tracker.h"
21 #include "ppapi/thunk/enter.h"
22 #include "ppapi/thunk/ppb_buffer_api.h"
23 #include "ppapi/thunk/ppb_instance_api.h"
24 #include "ppapi/thunk/thunk.h"
26 using ppapi::thunk::EnterResourceNoLock
;
27 using ppapi::thunk::PPB_Buffer_API
;
28 using ppapi::thunk::PPB_Instance_API
;
35 PP_Bool
DescribeHostBufferResource(PP_Resource resource
, uint32_t* size
) {
36 EnterResourceNoLock
<PPB_Buffer_API
> enter(resource
, true);
39 return enter
.object()->Describe(size
);
42 // TODO(dmichael): Refactor so this handle sharing code is in one place.
43 PP_Bool
ShareHostBufferResourceToPlugin(
44 HostDispatcher
* dispatcher
,
46 base::SharedMemoryHandle
* shared_mem_handle
) {
47 if (!dispatcher
|| resource
== 0 || !shared_mem_handle
)
49 EnterResourceNoLock
<PPB_Buffer_API
> enter(resource
, true);
53 int32_t result
= enter
.object()->GetSharedMemory(&handle
);
56 base::PlatformFile platform_file
=
58 reinterpret_cast<HANDLE
>(static_cast<intptr_t>(handle
));
59 #elif defined(OS_POSIX)
62 #error Not implemented.
65 *shared_mem_handle
= dispatcher
->ShareHandleWithRemote(platform_file
, false);
69 // SerializedVarReceiveInput will decrement the reference count, but we want
70 // to give the recipient a reference. This utility function takes care of that
71 // work for the message handlers defined below.
72 PP_Var
ExtractReceivedVarAndAddRef(Dispatcher
* dispatcher
,
73 SerializedVarReceiveInput
* serialized_var
) {
74 PP_Var var
= serialized_var
->Get(dispatcher
);
75 PpapiGlobals::Get()->GetVarTracker()->AddRefVar(var
);
79 bool InitializePppDecryptorBuffer(PP_Instance instance
,
80 HostDispatcher
* dispatcher
,
82 PPPDecryptor_Buffer
* buffer
) {
89 buffer
->resource
= HostResource();
90 buffer
->handle
= base::SharedMemoryHandle();
95 HostResource host_resource
;
96 host_resource
.SetHostResource(instance
, resource
);
99 if (DescribeHostBufferResource(resource
, &size
) == PP_FALSE
)
102 base::SharedMemoryHandle handle
;
103 if (ShareHostBufferResourceToPlugin(dispatcher
,
105 &handle
) == PP_FALSE
)
108 buffer
->resource
= host_resource
;
109 buffer
->handle
= handle
;
114 void Initialize(PP_Instance instance
,
116 PP_Bool allow_distinctive_identifier
,
117 PP_Bool allow_persistent_state
) {
118 HostDispatcher
* dispatcher
= HostDispatcher::GetForInstance(instance
);
125 new PpapiMsg_PPPContentDecryptor_Initialize(
126 API_ID_PPP_CONTENT_DECRYPTOR_PRIVATE
,
128 SerializedVarSendInput(dispatcher
, key_system
),
129 allow_distinctive_identifier
,
130 allow_persistent_state
));
133 void SetServerCertificate(PP_Instance instance
,
135 PP_Var server_certificate
) {
136 HostDispatcher
* dispatcher
= HostDispatcher::GetForInstance(instance
);
142 ArrayBufferVar
* server_certificate_buffer
=
143 ArrayBufferVar::FromPPVar(server_certificate
);
144 if (!server_certificate_buffer
||
145 server_certificate_buffer
->ByteLength() <
146 media::limits::kMinCertificateLength
||
147 server_certificate_buffer
->ByteLength() >
148 media::limits::kMaxCertificateLength
) {
153 const uint8_t* server_certificate_ptr
=
154 static_cast<const uint8_t*>(server_certificate_buffer
->Map());
155 const uint32_t server_certificate_size
=
156 server_certificate_buffer
->ByteLength();
157 std::vector
<uint8_t> server_certificate_vector(
158 server_certificate_ptr
, server_certificate_ptr
+ server_certificate_size
);
160 dispatcher
->Send(new PpapiMsg_PPPContentDecryptor_SetServerCertificate(
161 API_ID_PPP_CONTENT_DECRYPTOR_PRIVATE
,
164 server_certificate_vector
));
167 void CreateSessionAndGenerateRequest(PP_Instance instance
,
169 PP_SessionType session_type
,
170 PP_InitDataType init_data_type
,
172 HostDispatcher
* dispatcher
= HostDispatcher::GetForInstance(instance
);
179 new PpapiMsg_PPPContentDecryptor_CreateSessionAndGenerateRequest(
180 API_ID_PPP_CONTENT_DECRYPTOR_PRIVATE
, instance
, promise_id
,
181 session_type
, init_data_type
,
182 SerializedVarSendInput(dispatcher
, init_data
)));
185 void LoadSession(PP_Instance instance
,
187 PP_SessionType session_type
,
189 HostDispatcher
* dispatcher
= HostDispatcher::GetForInstance(instance
);
195 dispatcher
->Send(new PpapiMsg_PPPContentDecryptor_LoadSession(
196 API_ID_PPP_CONTENT_DECRYPTOR_PRIVATE
, instance
, promise_id
, session_type
,
197 SerializedVarSendInput(dispatcher
, session_id
)));
200 void UpdateSession(PP_Instance instance
,
204 HostDispatcher
* dispatcher
= HostDispatcher::GetForInstance(instance
);
210 dispatcher
->Send(new PpapiMsg_PPPContentDecryptor_UpdateSession(
211 API_ID_PPP_CONTENT_DECRYPTOR_PRIVATE
, instance
, promise_id
,
212 SerializedVarSendInput(dispatcher
, session_id
),
213 SerializedVarSendInput(dispatcher
, response
)));
216 void CloseSession(PP_Instance instance
,
219 HostDispatcher
* dispatcher
= HostDispatcher::GetForInstance(instance
);
225 StringVar
* session_id_string
= StringVar::FromPPVar(session_id
);
226 if (!session_id_string
||
227 session_id_string
->value().length() >
228 media::limits::kMaxSessionIdLength
) {
233 dispatcher
->Send(new PpapiMsg_PPPContentDecryptor_CloseSession(
234 API_ID_PPP_CONTENT_DECRYPTOR_PRIVATE
, instance
, promise_id
,
235 session_id_string
->value()));
238 void RemoveSession(PP_Instance instance
,
241 HostDispatcher
* dispatcher
= HostDispatcher::GetForInstance(instance
);
247 StringVar
* session_id_string
= StringVar::FromPPVar(session_id
);
248 if (!session_id_string
||
249 session_id_string
->value().length() >
250 media::limits::kMaxSessionIdLength
) {
255 dispatcher
->Send(new PpapiMsg_PPPContentDecryptor_RemoveSession(
256 API_ID_PPP_CONTENT_DECRYPTOR_PRIVATE
, instance
, promise_id
,
257 session_id_string
->value()));
260 void Decrypt(PP_Instance instance
,
261 PP_Resource encrypted_block
,
262 const PP_EncryptedBlockInfo
* encrypted_block_info
) {
263 HostDispatcher
* dispatcher
= HostDispatcher::GetForInstance(instance
);
269 PPPDecryptor_Buffer buffer
;
270 if (!InitializePppDecryptorBuffer(instance
,
278 std::string serialized_block_info
;
279 if (!SerializeBlockInfo(*encrypted_block_info
, &serialized_block_info
)) {
284 // PluginResourceTracker in the plugin process assumes that resources that it
285 // tracks have been addrefed on behalf of the plugin at the renderer side. So
286 // we explicitly do it for |encryped_block| here.
287 PpapiGlobals::Get()->GetResourceTracker()->AddRefResource(encrypted_block
);
290 new PpapiMsg_PPPContentDecryptor_Decrypt(
291 API_ID_PPP_CONTENT_DECRYPTOR_PRIVATE
,
294 serialized_block_info
));
297 void InitializeAudioDecoder(
298 PP_Instance instance
,
299 const PP_AudioDecoderConfig
* decoder_config
,
300 PP_Resource extra_data_buffer
) {
301 HostDispatcher
* dispatcher
= HostDispatcher::GetForInstance(instance
);
307 std::string serialized_decoder_config
;
308 if (!SerializeBlockInfo(*decoder_config
, &serialized_decoder_config
)) {
313 PPPDecryptor_Buffer buffer
;
314 if (!InitializePppDecryptorBuffer(instance
,
322 // PluginResourceTracker in the plugin process assumes that resources that it
323 // tracks have been addrefed on behalf of the plugin at the renderer side. So
324 // we explicitly do it for |extra_data_buffer| here.
325 PpapiGlobals::Get()->GetResourceTracker()->AddRefResource(extra_data_buffer
);
328 new PpapiMsg_PPPContentDecryptor_InitializeAudioDecoder(
329 API_ID_PPP_CONTENT_DECRYPTOR_PRIVATE
,
331 serialized_decoder_config
,
335 void InitializeVideoDecoder(
336 PP_Instance instance
,
337 const PP_VideoDecoderConfig
* decoder_config
,
338 PP_Resource extra_data_buffer
) {
339 HostDispatcher
* dispatcher
= HostDispatcher::GetForInstance(instance
);
345 std::string serialized_decoder_config
;
346 if (!SerializeBlockInfo(*decoder_config
, &serialized_decoder_config
)) {
351 PPPDecryptor_Buffer buffer
;
352 if (!InitializePppDecryptorBuffer(instance
,
360 // PluginResourceTracker in the plugin process assumes that resources that it
361 // tracks have been addrefed on behalf of the plugin at the renderer side. So
362 // we explicitly do it for |extra_data_buffer| here.
363 PpapiGlobals::Get()->GetResourceTracker()->AddRefResource(extra_data_buffer
);
366 new PpapiMsg_PPPContentDecryptor_InitializeVideoDecoder(
367 API_ID_PPP_CONTENT_DECRYPTOR_PRIVATE
,
369 serialized_decoder_config
,
374 void DeinitializeDecoder(PP_Instance instance
,
375 PP_DecryptorStreamType decoder_type
,
376 uint32_t request_id
) {
377 HostDispatcher
* dispatcher
= HostDispatcher::GetForInstance(instance
);
384 new PpapiMsg_PPPContentDecryptor_DeinitializeDecoder(
385 API_ID_PPP_CONTENT_DECRYPTOR_PRIVATE
,
391 void ResetDecoder(PP_Instance instance
,
392 PP_DecryptorStreamType decoder_type
,
393 uint32_t request_id
) {
394 HostDispatcher
* dispatcher
= HostDispatcher::GetForInstance(instance
);
401 new PpapiMsg_PPPContentDecryptor_ResetDecoder(
402 API_ID_PPP_CONTENT_DECRYPTOR_PRIVATE
,
408 void DecryptAndDecode(PP_Instance instance
,
409 PP_DecryptorStreamType decoder_type
,
410 PP_Resource encrypted_buffer
,
411 const PP_EncryptedBlockInfo
* encrypted_block_info
) {
412 HostDispatcher
* dispatcher
= HostDispatcher::GetForInstance(instance
);
418 PPPDecryptor_Buffer buffer
;
419 if (!InitializePppDecryptorBuffer(instance
,
427 std::string serialized_block_info
;
428 if (!SerializeBlockInfo(*encrypted_block_info
, &serialized_block_info
)) {
433 // PluginResourceTracker in the plugin process assumes that resources that it
434 // tracks have been addrefed on behalf of the plugin at the renderer side. So
435 // we explicitly do it for |encrypted_buffer| here.
436 PpapiGlobals::Get()->GetResourceTracker()->AddRefResource(encrypted_buffer
);
439 new PpapiMsg_PPPContentDecryptor_DecryptAndDecode(
440 API_ID_PPP_CONTENT_DECRYPTOR_PRIVATE
,
444 serialized_block_info
));
447 static const PPP_ContentDecryptor_Private content_decryptor_interface
= {
449 &SetServerCertificate
,
450 &CreateSessionAndGenerateRequest
,
456 &InitializeAudioDecoder
,
457 &InitializeVideoDecoder
,
458 &DeinitializeDecoder
,
464 PPP_ContentDecryptor_Private_Proxy::PPP_ContentDecryptor_Private_Proxy(
465 Dispatcher
* dispatcher
)
466 : InterfaceProxy(dispatcher
),
467 ppp_decryptor_impl_(NULL
) {
468 if (dispatcher
->IsPlugin()) {
469 ppp_decryptor_impl_
= static_cast<const PPP_ContentDecryptor_Private
*>(
470 dispatcher
->local_get_interface()(
471 PPP_CONTENTDECRYPTOR_PRIVATE_INTERFACE
));
475 PPP_ContentDecryptor_Private_Proxy::~PPP_ContentDecryptor_Private_Proxy() {
479 const PPP_ContentDecryptor_Private
*
480 PPP_ContentDecryptor_Private_Proxy::GetProxyInterface() {
481 return &content_decryptor_interface
;
484 bool PPP_ContentDecryptor_Private_Proxy::OnMessageReceived(
485 const IPC::Message
& msg
) {
486 if (!dispatcher()->IsPlugin())
487 return false; // These are only valid from host->plugin.
488 // Don't allow the plugin to send these to the host.
491 IPC_BEGIN_MESSAGE_MAP(PPP_ContentDecryptor_Private_Proxy
, msg
)
492 IPC_MESSAGE_HANDLER(PpapiMsg_PPPContentDecryptor_Initialize
,
494 IPC_MESSAGE_HANDLER(PpapiMsg_PPPContentDecryptor_SetServerCertificate
,
495 OnMsgSetServerCertificate
)
497 PpapiMsg_PPPContentDecryptor_CreateSessionAndGenerateRequest
,
498 OnMsgCreateSessionAndGenerateRequest
)
499 IPC_MESSAGE_HANDLER(PpapiMsg_PPPContentDecryptor_LoadSession
,
501 IPC_MESSAGE_HANDLER(PpapiMsg_PPPContentDecryptor_UpdateSession
,
503 IPC_MESSAGE_HANDLER(PpapiMsg_PPPContentDecryptor_CloseSession
,
505 IPC_MESSAGE_HANDLER(PpapiMsg_PPPContentDecryptor_RemoveSession
,
507 IPC_MESSAGE_HANDLER(PpapiMsg_PPPContentDecryptor_Decrypt
,
509 IPC_MESSAGE_HANDLER(PpapiMsg_PPPContentDecryptor_InitializeAudioDecoder
,
510 OnMsgInitializeAudioDecoder
)
511 IPC_MESSAGE_HANDLER(PpapiMsg_PPPContentDecryptor_InitializeVideoDecoder
,
512 OnMsgInitializeVideoDecoder
)
513 IPC_MESSAGE_HANDLER(PpapiMsg_PPPContentDecryptor_DeinitializeDecoder
,
514 OnMsgDeinitializeDecoder
)
515 IPC_MESSAGE_HANDLER(PpapiMsg_PPPContentDecryptor_ResetDecoder
,
517 IPC_MESSAGE_HANDLER(PpapiMsg_PPPContentDecryptor_DecryptAndDecode
,
518 OnMsgDecryptAndDecode
)
519 IPC_MESSAGE_UNHANDLED(handled
= false)
520 IPC_END_MESSAGE_MAP()
525 void PPP_ContentDecryptor_Private_Proxy::OnMsgInitialize(
526 PP_Instance instance
,
527 SerializedVarReceiveInput key_system
,
528 PP_Bool allow_distinctive_identifier
,
529 PP_Bool allow_persistent_state
) {
530 if (ppp_decryptor_impl_
) {
532 ppp_decryptor_impl_
->Initialize
,
534 ExtractReceivedVarAndAddRef(dispatcher(), &key_system
),
535 allow_distinctive_identifier
,
536 allow_persistent_state
);
540 void PPP_ContentDecryptor_Private_Proxy::OnMsgSetServerCertificate(
541 PP_Instance instance
,
543 std::vector
<uint8_t> server_certificate
) {
544 if (server_certificate
.size() < media::limits::kMinCertificateLength
||
545 server_certificate
.size() > media::limits::kMaxCertificateLength
) {
550 if (ppp_decryptor_impl_
) {
551 ScopedPPVar
server_certificate_var(
552 ScopedPPVar::PassRef(),
555 ->MakeArrayBufferPPVar(
556 static_cast<uint32_t>(server_certificate
.size()),
557 &server_certificate
[0]));
558 CallWhileUnlocked(ppp_decryptor_impl_
->SetServerCertificate
,
561 server_certificate_var
.get());
565 void PPP_ContentDecryptor_Private_Proxy::OnMsgCreateSessionAndGenerateRequest(
566 PP_Instance instance
,
568 PP_SessionType session_type
,
569 PP_InitDataType init_data_type
,
570 SerializedVarReceiveInput init_data
) {
571 if (ppp_decryptor_impl_
) {
572 CallWhileUnlocked(ppp_decryptor_impl_
->CreateSessionAndGenerateRequest
,
573 instance
, promise_id
, session_type
, init_data_type
,
574 ExtractReceivedVarAndAddRef(dispatcher(), &init_data
));
578 void PPP_ContentDecryptor_Private_Proxy::OnMsgLoadSession(
579 PP_Instance instance
,
581 PP_SessionType session_type
,
582 SerializedVarReceiveInput session_id
) {
583 if (ppp_decryptor_impl_
) {
584 CallWhileUnlocked(ppp_decryptor_impl_
->LoadSession
, instance
, promise_id
,
586 ExtractReceivedVarAndAddRef(dispatcher(), &session_id
));
590 void PPP_ContentDecryptor_Private_Proxy::OnMsgUpdateSession(
591 PP_Instance instance
,
593 SerializedVarReceiveInput session_id
,
594 SerializedVarReceiveInput response
) {
595 if (ppp_decryptor_impl_
) {
596 CallWhileUnlocked(ppp_decryptor_impl_
->UpdateSession
, instance
, promise_id
,
597 ExtractReceivedVarAndAddRef(dispatcher(), &session_id
),
598 ExtractReceivedVarAndAddRef(dispatcher(), &response
));
602 void PPP_ContentDecryptor_Private_Proxy::OnMsgCloseSession(
603 PP_Instance instance
,
605 const std::string
& session_id
) {
606 if (ppp_decryptor_impl_
) {
607 ScopedPPVar
session_id_var(ScopedPPVar::PassRef(),
608 StringVar::StringToPPVar(session_id
));
609 CallWhileUnlocked(ppp_decryptor_impl_
->CloseSession
, instance
, promise_id
,
610 session_id_var
.get());
614 void PPP_ContentDecryptor_Private_Proxy::OnMsgRemoveSession(
615 PP_Instance instance
,
617 const std::string
& session_id
) {
618 if (ppp_decryptor_impl_
) {
619 ScopedPPVar
session_id_var(ScopedPPVar::PassRef(),
620 StringVar::StringToPPVar(session_id
));
621 CallWhileUnlocked(ppp_decryptor_impl_
->RemoveSession
, instance
, promise_id
,
622 session_id_var
.get());
626 void PPP_ContentDecryptor_Private_Proxy::OnMsgDecrypt(
627 PP_Instance instance
,
628 const PPPDecryptor_Buffer
& encrypted_buffer
,
629 const std::string
& serialized_block_info
) {
630 ScopedPPResource
plugin_resource(
631 ScopedPPResource::PassRef(),
632 PPB_Buffer_Proxy::AddProxyResource(encrypted_buffer
.resource
,
633 encrypted_buffer
.handle
,
634 encrypted_buffer
.size
));
635 if (ppp_decryptor_impl_
) {
636 PP_EncryptedBlockInfo block_info
;
637 if (!DeserializeBlockInfo(serialized_block_info
, &block_info
))
639 CallWhileUnlocked(ppp_decryptor_impl_
->Decrypt
,
641 plugin_resource
.get(),
646 void PPP_ContentDecryptor_Private_Proxy::OnMsgInitializeAudioDecoder(
647 PP_Instance instance
,
648 const std::string
& serialized_decoder_config
,
649 const PPPDecryptor_Buffer
& extra_data_buffer
) {
650 ScopedPPResource plugin_resource
;
651 if (extra_data_buffer
.size
> 0) {
652 plugin_resource
= ScopedPPResource(
653 ScopedPPResource::PassRef(),
654 PPB_Buffer_Proxy::AddProxyResource(extra_data_buffer
.resource
,
655 extra_data_buffer
.handle
,
656 extra_data_buffer
.size
));
659 PP_AudioDecoderConfig decoder_config
;
660 if (!DeserializeBlockInfo(serialized_decoder_config
, &decoder_config
))
663 if (ppp_decryptor_impl_
) {
665 ppp_decryptor_impl_
->InitializeAudioDecoder
,
668 plugin_resource
.get());
672 void PPP_ContentDecryptor_Private_Proxy::OnMsgInitializeVideoDecoder(
673 PP_Instance instance
,
674 const std::string
& serialized_decoder_config
,
675 const PPPDecryptor_Buffer
& extra_data_buffer
) {
676 ScopedPPResource plugin_resource
;
677 if (extra_data_buffer
.resource
.host_resource() != 0) {
678 plugin_resource
= ScopedPPResource(
679 ScopedPPResource::PassRef(),
680 PPB_Buffer_Proxy::AddProxyResource(extra_data_buffer
.resource
,
681 extra_data_buffer
.handle
,
682 extra_data_buffer
.size
));
685 PP_VideoDecoderConfig decoder_config
;
686 if (!DeserializeBlockInfo(serialized_decoder_config
, &decoder_config
))
689 if (ppp_decryptor_impl_
) {
691 ppp_decryptor_impl_
->InitializeVideoDecoder
,
694 plugin_resource
.get());
698 void PPP_ContentDecryptor_Private_Proxy::OnMsgDeinitializeDecoder(
699 PP_Instance instance
,
700 PP_DecryptorStreamType decoder_type
,
701 uint32_t request_id
) {
702 if (ppp_decryptor_impl_
) {
704 ppp_decryptor_impl_
->DeinitializeDecoder
,
711 void PPP_ContentDecryptor_Private_Proxy::OnMsgResetDecoder(
712 PP_Instance instance
,
713 PP_DecryptorStreamType decoder_type
,
714 uint32_t request_id
) {
715 if (ppp_decryptor_impl_
) {
717 ppp_decryptor_impl_
->ResetDecoder
,
724 void PPP_ContentDecryptor_Private_Proxy::OnMsgDecryptAndDecode(
725 PP_Instance instance
,
726 PP_DecryptorStreamType decoder_type
,
727 const PPPDecryptor_Buffer
& encrypted_buffer
,
728 const std::string
& serialized_block_info
) {
729 ScopedPPResource plugin_resource
;
730 if (encrypted_buffer
.resource
.host_resource() != 0) {
731 plugin_resource
= ScopedPPResource(
732 ScopedPPResource::PassRef(),
733 PPB_Buffer_Proxy::AddProxyResource(encrypted_buffer
.resource
,
734 encrypted_buffer
.handle
,
735 encrypted_buffer
.size
));
738 if (ppp_decryptor_impl_
) {
739 PP_EncryptedBlockInfo block_info
;
740 if (!DeserializeBlockInfo(serialized_block_info
, &block_info
))
743 ppp_decryptor_impl_
->DecryptAndDecode
,
746 plugin_resource
.get(),