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