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