• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/ppapi_proxy_test.h"
6 
7 #include <sstream>
8 
9 #include "base/bind.h"
10 #include "base/bind_helpers.h"
11 #include "base/message_loop/message_loop_proxy.h"
12 #include "base/observer_list.h"
13 #include "base/run_loop.h"
14 #include "ipc/ipc_sync_channel.h"
15 #include "ppapi/c/pp_errors.h"
16 #include "ppapi/c/private/ppb_proxy_private.h"
17 #include "ppapi/proxy/ppapi_messages.h"
18 #include "ppapi/proxy/ppb_message_loop_proxy.h"
19 #include "ppapi/shared_impl/proxy_lock.h"
20 
21 namespace ppapi {
22 namespace proxy {
23 
24 namespace {
25 // HostDispatcher requires a PPB_Proxy_Private, so we always provide a fallback
26 // do-nothing implementation.
PluginCrashed(PP_Module module)27 void PluginCrashed(PP_Module module) {
28   NOTREACHED();
29 };
30 
GetInstanceForResource(PP_Resource resource)31 PP_Instance GetInstanceForResource(PP_Resource resource) {
32   // If a test relies on this, we need to implement it.
33   NOTREACHED();
34   return 0;
35 }
36 
SetReserveInstanceIDCallback(PP_Module module,PP_Bool (* is_seen)(PP_Module,PP_Instance))37 void SetReserveInstanceIDCallback(PP_Module module,
38                                   PP_Bool (*is_seen)(PP_Module, PP_Instance)) {
39   // This function gets called in HostDispatcher's constructor.  We simply don't
40   // worry about Instance uniqueness in tests, so we can ignore the call.
41 }
42 
AddRefModule(PP_Module module)43 void AddRefModule(PP_Module module) {}
ReleaseModule(PP_Module module)44 void ReleaseModule(PP_Module module) {}
IsInModuleDestructor(PP_Module module)45 PP_Bool IsInModuleDestructor(PP_Module module) { return PP_FALSE; }
46 
47 PPB_Proxy_Private ppb_proxy_private = {
48   &PluginCrashed,
49   &GetInstanceForResource,
50   &SetReserveInstanceIDCallback,
51   &AddRefModule,
52   &ReleaseModule,
53   &IsInModuleDestructor
54 };
55 
56 // We allow multiple harnesses at a time to respond to 'GetInterface' calls.
57 // We assume that only 1 harness's GetInterface function will ever support a
58 // given interface name. In practice, there will either be only 1 GetInterface
59 // handler (for PluginProxyTest or HostProxyTest), or there will be only 2
60 // GetInterface handlers (for TwoWayTest).  In the latter case, one handler is
61 // for the PluginProxyTestHarness and should only respond for PPP interfaces,
62 // and the other handler is for the HostProxyTestHarness which should only
63 // ever respond for PPB interfaces.
64 ObserverList<ProxyTestHarnessBase> get_interface_handlers_;
65 
MockGetInterface(const char * name)66 const void* MockGetInterface(const char* name) {
67   ObserverList<ProxyTestHarnessBase>::Iterator it =
68       get_interface_handlers_;
69   while (ProxyTestHarnessBase* observer = it.GetNext()) {
70     const void* interface = observer->GetInterface(name);
71     if (interface)
72       return interface;
73   }
74   if (strcmp(name, PPB_PROXY_PRIVATE_INTERFACE) == 0)
75     return &ppb_proxy_private;
76   return NULL;
77 }
78 
SetUpRemoteHarness(ProxyTestHarnessBase * harness,const IPC::ChannelHandle & handle,base::MessageLoopProxy * ipc_message_loop_proxy,base::WaitableEvent * shutdown_event,base::WaitableEvent * harness_set_up)79 void SetUpRemoteHarness(ProxyTestHarnessBase* harness,
80                         const IPC::ChannelHandle& handle,
81                         base::MessageLoopProxy* ipc_message_loop_proxy,
82                         base::WaitableEvent* shutdown_event,
83                         base::WaitableEvent* harness_set_up) {
84   harness->SetUpHarnessWithChannel(handle, ipc_message_loop_proxy,
85                                    shutdown_event, false);
86   harness_set_up->Signal();
87 }
88 
TearDownRemoteHarness(ProxyTestHarnessBase * harness,base::WaitableEvent * harness_torn_down)89 void TearDownRemoteHarness(ProxyTestHarnessBase* harness,
90                            base::WaitableEvent* harness_torn_down) {
91   harness->TearDownHarness();
92   harness_torn_down->Signal();
93 }
94 
RunTaskOnRemoteHarness(const base::Closure & task,base::WaitableEvent * task_complete)95 void RunTaskOnRemoteHarness(const base::Closure& task,
96                             base::WaitableEvent* task_complete) {
97  task.Run();
98  task_complete->Signal();
99 }
100 
101 }  // namespace
102 
103 // ProxyTestHarnessBase --------------------------------------------------------
104 
ProxyTestHarnessBase()105 ProxyTestHarnessBase::ProxyTestHarnessBase() : pp_module_(0x98765),
106                                                pp_instance_(0x12345) {
107   get_interface_handlers_.AddObserver(this);
108 }
109 
~ProxyTestHarnessBase()110 ProxyTestHarnessBase::~ProxyTestHarnessBase() {
111   get_interface_handlers_.RemoveObserver(this);
112 }
113 
GetInterface(const char * name)114 const void* ProxyTestHarnessBase::GetInterface(const char* name) {
115   return registered_interfaces_[name];
116 }
117 
RegisterTestInterface(const char * name,const void * test_interface)118 void ProxyTestHarnessBase::RegisterTestInterface(const char* name,
119                                                  const void* test_interface) {
120   registered_interfaces_[name] = test_interface;
121 }
122 
SupportsInterface(const char * name)123 bool ProxyTestHarnessBase::SupportsInterface(const char* name) {
124   sink().ClearMessages();
125 
126   // IPC doesn't actually write to this when we send a message manually
127   // not actually using IPC.
128   bool unused_result = false;
129   PpapiMsg_SupportsInterface msg(name, &unused_result);
130   GetDispatcher()->OnMessageReceived(msg);
131 
132   const IPC::Message* reply_msg =
133       sink().GetUniqueMessageMatching(IPC_REPLY_ID);
134   EXPECT_TRUE(reply_msg);
135   if (!reply_msg)
136     return false;
137 
138   TupleTypes<PpapiMsg_SupportsInterface::ReplyParam>::ValueTuple reply_data;
139   EXPECT_TRUE(PpapiMsg_SupportsInterface::ReadReplyParam(
140       reply_msg, &reply_data));
141 
142   sink().ClearMessages();
143   return reply_data.a;
144 }
145 
146 // PluginProxyTestHarness ------------------------------------------------------
147 
PluginProxyTestHarness(GlobalsConfiguration globals_config)148 PluginProxyTestHarness::PluginProxyTestHarness(
149     GlobalsConfiguration globals_config)
150     : globals_config_(globals_config) {
151 }
152 
~PluginProxyTestHarness()153 PluginProxyTestHarness::~PluginProxyTestHarness() {
154 }
155 
GetGlobals()156 PpapiGlobals* PluginProxyTestHarness::GetGlobals() {
157   return plugin_globals_.get();
158 }
159 
GetDispatcher()160 Dispatcher* PluginProxyTestHarness::GetDispatcher() {
161   return plugin_dispatcher_.get();
162 }
163 
SetUpHarness()164 void PluginProxyTestHarness::SetUpHarness() {
165   // These must be first since the dispatcher set-up uses them.
166   CreatePluginGlobals();
167   // Some of the methods called during set-up check that the lock is held.
168   ProxyAutoLock lock;
169 
170   resource_tracker().DidCreateInstance(pp_instance());
171 
172   plugin_dispatcher_.reset(new PluginDispatcher(
173       &MockGetInterface,
174       PpapiPermissions(),
175       false));
176   plugin_dispatcher_->InitWithTestSink(&sink());
177   // The plugin proxy delegate is needed for
178   // |PluginProxyDelegate::GetBrowserSender| which is used
179   // in |ResourceCreationProxy::GetConnection| to get the channel to the
180   // browser. In this case we just use the |plugin_dispatcher_| as the channel
181   // for test purposes.
182   plugin_delegate_mock_.set_browser_sender(plugin_dispatcher_.get());
183   PluginGlobals::Get()->set_plugin_proxy_delegate(&plugin_delegate_mock_);
184   plugin_dispatcher_->DidCreateInstance(pp_instance());
185 }
186 
SetUpHarnessWithChannel(const IPC::ChannelHandle & channel_handle,base::MessageLoopProxy * ipc_message_loop,base::WaitableEvent * shutdown_event,bool is_client)187 void PluginProxyTestHarness::SetUpHarnessWithChannel(
188     const IPC::ChannelHandle& channel_handle,
189     base::MessageLoopProxy* ipc_message_loop,
190     base::WaitableEvent* shutdown_event,
191     bool is_client) {
192   // These must be first since the dispatcher set-up uses them.
193   CreatePluginGlobals();
194   // Some of the methods called during set-up check that the lock is held.
195   ProxyAutoLock lock;
196 
197   resource_tracker().DidCreateInstance(pp_instance());
198   plugin_delegate_mock_.Init(ipc_message_loop, shutdown_event);
199 
200   plugin_dispatcher_.reset(new PluginDispatcher(
201       &MockGetInterface,
202       PpapiPermissions(),
203       false));
204   plugin_dispatcher_->InitPluginWithChannel(&plugin_delegate_mock_,
205                                             base::kNullProcessId,
206                                             channel_handle,
207                                             is_client);
208   plugin_delegate_mock_.set_browser_sender(plugin_dispatcher_.get());
209   PluginGlobals::Get()->set_plugin_proxy_delegate(&plugin_delegate_mock_);
210   plugin_dispatcher_->DidCreateInstance(pp_instance());
211 }
212 
TearDownHarness()213 void PluginProxyTestHarness::TearDownHarness() {
214   {
215     // Some of the methods called during tear-down check that the lock is held.
216     ProxyAutoLock lock;
217 
218     plugin_dispatcher_->DidDestroyInstance(pp_instance());
219     plugin_dispatcher_.reset();
220 
221     resource_tracker().DidDeleteInstance(pp_instance());
222   }
223   plugin_globals_.reset();
224 }
225 
CreatePluginGlobals()226 void PluginProxyTestHarness::CreatePluginGlobals() {
227   if (globals_config_ == PER_THREAD_GLOBALS) {
228     plugin_globals_.reset(new PluginGlobals(PpapiGlobals::PerThreadForTest()));
229     PpapiGlobals::SetPpapiGlobalsOnThreadForTest(GetGlobals());
230     // Enable locking in case some other unit test ran before us and disabled
231     // locking.
232     ProxyLock::EnableLockingOnThreadForTest();
233   } else {
234     plugin_globals_.reset(new PluginGlobals());
235     ProxyLock::EnableLockingOnThreadForTest();
236   }
237 }
238 
239 base::MessageLoopProxy*
GetIPCMessageLoop()240 PluginProxyTestHarness::PluginDelegateMock::GetIPCMessageLoop() {
241   return ipc_message_loop_;
242 }
243 
244 base::WaitableEvent*
GetShutdownEvent()245 PluginProxyTestHarness::PluginDelegateMock::GetShutdownEvent() {
246   return shutdown_event_;
247 }
248 
249 IPC::PlatformFileForTransit
ShareHandleWithRemote(base::PlatformFile handle,base::ProcessId,bool should_close_source)250 PluginProxyTestHarness::PluginDelegateMock::ShareHandleWithRemote(
251     base::PlatformFile handle,
252     base::ProcessId /* remote_pid */,
253     bool should_close_source) {
254   return IPC::GetFileHandleForProcess(handle,
255                                       base::Process::Current().handle(),
256                                       should_close_source);
257 }
258 
259 std::set<PP_Instance>*
GetGloballySeenInstanceIDSet()260 PluginProxyTestHarness::PluginDelegateMock::GetGloballySeenInstanceIDSet() {
261   return &instance_id_set_;
262 }
263 
Register(PluginDispatcher * plugin_dispatcher)264 uint32 PluginProxyTestHarness::PluginDelegateMock::Register(
265     PluginDispatcher* plugin_dispatcher) {
266   return 0;
267 }
268 
Unregister(uint32 plugin_dispatcher_id)269 void PluginProxyTestHarness::PluginDelegateMock::Unregister(
270     uint32 plugin_dispatcher_id) {
271 }
272 
GetBrowserSender()273 IPC::Sender* PluginProxyTestHarness::PluginDelegateMock::GetBrowserSender() {
274   return browser_sender_;
275 }
276 
GetUILanguage()277 std::string PluginProxyTestHarness::PluginDelegateMock::GetUILanguage() {
278   return std::string("en-US");
279 }
280 
PreCacheFont(const void * logfontw)281 void PluginProxyTestHarness::PluginDelegateMock::PreCacheFont(
282     const void* logfontw) {
283 }
284 
SetActiveURL(const std::string & url)285 void PluginProxyTestHarness::PluginDelegateMock::SetActiveURL(
286     const std::string& url) {
287 }
288 
CreateBrowserFont(Connection connection,PP_Instance instance,const PP_BrowserFont_Trusted_Description & desc,const Preferences & prefs)289 PP_Resource PluginProxyTestHarness::PluginDelegateMock::CreateBrowserFont(
290     Connection connection,
291     PP_Instance instance,
292     const PP_BrowserFont_Trusted_Description& desc,
293     const Preferences& prefs) {
294   return 0;
295 }
296 
297 // PluginProxyTest -------------------------------------------------------------
298 
PluginProxyTest()299 PluginProxyTest::PluginProxyTest() : PluginProxyTestHarness(SINGLETON_GLOBALS) {
300 }
301 
~PluginProxyTest()302 PluginProxyTest::~PluginProxyTest() {
303 }
304 
SetUp()305 void PluginProxyTest::SetUp() {
306   SetUpHarness();
307 }
308 
TearDown()309 void PluginProxyTest::TearDown() {
310   TearDownHarness();
311 }
312 
313 // PluginProxyMultiThreadTest --------------------------------------------------
314 
PluginProxyMultiThreadTest()315 PluginProxyMultiThreadTest::PluginProxyMultiThreadTest() {
316 }
317 
~PluginProxyMultiThreadTest()318 PluginProxyMultiThreadTest::~PluginProxyMultiThreadTest() {
319 }
320 
RunTest()321 void PluginProxyMultiThreadTest::RunTest() {
322   main_thread_message_loop_proxy_ =
323       PpapiGlobals::Get()->GetMainThreadMessageLoop();
324   ASSERT_EQ(main_thread_message_loop_proxy_.get(),
325             base::MessageLoopProxy::current());
326   nested_main_thread_message_loop_.reset(new base::RunLoop());
327 
328   secondary_thread_.reset(new base::DelegateSimpleThread(
329       this, "PluginProxyMultiThreadTest"));
330 
331   {
332     ProxyAutoLock auto_lock;
333 
334     // MessageLoopResource assumes that the proxy lock has been acquired.
335     secondary_thread_message_loop_ = new MessageLoopResource(pp_instance());
336 
337     ASSERT_EQ(PP_OK,
338         secondary_thread_message_loop_->PostWork(
339             PP_MakeCompletionCallback(
340                 &PluginProxyMultiThreadTest::InternalSetUpTestOnSecondaryThread,
341                 this),
342             0));
343   }
344 
345   SetUpTestOnMainThread();
346 
347   secondary_thread_->Start();
348   nested_main_thread_message_loop_->Run();
349   secondary_thread_->Join();
350 
351   {
352     ProxyAutoLock auto_lock;
353 
354     // The destruction requires a valid PpapiGlobals instance, so we should
355     // explicitly release it.
356     secondary_thread_message_loop_ = NULL;
357   }
358 
359   secondary_thread_.reset(NULL);
360   nested_main_thread_message_loop_.reset(NULL);
361   main_thread_message_loop_proxy_ = NULL;
362 }
363 
CheckOnThread(ThreadType thread_type)364 void PluginProxyMultiThreadTest::CheckOnThread(ThreadType thread_type) {
365   ProxyAutoLock auto_lock;
366   if (thread_type == MAIN_THREAD) {
367     ASSERT_TRUE(MessageLoopResource::GetCurrent()->is_main_thread_loop());
368   } else {
369     ASSERT_EQ(secondary_thread_message_loop_.get(),
370               MessageLoopResource::GetCurrent());
371   }
372 }
373 
PostQuitForMainThread()374 void PluginProxyMultiThreadTest::PostQuitForMainThread() {
375   main_thread_message_loop_proxy_->PostTask(
376       FROM_HERE,
377       base::Bind(&PluginProxyMultiThreadTest::QuitNestedLoop,
378                  base::Unretained(this)));
379 }
380 
PostQuitForSecondaryThread()381 void PluginProxyMultiThreadTest::PostQuitForSecondaryThread() {
382   ProxyAutoLock auto_lock;
383   secondary_thread_message_loop_->PostQuit(PP_TRUE);
384 }
385 
Run()386 void PluginProxyMultiThreadTest::Run() {
387   ProxyAutoLock auto_lock;
388   ASSERT_EQ(PP_OK, secondary_thread_message_loop_->AttachToCurrentThread());
389   ASSERT_EQ(PP_OK, secondary_thread_message_loop_->Run());
390   secondary_thread_message_loop_->DetachFromThread();
391 }
392 
QuitNestedLoop()393 void PluginProxyMultiThreadTest::QuitNestedLoop() {
394   nested_main_thread_message_loop_->Quit();
395 }
396 
397 // static
InternalSetUpTestOnSecondaryThread(void * user_data,int32_t result)398 void PluginProxyMultiThreadTest::InternalSetUpTestOnSecondaryThread(
399     void* user_data,
400     int32_t result) {
401   EXPECT_EQ(PP_OK, result);
402   PluginProxyMultiThreadTest* thiz =
403       static_cast<PluginProxyMultiThreadTest*>(user_data);
404   thiz->CheckOnThread(SECONDARY_THREAD);
405   thiz->SetUpTestOnSecondaryThread();
406 }
407 
408 // HostProxyTestHarness --------------------------------------------------------
409 
410 class HostProxyTestHarness::MockSyncMessageStatusReceiver
411     : public HostDispatcher::SyncMessageStatusReceiver {
412  public:
BeginBlockOnSyncMessage()413   virtual void BeginBlockOnSyncMessage() OVERRIDE {}
EndBlockOnSyncMessage()414   virtual void EndBlockOnSyncMessage() OVERRIDE {}
415 };
416 
HostProxyTestHarness(GlobalsConfiguration globals_config)417 HostProxyTestHarness::HostProxyTestHarness(GlobalsConfiguration globals_config)
418     : globals_config_(globals_config),
419       status_receiver_(new MockSyncMessageStatusReceiver) {
420 }
421 
~HostProxyTestHarness()422 HostProxyTestHarness::~HostProxyTestHarness() {
423 }
424 
GetGlobals()425 PpapiGlobals* HostProxyTestHarness::GetGlobals() {
426   return host_globals_.get();
427 }
428 
GetDispatcher()429 Dispatcher* HostProxyTestHarness::GetDispatcher() {
430   return host_dispatcher_.get();
431 }
432 
SetUpHarness()433 void HostProxyTestHarness::SetUpHarness() {
434   // These must be first since the dispatcher set-up uses them.
435   CreateHostGlobals();
436 
437   host_dispatcher_.reset(new HostDispatcher(
438       pp_module(),
439       &MockGetInterface,
440       status_receiver_.release(),
441       PpapiPermissions::AllPermissions()));
442   host_dispatcher_->InitWithTestSink(&sink());
443   HostDispatcher::SetForInstance(pp_instance(), host_dispatcher_.get());
444 }
445 
SetUpHarnessWithChannel(const IPC::ChannelHandle & channel_handle,base::MessageLoopProxy * ipc_message_loop,base::WaitableEvent * shutdown_event,bool is_client)446 void HostProxyTestHarness::SetUpHarnessWithChannel(
447     const IPC::ChannelHandle& channel_handle,
448     base::MessageLoopProxy* ipc_message_loop,
449     base::WaitableEvent* shutdown_event,
450     bool is_client) {
451   // These must be first since the dispatcher set-up uses them.
452   CreateHostGlobals();
453 
454   delegate_mock_.Init(ipc_message_loop, shutdown_event);
455 
456   host_dispatcher_.reset(new HostDispatcher(
457       pp_module(),
458       &MockGetInterface,
459       status_receiver_.release(),
460       PpapiPermissions::AllPermissions()));
461   ppapi::Preferences preferences;
462   host_dispatcher_->InitHostWithChannel(&delegate_mock_,
463                                         base::kNullProcessId, channel_handle,
464                                         is_client, preferences);
465   HostDispatcher::SetForInstance(pp_instance(), host_dispatcher_.get());
466 }
467 
TearDownHarness()468 void HostProxyTestHarness::TearDownHarness() {
469   HostDispatcher::RemoveForInstance(pp_instance());
470   host_dispatcher_.reset();
471   host_globals_.reset();
472 }
473 
CreateHostGlobals()474 void HostProxyTestHarness::CreateHostGlobals() {
475   if (globals_config_ == PER_THREAD_GLOBALS) {
476     host_globals_.reset(new TestGlobals(PpapiGlobals::PerThreadForTest()));
477     PpapiGlobals::SetPpapiGlobalsOnThreadForTest(GetGlobals());
478     // The host side of the proxy does not lock.
479     ProxyLock::DisableLockingOnThreadForTest();
480   } else {
481     ProxyLock::DisableLockingOnThreadForTest();
482     host_globals_.reset(new TestGlobals());
483   }
484 }
485 
486 base::MessageLoopProxy*
GetIPCMessageLoop()487 HostProxyTestHarness::DelegateMock::GetIPCMessageLoop() {
488   return ipc_message_loop_;
489 }
490 
GetShutdownEvent()491 base::WaitableEvent* HostProxyTestHarness::DelegateMock::GetShutdownEvent() {
492   return shutdown_event_;
493 }
494 
495 IPC::PlatformFileForTransit
ShareHandleWithRemote(base::PlatformFile handle,base::ProcessId,bool should_close_source)496 HostProxyTestHarness::DelegateMock::ShareHandleWithRemote(
497     base::PlatformFile handle,
498     base::ProcessId /* remote_pid */,
499     bool should_close_source) {
500   return IPC::GetFileHandleForProcess(handle,
501                                       base::Process::Current().handle(),
502                                       should_close_source);
503 }
504 
505 
506 // HostProxyTest ---------------------------------------------------------------
507 
HostProxyTest()508 HostProxyTest::HostProxyTest() : HostProxyTestHarness(SINGLETON_GLOBALS) {
509 }
510 
~HostProxyTest()511 HostProxyTest::~HostProxyTest() {
512 }
513 
SetUp()514 void HostProxyTest::SetUp() {
515   SetUpHarness();
516 }
517 
TearDown()518 void HostProxyTest::TearDown() {
519   TearDownHarness();
520 }
521 
522 // TwoWayTest ---------------------------------------------------------------
523 
TwoWayTest(TwoWayTest::TwoWayTestMode test_mode)524 TwoWayTest::TwoWayTest(TwoWayTest::TwoWayTestMode test_mode)
525     : test_mode_(test_mode),
526       host_(ProxyTestHarnessBase::PER_THREAD_GLOBALS),
527       plugin_(ProxyTestHarnessBase::PER_THREAD_GLOBALS),
528       io_thread_("TwoWayTest_IOThread"),
529       plugin_thread_("TwoWayTest_PluginThread"),
530       remote_harness_(NULL),
531       local_harness_(NULL),
532       channel_created_(true, false),
533       shutdown_event_(true, false) {
534   if (test_mode == TEST_PPP_INTERFACE) {
535     remote_harness_ = &plugin_;
536     local_harness_ = &host_;
537   } else {
538     remote_harness_ = &host_;
539     local_harness_ = &plugin_;
540   }
541 }
542 
~TwoWayTest()543 TwoWayTest::~TwoWayTest() {
544   shutdown_event_.Signal();
545 }
546 
SetUp()547 void TwoWayTest::SetUp() {
548   base::Thread::Options options;
549   options.message_loop_type = base::MessageLoop::TYPE_IO;
550   io_thread_.StartWithOptions(options);
551   plugin_thread_.Start();
552 
553   // Construct the IPC handle name using the process ID so we can safely run
554   // multiple |TwoWayTest|s concurrently.
555   std::ostringstream handle_name;
556   handle_name << "TwoWayTestChannel" << base::GetCurrentProcId();
557   IPC::ChannelHandle handle(handle_name.str());
558   base::WaitableEvent remote_harness_set_up(true, false);
559   plugin_thread_.message_loop_proxy()->PostTask(
560       FROM_HERE,
561       base::Bind(&SetUpRemoteHarness,
562                  remote_harness_,
563                  handle,
564                  io_thread_.message_loop_proxy(),
565                  &shutdown_event_,
566                  &remote_harness_set_up));
567   remote_harness_set_up.Wait();
568   local_harness_->SetUpHarnessWithChannel(handle,
569                                           io_thread_.message_loop_proxy().get(),
570                                           &shutdown_event_,
571                                           true);  // is_client
572 }
573 
TearDown()574 void TwoWayTest::TearDown() {
575   base::WaitableEvent remote_harness_torn_down(true, false);
576   plugin_thread_.message_loop_proxy()->PostTask(
577       FROM_HERE,
578       base::Bind(&TearDownRemoteHarness,
579                  remote_harness_,
580                  &remote_harness_torn_down));
581   remote_harness_torn_down.Wait();
582 
583   local_harness_->TearDownHarness();
584 
585   io_thread_.Stop();
586 }
587 
PostTaskOnRemoteHarness(const base::Closure & task)588 void TwoWayTest::PostTaskOnRemoteHarness(const base::Closure& task) {
589   base::WaitableEvent task_complete(true, false);
590   plugin_thread_.message_loop_proxy()->PostTask(FROM_HERE,
591       base::Bind(&RunTaskOnRemoteHarness,
592                  task,
593                  &task_complete));
594   task_complete.Wait();
595 }
596 
597 
598 }  // namespace proxy
599 }  // namespace ppapi
600