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