Home | History | Annotate | Download | only in mac
      1 // Copyright 2016 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 "base/mac/mach_port_broker.h"
      6 
      7 #include "base/command_line.h"
      8 #include "base/synchronization/lock.h"
      9 #include "base/synchronization/waitable_event.h"
     10 #include "base/test/multiprocess_test.h"
     11 #include "base/test/test_timeouts.h"
     12 #include "testing/gtest/include/gtest/gtest.h"
     13 #include "testing/multiprocess_func_list.h"
     14 
     15 namespace base {
     16 
     17 namespace {
     18 const char kBootstrapPortName[] = "thisisatest";
     19 }
     20 
     21 class MachPortBrokerTest : public testing::Test,
     22                            public base::PortProvider::Observer {
     23  public:
     24   MachPortBrokerTest()
     25       : broker_(kBootstrapPortName),
     26         event_(base::WaitableEvent::ResetPolicy::MANUAL,
     27                base::WaitableEvent::InitialState::NOT_SIGNALED),
     28         received_process_(kNullProcessHandle) {
     29     broker_.AddObserver(this);
     30   }
     31   ~MachPortBrokerTest() override {
     32     broker_.RemoveObserver(this);
     33   }
     34 
     35   // Helper function to acquire/release locks and call |PlaceholderForPid()|.
     36   void AddPlaceholderForPid(base::ProcessHandle pid) {
     37     base::AutoLock lock(broker_.GetLock());
     38     broker_.AddPlaceholderForPid(pid);
     39   }
     40 
     41   // Helper function to acquire/release locks and call |FinalizePid()|.
     42   void FinalizePid(base::ProcessHandle pid,
     43                    mach_port_t task_port) {
     44     base::AutoLock lock(broker_.GetLock());
     45     broker_.FinalizePid(pid, task_port);
     46   }
     47 
     48   void WaitForTaskPort() {
     49     event_.Wait();
     50   }
     51 
     52   // base::PortProvider::Observer:
     53   void OnReceivedTaskPort(ProcessHandle process) override {
     54     received_process_ = process;
     55     event_.Signal();
     56   }
     57 
     58  protected:
     59   MachPortBroker broker_;
     60   WaitableEvent event_;
     61   ProcessHandle received_process_;
     62 };
     63 
     64 TEST_F(MachPortBrokerTest, Locks) {
     65   // Acquire and release the locks.  Nothing bad should happen.
     66   base::AutoLock lock(broker_.GetLock());
     67 }
     68 
     69 TEST_F(MachPortBrokerTest, AddPlaceholderAndFinalize) {
     70   // Add a placeholder for PID 1.
     71   AddPlaceholderForPid(1);
     72   EXPECT_EQ(0u, broker_.TaskForPid(1));
     73 
     74   // Finalize PID 1.
     75   FinalizePid(1, 100u);
     76   EXPECT_EQ(100u, broker_.TaskForPid(1));
     77 
     78   // Should be no entry for PID 2.
     79   EXPECT_EQ(0u, broker_.TaskForPid(2));
     80 }
     81 
     82 TEST_F(MachPortBrokerTest, FinalizeUnknownPid) {
     83   // Finalizing an entry for an unknown pid should not add it to the map.
     84   FinalizePid(1u, 100u);
     85   EXPECT_EQ(0u, broker_.TaskForPid(1u));
     86 }
     87 
     88 MULTIPROCESS_TEST_MAIN(MachPortBrokerTestChild) {
     89   CHECK(base::MachPortBroker::ChildSendTaskPortToParent(kBootstrapPortName));
     90   return 0;
     91 }
     92 
     93 TEST_F(MachPortBrokerTest, ReceivePortFromChild) {
     94   ASSERT_TRUE(broker_.Init());
     95   CommandLine command_line(
     96       base::GetMultiProcessTestChildBaseCommandLine());
     97   broker_.GetLock().Acquire();
     98   base::Process test_child_process = base::SpawnMultiProcessTestChild(
     99       "MachPortBrokerTestChild", command_line, LaunchOptions());
    100   broker_.AddPlaceholderForPid(test_child_process.Handle());
    101   broker_.GetLock().Release();
    102 
    103   WaitForTaskPort();
    104   EXPECT_EQ(test_child_process.Handle(), received_process_);
    105 
    106   int rv = -1;
    107   ASSERT_TRUE(test_child_process.WaitForExitWithTimeout(
    108       TestTimeouts::action_timeout(), &rv));
    109   EXPECT_EQ(0, rv);
    110 
    111   EXPECT_NE(static_cast<mach_port_t>(MACH_PORT_NULL),
    112             broker_.TaskForPid(test_child_process.Handle()));
    113 }
    114 
    115 TEST_F(MachPortBrokerTest, ReceivePortFromChildWithoutAdding) {
    116   ASSERT_TRUE(broker_.Init());
    117   CommandLine command_line(
    118       base::GetMultiProcessTestChildBaseCommandLine());
    119   broker_.GetLock().Acquire();
    120   base::Process test_child_process = base::SpawnMultiProcessTestChild(
    121       "MachPortBrokerTestChild", command_line, LaunchOptions());
    122   broker_.GetLock().Release();
    123 
    124   int rv = -1;
    125   ASSERT_TRUE(test_child_process.WaitForExitWithTimeout(
    126       TestTimeouts::action_timeout(), &rv));
    127   EXPECT_EQ(0, rv);
    128 
    129   EXPECT_EQ(static_cast<mach_port_t>(MACH_PORT_NULL),
    130             broker_.TaskForPid(test_child_process.Handle()));
    131 }
    132 
    133 }  // namespace base
    134