Home | History | Annotate | Download | only in proxy
      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