blob: 4fabf2ae6038e1ccf986b3122372ce497b4c457b [file] [log] [blame]
Avi Drissmand387f0922022-09-14 20:51:311// Copyright 2017 The Chromium Authors
erikchen337e9da2017-06-09 17:49:452// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Arthur Sonzognid4ee5452024-07-18 21:51:545#ifdef UNSAFE_BUFFERS_BUILD
6// TODO(crbug.com/351564777): Remove this and convert code to safer constructs.
7#pragma allow_unsafe_buffers
8#endif
9
Ken Rockotdba46db2018-07-04 18:41:0410#include "mojo/core/handle_table.h"
erikchen337e9da2017-06-09 17:49:4511
12#include <memory>
13
14#include "base/synchronization/lock.h"
15#include "base/trace_event/memory_allocator_dump.h"
16#include "base/trace_event/memory_dump_request_args.h"
17#include "base/trace_event/process_memory_dump.h"
David 'Digit' Turnerea071142018-10-29 15:38:1218#include "base/trace_event/traced_value.h"
Ken Rockotdba46db2018-07-04 18:41:0419#include "mojo/core/dispatcher.h"
Hector Dearman2adfd4c2017-10-09 11:31:3520#include "testing/gmock/include/gmock/gmock.h"
erikchen337e9da2017-06-09 17:49:4521#include "testing/gtest/include/gtest/gtest.h"
22
Hector Dearman2adfd4c2017-10-09 11:31:3523using base::trace_event::MemoryAllocatorDump;
Tushar Agarwalcf74c7e82022-06-08 17:31:0224using testing::ByRef;
Hector Dearman2adfd4c2017-10-09 11:31:3525using testing::Contains;
26using testing::Eq;
Hector Dearman2adfd4c2017-10-09 11:31:3527
erikchen337e9da2017-06-09 17:49:4528namespace mojo {
Ken Rockotdba46db2018-07-04 18:41:0429namespace core {
erikchen337e9da2017-06-09 17:49:4530namespace {
31
Tushar Agarwalcf74c7e82022-06-08 17:31:0232using ::testing::IsNull;
33using ::testing::Ne;
34using ::testing::NotNull;
35using ::testing::SizeIs;
36
erikchen337e9da2017-06-09 17:49:4537class FakeMessagePipeDispatcher : public Dispatcher {
38 public:
Anand K Mistry48d93df2020-06-18 00:04:2239 FakeMessagePipeDispatcher() = default;
erikchen337e9da2017-06-09 17:49:4540
Peter Boströmfeef05a2021-10-05 21:35:0841 FakeMessagePipeDispatcher(const FakeMessagePipeDispatcher&) = delete;
42 FakeMessagePipeDispatcher& operator=(const FakeMessagePipeDispatcher&) =
43 delete;
44
erikchen337e9da2017-06-09 17:49:4545 Type GetType() const override { return Type::MESSAGE_PIPE; }
46
47 MojoResult Close() override { return MOJO_RESULT_OK; }
48
49 private:
Anand K Mistry48d93df2020-06-18 00:04:2250 ~FakeMessagePipeDispatcher() override = default;
erikchen337e9da2017-06-09 17:49:4551};
52
53void CheckNameAndValue(base::trace_event::ProcessMemoryDump* pmd,
54 const std::string& name,
Hector Dearman2adfd4c2017-10-09 11:31:3555 uint64_t value) {
erikchen337e9da2017-06-09 17:49:4556 base::trace_event::MemoryAllocatorDump* mad = pmd->GetAllocatorDump(name);
57 ASSERT_TRUE(mad);
58
Hector Dearman2adfd4c2017-10-09 11:31:3559 MemoryAllocatorDump::Entry expected(
60 "object_count", MemoryAllocatorDump::kUnitsObjects, value);
61 EXPECT_THAT(mad->entries(), Contains(Eq(ByRef(expected))));
erikchen337e9da2017-06-09 17:49:4562}
63
64} // namespace
65
Tushar Agarwalcf74c7e82022-06-08 17:31:0266TEST(HandleTableTest, GetInvalidDispatcher) {
67 HandleTable handle_table;
68 const base::AutoLock auto_lock(handle_table.GetLock());
69 EXPECT_THAT(handle_table.GetDispatcher(MojoHandle(2)), IsNull());
70}
71
72TEST(HandleTableTest, GetDispatcher) {
73 const scoped_refptr<Dispatcher> dispatcher(new FakeMessagePipeDispatcher);
74
75 HandleTable handle_table;
76 const base::AutoLock auto_lock(handle_table.GetLock());
77
78 const MojoHandle handle = handle_table.AddDispatcher(dispatcher);
79 ASSERT_THAT(handle, Ne(MOJO_HANDLE_INVALID));
80 EXPECT_THAT(handle_table.GetDispatcher(handle), Eq(dispatcher));
81}
82
83TEST(HandleTableTest, AddAndGetDispatchers) {
84 const scoped_refptr<Dispatcher> one(new FakeMessagePipeDispatcher);
85 const scoped_refptr<Dispatcher> two(new FakeMessagePipeDispatcher);
86 const scoped_refptr<Dispatcher> three(new FakeMessagePipeDispatcher);
87
88 HandleTable handle_table;
89 const base::AutoLock auto_lock(handle_table.GetLock());
90
91 const MojoHandle one_handle = handle_table.AddDispatcher(one);
92 ASSERT_THAT(one_handle, Ne(MOJO_HANDLE_INVALID));
93 EXPECT_THAT(handle_table.GetDispatcher(one_handle), Eq(one));
94
95 const MojoHandle two_handle = handle_table.AddDispatcher(two);
96 ASSERT_THAT(two_handle, Ne(MOJO_HANDLE_INVALID));
97 EXPECT_THAT(handle_table.GetDispatcher(two_handle), Eq(two));
98
99 const MojoHandle three_handle = handle_table.AddDispatcher(three);
100 ASSERT_THAT(three_handle, Ne(MOJO_HANDLE_INVALID));
101 EXPECT_THAT(handle_table.GetDispatcher(three_handle), Eq(three));
102
103 EXPECT_THAT(handle_table.GetDispatcher(one_handle), Eq(one));
104 EXPECT_THAT(handle_table.GetDispatcher(two_handle), Eq(two));
105 EXPECT_THAT(handle_table.GetDispatcher(three_handle), Eq(three));
106}
107
108TEST(HandleTableTest, GetAndRemoveInvalidDispatcher) {
109 HandleTable handle_table;
110 const base::AutoLock auto_lock(handle_table.GetLock());
111
112 scoped_refptr<Dispatcher> dispatcher;
113 EXPECT_THAT(handle_table.GetAndRemoveDispatcher(MojoHandle(2), &dispatcher),
114 Eq(MOJO_RESULT_INVALID_ARGUMENT));
115 EXPECT_THAT(dispatcher, IsNull());
116}
117
118TEST(HandleTableTest, GetAndRemoveDispatchers) {
119 const scoped_refptr<Dispatcher> one(new FakeMessagePipeDispatcher);
120 const scoped_refptr<Dispatcher> two(new FakeMessagePipeDispatcher);
121 const scoped_refptr<Dispatcher> three(new FakeMessagePipeDispatcher);
122
123 HandleTable handle_table;
124 const base::AutoLock auto_lock(handle_table.GetLock());
125
126 const MojoHandle one_handle = handle_table.AddDispatcher(one);
127 const MojoHandle two_handle = handle_table.AddDispatcher(two);
128 const MojoHandle three_handle = handle_table.AddDispatcher(three);
129 EXPECT_THAT(handle_table.GetDispatcher(one_handle), Eq(one));
130 EXPECT_THAT(handle_table.GetDispatcher(two_handle), Eq(two));
131 EXPECT_THAT(handle_table.GetDispatcher(three_handle), Eq(three));
132
133 scoped_refptr<Dispatcher> dispatcher;
134 EXPECT_THAT(handle_table.GetAndRemoveDispatcher(three_handle, &dispatcher),
135 Eq(MOJO_RESULT_OK));
136 EXPECT_THAT(dispatcher, NotNull());
137 EXPECT_THAT(handle_table.GetDispatcher(three_handle), IsNull());
138
139 dispatcher.reset();
140 EXPECT_THAT(handle_table.GetAndRemoveDispatcher(two_handle, &dispatcher),
141 Eq(MOJO_RESULT_OK));
142 EXPECT_THAT(dispatcher, NotNull());
143 EXPECT_THAT(handle_table.GetDispatcher(two_handle), IsNull());
144
145 dispatcher.reset();
146 EXPECT_THAT(handle_table.GetAndRemoveDispatcher(one_handle, &dispatcher),
147 Eq(MOJO_RESULT_OK));
148 EXPECT_THAT(dispatcher, NotNull());
149 EXPECT_THAT(handle_table.GetDispatcher(one_handle), IsNull());
150}
151
152TEST(HandleTableTest, GetAndRemoveDispatcherInTransit) {
153 const scoped_refptr<Dispatcher> one(new FakeMessagePipeDispatcher);
154 const scoped_refptr<Dispatcher> two(new FakeMessagePipeDispatcher);
155 const scoped_refptr<Dispatcher> three(new FakeMessagePipeDispatcher);
156
157 HandleTable handle_table;
158 const base::AutoLock auto_lock(handle_table.GetLock());
159
160 const MojoHandle one_handle = handle_table.AddDispatcher(one);
161 const MojoHandle two_handle = handle_table.AddDispatcher(two);
162 const MojoHandle three_handle = handle_table.AddDispatcher(three);
163 const MojoHandle handles[] = {one_handle, two_handle, three_handle};
164
165 std::vector<Dispatcher::DispatcherInTransit> dispatchers_in_transit;
166 // Leave out the last handle.
167 EXPECT_THAT(
168 handle_table.BeginTransit(handles,
169 /*num_handles=*/2, &dispatchers_in_transit),
170 Eq(MOJO_RESULT_OK));
171 EXPECT_THAT(dispatchers_in_transit, SizeIs(2));
172
173 scoped_refptr<Dispatcher> dispatcher;
174 EXPECT_THAT(handle_table.GetAndRemoveDispatcher(three_handle, &dispatcher),
175 Eq(MOJO_RESULT_OK));
176 EXPECT_THAT(dispatcher, NotNull());
177 EXPECT_THAT(handle_table.GetDispatcher(three_handle), IsNull());
178
179 dispatcher.reset();
180 EXPECT_THAT(handle_table.GetAndRemoveDispatcher(two_handle, &dispatcher),
181 Eq(MOJO_RESULT_BUSY));
182 EXPECT_THAT(dispatcher, IsNull());
183 EXPECT_THAT(handle_table.GetDispatcher(two_handle), NotNull());
184
185 dispatcher.reset();
186 EXPECT_THAT(handle_table.GetAndRemoveDispatcher(one_handle, &dispatcher),
187 Eq(MOJO_RESULT_BUSY));
188 EXPECT_THAT(dispatcher, IsNull());
189 EXPECT_THAT(handle_table.GetDispatcher(one_handle), NotNull());
190}
191
192TEST(HandleTableTest, InvalidExtraBeginTransit) {
193 const scoped_refptr<Dispatcher> one(new FakeMessagePipeDispatcher);
194 const scoped_refptr<Dispatcher> two(new FakeMessagePipeDispatcher);
195 const scoped_refptr<Dispatcher> three(new FakeMessagePipeDispatcher);
196
197 HandleTable handle_table;
198 const base::AutoLock auto_lock(handle_table.GetLock());
199
200 const MojoHandle one_handle = handle_table.AddDispatcher(one);
201 const MojoHandle two_handle = handle_table.AddDispatcher(two);
202 const MojoHandle three_handle = handle_table.AddDispatcher(three);
203 const MojoHandle handles[] = {one_handle, two_handle, three_handle};
204
205 std::vector<Dispatcher::DispatcherInTransit> dispatchers_in_transit;
206 // Leave out the first handle.
207 EXPECT_THAT(
208 handle_table.BeginTransit(handles + 1,
209 /*num_handles=*/2, &dispatchers_in_transit),
210 Eq(MOJO_RESULT_OK));
211 EXPECT_THAT(dispatchers_in_transit, SizeIs(2));
212
213 dispatchers_in_transit.clear();
214 EXPECT_THAT(
215 handle_table.BeginTransit(handles,
216 /*num_handles=*/3, &dispatchers_in_transit),
217 Eq(MOJO_RESULT_BUSY));
218 EXPECT_THAT(dispatchers_in_transit, SizeIs(1));
219}
220
221TEST(HandleTableTest, CompleteTransitAndClose) {
222 const scoped_refptr<Dispatcher> one(new FakeMessagePipeDispatcher);
223 const scoped_refptr<Dispatcher> two(new FakeMessagePipeDispatcher);
224 const scoped_refptr<Dispatcher> three(new FakeMessagePipeDispatcher);
225
226 HandleTable handle_table;
227 const base::AutoLock auto_lock(handle_table.GetLock());
228
229 const MojoHandle one_handle = handle_table.AddDispatcher(one);
230 const MojoHandle two_handle = handle_table.AddDispatcher(two);
231 const MojoHandle three_handle = handle_table.AddDispatcher(three);
232 const MojoHandle handles[] = {one_handle, two_handle, three_handle};
233
234 std::vector<Dispatcher::DispatcherInTransit> dispatchers_in_transit;
235 EXPECT_THAT(
236 handle_table.BeginTransit(handles,
237 /*num_handles=*/3, &dispatchers_in_transit),
238 Eq(MOJO_RESULT_OK));
239 EXPECT_THAT(dispatchers_in_transit, SizeIs(3));
240
241 handle_table.CompleteTransitAndClose(dispatchers_in_transit);
242 EXPECT_THAT(handle_table.GetDispatcher(three_handle), IsNull());
243 EXPECT_THAT(handle_table.GetDispatcher(two_handle), IsNull());
244 EXPECT_THAT(handle_table.GetDispatcher(one_handle), IsNull());
245}
246
247TEST(HandleTableTest, CancelTransit) {
248 const scoped_refptr<Dispatcher> one(new FakeMessagePipeDispatcher);
249 const scoped_refptr<Dispatcher> two(new FakeMessagePipeDispatcher);
250 const scoped_refptr<Dispatcher> three(new FakeMessagePipeDispatcher);
251
252 HandleTable handle_table;
253 const base::AutoLock auto_lock(handle_table.GetLock());
254
255 const MojoHandle one_handle = handle_table.AddDispatcher(one);
256 const MojoHandle two_handle = handle_table.AddDispatcher(two);
257 const MojoHandle three_handle = handle_table.AddDispatcher(three);
258 const MojoHandle handles[] = {one_handle, two_handle, three_handle};
259
260 std::vector<Dispatcher::DispatcherInTransit> dispatchers_in_transit;
261 EXPECT_THAT(
262 handle_table.BeginTransit(handles,
263 /*num_handles=*/3, &dispatchers_in_transit),
264 Eq(MOJO_RESULT_OK));
265 EXPECT_THAT(dispatchers_in_transit, SizeIs(3));
266
267 handle_table.CancelTransit(dispatchers_in_transit);
268
269 scoped_refptr<Dispatcher> dispatcher;
270 EXPECT_THAT(handle_table.GetAndRemoveDispatcher(three_handle, &dispatcher),
271 Eq(MOJO_RESULT_OK));
272 EXPECT_THAT(dispatcher, NotNull());
273 EXPECT_THAT(handle_table.GetDispatcher(three_handle), IsNull());
274
275 dispatcher.reset();
276 EXPECT_THAT(handle_table.GetAndRemoveDispatcher(two_handle, &dispatcher),
277 Eq(MOJO_RESULT_OK));
278 EXPECT_THAT(dispatcher, NotNull());
279 EXPECT_THAT(handle_table.GetDispatcher(two_handle), IsNull());
280
281 dispatcher.reset();
282 EXPECT_THAT(handle_table.GetAndRemoveDispatcher(one_handle, &dispatcher),
283 Eq(MOJO_RESULT_OK));
284 EXPECT_THAT(dispatcher, NotNull());
285 EXPECT_THAT(handle_table.GetDispatcher(one_handle), IsNull());
286}
287
erikchen337e9da2017-06-09 17:49:45288TEST(HandleTableTest, OnMemoryDump) {
289 HandleTable ht;
290
291 {
292 base::AutoLock auto_lock(ht.GetLock());
Ken Rockotdba46db2018-07-04 18:41:04293 scoped_refptr<Dispatcher> dispatcher(new FakeMessagePipeDispatcher);
erikchen337e9da2017-06-09 17:49:45294 ht.AddDispatcher(dispatcher);
295 }
296
erikchen30661e12017-06-09 21:56:03297 base::trace_event::MemoryDumpArgs args = {
Ho Cheungadbf3fb2023-09-08 02:01:11298 base::trace_event::MemoryDumpLevelOfDetail::kDetailed};
erikchenf62ea042018-05-25 21:30:57299 base::trace_event::ProcessMemoryDump pmd(args);
erikchen337e9da2017-06-09 17:49:45300 ht.OnMemoryDump(args, &pmd);
301
Hector Dearman2adfd4c2017-10-09 11:31:35302 CheckNameAndValue(&pmd, "mojo/message_pipe", 1);
303 CheckNameAndValue(&pmd, "mojo/data_pipe_consumer", 0);
erikchen337e9da2017-06-09 17:49:45304}
305
Ken Rockotdba46db2018-07-04 18:41:04306} // namespace core
erikchen337e9da2017-06-09 17:49:45307} // namespace mojo