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:
MachPortBrokerTest()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 }
~MachPortBrokerTest()31 ~MachPortBrokerTest() override {
32 broker_.RemoveObserver(this);
33 }
34
35 // Helper function to acquire/release locks and call |PlaceholderForPid()|.
AddPlaceholderForPid(base::ProcessHandle pid)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()|.
FinalizePid(base::ProcessHandle pid,mach_port_t task_port)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
WaitForTaskPort()48 void WaitForTaskPort() {
49 event_.Wait();
50 }
51
52 // base::PortProvider::Observer:
OnReceivedTaskPort(ProcessHandle process)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
TEST_F(MachPortBrokerTest,Locks)64 TEST_F(MachPortBrokerTest, Locks) {
65 // Acquire and release the locks. Nothing bad should happen.
66 base::AutoLock lock(broker_.GetLock());
67 }
68
TEST_F(MachPortBrokerTest,AddPlaceholderAndFinalize)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
TEST_F(MachPortBrokerTest,FinalizeUnknownPid)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
MULTIPROCESS_TEST_MAIN(MachPortBrokerTestChild)88 MULTIPROCESS_TEST_MAIN(MachPortBrokerTestChild) {
89 CHECK(base::MachPortBroker::ChildSendTaskPortToParent(kBootstrapPortName));
90 return 0;
91 }
92
TEST_F(MachPortBrokerTest,ReceivePortFromChild)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
TEST_F(MachPortBrokerTest,ReceivePortFromChildWithoutAdding)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