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